You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(coding-agents): optInOnly — run memory only in projects that were opted in (#3433)
Closes#3427.
By default every project gets memory, which is what makes the plugin zero-setup.
For shared machines and client work that is the wrong default: unrelated
directories create banks nobody asked for, and there was no way to say "off
unless I name it".
{ "optInOnly": true, "optInPaths": ["~/work/client-x", "~/oss"] }
Anything outside those paths is inert — no bank created, nothing retained, no
seed — and the agent behaves as it would without the plugin.
Approval is deliberately separate from routing. `optInPaths` says WHICH PROJECTS,
not which bank, so an approved repo keeps its usual coding-agent::{gitProject}
name and approving costs no naming decisions. Paths are prefixes with `~`
expanded, so approving ~/work approves the repos under it while each still gets
its own bank. That is why this is not built on mapPathToBank, which the issue
reporter and I both first reached for: using it for approval forces you to name a
bank per project and collapses a whole tree into one.
A mapPathToBank entry does count as opted in — routing a path to a named bank
already declares that project. A bare bankId does not: it names a bank rather
than a project, so it cannot express which work may be remembered, and a privacy
switch has to fail closed.
Enforced through the `disabled` gate every entry point already checks after bank
resolution: applyBankConfig takes the directory the bank came from and returns a
disabled config when it is not opted in. That reuses a path already known to stop
a run before anything creates a bank, rather than adding a second thing nine call
sites must remember.
Verified end to end against a live server as well as in unit tests: an unlisted
project produced no plugin events and no bank, while an opted-in one under the
same config seeded, injected and retained normally.
Why not a `.hindsight.json` in the repo (the issue's Idea C): the config module
deliberately reads no repo-carried file, because an untrusted repository must not
be able to influence memory behaviour — and here it would let a cloned repo turn
memory ON, which is exactly backwards for a privacy control.
|`optInOnly`|`false`| run memory ONLY in opted-in projects — everything else is inert, with no bank created; see Opt-in only |
340
+
|`optInPaths`| — | directories opted in, matched as prefixes with `~` expanded; each repo beneath keeps its own dynamic bank |
313
341
|`resolveWorktrees`|`true`|`{gitProject}`: linked worktrees share the main repo's bank |
314
342
|`retainTags`| — | extra tags on every document written by the integration, e.g. `["project:{gitProject}"]` — see **Recording where a memory came from** below |
315
343
|`retainMetadata`| — | extra metadata on every document written by the integration, e.g. `{"repo": "{gitProject}"}`|
|`optInOnly`|`false`| run memory ONLY in opted-in projects — everything else is inert, with no bank created; see [Opt-in only](#opt-in-only)|
333
+
|`optInPaths`| — | directories opted in, matched as prefixes with `~` expanded; each repo beneath keeps its own dynamic bank |
306
334
|`resolveWorktrees`|`true`|`{gitProject}`: linked worktrees share the main repo's bank |
307
335
|`retainTags`| — | extra tags on every document written by the integration, e.g. `["project:{gitProject}"]` — see **Recording where a memory came from** below |
308
336
|`retainMetadata`| — | extra metadata on every document written by the integration, e.g. `{"repo": "{gitProject}"}`|
disabled?: boolean;// hard off-switch — inert plugin, for a no-memory baseline (default false)
68
77
retainSessions?: boolean;// opencode plugin write-back (default true; set false to opt out). Hook harnesses always write back on Stop and ignore this flag.
0 commit comments