diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b02bbaa..8474b19 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -587,7 +587,7 @@ decide. No scheduler, no assignment, no orchestrator. **Backend capabilities manifest.** The `/health` endpoint returns `git_sha` and a `capabilities` list (`claims`, `structured_tasks`, `task_ids`, `checkpoint_notes`, `branch_disposition`, `freshness`, `compact_state`, -`worktrees`, `worktree_binding`). +`worktrees`, `worktree_binding`, `activation_health`). Agents probe this when a 404 or missing section suggests the backend is running stale code. The capabilities list is hardcoded in `main.py` and updated when new features ship. @@ -604,6 +604,17 @@ last commit). This keeps worktree usage visible exactly where agents already look for coordination state — `## Active work` — while preserving solo-agent claims that do not need a worktree. +**Repo-state drift detection.** The CLI records the working repo's git HEAD and +branch on every checkpoint it creates — stored under the commit's `context_blob` +via the V4 commit endpoint's `repo_state` field. On a later `smriti state`, the +CLI inspects the local git repo and compares it against that recorded state, +appending a `## Repo state` section: branch / HEAD / root, working-tree health +(dirty, untracked, detached HEAD), and — the trust signal — how far the repo has +moved since the checkpoint (N commits ahead, diverged, or taken on a different +branch). The comparison is entirely client-side and read-only: no fetch, no +reconciliation. The backend cannot see the user's working tree, so it only +stores what the CLI captures; computing the drift is the CLI's job. + --- ## What Is Not Yet In the Architecture diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6d00e3..bf63cce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -135,7 +135,7 @@ EXPECTED_OUTCOMES at minimum. Smriti has three agent-facing surfaces beyond the chat UI: -- **CLI** (`cli/smriti_cli/main.py`) — `smriti` command, 14 commands +- **CLI** (`cli/smriti_cli/main.py`) — `smriti` command, 16 commands - **MCP server** (`cli/smriti_cli/mcp_server.py`) — `smriti-mcp` command, 21 tools - **Skill pack** (`cli/smriti_cli/skill_pack/`) — versioned instruction files for Claude Code and Codex diff --git a/DECISIONS.md b/DECISIONS.md index 1073bed..9c55727 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -623,6 +623,37 @@ demand from existing data, with no new schema. It is deliberately a read-only aggregate, not a new primitive: it surfaces what checkpoints, claims, and notes already record, rather than introducing a new kind of state. +### Why repo-state drift detection lives in the CLI, not the backend + +`smriti state` compares the working git repo against the HEAD and branch the +latest checkpoint recorded. That comparison runs entirely in the CLI: the CLI +reads local git, and the backend only stores the `repo_state` the CLI captured +on each checkpoint. + +The backend cannot see the user's working tree — it is an HTTP service that may +run on another machine. Any drift verdict it produced would be +authoritative-but-blind. The same reasoning that keeps worktree drift a +per-request git probe keeps repo-state drift client-side: git is the only honest +source, and only the CLI stands in the repo. + +Checkpoints created before this feature, or by the MCP server (which has no repo +to inspect), record no `repo_state` and are left uncompared — the feature +degrades to silence, never to a wrong answer. + +### Why destructive Space deletion is gated, not prevented + +Deleting a Space cascades to every checkpoint, session, and turn under it. A +destructive-operations incident — `smriti space delete -y` wiping a +fully populated Space — showed a single confirmation flag was not enough. + +The gate is an explicit, separate force signal at every layer that can delete a +Space: `--force` on the CLI (orthogonal to `-y`), an echo-back `confirm_space` +argument on the MCP tool (an MCP tool cannot open an interactive prompt, so the +confirmation has to be a tool argument), and `force=true` on `DELETE +/api/v2/repos/{id}` so the backend refuses a populated-Space delete no matter +which client calls it. Deletion stays possible — it just cannot happen by +accident; an empty Space still deletes without the extra flag. + --- ## Open questions and deferred decisions diff --git a/README.md b/README.md index bf777c0..1da1d16 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ Smriti replaces that with a structured reasoning-state layer. Agents read the cu The entire coordination substrate was developed with Claude Code and Codex working in parallel on the same codebase, coordinating through Smriti's own state. Current project metrics (`smriti metrics smriti-dev`): -- **87 checkpoints** across **2 agents** (Claude Code: 51, Codex: 36) -- **47 cross-agent continuations** — checkpoints where a different agent picked up where the previous one left off -- **53 work claims** at **98% completion** — nearly every declared intent finished +- **117 checkpoints** across **2 agents** (Claude Code: 70, Codex: 47) +- **61 cross-agent continuations** — checkpoints where a different agent picked up where the previous one left off +- **77 work claims** at **96% completion** — nearly every declared intent finished - **7 milestones** marking proven coordination proofs The strongest proof: two agents started near-simultaneously, read the same task surface (4 tasks with stable IDs and intent hints), and independently picked different complementary tasks — one chose `[test]`, the other chose `[implement]` — without any human routing. No orchestrator. No task queue. Just structured metadata on the shared state. @@ -52,6 +52,7 @@ One project, one Smriti Space, multiple agents. Each reads the state, declares i - **Structured tasks with intent hints** — checkpoint tasks carry optional `intent_hint`, `blocked_by`, `status` (open/done), and stable `id` slugs. Agents self-select complementary work from the task list. - **Task-referenced claims** — claims can reference a specific task ID (`--task-id impl-1`), enabling precise collision detection when agents start near-simultaneously. - **Freshness checks** (`--since`) — agents detect whether the state has moved since their base before checkpointing. +- **Repo-state drift detection** — `smriti state` compares the working git repo against the HEAD and branch the latest checkpoint recorded, flagging when the repo has moved on (commits ahead of the checkpoint, a different branch, a dirty tree). The reasoning state stops being "trust me" — it tells you when it may be stale. - **Branch disposition** — branches are explicitly marked `integrated`, `abandoned`, or `active` so the state brief stays clean. - **Checkpoint notes** — additive annotations (note, milestone, noise) on existing checkpoints without modifying the immutable reasoning state. - **Backend capabilities** (`/health`) — the backend advertises its feature surface so agents can detect stale backends. `smriti doctor` diagnoses backend reachability and runtime/code mismatches. @@ -59,6 +60,7 @@ One project, one Smriti Space, multiple agents. Each reads the state, declares i - **Project metrics** (`smriti metrics `) — coordination, state quality, and branch lifecycle KPIs computed on demand from existing data. - **Project Current State** (`smriti current `) — a compact, packaged snapshot of where a project is right now: current direction, counts, attention signals, active work, recent milestones, open tasks by intent, and recent activity. Founder- and agent-facing; also rendered as a panel in the chat UI. - **Worktrees** (`smriti worktree open/list/show/close`) — first-class git worktree primitive so multiple agents can work on the same project without sharing one checkout. Each agent gets its own working tree and staging index, eliminating the cross-agent commit pollution failure mode that motivated the feature. Claims can be bound to a worktree (`smriti claim create --worktree `); the state brief surfaces per-claim working-tree drift (branch, dirty count, ahead/behind vs origin/main, last commit) so agents can see what other agents are editing without asking. The skill pack teaches the reflex. +- **Destructive-action guards** — deleting a Space that still holds checkpoints requires an explicit `--force` (CLI), an echo-back `confirm_space` argument (MCP tool), or `force=true` (API). Real reasoning state cannot be wiped by a single careless flag. --- @@ -177,6 +179,15 @@ space argument, and a Claude or Codex session opened anywhere in the repo connects to the right space on its own. Use `smriti attach ` to attach a repo (or re-point one) without the full `init`. +Once attached, the everyday commands need no `` argument — run them from +anywhere inside the repo: + +```bash +smriti state # the continuation brief — read first each session +smriti current # compact snapshot: direction, attention, open work +smriti metrics # project coordination KPIs +``` + **MCP config** (Claude Code, Cursor, Windsurf). `smriti init` prints a ready-to-paste MCP config block with the executable path and API URL already resolved for your machine — use what it prints. If you configure MCP manually diff --git a/REPO_STRUCTURE.md b/REPO_STRUCTURE.md index b13c64b..d17db4f 100644 --- a/REPO_STRUCTURE.md +++ b/REPO_STRUCTURE.md @@ -114,15 +114,16 @@ smriti/ │ ├── pyproject.toml Installable as `pip install -e ./cli` │ │ → `smriti` + `smriti-mcp` on PATH │ ├── smriti_cli/ -│ │ ├── main.py argparse dispatcher: init, doctor, space, state, -│ │ │ current, checkpoint, fork, restore, compare, -│ │ │ branch, claim, worktree, skills, metrics +│ │ ├── main.py argparse dispatcher: init, attach, doctor, +│ │ │ quickstart, space, state, current, +│ │ │ checkpoint, fork, restore, compare, branch, +│ │ │ claim, worktree, skills, metrics │ │ ├── mcp_server.py FastMCP server (21 tools, stdio transport) │ │ ├── client.py SmritiClient HTTP wrapper (includes claims/worktrees) │ │ ├── formatters.py Continuation-oriented markdown renderers │ │ │ (multi-branch, active claims, divergence) │ │ └── skill_pack/ Agent skill pack source and renderer -│ │ ├── template.md Single source of truth (v2.3, 15 sections) +│ │ ├── template.md Single source of truth (v2.4, 15 sections) │ │ ├── renderer.py Pure-function render + versioned install │ │ └── targets.py Target configs (claude-code, codex) │ └── tests/ CLI + MCP tests (151 tests)