| name | seed-memory |
| description | Seed Kai's memory on a fresh local install — infer who the user is and what the project(s) are from the workspace + git (single repo or a multi-repo parent dir), ask only what can't be inferred, and commit durable facts via the memory tool so future sessions start with context instead of a blank slate |
| version | 1.1.0 |
| author | kai-agent |
| metadata | {"kai":{"tags":["kai","onboarding","memory","local","setup","first-run"]}} |
Seed Memory
You're running locally (self-host) and your memory is empty. This is the one-time
pass that gives every future session a head start: who the user is, what they're
working on, and how they like to work — committed to memory so you never have to
re-ask.
This is local-mode onboarding. There is no Kai backend, no GitHub MCP, no
kai_* tools. Your sources of truth are the local workspace (via the terminal)
and a short interview. Your write path is the memory tool — nothing else.
The Rules
- Infer first, ask last. Most of what belongs in memory is already on disk —
the stack, the layout, the conventions, the user's name and email (git config).
Read those silently. Only ask for what you genuinely cannot observe: the
user's role, their goals for this codebase, and their working preferences.
- One short interview, not an interrogation. A handful of questions, asked
together, once. If the user skips them, seed what you inferred and move on.
- Memory is the
memory tool, not files. You commit facts with
memory(action="remember", content="…"). Do not hand-write
MEMORY.md/USER.md — there is no such snapshot here; the memory tool files
each fact into the right bank (user / project / topic) on its own.
- One fact per
remember call. Short, declarative, durable. "Prefers
conventional commits and squash-merges" — not a paragraph, not a transcript.
- Durable, not ephemeral. Seed facts that stay true across sessions (who,
what, how). Never seed today's task, a transient error, or anything secret
(keys, tokens,
.env contents — the tool will block these anyway).
- Don't narrate the scan. The user sees the intro and the interview, then a
short recap at the end. Not a play-by-play of every file you read.
Phase 1: Intro + interview (1 message)
Send one message. Introduce the pass in a sentence, then ask only the
inference-resistant questions. Keep it to ~4 questions, batched:
I'm setting up my memory for this workspace so future sessions start with
context. I've read what's on disk — a few things I can't tell from the code:
- What's your role here (and what should I call you)?
- What are you trying to get done in this codebase over the next while?
- Any working preferences I should hold to (commit style, test bar, what to
never touch, when to ask vs. just do it)?
- Anything about the project that isn't obvious from the files?
Then start Phase 2 immediately — don't wait. If they answer, fold it in. If they
don't, seed what you inferred.
Phase 2: Scan the workspace (silent)
Use the terminal. Read fast, record signals, don't dump. You're after three
things: the project, the conventions, and the user's identity.
First, detect the workspace shape. The cwd is either one repo or a parent
directory of many (e.g. ~/Development, a monorepo-of-repos). Check before you
assume single-project:
git rev-parse --is-inside-work-tree 2>/dev/null && echo "single repo"
ls -d */.git 2>/dev/null | wc -l
- Single repo → scan it directly (below) and seed one project.
- Multi-repo workspace → loop the child repos and capture the same per-repo
signals for each (name, language, conventions, owner, recency). Seed one fact
per repo, plus one workspace-overview fact (how many repos, the shared
stack, who owns what). Don't flatten ten repos into a single vague note. Cap at
the ~15 most recently active (
git -C <repo> log -1 --format=%ct) if there are
many; say so in the overview rather than silently dropping the rest.
The per-repo capture is identical either way:
Identity (cheap, high-value):
git config user.name; git config user.email
git log --no-merges -20 --format='%an' | sort | uniq -c | sort -rn
Project shape:
README*, CONTRIBUTING*, CODEOWNERS, LICENSE
- Manifests:
package.json / pyproject.toml / go.mod / Cargo.toml /
Gemfile / pom.xml / composer.json — name, language, key deps, scripts.
- Top-level layout (
ls, a shallow tree) — services, packages, entrypoints.
- Containerization / CI / infra:
Dockerfile*, docker-compose*,
.github/workflows/*, vercel.json, modal.toml, Terraform.
Conventions — how the team works (this is what makes future PRs feel native):
- Formatter/linter:
.prettierrc*, biome.json, .editorconfig,
[tool.ruff]/[tool.black] in pyproject.toml, .eslintrc*,
.golangci.yml. Record the actual tool(s).
- Test framework: infer from manifests (pytest / vitest / jest / go test /
cargo test) and a tests/ or __tests__/ dir. Note how to run them.
- Commit style: count Conventional-Commits prefixes in the last 50 subjects —
git log --no-merges -50 --format='%s' → if ≥60% start with
feat:/fix:/chore:/docs:/refactor:/test:/ci:/build:/perf:,
the team uses Conventional Commits; else "freeform".
- Branch/merge culture (best-effort):
git branch -a, and from
git log --merges -20 whether history is squashed or preserved.
Skip what isn't there. Record what's clearly true. Move on.
Phase 3: Commit the seed (the memory tool)
Now turn the signals into durable memory. One fact per call,
memory(action="remember", content="…"). The tool routes each into the right
bank — you don't pick the file.
Seed across these four groups (only what you actually established):
User — identity and preferences:
memory(action="remember", content="User is <name> (<email>), <role>. Call them <preferred name>.")
memory(action="remember", content="User's goal in this workspace: <goal in their words>.")
memory(action="remember", content="Working preference: <e.g. confirm before paid/destructive actions; analyze freely>.")
Project — what this codebase is:
memory(action="remember", content="Project <name>: <one-line what-it-is>. Primary language <lang>, <framework/runtime>. Entrypoint(s): <…>.")
memory(action="remember", content="<name> layout: <services/packages and what each does>.")
Conventions — how to work here:
memory(action="remember", content="<name> uses <formatter> + <test framework>; run tests with `<command>`.")
memory(action="remember", content="<name> commit style: <Conventional Commits | freeform>; merges are <squash | merge-commit | rebase>.")
memory(action="remember", content="In <name>, never touch <files/dirs the user flagged>; <area> needs care because <reason>.")
Multi-repo workspaces — when the cwd holds many repos, seed one fact per repo
(fold its language + conventions + owner into a single line) plus one overview:
memory(action="remember", content="Workspace <dir> holds <N> repos; mostly <stack>. Active: <repo-a>, <repo-b>, <repo-c>.")
memory(action="remember", content="Repo <repo-a> (<lang>): <one-line>. Conventional Commits, <formatter>, tests in <dir>. Primary owner <name>.")
memory(action="remember", content="Repo <repo-b> (<lang>): <one-line>. Freeform commits, no formatter. Primary owner <name>.")
Real example of the per-repo signals to fold in (captured from a 12-repo tree):
kai-agent — Python+JS/TS, 40/40 conventional commits, tests/, owner you;
kai-backend — JS/TS, biome, 22/40 conventional, owner fatihbugrakdogan;
openevolve — Python, ruff/black, freeform commits, owner Asankhaya Sharma.
Constraints — anything the user called out that should always hold.
Rules for good seeds: declarative, present-tense, self-contained (won't be
ambiguous read cold in three weeks), and free of secrets. If a fact is uncertain,
don't seed it — a wrong memory is worse than a missing one.
Phase 4: Confirm (1 message)
Verify the seed took and show the user what you'll carry forward. Run a quick
recall to prove it's queryable, then recap in one short message:
memory(action="recall", content="What do you know about this user and project?")
Memory seeded. Carrying forward: you're (), working on ;
is , tested with , . I'll hold to
. Future sessions start from here — tell me anything to add or
correct and I'll update it.
Then stop. Don't launch into work unless asked — this pass is about memory, not
the first task. (For the GitHub/team-workspace flow instead, that's the
self-onboard skill.)
When to use this
- First run on a fresh local install, when
recall comes back empty.
- The user explicitly asks you to "learn the project", "remember who I am", or
"set up your memory".
- You've moved to a new workspace/repo and have no memory of it.
Don't re-run it on a workspace you already have memory for — recall first; if
there's already context, just fill the gaps instead of re-seeding from scratch.