| name | session-memory-contract |
| description | Canonical operational contract for Agent Orchestra session-state survival and handoffs. Use when discovering where plan, design, review, startup, calibration, tracking, or plugin state belongs. DO NOT USE FOR: designing new storage mechanisms or writing rationale docs (use design-exploration or documentation-finalization). |
Session Memory Contract
Operational source of truth for Agent Orchestra session-state shapes, survival labels, canonical read/write mechanisms, and cross-tool fungibility. This skill documents the mechanisms already used by the repo; it does not create a new persistence layer.
When to Use
- When a skill, agent, command, or script reads or writes plan, design, review, startup, calibration, tracking, or plugin-release state.
- When documenting whether state survives compaction, conversation end, worktree switches, or a Copilot-to-Claude handoff.
- When replacing vague
session memory wording with a row-specific survival label and canonical mechanism.
- When deciding whether a local cache must be reconciled against a durable GitHub marker.
Survival Vocabulary
Use these labels exactly when documenting a state shape.
| Label | Meaning |
|---|
per-dispatch | Survives only the current prompt, subagent dispatch, command invocation, or tool call. |
within-conversation | Survives while the current chat conversation and its session memory remain available, including VS Code compaction when /memories/session/ is preserved. It is not a cross-conversation or cross-tool guarantee. |
within-worktree | Survives in local files tied to the checked-out worktree and machine. It is available to tools that share that checkout, but not to a fresh clone or remote/cloud agent unless separately committed or copied. |
durable | Survives conversation end and tool/model handoff through GitHub issues, PR comments, PR bodies, issue bodies, or committed repository files. |
per-process | Special value for PID-keyed temp files. Use only when a state file is intentionally scoped to one process lifetime rather than to a conversation or worktree. |
Surface-naming requirement: when survival depends on the execution surface, write the label as {base}:{surface}. Examples: within-conversation:inline, within-conversation:subagent, within-conversation:hooks, or within-worktree:hooks. The base must still be one of per-dispatch, within-conversation, within-worktree, or durable; per-process remains a special value for PID-keyed temp files.
Use these cross-tool fungibility values in the table and in citations: yes, no, partial - {trigger or limitation}, or n/a.
Contract Rules
- Per-shape read precedence: follow the lookup chain named by the row for that exact state shape. Do not apply a plan-cache lookup chain to design, review, startup, calibration, or tracking state just because both mention session memory.
- Write precedence: write only through the row's canonical owner and mechanism. Do not mirror local caches into durable GitHub comments unless the row explicitly says that path owns the durable write.
- Honest gaps: if a surface has no write mechanism, no durable equivalent, or only a best-effort fallback, say that directly and continue through the documented fail-open or recovery path.
- No-new-mechanism rule: this contract records current mechanisms. Do not introduce a new persistence mechanism, Claude-only session store, or automatic sync path while citing this skill.
- Survival-label rule: state-owning docs must carry a nearby survival label and cite the owning contract row. Generic namespace traversal is exempt when it only says to list or inspect a namespace such as
/memories/session/ or .copilot-tracking/ and does not prescribe a concrete state shape or write.
- Cache-vs-durable conflict rule: durable GitHub or committed sources win over stale local caches, but a provably fresher in-conversation cache is the source for the next durable write. For example, mid-flight plan progress annotations in the active cache must not be discarded just because the durable artifact has not been updated yet. Local caches may be recreated from durable sources when they are stale, and D9 comparisons normalize transport-only formatting drift before deciding whether a durable marker changed.
Canonical State Rows
| ID | Shape | Survival | Copilot canonical mechanism | Claude canonical mechanism | Cross-tool fungibility | Citation/delegation notes |
|---|
| SMC-01 | single-issue plan cache | within-conversation; durable only after an explicit handoff marker write | Persist and update /memories/session/plan-issue-{ID}.md with vscode/memory; D9 writes <!-- plan-issue-{ID} --> only on Pause/Stop when needed. | /plan and /orchestrate use GitHub issue comments with <!-- plan-issue-{ID} --> plus parent dispatch context, persisted via skills/session-memory-contract/scripts/persist-marker.ps1 (family plan-issue, issue #893 — the ONLY documented write path, never a hand-composed gh issue comment; that rule buys a single audited writer, not protection from updated_at advancement — see handoff-markers.md § What the write-path rule buys); Claude has no separate vscode/memory cache. | partial - same-session cache is not cross-tool; durable marker handoff is cross-tool. #379 follow-up/cross-link needed for the partial path. | Citations: Issue-Planner, Code-Conductor, Claude guide. Pending #384 (). Update this row when #384 resolves: revise the cache/marker split if plan-storage ownership changes. |
| SMC-02 | bundled plan cache | within-conversation; durable only through per-issue handoff marker writes | Persist /memories/session/plan-bundle-{primary}-{secondary1}-{secondaryN}.md; Code-Conductor reads bundle plans before single-issue plans and writes per-issue <!-- plan-issue-{ID} --> markers only on bundle D9 Pause/Stop when needed. | /orchestrate carries bundle context to code-conductor; durable resume reads each issue's GitHub markers rather than a Claude-local bundle cache. |
Applies to every row above that names persist-marker.ps1 or persist-phase-ledger.ps1 as the ONLY documented write path. That rule buys a single audited writer — one place where the family registry, payload hygiene, validator adapters and burst ordering are enforced. It does not buy protection from updated_at advancement. Whether a given write advances anything depends on the family's write shape, not on the primitive: an upsert family's write replaces the target comment's whole body and advances updated_at on every family sitting beside it, exactly as a hand-composed call would, while a post-new family's write POSTs a fresh comment and advances nothing. updated_at never moves backwards. Before replacing a comment's whole body, read handoff-markers.md § What the write-path rule buys, which carries the shape split and lists who derives meaning from that field and which of them a touch would break.
Gotchas
| Trigger | Gotcha | Fix |
|---|
| Treating a local cache as if it were a handoff | A Copilot /memories/session/ file can survive compaction but still disappear at conversation end or be invisible to Claude and cloud agents. | Check the owning SMC row. If cross-tool resume is required, use the row's durable marker or document the honest gap instead of inventing a mirror store. |
| Trigger | Gotcha | Fix |
|---|
| Adding a new state shape without a survival label | Later docs cannot tell whether the state survives dispatch, conversation end, worktree changes, or GitHub handoff. | Add a nearby Survival: {label}; contract: SMC-XX callout in the state-owning file, or add a new contract row in this skill if the shape is genuinely new. |
References