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
Copy file name to clipboardExpand all lines: ARCHITECTURE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -242,7 +242,7 @@ ts: 2026-06-14T16:10:00-07:00
242
242
243
243
All three construct the Service identically via a small `wire()` that picks adapters (native vs ripgrep search, real vs fake store) — keep composition in one place.
244
244
245
-
**Session resolution (adapter-side, see ADR 0003).**`core` stays pure: every session-scoped method takes an explicit `SessionID`. *Which* session an adapter is acting for is discovered at the edge by `harness.ResolveSessionID(explicit, allowDefault)`, with precedence `explicit param/flag → CLAUDE_CODE_SESSION_ID (set by Claude Code in each session's env) → DOSSIER_SESSION → sess_default`. The MCP adapter calls it with `allowDefault=false` and **degrades visibly** (`harness_capability_unavailable`) rather than silently sharing the `sess_default` bucket across concurrent sessions; the CLI calls it with `allowDefault=true` for manual use. This is the bridge that lets an in-session agent call `dossier_switch` with only a slug. The **TUI carries no session identity at all** (it does not expose `Switch`/`Active`) — it is a read/edit viewer over the store; see [ADR 0004](docs/adr/0004-tui-no-session.md).
245
+
**Session resolution (adapter-side, see ADR 0003).**`core` stays pure: every session-scoped method takes an explicit `SessionID`. *Which* session an adapter is acting for is discovered at the edge by `harness.ResolveSessionID(explicit, allowDefault)`, with precedence `explicit param/flag → CLAUDE_CODE_SESSION_ID (set by Claude Code in each session's env) → DOSSIER_SESSION → sess_default`. The MCP adapter calls it with `allowDefault=false` and **degrades visibly** (`harness_capability_unavailable`) rather than silently sharing the `sess_default` bucket across concurrent sessions; the CLI calls it with `allowDefault=true` for manual use. This is the bridge that lets an in-session agent call `dossier_session` with only a slug. The **TUI carries no session identity at all** (it does not expose `Switch`/`Active`/`Session` binding) — it is a read/edit viewer over the store; see [ADR 0004](docs/adr/0004-tui-no-session.md).
246
246
247
247
**MCP**: use the official Go MCP SDK over stdio. Each `dossier_*` tool (SPEC §8.1) is a ~10-line handler: parse input → call one Service method → marshal `Result` into the §8.2 envelope. Map typed errors → §8.2 codes in **one** place (`mcp/errors.go`).
Copy file name to clipboardExpand all lines: BUILD-DECISIONS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -29,7 +29,7 @@ This document closes the implementation-discovery questions so the build can sta
29
29
30
30
These are smaller inconsistencies a dev agent *will* hit. Resolved here; mechanics in `ARCHITECTURE.md` §"Concurrency & Revisions".
31
31
32
-
1.**`base_revision` does not belong in Dossier frontmatter.** SPEC §4.1 lists it as a (optional) frontmatter field, but a revision is a *session-side* fact, not a property of the Dossier. **Remove it from frontmatter.** Instead: `dossier_recall`, `dossier_active`, and `dossier_switch`**return** the current revision; the agent passes it back as `base_revision` on `dossier_save`. The session binding persists it as `last_seen_revision`.
32
+
1.**`base_revision` does not belong in Dossier frontmatter.** SPEC §4.1 lists it as a (optional) frontmatter field, but a revision is a *session-side* fact, not a property of the Dossier. **Remove it from frontmatter.** Instead: `dossier_recall`and `dossier_session`**return** the current revision; the agent passes it back as `base_revision` on `dossier_save`. The session binding persists it as `last_seen_revision`.
33
33
34
34
2.**Recall output must include the revision.** SPEC §14.2 / §8 don't show recall returning a revision, but the agent needs it to save later. Recall returns `{distilled_state, frontmatter, revision, token_estimate, warnings}`.
> **Stage: All Milestones Completed (Project Fully Finished) + Lead Tracking + TUI Enhancements.** The entire Dossier durable memory layer (codename *chainlink*) is fully implemented, verified, and integrated across all surfaces (CLI, MCP, and the Bubble Tea TUI).
20
20
> -**Milestone 1–5:** Core file store, CLI, recall, warnings, lexical search/suggestions, promote/link flow, and the MCP stdio server are implemented.
21
21
> -**Milestone 6:** Active session binding, hook installation for Claude Code, confirmation prompts, capability detection, non-clobbering configurations, and the interactive **Rich TUI** (dashboard, detail recall view with native markdown rendering and fsnotify hot-refreshing, status/priority/next-action inline editing, ambiguity link resolution, and syntax-highlighted merge conflict resolving) are fully completed.
22
-
> -**Lead Tracking & Accountability:** A newly added `Lead` field allows assigning team members to specific dossiers. Supported end-to-end through `dossier promote --lead`, `dossier lead`, `dossier_set_lead` MCP tool, and visually grouped in the TUI with an inline `a` (assign) editor.
22
+
> -**Lead Tracking & Accountability:** A newly added `Lead` field allows assigning team members to specific dossiers. Supported end-to-end through `dossier promote --lead`, `dossier lead`, `dossier_update` MCP tool, and visually grouped in the TUI with an inline `a` (assign) editor.
23
23
> -**Milestone 7:** Optimistic concurrency control, non-overlapping frontmatter auto-merging, DP LCS unified diff body conflict generation (writing to `conflicts/`), and `dossier merge` CLI/Service commands are verified.
24
24
> -**Milestone 8:** The final Distillation Guide is authored in `assets/guide.md` and embedded in the binary to be written to `~/.dossier/context/guide.md` upon initialization. It has been upgraded to employ rigorous linguistic compression (syntactic pruning, lexical density, and negative space framing). All dogfooding validations, test sweeps, and PRD success metrics have been fully met.
25
25
> -**Stable Install & Auto-MCP Configuration:** Implemented stable binary self-install path command (`dossier install`, default `~/.local/bin/dossier`), volatile path detection on `init`, and auto-registration of both the MCP stdio server and lifecycle hooks in Claude Code's user/global configuration files (preserving existing third-party configs and backing up changed files).
26
26
> -**v1 rescoped to Claude Code only (2026-06-16):** Codex and Antigravity harnesses removed from code and docs. Claude Code is the single supported harness — it provides the full capability set; the degraded Tier 2/3 levels other harnesses reached were insufficient. The `Harness` interface/registry remain for possible future harnesses.
27
-
> -**In-session Dossier switching fixed (2026-06-16, ADR 0003):** Previously the MCP `dossier_switch`/`dossier_active` tools required a `session_id` the agent had no way to obtain, so an agent could not change (or even read) its active Dossier from inside Claude Code. Root cause + fix: Claude Code sets `CLAUDE_CODE_SESSION_ID` in the MCP server's env (verified identical to the transcript UUID and hook stdin `session_id`). A shared `harness.ResolveSessionID` now resolves the session at the adapter edge (precedence: explicit → `CLAUDE_CODE_SESSION_ID` → `DOSSIER_SESSION` → `sess_default`); MCP degrades visibly instead of falling back to the shared bucket. An agent can now call `dossier_switch` with just a slug; per-session isolation is preserved. See `docs/harness-capabilities.md` (§ MCP Session Identity) and ADR 0003.
27
+
> -**In-session Dossier switching fixed (2026-06-16, ADR 0003):** Previously the MCP `dossier_session` tool (consolidating switch/active) required a `session_id` the agent had no way to obtain, so an agent could not change (or even read) its active Dossier from inside Claude Code. Root cause + fix: Claude Code sets `CLAUDE_CODE_SESSION_ID` in the MCP server's env (verified identical to the transcript UUID and hook stdin `session_id`). A shared `harness.ResolveSessionID` now resolves the session at the adapter edge (precedence: explicit → `CLAUDE_CODE_SESSION_ID` → `DOSSIER_SESSION` → `sess_default`); MCP degrades visibly instead of falling back to the shared bucket. An agent can now call `dossier_session` with just a slug; per-session isolation is preserved. See `docs/harness-capabilities.md` (§ MCP Session Identity) and ADR 0003.
28
28
> -**Hardening (2026-06-17):** Addressed critical system stability and performance risks. Prevented OOM crashes by streaming artifact frontmatter instead of loading large bodies. Fixed severe O(N) performance degradation by bypassing full YAML parsing with fast-path string lookups during directory scans. Ensured strict history preservation, bounded LCS diff matrices for massive conflict files, resolved symlink-destructive writes in the harness adapter, and fortified non-interactive stdin blocking. Enhanced `Doctor` with comprehensive provenance validation, artifact origin checks, and unresolved conflict reporting. Improved `SessionEnd` safety by adding explicit audit logging for missing payload scenarios.
29
29
> -**TUI de-sessioned (2026-06-17, ADR 0004):** The TUI no longer resolves or carries a session identity and no longer exposes the per-session active binding. Removed the `a` ("make active") key, the `★` active marker/column, the `Session:`/`Active:` header fields, and the standalone-session footer warning — these only ever acted on the `sess_default` bucket that no live agent session reads (the "make-active does nothing for me" / "fixed Session value" confusion). The TUI is now purely a reactive browse/edit viewer (list, markdown recall with live hot-refreshing, status/priority/next-action inline editing, link, syntax-highlighted merge). `Service.Switch`/`Active` are unchanged and remain the CLI/MCP surface for per-session binding. Narrows B9 (see ADR 0004); supersedes ADR 0002 and obsoletes `docs/tui-plan.md`'s catch-up section.
-`dossier_recall(id)` — token-targeted resume, returns the filesystem path of the dossier (§4.2)
182
182
-`dossier_search(query, dossier_id?)`
183
183
-`dossier_save(id)` — governed write, no gate (§4.4, §4.11)
184
184
-`dossier_promote()` — promote current session
185
185
-`dossier_link(id?)` — with suggestions
186
186
-`dossier_merge(a, b)` — conflicts surfaced
187
-
-`dossier_active()` / `dossier_switch(id)` — inspect or change the Dossier bound to the current agent session
188
-
-`dossier_set_status` — lifecycle status change
189
-
-`dossier_update(id, next_action?, open_questions?, importance?, urgency?, due_date?)` — update any metadata fields in one call
190
-
-`dossier_path(id?)` — returns the active or specified Dossier directory path for inspection in the user's own tools
187
+
-`dossier_session(id?)` — inspect or change the Dossier bound to the current agent session
188
+
-`dossier_update(id, name?, status?, lead?, next_action?, open_questions?, importance?, urgency?, due_date?)` — update any metadata or frontmatter fields in one call
191
189
192
190
Write tools **commit without a human gate** (D4), but writes are governed by the Distillation Guide and fire on a deterministic cadence (§4.11) — not at the agent's discretion. Safety is structural: nothing is deleted, the audit log records every write, and the user can edit any Distilled State after the fact. Exceptions: ambiguous link targets and merge conflict resolution require human disambiguation; that's contradiction/target resolution, not a distillation review gate.
193
191
@@ -201,7 +199,7 @@ Write tools **commit without a human gate** (D4), but writes are governed by the
201
199
- Generates/refreshes a **context file** per Dossier for harnesses without MCP.
202
200
203
201
### 5.3 Slash command (in-session)
204
-
-**`/dossier`** — lists Dossiers grouped by `status`, in surfacing order (§4.1), without leaving the agent session. Optional args: `/dossier active`, `/dossier blocked`, etc. to filter to one status. It also supports selecting/switching the session's active Dossier from the list. Thin wrapper over `dossier_list` + `dossier_switch`; this is the quick "what's on my plate right now" view mid-conversation.
202
+
-**`/dossier`** — lists Dossiers grouped by `status`, in surfacing order (§4.1), without leaving the agent session. Optional args: `/dossier active`, `/dossier blocked`, etc. to filter to one status. It also supports selecting/switching the session's active Dossier from the list. Thin wrapper over `dossier_list` + `dossier_session`; this is the quick "what's on my plate right now" view mid-conversation.
205
203
206
204
### 5.4 Hooks (deterministic behavior)
207
205
Some behavior must not depend on the agent choosing to act; hooks make it deterministic where the harness supports them (e.g. Claude Code), with the context-file/skill fallback elsewhere.
@@ -290,7 +288,7 @@ That makes the behavior automatic without any user-visible ceremony at session s
290
288
The confirmation itself should be lightweight:
291
289
> "I see a couple of Dossiers that look related — *Auth refactor (active, last updated 3 days ago)* and *Login flow cleanup (blocked)*. Is one of these the right one to continue, or is this a separate thread?"
292
290
293
-
If the user picks one, bind to it (`dossier_switch`) and resume. If none fit, proceed with creation.
291
+
If the user picks one, bind to it (`dossier_session`) and resume. If none fit, proceed with creation.
294
292
295
293
**Design notes:**
296
294
- The check is zero-latency because the library is already in context — this is not a search call, just an in-context scan.
Copy file name to clipboardExpand all lines: SPEC.md
+3-8Lines changed: 3 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -287,7 +287,7 @@ Binding fields:
287
287
}
288
288
```
289
289
290
-
If a harness cannot expose a durable session id, the agent may maintain binding in context only. In that case, Dossier must still support `dossier_switch(id)` and `dossier_active()` during the session, but deterministic recovery of the binding after restart is not guaranteed.
290
+
If a harness cannot expose a durable session id, the agent may maintain binding in context only. In that case, Dossier must still support `dossier_session(id?)` during the session, but deterministic recovery of the binding after restart is not guaranteed.
291
291
292
292
### 5.2 Switching
293
293
@@ -444,11 +444,7 @@ Required tools:
444
444
- `dossier_promote`
445
445
- `dossier_link`
446
446
- `dossier_merge`
447
-
- `dossier_active`
448
-
- `dossier_switch`
449
-
- `dossier_path`
450
-
- `dossier_set_status`
451
-
- `dossier_set_lead`
447
+
- `dossier_session`
452
448
- `dossier_update`
453
449
454
450
### 8.2 Tool Contracts
@@ -964,8 +960,7 @@ Checks:
964
960
965
961
- Each session can bind zero or one active Dossier.
966
962
- Two sessions can bind different Dossiers.
967
-
- `dossier_active`reports current binding.
968
-
- `dossier_switch`changes binding and returns new Distilled State.
963
+
- `dossier_session`reports or changes session binding and returns new Distilled State when switching.
969
964
- `/clear`removes session context but does not alter Dossier files.
`Present the candidates to the user: "I found Dossiers that look related — [for each: Name (status, N days since last update)]. Is one of these the right one to continue, or is this a separate thread?"`,
305
-
`If the user picks one: call dossier_switch with its slug to bind it, then dossier_recall to load its state.`,
307
+
`If the user picks one: call dossier_session with its slug to bind it, then dossier_recall to load its state.`,
306
308
`If the user confirms this is a new topic: call dossier_promote again with force=true.`,
307
309
},
308
310
}, NewError(ErrAmbiguousTarget, "Multiple likely Dossiers match this promote request.")
@@ -1471,7 +1476,7 @@ func (s *Service) SessionStart(ctx context.Context, sessionID string) (string, e
1471
1476
sb.WriteString("No active Dossier is bound to this session.\n\n")
1472
1477
sb.WriteString("When the user names a topic to work on, check the Open Dossiers list above before creating anything:\n")
1473
1478
sb.WriteString("1. If a close match exists, surface it: \"I see [Name] ([status], last touched N days ago) — is that the one to continue, or is this a new thread?\"\n")
1474
-
sb.WriteString("2. If the user confirms an existing one, call dossier_switch with its slug.\n")
1479
+
sb.WriteString("2. If the user confirms an existing one, call dossier_session with its slug.\n")
1475
1480
sb.WriteString("3. If none match or the user says it's new, call dossier_promote — it will run a similarity check and flag any missed candidates before creating.\n")
0 commit comments