Parallax
Memory
A lesson comes only from an outcome. Your decisions on suggestions write lessons back. The next session is handed them, with a receipt that shows what it got.
Lessons
A lesson is one or two sentences, in the imperative, naming the file or function, written by the reviewer that found the mechanism. It exists only when something verifiable happened. The sources that can make one:
- a finding the sandbox proved (a test failed, then passed with the fix);
- a fix PR you merged;
- a read that two sessions each proved dispensable, or a tool call the same correction fixed on two sessions (load-bearing and tool-path lessons);
- the same uncorrected tool failure on two sessions, or the same verify command passed on three (mined; recurrence is the proof).
A review verdict, a fork that diverged, a rejected finding, a single corrected call: none of these make a lesson. Reviewer consensus never does.
A lesson is scoped to the repository it was born in. It widens to the account in exactly one way: a proven finding or a merged fix from a second repository of the same account matches it. It expires 30 days after its last confirmation; a later proven finding that names the same code confirms it instead of duplicating it and pushes the expiry out. There is no cross-tenant recall.
Source: packages/recall/cards/recall.input.json · packages/recall/cards/recall.output.json
Write-back from your decisions
When a pull request gets a new head or closes, the door reads every suggestion it posted there and decides what you did with it:
| state | read as | then |
|---|---|---|
applied | the replacement is at the suggestion's place at the new head (GitHub's Apply, or the same fix typed by hand) | accepted: a repo-scope lesson entry is created or confirmed |
dismissed | a maintainer replied refusing it (not a bug, won't fix, taste, duplicate, superseded, already fixed, other), or the PR merged with it unapplied | suppressed: the entry is demoted with your words as the reason (first 200 characters); it is never injected again |
abandoned | the PR closed without merging, or the place could not be located at the merge head | nothing: says nothing about the finding |
open | the PR is open and you have not decided | observed again on the next event |
Only a maintainer's reply counts (owner, member, collaborator; never a bot). A merged fix PR is accepted; a fix PR closed with a typed refusal is dismissed. A proven finding writes back as accepted on its own.
One entry per mechanism per repository, lesson/<lens-title slug>-<hash>: a second acceptance of the same finding appends a receipt (which seat, under which guidance, on which PR) to the same entry rather than a duplicate. A demoted entry is never lifted by a later acceptance; only a person editing the store changes it. The entry is active, and so injectable, only when it carries an accepted receipt and the accepting seat’s lab. The write-back calls no model and never widens a decision beyond the repository it was made on.
Source: packages/github/cards/acceptance.input.json · packages/continual/cards/write-back.input.json · packages/continual/cards/store.json · packages/calibration/cards/suggestion-outcome.input.json
The review’s own memory
A review is many calls: seats × shards × lenses. The session-memory package records each call’s result with no model call and hands it to every later call of the same review, after the shard text so the shared header stays a cache prefix:
- tool paths: a command that passed after a related command failed, errored or timed out (
PYTHONPATH=src pytestfound on shard 1 reaches shard 2 and every other seat); - hypotheses: refuted or confirmed, with their evidence ids;
- findings: what one seat reported, for the other seats and lenses;
- cross-session facts: what the batch’s other sessions taught (contradictions, repeated mistakes, decisions).
At the end of the review these persist: an executed tool path as an active memory entry for 90 days; hypotheses, findings and cross-session facts as candidates for 30 days. The next review of the repository is handed them as Recalled from earlier sessions: lines with the session, seat and commit, and the ledger counts a hit when a recalled subject came up again. Stored and recalled entries have no count cap. Each call receives at most 12,000 characters of memory, ordered by relevance to its files, then tool paths, then recency. The separate cross-session context block is bounded at 24,000 characters. Both blocks count omitted entries; the full record keeps them.
Source: packages/session-memory/cards/policy.json · packages/session-memory/cards/session-memory.input.json
What is injected into your agent
Lessons are the only imperative lines your agent receives. Everything else it is handed is a cited fact. There are four moments:
| moment | what |
|---|---|
| Session start (the hook hosts: Claude Code, Codex, Cursor; the MCP preamble) | GET /v1/brief for the checkout: LESSONS (the repository's active lessons, newest confirmation first, up to 8), SWEPT SINCE YOUR LAST SESSION HERE (the sweep lines nobody has seen), YOUR FILES (who edited each modified file in the last 14 days and what was proven or reverted there), NOTES, CORRECTED BEFORE (a failed call an earlier session then fixed; the words a human used to ask again), and a one-sentence CONTRACT asking the agent to use parallax_ask before changing a system it can name and to credit a lesson it applied. Cut at 6,000 characters because Claude Code truncates a hook's context at 8,000. |
| Every request through the proxy | A short block appended to the system message: "Parallax recall for this repo (N lessons, delete at GET /v1/recall)". A lesson that names a file is injected only when the request mentions that file; one that names none is repository-wide. File-relevant first, then repository, then account scope. |
| When the agent is mechanically uncertain | The PostToolUse hook detects a search repeated for the same identifier, an edit that missed, an edit to a file the session never read, or a test that failed twice on the same file, and asks GET /v1/context for that file or symbol: the code-graph slice, the lessons that name it, what was proven and reverted there, the notes that cite it. Once per subject per session. |
| Prime Agent | Prime has no hook. The capture skill's start returns recall for the session: the repository's execution-verified tool paths, labelled [tool path], each with its session, seat and commit. |
Each person under an account carries one preference card: recording full | incognito | off, surfacing 0 (nothing volunteered; the tools still answer) to 3 (the brief and the context pushes), and lesson_cap 1–20, the most lessons the brief and the proxy inject for that person. Read and set it at GET|PUT /v1/persons/preference.
Source: packages/brief/cards/brief.input.json · packages/recall/cards/recall.input.json · packages/persons/cards/preference.json · scripts/session-start.ts · packages/prime-capture/cards/prime-capture.input.json
Recall receipts: how to see it
Every lesson carries its provenance: the session and finding that made it, each confirmation, and when it expires. Every injection is recorded as a set.
# every lesson on the account, with sources, confirmations and expires_at
curl -s -H "authorization: Bearer $PARALLAX_TOKEN" "$PARALLAX_URL/v1/recall"
# what the next session in this repository is handed
curl -s -H "authorization: Bearer $PARALLAX_TOKEN" "$PARALLAX_URL/v1/recall/active?repo=$PWD"
# the brief as the hook sees it
curl -s -H "authorization: Bearer $PARALLAX_TOKEN" "$PARALLAX_URL/v1/brief?repo=$PWD"
# the review ledger with the Brain: lessons per repository and what each review was handed
curl -s -H "authorization: Bearer $PARALLAX_TOKEN" "$PARALLAX_URL/v1/review-ledger?brain=true"On the door, each injection appends one line to <scope dir>/injections.jsonl in the continual store: { at_ms, session_id, surface: review | recall | brief | context, set_sha256, entries, chars }, and logs [parallax continual] <session> -> <surface> N entries set <sha> …. The set hash is how a later outcome is joined to what the session was handed. The hook’s brief file also records the provenance of every lesson handed (lessonsHanded: id, lens, kind, seat, sessions), and each review writes session-memory.jsonl with what it learned, recalled and hit; packages/session-memory/scripts/show.ts prints it.
To remove a lesson: DELETE /v1/recall/:id. It is gone and never re-created from the same source. Deleting a session with DELETE /v1/sessions/:id also deletes the lessons whose only source it was. A dismissed suggestion’s suppression lives in the store entry’s receipts (Control says what is kept for how long).
Source: packages/continual/cards/write-back.output.json · packages/ledger/cards/ledger.input.json · packages/server/cards/server.input.json · packages/session-memory/cards/session-memory.output.json