Skip to content

feat(init): seed store project on init + nag unwired repos on four surfaces - #48

Merged
s-annam merged 1 commit into
mainfrom
feat/per-repo-init-nag-issue-3
Jul 24, 2026
Merged

feat(init): seed store project on init + nag unwired repos on four surfaces#48
s-annam merged 1 commit into
mainfrom
feat/per-repo-init-nag-issue-3

Conversation

@s-annam

@s-annam s-annam commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

The memory link is per-repo, and nothing said so. install.sh wires only the repo it runs in, so every other project silently remembered nothing — a failure with no symptom.

Worse, the documented fix was broken: in a repo that had never saved memory, link_project_memory found no <store>/projects/<name>/ and returned ("skip", "no store project dir yet"), making okfmem init a silent no-op in exactly the case the step exists for. It now seeds that dir (starter MEMORY.md + STATE.md, never overwriting an existing file) and links it — a fresh repo wires up in one command.

With the fix real, the instruction is now unmissable on four surfaces, all sharing one read-only probe so they can't drift:

okfmem init --project-link-state   # linked <name> | unlinked <name> | not-a-repo | no-claude
Surface Behavior
install.sh / install.ps1 Ruled banner: "ONE MORE STEP — REQUIRED IN EVERY REPO", naming the repo actually wired
SessionStart hook (memory_pull.py) Reminder when unlinked, printed even under --quiet
/okfmem Probes after status; leads the summary with the fix
/okfmem-save Probes first, stops and fixes before writing

Two deliberate choices worth review:

  • Printing under --quiet. SessionStart is the only okfmem surface that fires in a repo the user never ran init in, and its stdout reaches the agent as context. A silent unlinked repo is precisely the failure the notice exists to catch, so --quiet suppresses the pull line but not this one (documented in the flag's help text). Fail-open contract preserved — unlinked_repo_notice never raises, exit code unchanged.
  • Stop hook stays silent. Stop-hook stdout is not surfaced to the user on exit 0, and blocking a session over unwired memory is the wrong trade. SessionStart covers the case Stop can't reach anyway.

The probe also removes a real Windows bug: /okfmem-save derived the encoded project path with sed 's|/|-|g', but encode_root encodes the drive colon (C:\C--). No surface re-derives that path now.

Rung-1 discipline: the probe is read-only and never prompts; seeding is additive, inside the user's own store, and only for the repo they explicitly ran init in. --dry-run writes nothing.

Refs #3

Test plan

  • python3 scripts/check-leaks.py exits 0 — "scanned 62 tracked files, no leaks"
  • python3 -m pytest -q209 passed, 1 skipped
  • ruff check clean on all changed files
  • bash -n install.sh OK
  • New coverage: seeding, dry-run writes nothing, seed idempotent, 6 probe cases (unlinked before init / linked after / unlinked when the link points elsewhere / not-a-repo / no-claude / never-raises), notice fires only when unlinked, notice never raises
  • Live probe: linked okfmem in-repo, not-a-repo outside
  • install.ps1 not parse-checked locally — no pwsh on this machine. Verified pure ASCII (grep -nP '[^\x00-\x7F]' clean, per the BOM-less-cp1252 hazard). Windows CI is the first real parse check; worth an extra eye on that job.

Provenance

Code implementation via: Claude Opus 4.8 (1M context), high effort
Verification: local test suite + leak gate green; CI verify pending

…rfaces

The memory link is per-repo, but nothing told the user that. `install.sh`
wires only the repo it runs in, so every other project silently remembers
nothing — a failure with no symptom, which is the worst kind to ship to a
new user.

Worse, the documented fix didn't work. In a repo that had never saved
memory, `link_project_memory` found no `<store>/projects/<name>/` and
returned `("skip", "no store project dir yet")` — so `okfmem init` was a
silent no-op in exactly the case the step exists for. It now seeds that
directory (starter `MEMORY.md` + `STATE.md`, never overwriting) and links
it, so a fresh repo wires up in one command.

With the fix real, make the instruction unmissable. All four surfaces
share one read-only probe, `okfmem init --project-link-state`, so they
can't drift and none of them re-derives the encoded project path by hand
(`encode_root` encodes the drive colon on Windows; the skill's old
`sed 's|/|-|g'` was wrong there).

- memory_init.py: `_seed_store_project`, `project_link_state` probe
  (linked | unlinked | not-a-repo | no-claude), `--project-link-state`
  dispatched before the store-shape check so an unconfigured box answers
  instead of exiting 2
- install.sh / install.ps1: ruled banner naming the repo actually wired,
  plus a step counter replacing hardcoded numbering that skipped 1
- memory_pull.py: SessionStart reminder when the repo is unlinked,
  printed even under `--quiet` — SessionStart is the only okfmem surface
  that fires in a repo the user never ran init in, and its stdout reaches
  the agent. Stop-hook stdout is invisible on exit 0, so it stays silent.
- skills/okfmem, skills/okfmem-save: probe first, lead with the fix
- README.md: per-repo setup section

Refs #3
@s-annam

s-annam commented Jul 24, 2026

Copy link
Copy Markdown
Owner Author

Windows verification — closes the open install.ps1 checkbox

Ran on a real Windows 11 machine that has both PowerShell editions, so this covers the parse the author couldn't do locally.

install.ps1 parse-check (AST, no execution)

Parsed via [System.Management.Automation.Language.Parser]::ParseFile(...) under both editions:

  • Windows PowerShell 5.1.26100 — 0 errors. This is the edition that matters for the BOM-less/cp1252 hazard (#Requires -Version 5.1 is the floor), and it's clean.
  • PowerShell 7.6.3 — 0 errors.
  • grep -nP '[^\x00-\x7F]' clean → pure ASCII confirmed independently.

Live install run

pwsh -NoProfile -NonInteractive -File install.ps1exit 0, fully idempotent against an already-installed store:

  • backfill — 2270 pages scanned across 14 projects, 1 stamped, remainder already-stamped (additive, no churn).
  • initfully wired — nothing to do: memory link, registry, .gitignore, pointers, stale refs, skills, stop hook, pull hook all reported up to date.
  • remote stepSet-StoreRemote correctly early-returned (Store already has a remote) rather than re-prompting.
  • non-interactive contract — under -NonInteractive, Read-Host throws, so Read-PromptAnswer returns $null and both the remote and statusline prompts skipped cleanly with the exit code unchanged. This is the fail-open path the PR relies on, exercised end to end.
  • nag banner — the ONE MORE STEP — REQUIRED IN EVERY REPO block rendered, naming the repo actually wired (okfmem).

New probe surface

The four-surface probe added by this PR, checked directly:

  • okfmem init --project-link-statelinked okfmem in-repo, not-a-repo from outside any repo — matches the documented probe cases.
  • okfmem init --statusline-statecustom, which is exactly why the live installer skipped the badge step silently (correct behavior on a machine with an existing statusline).

Incidental (pre-existing, not this PR)

init emits ! legacy clone found ~\claude-memory — the known retired-memgraph leftover. Warn-not-delete, hands over the manual command; unrelated to these changes.

@s-annam
s-annam merged commit 58597c6 into main Jul 24, 2026
3 checks passed
@s-annam
s-annam deleted the feat/per-repo-init-nag-issue-3 branch July 24, 2026 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant