Hindsight Coding Agent
How this machine's Hindsight coding-agent memory works β the plugin behind the π§ banner.
by vectorize-io Β· MIT
The skill
How this machine's Hindsight coding-agent memory works β the plugin behind the π§ banner. Use when the user says "store/remember this in hindsight", asks what the memory/knowledge pages are, wants to configure per-repo memory (disable, rename banks, git depth), or something memory-related looks broken.
<!-- GENERATED from README.md (its skill:begin regions) + skill-src/preamble.md. Edit those, then run: npm run skill:build -->
Hindsight Coding-Agent Memory
This machine runs the hindsight-coding-agents plugin: long-term project memory for coding
sessions, backed by a Hindsight server. You (the agent) are already wired into it β this skill
explains what happens automatically, which tools you have, and how to configure or debug it.
What happens automatically (no action needed)
- Per-repo memory bank: each repository resolves to a bank (shown in the session banner:
β³ memory bank βcoding-agent::<repo>β). Worktrees share the main repo's bank. - Ingestion builds itself: on first open, the bank is seeded from recent commit messages and a read-only codebase survey; every session start, a background engine tops it up (new commits, new conversations) and keeps 5 knowledge pages current. There is NO ingest command to run.
- Session synthesis: by default, the first prompt of a session triggers one deep memory
synthesis (
reflect) injected into context.autoInjectswitches the source:pages(knowledge page search hits),recall(recalled observations), ornone(nothing injected; the agent searches the knowledge pages first and reflects only when they are too shallow). - Write-back: the session transcript is retained into the bank automatically at session end (per-turn on opencode). The user never needs to "save" a conversation.
Storing things deliberately
When the user says "store this in hindsight" / "remember this":
- The current conversation is captured automatically at session end β say so; no tool needed.
- An external document, notes, or durable findings β
hindsight_ingest_document(title, content). - A new feature/initiative being started β
hindsight_capture_initiative(title, summary), right after the plan is agreed and before code is written. - A plan that materially changed (goal, scope, or rationale β including mid-implementation) β
call
hindsight_capture_initiativeagain withrelates_to_page_idset to that initiative's page id, summarising the current intent. Same page, updated plan β never a second page. Trivial course-corrections don't count.
Retrieving
hindsight_search_knowledge_pages(query)β FIRST STOP for project questions (components, conventions, past decisions, initiatives). Server-side hybrid search, fast.hindsight_read_knowledge_page(page_id)/hindsight_list_knowledge_pagesβ read pages fully.hindsight_reflect(query)β deep reasoning over the whole memory for WHY questions and exact decided values; slower (seconds), use deliberately.- Credit visibly whenever memory informs an answer: start that part with
π§ From Hindsight memory (<page>): β¦β and never credit memory that didn't contribute.
Correcting wrong or stale memory
If you verify that something Hindsight served is wrong or outdated (the code, git, or an external
source contradicts it), FIX THE RECORD β don't just ignore it. Call
hindsight_ingest_document with:
- title:
Correction: <topic>(e.g.Correction: retry policy 4xx set) - content: (1) what memory claimed, (2) what is verifiably true now, (3) the evidence you checked (file/commit/output). Quote exact values verbatim.
Newer facts supersede older ones in retrieval, so one clear correction permanently outranks the stale memory. Do this whenever you catch a wrong injected memory, a stale knowledge-page claim, or an outdated decision β silent disregard leaves the trap armed for the next session.
Install / update
npx @vectorize-io/hindsight-coding-agents install all # every detected agent, wired natively
npx @vectorize-io/hindsight-coding-agents install claude-code # or just one
npx @vectorize-io/hindsight-coding-agents uninstall all # removes exactly what install added
npx @vectorize-io/hindsight-coding-agents update # refresh the runtime only, no rewiring
npx @vectorize-io/hindsight-coding-agents stats # how often each agent uses Hindsight
install takes an explicit target β all, or one or more harness names. A bare
npx @vectorize-io/hindsight-coding-agents install changes nothing and prints the choice, so wiring every agent on
the machine is never something that happens by accident. Updating is the same install
command again β it re-copies the runtime in place.
Day to day you should not have to: once a day, a session start checks npm and re-stages a newer
runtime in the background (autoUpdate, on by default β set it to false to pin the version you
have). That is the update command above, which refreshes the copy every wired agent already
points at and deliberately touches no host config; re-run install yourself after a release that
adds a new hook, or to wire another agent.
Local daemon settings (daemon mode)
Daemon settings keep the names the old per-agent Claude Code plugin used, so an existing environment carries over unchanged:
| field | env | default | meaning |
|---|---|---|---|
serverMode |
HINDSIGHT_SERVER_MODE |
cloud |
cloud | self-hosted | daemon |
apiPort |
HINDSIGHT_API_PORT |
9077 |
port the local daemon listens on |
daemonIdleTimeout |
HINDSIGHT_DAEMON_IDLE_TIMEOUT |
β | deprecated, ignored: the daemon no longer exits on its own |
daemonProfile |
HINDSIGHT_DAEMON_PROFILE |
coding-agent |
which local database it uses |
embedVersion |
HINDSIGHT_EMBED_VERSION |
latest |
which hindsight-embed release to run |
embedPackagePath |
HINDSIGHT_EMBED_PACKAGE_PATH |
β | run a local checkout instead (development) |
Any HINDSIGHT_API_* variable you export is forwarded to the daemon, so server-side settings need
no equivalent here.
Configuration
Configuration is one JSON file: ~/.hindsight/coding-agent.json. Layering, later wins per field:
- built-in defaults
- environment variables β
HINDSIGHT_API_URL,HINDSIGHT_API_TOKEN, and one per scalar setting (HINDSIGHT_<FIELD_IN_CAPS>), for containers and CI that inject config rather than write a file - the file's top level
- its
harnesses.<name>section β per-agent override - its
paths.<prefix>section β per-directory override, applied after the bank is resolved (see Per-directory overrides) - its
banks.<resolvedBankId>section β per-repo override, applied after the bank is resolved (see Per-repo opt-in/out)
Environment variables are a fallback: the file wins wherever it sets a value, so adding env to
an existing setup changes nothing. The two list-valued settings, retainTags and optInPaths, take
a comma-separated value (HINDSIGHT_RETAIN_TAGS="project:{gitProject},env:work"); entries are
trimmed and blanks dropped.
The map-valued settings (mapPathToBank, harnesses, paths, banks, retainMetadata) are file-only β
per-key branching doesn't survive flattening into one variable. maxParallelRetains is available
as HINDSIGHT_MAX_PARALLEL_RETAINS for containers and CI.
HINDSIGHT_CONFIG moves the file itself β point it at another path for a container or a test
harness where $HOME is not the right anchor. It is still exactly one file; only its location
changes. (The other variables that are not settings are HINDSIGHT_LOG_FILE, HINDSIGHT_DIAG_FILE,
HINDSIGHT_USAGE_FILE and HINDSIGHT_LOG_LEVEL β see Diagnostics & logging.)
When a change takes effect
Config is read when a process starts β the file is not watched β so when an edit applies depends on what reads it:
| host | reads the file | an edit applies |
|---|---|---|
| hook harnesses (Claude Code, Codex CLI, Cursor CLI, GitHub Copilot CLI, Grok Build, Antigravity CLI, Devin) | once per hook invocation β each hook is its own short-lived process | on your next prompt |
| persistent plugins (opencode, opencode 2, Kilo CLI, Cline CLI, pi, Prime Agent, DeepSeek Harness) | once per workspace, when the host loads the plugin | after restarting the agent |
the MCP server behind the hindsight_* tools |
once at startup | in your next session |
apiToken is the exception. Every host re-reads it when the server rejects a request, so enabling
authentication or rotating the key is picked up on the next call with nothing to restart β
otherwise a rotation would leave a long-running agent failing every memory call until it was
restarted. Everything else follows the table: apiUrl, disabled, bank routing, gitIngest, and
the survey and knowledge-page settings.
hindsight_diagnose reports both sides of that gap β what the file says now, and what the running
client is actually using.
Opt-in only
By default every project gets memory β that is what makes the plugin zero-setup. If you would rather nothing be remembered until you say so, turn memory off everywhere and name the projects that may use it:
{
"optInOnly": true,
"optInPaths": ["~/work/client-x", "~/oss"],
}
Anything outside those paths is inert: no bank is created, nothing is retained, no seed runs,
and the agent behaves exactly as it would without the plugin. Approving costs nothing else β
optInPaths says which projects, not which bank, so an approved repo keeps its usual
coding-agent::{gitProject} name. Paths are prefixes, so approving ~/work approves every repo
under it while each still gets its own bank.
A mapPathToBank entry counts as opted in too, since 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 say which work may be remembered, and a privacy switch has to fail closed.
There is no per-repo opt-in file, for the same reason there is no repo-carried config at all: a cloned repository must not be able to turn memory on.
There is deliberately no repo-carried config file β per-repo bank routing is mapPathToBank,
per-agent differences are harnesses.<name>.
Each entry point knows which harness it is (the opencode plugin is loaded by opencode, the codex hook by Codex...), so one shared config serves several agents side by side:
{
"apiUrl": "https://api.hindsight.vectorize.io",
"harnesses": {
"opencode": { "reflectTimeoutMs": 60000 },
"claude-code": { "disabled": true }, // e.g. memory off for Claude only
},
}
Reference
| field | default | meaning |
|---|---|---|
apiUrl |
https://api.hindsight.vectorize.io |
Hindsight API base URL (set to http://localhost:8888 for a local server) |
apiToken |
β | bearer token (Hindsight Cloud). Picked up without restarting the agent: a long-lived host re-reads it after a rejected request, so enabling auth or rotating the key mid-session recovers on the next call |
bankId |
β | explicit static bank; unset β per-repo dynamic resolution (below) |
dynamicBankId |
dynamic iff no bankId |
force dynamic (true) or static (false) resolution |
bankIdTemplate |
"coding-agent::{gitProject}" |
dynamic bank id format; the default makes every agent share one bank per repo |
mapPathToBank |
β | absolute path β bank; longest prefix wins; linked worktrees inherit their main checkout's mapping; overrides everything |
optInOnly |
false |
run memory ONLY in opted-in projects β everything else is inert, with no bank created; see Opt-in only |
optInPaths |
β | directories opted in, matched as prefixes with ~ expanded; each repo beneath and its linked worktrees are approved while keeping their own dynamic bank |
resolveWorktrees |
true |
linked worktrees inherit the main checkout's bank identity, path approval, and mapping |
retainTags |
β | extra tags on every document written by the integration, e.g. ["project:{gitProject}"] β see Recording where a memory came from below |
retainMetadata |
β | extra metadata on every document written by the integration, e.g. {"repo": "{gitProject}"} |
retainContext |
see description | the context sent with every session write-back. Extraction reads it to decide whose claim a sentence is, so the default names both speakers, and asks for an agent's own "fixed" or "passes" to be stored as its claim rather than as fact. Accepts the same {placeholder} templates as retainTags |
manageBankConfig |
true |
let the plugin shape the bank's own configuration β the retain strategies it writes under, the knowledge entity-label group, and, on a bank that has none, the missions. Writing is additive: it adds what the bank does not define and never overwrites what is there, so your control-plane edits survive β the one exception is the extraction mode of its own strategies, which follows retainExtractionMode. Set false to keep it out of the bank config entirely β see A bank you shape yourself below |
retainExtractionMode |
"concise" |
how the server extracts memories from sessions, commits and documents: "concise", "verbose", "verbatim" or "chunks" (store the text, no extraction). Every Stop writes the session back, so this is what each turn costs β "verbose" pulls more detail for several times the tokens. Kept in sync on the plugin's own retain strategies every session, so a change reaches existing banks too (not with manageBankConfig: false) |
defaultBankConfig |
β | bank-config fields of your own for the banks the plugin shapes, e.g. {"enable_observations": false, "enable_auto_consolidation": false, "mental_model_min_refresh_interval_seconds": 21600}. Keys are the bank-config API's own field names. Written under the same additive rule as the rest: only where the bank does not define the field, so a bank the plugin creates is born with these instead of the server's defaults and a value you set in the control plane is never overwritten. Wins over the template on a key both name (enable_observations); retain_strategies, entity_labels and retain_extraction_mode are refused, since the plugin governs them itself. Ignored with manageBankConfig: false β see A bank you shape yourself below. File-only, like recallOptions; in a banks.<id> section it replaces the global map rather than merging into it |
observationScopes |
"shared" |
how consolidation groups observations: "shared" (default) = ONE global scope per bank, so every agent on a repo builds one set of beliefs; also "combined" (the server default), "per_tag", "all_combinations", [["t"]]; "per_source" adds a scope per source: kind alongside the global one, so commit knowledge and conversation knowledge consolidate apart |
disabled |
false |
hard off-switch (inert plugin/hook β a no-memory baseline) |
reflectTimeoutMs |
20000 |
automatic session-reflect timeout; on hook harnesses the installer registers a 30s prompt-hook timeout, so going above ~20s also means raising that hook's timeout in the host's config, or the host kills the hook mid-reflect; on timeout or a 5xx the hook falls back to knowledge-page search, then to a raw recall of observations (recorded) |
reflectToolTimeoutMs |
330000 |
timeout for the agent-invoked hindsight_reflect tool β a call the agent waits on, whose high-budget synthesis on a populated bank runs for minutes. Defaults above the server's own reflect wall timeout (HINDSIGHT_API_REFLECT_WALL_TIMEOUT, 300s) so the server decides when to give up. Unset, it inherits an explicitly raised reflectTimeoutMs, but a short one never lowers it |
injectTimeoutMs |
7000 |
retrieval timeout in milliseconds for autoInject: "pages" and autoInject: "recall"; also the shared budget for page search then recall after a reflect timeout/5xx (recall gets only the time left after page search). Set e.g. 2000 to limit turn latency or 15000 for a slower self-hosted bank. Environment fallback: HINDSIGHT_INJECT_TIMEOUT_MS. On hook harnesses, injection must fit the host's prompt-hook timeout (30s by default); for reflect with fallback, allow for reflectTimeoutMs + injectTimeoutMs, and raise the host hook's timeout when needed |
reflectBudget |
"high" |
reflect budget for the hindsight_reflect tool: "low", "mid" or "high". Drop it on a large bank where high-budget synthesis exceeds the server's wall timeout. The automatic session-start reflect always uses "low" to fit its hook window and is unaffected |
autoInject |
"reflect" |
what to inject once, on the session's first prompt: "reflect" = a low-budget reflect synthesis (on timeout/5xx it falls back to page search, then recall); "pages" = the knowledge pages matching the prompt by search; "recall" = the bank's memories recalled for the prompt (what it asks for is recallOptions, observations by default); "none" = nothing β the agent searches knowledge pages first and reflects only when they are too shallow. "pages" and "recall" are retrieval only (no LLM), their time budget is injectTimeoutMs, and when one finds nothing for the prompt it tries again on the next one, up to 5 prompts |
autoReflect |
true |
deprecated β use autoInject. Still honoured (false = autoInject: "none"), ignored when autoInject is set, and logs a deprecation warning |
pageSearchLimit |
3 |
knowledge pages ONE search returns. Applies to every search of the bank β the autoInject: "pages" injection, the reflect fallback, and the agent's own hindsight_search_knowledge_pages tool β because the limit lives on the client they all share |
recallOptions |
see description | overrides merged key-by-key into the body of every recall β the autoInject: "recall" source and the reflect fallback. Keys are the API's own recall parameters, passed straight through, so anything recall accepts is settable without a new option here; query is the one field it cannot replace. The default body is {"types": ["observation"], "budget": "low", "max_tokens": 2000, "include": {"entities": null}}, and what you set is merged over it one key at a time β {"max_tokens": 4000} changes the budget and leaves the rest alone. Observations are the consolidated layer, so they answer best per token, but a bank with consolidation disabled never grows any and the default recall comes back empty on it: set {"types": ["world", "experience"]} there, or {"types": null} for every type. File-only, like retainMetadata β an object does not flatten into an env var |
toolGuideExtra |
β | your own guidance on how the agent should treat memory, added after the built-in tool guide (at session start and on every refresh) and after the crediting note returned with hindsight_search_knowledge_pages results. It adds to the built-in text, never replaces it. Set it per harness or per bank like any other key, e.g. "Memory is a past record, not current state: verify any claim against the code before acting on it." |
pageRefreshEveryTurns |
1 |
refetch the knowledge pages and re-inject the page roster + tool guide every N user turns (0 also means 1) |
pageTriggerType |
"cron" |
when NEW knowledge pages refresh, i.e. what keeping them current costs β "cron" (default) on pageTriggerCron only and only when actually stale, "auto-refresh" after every consolidation that produced new material, "manual" never on their own. Auto-refresh is the most current and by far the most expensive: one synthesis per page per consolidation. Maps to the page's trigger.refresh_cron, or trigger.refresh_after_consolidation in the Hindsight API (true for auto-refresh, false for manual) |
pageTriggerCron |
"H * * * *" |
Use this skill
Connect your agent to the Skill Store MCP server and ask for it by ref: vectorize-io/hindsight-coding-agent-81610496441.
Details
- Publisher
- vectorize-io
- Category
- AI & Agents βΊ Memory & context
- License
- MIT
- Updated
- 2026-10-19
References
More from vectorize-io
- Code Review Review changed code against project standards.
- Figure Draw an animated figure (boxes, arrows, moving data) as one self-contained SVG for a GitHub READMβ¦
- Hs Release Cut a core Hindsight release (vX.Y.Z) and open the changelog + blog PR.
- Ship It Take a PR from review to merged β run the repo's code-review skill on it in a loop (review, fix,β¦