Lore
OfficialProvides persistent AI memory backed by Notion, storing and retrieving conversations, decisions, follow-up tasks, durable relationships, and facts as Notion pages across Projects, Topics, Memories, Entities, and Facts databases.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Loresave our decision to use Postgres for the analytics service"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Kennen
AI memory backed by Notion.
This project started as a fork of makenotion/lore and is now maintained independently by PassionFactory Corp. It is not affiliated with or endorsed by Notion Labs, Inc.
Kennen gives your AI assistants a persistent, shared memory: it stores
conversations, decisions, follow-up tasks, and durable relationships as Notion
pages that any teammate or agent session can read back. Anything you use with
the Model Context Protocol (Claude Code,
Codex, Cursor, OMP, and other MCP hosts) can recall, save, and reason over the
same vault, so context survives /clear, new branches, and handoffs between
people.
Under the hood, Kennen organizes a vault into five core Notion databases: Projects, Topics, Memories, Entities (canonical-handle resolution), and Facts. The same domain services power three surfaces: an MCP server for AI assistants, a CLI for humans, and hook commands that wire automatic context loading and session saving into supported hosts.
Quick Start
1. Install Kennen
Install from npm (recommended)
npm install -g @amond-ai/kennen
# or
npm install -D @amond-ai/kennenPublic npm requires no registry configuration or package token.
Build from source
git clone https://github.com/amond-ai/kennen.git
cd kennen && mise install && bun install && bun run build && npm linkmise installs the pinned Node.js and Bun versions.
npm link makes kennen available globally on your PATH from the clone.
Run kennen --version to confirm either installation route, then continue with
step 2 below.
For project-local installs, run npx kennen <command> from inside the project
or add a kennen script to package.json. See
docs/dev-dependency-install.md for the
Yarn PnP wiring and path-portable setup teams use to share assistant config
across a repo.
2. Join an Existing Shared Vault
Most operators should join an already initialized shared vault. A Kennen vault is
a Notion page that already contains the five databases (Projects, Topics,
Memories, Entities, Facts). Joining that vault means pointing your local
.kennen.yaml at the shared vault.pageId; do not run database initialization
against a shared page that your team lead has already bootstrapped.
.kennen.yaml is local-only. Keep it out of version control, and distribute
shared values such as vault.pageId through onboarding docs instead of
committing config. This is the current policy even for credential-free shared
vault config and supersedes older changelog notes that allowed intentional
committed config.
Notion page IDs are access locators, not bearer credentials: knowing a page ID
does not grant access unless the caller's Notion token can already read that
page. Even so, keep vault.pageId out of version control so external clones of
a public repo don't auto-target a maintainer's vault. If a personal or
accidental page ID lands in git history, scrub the working tree and decide with
the page owner whether to replace the page or rewrite history.
Internal Notion engineer + shared vault
Use Kennen's ntn-backed auth flow. It auto-installs ntn when needed, runs
ntn login, and stores the per-user token where Kennen can read it.
# Join by pointing local config at the initialized shared vault.
# Do not run database initialization against an existing shared vault.
cat > .kennen.yaml <<'YAML'
vault:
pageId: "<shared-vault-page-id>"
YAML
kennen auth --login
kennen auth --status
kennen statusExternal operator + shared vault
Create a Notion Personal Access Token at notion.so/developers/tokens, then
use it through the canonical Notion SDK environment variable. Do not use
secret_ integration tokens from notion.so/profile/integrations for team
rollout; they share one rate-limit bucket across every operator using the same
integration. Persist NOTION_API_TOKEN in your shell profile or assistant host
environment before running kennen install and restarting your assistant.
export NOTION_API_TOKEN="<notion-pat>"
# Join by pointing local config at the initialized shared vault.
# Do not run database initialization against an existing shared vault.
cat > .kennen.yaml <<'YAML'
vault:
pageId: "<shared-vault-page-id>"
YAML
kennen auth --status
kennen statusThe last two commands verify that Kennen can resolve auth and read the vault. After they pass, configure your assistant in step 3. Restart or reconnect the assistant after install or config changes so it reloads the MCP server and hooks.
Token resolution order is NOTION_API_TOKEN -> ntn-resolved auth.json.
The first source available wins. See
docs/authentication.md for the full priority chain,
multi-workspace selection, and troubleshooting.
If setup is broken and the next command is unclear, run kennen doctor from the
project. It performs read-only checks across config discovery, auth, vault
access, MCP host config, hooks, and recent background hook failures, then ends
with one prioritized next action.
3. Configure Your Assistant
# Internal ntn path:
kennen install --ntn
# External PAT path, after exporting NOTION_API_TOKEN:
kennen installBoth install paths configure every supported assistant integration
(--client all, including OMP) and fill in any missing side from an older
install. Use --client to install only one. Keep --ntn on client-scoped
commands when using the internal ntn path; omit it for the PAT path after
exporting NOTION_API_TOKEN:
kennen install --ntn --client claude
kennen install --ntn --client codex
kennen install --ntn --client cursor
kennen install --ntn --client omp
kennen install --ntn --client cursor --cursor-globalclaude: writes Claude Code settings plus.mcp.jsoncodex: writes.codex/config.tomlplus.codex/hooks.jsoncursor: writes<projectDir>/.cursor/mcp.json(--cursor-globalopts into~/.cursor/mcp.json)omp: writes the project.omp/mcp.json
OMP's native .omp/mcp.json takes precedence over a root .mcp.json for OMP
discovery. OMP receives Kennen's MCP tools without Claude/Codex lifecycle hooks;
restart OMP or run /mcp reload after installing or changing its config.
Codex only loads project-scoped .codex/* files for trusted projects.
Cursor's MCP runtime doesn't currently support session-end / Stop hooks, so the Cursor installer only writes the MCP entry; the Stop-triggered autosave and the detached auto-digest spawn run only under Claude Code or Codex. Recall / save / scan paths work identically across Claude Code, Codex, Cursor, and OMP.
Claude Code plugin
Claude Code users can install Kennen as a plugin instead of running
kennen install --client claude. The plugin provides the Kennen MCP server, the
wake-up (UserPromptSubmit) and autosave (Stop) hooks, and a kennen-memory
skill. It still runs the kennen CLI, so install Kennen (step 1) and join a vault
(step 2) first.
claude plugin marketplace add amond-ai/kennen
claude plugin install kennen@kennen --scope projectThe plugin starts
kennenfrom the Claude Code project directory, and both the MCP server and the hooks find.kennen.yamlby searching upward from there. A project-localnode_modules/.bin/kennen, in the project or any parent directory, takes precedence over a global one. In a Yarn PnP project the plugin runsyarn run -T kenneninstead.The hooks do nothing in projects without a
.kennen.yaml. The MCP server still starts there in diagnostic mode and reports how to set up a vault.Use either the plugin or
kennen install --client claudein a project, not both. With both installed, every hook runs twice and Claude Code loads two Kennen MCP servers. The plugin's tools are namedmcp__plugin_kennen_kennen__<tool>.The plugin launcher needs a POSIX
sh.
Other MCP Hosts
For agents not directly supported by kennen install --client, run
kennen install --print-config json or kennen install --print-config toml and
paste the emitted MCP server snippet into the host's config file. See
docs/mcp-hosts.md for host notes and hook limitations.
OMP is already supported natively; do not use --print-config for OMP.
Restart or reconnect your assistant after kennen install or manual host config
changes so it reloads the MCP server. For OMP, /mcp reload is also available;
OMP does not install Kennen lifecycle hooks.
4. Advanced and Maintenance Flows
Team-lead / first-time shared-vault bootstrap
Use this path only when you are creating the shared vault databases for the first time. Pick or create the Notion page your team will share, make sure your auth source can write to it, then run:
kennen init <page-id>That command creates the five databases inside the page (Projects, Topics,
Memories, Entities, Facts) and writes your local .kennen.yaml. Operators who
join the initialized vault later should use step 2 instead of running
initialization again.
See docs/team-rollout.md for the per-engineer
onboarding flow and team-lead runbook.
Personal or Scratch Vault Creation
For personal vaults or fresh-onboarding scratch use, the no-arg flow creates a
workspace-level page on your behalf using the active auth source. If no auth
resolves, it auto-installs ntn, runs ntn login, and then writes
.kennen.yaml:
kennen init # default title: "Kennen Vault - <basename(cwd)>"
kennen init --name "Kennen Vault Widget" # explicit titleFor direct non-ntn setup, create a Notion Personal Access Token at
notion.so/developers/tokens, set the canonical Notion SDK env var, and make
sure the operator's Notion account can access the vault page before
bootstrapping a new vault:
export NOTION_API_TOKEN="<notion-pat>"Dev-Environment Setup
Use the dev environment only when you intentionally want a dev-environment vault:
kennen init --ntn-env devIf your existing ntn auth points at a different environment than --ntn-env,
Kennen exits 1 with recovery copy (typically
ntn logout && NOTION_KEYRING=0 NOTION_ENV=<env> ntn login) rather than
silently creating a vault in the wrong environment.
To run ntn yourself, set NOTION_KEYRING=0 before logging in. ntn defaults
to macOS Keychain storage, which Kennen does not read; the env var forces
file-mode storage at ~/.config/notion/auth.json:
NOTION_KEYRING=0 ntn loginKennen reads the resulting auth.json automatically. See
docs/team-rollout.md#known-gotcha-direct-ntn-login-outside-kennen
for the persistent shell-rc setup if you use ntn for other tooling too.
Refresh Auth for an Existing Vault
Once your local .kennen.yaml points at a configured vault, refresh ntn auth
and preflight access with:
kennen auth --loginAny auth.token value in .kennen.yaml is rejected at config load time. Use
NOTION_API_TOKEN for Personal Access Tokens or kennen auth --login for ntn
auth.
Legacy Four-Database Vault Migration
Vaults created before the Entities database was introduced need one
bootstrap step before the entity backfill: run
kennen vault ensure-entities, then run
kennen migrate --build-entities --allow-unscoped to preview the vault-wide
backfill and kennen migrate --build-entities --allow-unscoped --yes in a quiet
window to canonicalize the fact graph. Use --project <name> in both commands
for a project-scoped pass.
5. Teach Your Agents to Use Kennen
kennen install wires the MCP server and hooks into the assistant host, but
agents still need repo-local instructions that tell them to prefer the shared
Kennen vault for team knowledge. Add a "Memory and note-taking" section to the
root AGENTS.md and, when the repo uses Claude Code, mirror it in
CLAUDE.md or another host-specific instruction file.
A minimal starter:
### Memory and note-taking
- Use Kennen for cross-session and cross-team knowledge. Kennen stores memories,
facts, decisions, and tasks in the shared vault, so every team member and
agent session benefits. Prefer Kennen over file-based memory for anything the
team should know.
- Use file-based memory only for personal preferences or local-only context
that should not be shared.
- At session start, call `kennen-context` with `action: "wake-up"` to load recent
project context when the tool is available.
- In Codex, automatic wake-up ranks against the first prompt. After `/clear` or
a major topic pivot, call `kennen-context` again with `action: "wake-up"` and
`userQuery` set to the new task prompt.
- Save non-obvious discoveries with `kennen-memory` and `action: "save"`.
- Record architectural decisions with `kennen-decision` and `action: "create"`.
- Record durable component relationships with `kennen-fact` and
`action: "create"` after saving a supporting memory; pass
`sourceMemoryId`, or pass `agent` + `session` so Kennen can auto-link the
fact to the earlier memory in the same process.
- Track follow-up work with `kennen-task` and `action: "create"`; close tasks
with `action: "close"` as soon as the work is done or cancelled.Adapt the snippet to the repo. For example, if Kennen is installed as a Yarn PnP
devDependency, tell agents to run CLI commands as
yarn run -T kennen <subcommand> while still calling MCP tools by their normal
kennen-* names.
Related MCP server: Memorium
Data Model
A vault is a Notion page containing five core databases:
Database | Title Property | Key Properties | Relations |
Projects | Name | Type (project/person/agent), Path, Status, Description | -- |
Topics | Name | Description | Project |
Memories | Title | Source, Author, Agent, Tags, Session + page body | Project, Topic |
Entities | Name | Aliases, Kind, Description | Project, Source (Memory) |
Facts | Subject | Predicate, Object, Valid From, Valid Until, Confidence | Project, Source (Memory), SubjectEntity, ObjectEntity |
kennen init creates all five databases on a new vault. Vaults created
before the Entities database was introduced only have four (no Entities);
they need a one-time legacy migration via kennen vault ensure-entities to
create the Entities database and add the SubjectEntity / ObjectEntity
relation columns to Facts. Plan/apply the vault-wide backfill with
kennen migrate --build-entities --allow-unscoped and
kennen migrate --build-entities --allow-unscoped --yes, or use
--project <name> in both commands for a project-scoped pass, to fill
historical rows that do not already have relation values. See
docs/team-rollout.md#entities-database-cutover.
Predicate values accepted by kennen-fact action='create' are profile-aware.
Generic predicates is_a, has_a, and related_to are always available; the
active profile contributes the rest of the agent-writable predicate set. The
default profile currently adds uses, depends_on, created_by, owned_by,
replaces, extends, and conflicts_with, while other profiles can expose
different domain-specific predicates. See
docs/profiles.md#taxonomy-contract and
the active profile taxonomy for the writable set in a given vault.
System-managed predicates are decided_by, supersedes_decision, informs
(kennen-decision action='create' / supersede) and mentions
(kennen-memory action='save'). Historical tracking predicates (needs_action,
waiting_on, blocked_by) are legacy row values only; use
kennen-task action='create' for tracked work.
Fact confidence (categorical): certain, likely, speculative. This is
the agent-writable stance on Facts. The separate numeric Facts Confidence Score column is system-managed: read citations raise it,
contradiction/supersession signals lower it, and neglect decay reduces untouched
facts over time. Do not try to write the numeric score through MCP inputs.
Memory sources: new writes accept conversation, autosave_learning,
file, manual, and digest. agent_diary is retained for historical rows
and explicit audit recall only.
Memory kinds: note, decision, incident, runbook, postmortem,
policy, task, procedure. Procedures are reviewed governance memory:
propose them through kennen-procedure action='propose', then approve or reject
them through kennen-memory action='approve' /
kennen-memory action='reject'. kennen-memory action='save' does not create
kind: "procedure" rows.
Memory statuses: informational, proposed, accepted, superseded, deprecated, rejected
Topic keys
Recurring non-procedure memory topics (decision, runbook, incident,
postmortem, and policy) can pass topicKey to
kennen-memory action='save'. Rows upsert by (Topic Key + exact Project relation set): a matching row gets a revision appended and its Revision Count
incremented instead of creating a new memory. Use stable prefixes matching those
save families: decision/, runbook/, incident/, postmortem/, and
policy/. Procedure topic keys use the procedure/ family, but they are
supplied to kennen-procedure action='propose' for proposal idempotency and
conflict detection rather than to kennen-memory action='save' for revision
chains. Only the non-procedure save families form kennen-memory revision chains;
note and task kinds do not form revision chains. Use
kennen-memory action='suggest-topic-key' to derive a key, and see
docs/memory-workflows.md for
promotion and re-keying rules.
Save digests regularly (kennen-context action='digest' → synthesize →
kennen-memory action='save' with source: "digest"). When a digest from the
last 7 days exists, kennen-context action='wake-up' surfaces it at the top and
trims the raw-memory list underneath — a denser, lower-token starting point
than a long stream of individual memories.
MCP Tools
Kennen exposes a small set of polymorphic tools, each multiplexing several
actions behind one MCP registration. The prior single-purpose tool names and
task aliases were removed in the 0.6.0 deprecation purge. See
docs/mcp-tools.md for the current tool list, action
reference, and task/fact migration notes.
CLI Commands
Core commands:
kennen init [page-id]creates vault databases and writes.kennen.yaml.kennen installwrites assistant MCP config and supported hooks; add--ntnto select the internal ntn bootstrap path.kennen auth --loginrefreshes ntn auth and verifies vault access.kennen doctordiagnoses setup health and prints the next repair action.kennen search <query>searches memories.kennen memory save <title>saves a manual memory from the shell.kennen decision create <statement>records a decision with rationale.kennen ask <entity>queries facts and tasks about an entity.kennen statusreports vault health and active project resolution.kennen costs summarysummarizes the opt-in local cost ledger.kennen migrateruns schema and one-shot data migrations.kennen entities merge --from <loser-id> --into <winner-id>previews or applies duplicate Entity merges.kennen conflicts scansurfaces read-only conflict candidates for agent judgment.
See docs/cli.md for a compact CLI command overview. See
docs/conflict-detection.md for conflict verdict
rules, scan caps, and the repeat-until-clean workflow.
Hooks
Kennen installs hook commands for supported AI coding assistants:
Auto-save (
kennen hooks autosave) runs on assistantStopand saves the session after enough user messages.Wake-up (
kennen hooks wakeup) loads the latest digest, recent memories, active facts, and task-matched context before the first response.
Claude Code and Codex installs wire hooks automatically using bin dispatch
(kennen hooks ..., or yarn run -T kennen hooks ... under Yarn PnP). The
hooks/autosave.sh and hooks/wakeup.sh scripts are compatibility
entrypoints for older absolute-path installs. Cursor and --print-config
hosts only get the MCP tool surface.
See docs/hooks.md for host timing, auth forwarding, auto-digest
behavior, and compatibility notes.
Configuration
Kennen is configured via .kennen.yaml. The file is located by searching upward
from the current working directory.
.kennen.yaml is local-only — keep it out of version control. Copy
.kennen.example.yaml to .kennen.yaml and fill in your values, or run
kennen init to generate one. Distribute shared team values (vault.pageId,
auth.workspaceId) through your onboarding docs rather than committing config;
even credential-free shared vault config stays outside git under the current
policy. Never put auth.token, personal scratch vault page IDs, or personally
identifying values in the file.
Threat-model posture for vault.pageId: a Notion page ID is not a credential,
and exposing one does not bypass Notion permissions. Even so, keep page IDs out
of git so external clones of a public repo don't auto-target an unrelated
vault. A page ID that lands in history by accident should be removed from the
working tree; history rewrite or page replacement is only needed when the owner
considers the page location itself sensitive.
# Required: Notion page ID containing the vault databases
vault:
pageId: "<shared-team-vault-page-id>"
# Optional: workspace selector for multi-workspace ntn auth.json setups
# auth:
# workspaceId: "workspace-id"
#
# Optional: read-only inherited vaults and deliberate promotion destinations.
# Normal save/update tools still write only to vault.pageId.
# upstreamVaults:
# - name: "Engineering"
# pageId: "engineering-vault-id"
# priority: 10
# promotionTargets:
# - name: "Team"
# pageId: "team-vault-id"
# requireReview: true
# Map directories to named projects (for monorepo support)
projects:
- name: "Server"
path: "src/server"
tags: ["backend"]
- name: "Client"
path: "src/client"
tags: ["frontend"]
# Auto-detect projects from workspace patterns
# detect:
# patterns: ["packages/*/package.json"]
# exclude: ["node_modules"]
# Hook behavior
hooks:
autoSave: true
# Inject digest, memories, tasks, active facts, and decisions at session start.
# Set to false to skip the context injection (reduces prompt overhead
# and the Notion round-trip at session start).
wakeUp: true
saveInterval: 5 # save after every 5 user messagesToken resolution order: NOTION_API_TOKEN environment variable, then
ntn-resolved ~/.config/notion/auth.json. The first available source wins.
Any auth.token value in .kennen.yaml is rejected at config load time; move
credentials to NOTION_API_TOKEN or ntn auth. Multi-workspace ntn setups
select a workspace with NOTION_WORKSPACE_ID or auth.workspaceId.
Notion rate limits are per token. ntn-issued tokens and PATs give each
operator an independent bucket; distributing one shared secret_ integration
token through NOTION_API_TOKEN collapses everyone onto one bucket. See
AGENTS.md for the operational rationale, and
src/auth/AGENTS.md for the priority chain
implementation, ntn version policy, and keychain-mode workaround.
Environment variables
Variable | Effect |
| Canonical Notion bearer token env var for Personal Access Tokens. Takes precedence over ntn |
| Selects a workspace from a multi-workspace ntn |
| Override the |
| Override the |
| Suppress the Stop-triggered auto-digest scheduler (CLI |
| Skip OSC 8 clickable hyperlinks in |
| Honored alongside |
Monorepo Support
Projects map directories to named scopes using the projects array in
.kennen.yaml. Kennen resolves the current project from your working directory
using longest-prefix matching.
Given this config:
projects:
- name: "Root"
path: "."
- name: "Server"
path: "src/server"
- name: "Auth"
path: "src/server/auth"Running from src/server/auth/middleware resolves to the "Auth" project.
Memories, facts, and searches are automatically scoped to the matched project.
Development
Prerequisites: mise (pins Node.js and Bun via mise.toml)
mise install # Install the pinned Node.js and Bun
bun install # Install dependencies and the husky Git hooks
bun run build # Build with tsup (ESM, 4 entry points)
bun run typecheck # Type-check with tsc --noEmit
bun run lint # Lint with eslint
bun run lint:fix # Lint and auto-fix
bun run format # Format with prettier
bun run format:check # Check prettier formatting
bun run test # Run tests with vitest
bun run dev # Watch mode (tsup --watch)See CONTRIBUTING.md, AGENTS.md, and the
subsystem guides under src/*/AGENTS.md for contributor conventions,
architecture notes, and the non-negotiable stability rules. If you are changing
anything under .github/workflows/, read docs/ci.md first —
it documents the fork-safety contract every workflow must keep.
Changelog
Notable user-facing changes are recorded in CHANGELOG.md.
License
MIT. Copyright (c) 2026 PassionFactory Corp. Portions derived from makenotion/lore remain Copyright (c) 2026 Notion Labs, Inc. and are used under the same MIT License.
This server cannot be deployed
Maintenance
Related MCP Connectors
- mcpOAuthai.butlerbrain
Persistent memory for AI assistants. Save once; recall from Claude, ChatGPT, or any MCP client.
Persistent personal memory for AI assistants — save, search, and recall across every MCP client.
- JustOnceOAuthai.justonce
Persistent memory for AI assistants — one shared, OAuth-secured vault for every MCP client.
Persistent memory for AI agents across Claude, ChatGPT and any MCP client.
Related MCP Servers
AlicenseNot gradedqualityBmaintenanceEnables persistent memory storage and retrieval for MCP clients, allowing AI assistants to remember facts and context across conversations.17 npmMIT- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to have persistent long-term memory by automatically storing and retrieving important information via MCP tools.MIT
- AlicenseAqualityBmaintenanceProvides a shared, persistent memory layer for AI assistants, letting them read and write to a local Obsidian vault through MCP with validation, secret rejection, and deduplication.8Apache 2.0
- AlicenseNot gradedqualityAmaintenanceProvides persistent, shared memory for AI agents via MCP, enabling retrieval of relevant memories instead of loading entire context. Allows agents across projects, machines, and tools to share a single auditable, markdown-native brain.3AGPL 3.0