Smriti previously required passing <space> on every command, and the
repo↔space binding lived only inside a hardcoded SessionStart hook
string. This makes the binding durable and ambient.
- New cli/smriti_cli/attachment.py reads/writes `.smriti.json` at the
repo root — a committed file that binds the repo to a space and
travels with it (repo A→space A, repo B→space B).
- The <space> positional is now optional on state, current, metrics,
checkpoint create/list, claim create/list, and worktree open/list.
When omitted it resolves from the nearest `.smriti.json`, walking up
from the working directory, so any session opened inside the repo
stays connected without re-passing the space.
- `smriti init` writes `.smriti.json` and binds the space's backend
project_root to the checkout. The generated SessionStart hook is now
space-less (`smriti state --compact`) — identical across every
project and stable when a project is re-attached.
- New `smriti status` command: a day-two continuity check showing the
attachment, backend health, and open work.
- CLI api_url also resolves from the attachment as a last-resort
default, behind --api-url and SMRITI_API_URL.
MCP tool signatures are intentionally unchanged this sprint.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`smriti current` already normalizes a list-valued blocked_by to a clean
comma-separated string via the backend CurrentTask validator, but `smriti
state` rendered it through an f-string and leaked the raw Python list repr
(['a', 'b']) into the state brief — the surface agents read at session start.
Add a `_coerce_blocked_by` helper in the CLI formatters mirroring that
validator, and apply it in `_normalize_task_item` so every `smriti state`
task line renders blocked_by the same way `smriti current` does. Adds
regression tests.
External-machine validation found GET /api/v5/current 500s on a real
project: a structured task can carry `blocked_by` as a list of dependency
labels, but CurrentTask.blocked_by is typed Optional[str], so constructing
the model raised a Pydantic ValidationError.
Add a field validator that normalizes `blocked_by` — string, list, or null —
to a single display string. The API contract is unchanged (blocked_by stays
a string), so the CLI and the Project Current State UI panel, which both
read this endpoint, need no change. Adds a regression test.
The 3-way merge auto-applied both Claude's and Codex's MCP-config intros
without flagging a conflict, leaving two paragraphs that both say "smriti
init prints the config." Collapse them into one — keeping the quickstart-first
onboarding wording and folding in Codex's `which smriti-mcp` manual-config tip.
An external-machine validation pass confirmed setup, local-first, doctor,
quickstart, and init all work — but the README still routed a new user
straight to `smriti init`, which opens an empty space where Smriti's value
is not yet visible.
Restructure the "Getting started" flow: a new step 3 runs `smriti doctor`
then `smriti quickstart` so the first thing a user sees is a populated demo
space. The init step now says to cd into your own project first; the MCP
guidance defers to the resolved config `smriti init` prints rather than a
bare `smriti-mcp`; mock-mode limits and "Try the demo" are clarified to match.
A fresh install opens to an empty space, so Smriti's value — which only
shows once reasoning has accumulated — is invisible on day one. `smriti
quickstart` seeds one small, finished project (a rate-limiting feature
built by two agents, with a branch explored and dropped) and prints a
short guided walkthrough.
The demo space `smriti-demo` carries a marker in its description: --remove
only deletes a marked space, --reset rebuilds it, and seeding rolls back a
half-built space on failure. The fixture is plain structured data with
content-integrity tests guarding counts, intent types, note kinds, the
demo marker, and branch divergence.
Packaging/readiness pass — documentation only, no feature or behavior change.
- REPO_STRUCTURE.md, CONTRIBUTING.md: corrected test counts (156 integration,
133 unit, 151 CLI), local-first setup flow (make setup-local / dev-local),
command count, new routes/types/test files.
- README.md: refreshed dogfood metrics, added Project Current State and
smriti doctor to the surfaces, SQLite to the tech stack.
- cli/README.md: MCP tool count 17 -> 21 (added the four worktree tools),
documented the smriti worktree commands.
- ARCHITECTURE.md: API table now lists the Project Current State and metrics
endpoints; new Database modes section (local SQLite / Postgres).
- DECISIONS.md: recorded the local-first SQLite mode and Project Current
State surface decisions.
- AGENTS.md: regenerated from skill pack template v2.3 (was a stale v1.5
render); the .claude/ claude-code render was likewise refreshed locally.
.env.example, docs/DEMO_SCRIPT.md, and CLAUDE.md were reviewed and left as-is.
Smriti can now run against a file-backed SQLite database with no Docker
and no Postgres, removing the operate-a-backend burden for solo builders.
Postgres remains the stronger shared/team mode, unchanged.
- Portable column types (app/db/types.py): JSON renders as JSONB on
PostgreSQL and generic JSON on SQLite; the pgvector embedding column
renders as JSON on SQLite. Same models and create_all on both backends.
- Mode resolution (config.py): SMRITI_DB_MODE=local|postgres, defaulting
to local when unconfigured. An explicitly-set Postgres DATABASE_URL
preserves Postgres behavior, so existing setups are unaffected. Local
DB defaults to ~/.smriti/smriti.db; SMRITI_LOCAL_DB_PATH overrides.
- SQLite engine setup (database.py): check_same_thread plus foreign_keys
/ WAL / busy_timeout pragmas; a lazy first-run create_all bootstrap on
first DB use, which keeps the integration test suite insulated.
- Removed the integration-test JSONB/VECTOR DDL substitution hack — the
models are genuinely portable now, so conftest needs no type patching.
- Alembic resolves its URL through the same logic (Postgres mode only).
- New persistent file-backed SQLite smoke test, plus mode-resolution and
per-dialect type-rendering tests.
Local mode uses create_all, not Alembic. No schema changes.
Type the commit metadata blob — new Note and CommitMetadata interfaces
in types/index.ts — so commit.metadata.notes resolves to Note[] instead
of unknown. This fixes the three CommitDetailPage errors where .length,
.map, and the JSX child type all failed against an unknown/{}-typed
notes field.
Normalize the structured-task list to strings at the rows() call in
ChatWorkspacePage so the string-list renderer receives string[] rather
than (string | StructuredTask)[].
No behavior change. npm run build (tsc -b + vite build) and tsc --noEmit
are now clean.
Add GET /api/v5/current/spaces/{id} — a packaged, computed-on-demand
snapshot of where a space is right now: current direction, counts,
attention signals (open questions, divergence, active work), active
work claims, open tasks grouped by intent, recent milestones, and
recent activity. Shared payload contract with the smriti current CLI
surface built in parallel.
Render it as the ProjectCurrentState panel at the top of LineagePage,
replacing the hand-rolled current-state summary. Extract a shared
_get_active_claims helper so the state and current endpoints report
active work identically. No schema changes.
CONTRIBUTING: fix stale test counts (177 integration / 97 unit / 70 CLI
became 122 / 125 / 122 across V1+V2 work).
DECISIONS: expand the V2 worktree rationale section. The V2 PR shipped
a single paragraph on "why binding is optional"; this adds the broader
design rationale that motivates the primitive itself — the chaanbeen
catastrophic failure mode, why git worktrees vs separate clones, why
state-brief shells out to git per request rather than persisting drift,
why the probe cache is 60s. Existing "binding is optional" paragraph
stays, now flowing naturally from the expanded context.
Done in worktree ~/.smriti/worktrees/smriti-dev/claude-code-555d3005
on branch smriti/claude-code/555d3005 in parallel with Codex's
worktree-list-probe work (V2 dogfood test).
V1 mentioned that claim binding and state-brief enrichment would land
in V2. V2 is now on main (39003a8), so update the bullet to describe
the actual current behavior: bind a claim to a worktree, see drift
in state brief, skill pack v2.0 teaches the reflex. Tool count
unchanged at 21 (V2 added params to existing tools, not new ones).
- README: 17 → 21 MCP tools, add worktrees bullet to coordination
primitives (notes V1 = CRUD primitive only; binding + state-brief
enrichment deferred to V2)
- CONTRIBUTING: 17 → 21 MCP tools
DECISIONS.md and skill pack template are intentionally not touched —
the V1 prompt explicitly deferred those to V2 so the rationale and
skill pack reflexes can be written together with the actual usage
patterns we'll learn from V2 (claim binding + state brief).
Adds WorkTree schema and migration, /api/v5/worktrees CRUD, CLI and MCP worktree surfaces, targeted regression tests, health capability, and minimal docs. Live Postgres migration/manual localhost verification intentionally remain pending until the full backend provider-config gate is resolved.
Captured three screenshots for the README using playwright against
the live local environment:
- lineage-dashboard.png — real LineagePage showing 56 checkpoints,
summary panel, needs-attention signal, author badges
- checkpoint-detail.png — the autonomy milestone checkpoint with
structured tasks (intent badges), entities, and founder notes
- cli-state-and-metrics.png — terminal-styled render of real CLI
output from smriti state --compact and smriti metrics
Fixed a crash in CommitDetailPage exposed by the screenshot attempt:
diffList was typed list[str] but tasks are now structured objects
after the task IDs feature landed. React threw "Objects are not
valid as a React child" when trying to render the diff result.
Fix normalizes tasks to their text field before diffing.
README now references real images instead of inline code blocks.
TypeScript clean, 331 tests pass.
The 3 screenshot placeholders pointed at files that don't exist yet,
which would render as broken images on GitHub. Replaced with inline
code blocks showing real CLI output (smriti state --compact and
smriti metrics) — these render cleanly now and can be swapped for
actual screenshots later when captured.
Removed stale Loom link and old checkpoint-diff screenshot reference.
README now references 3 new screenshots matching the current product:
LineagePage dashboard, CLI state+metrics, checkpoint detail with
structured tasks and notes. Screenshots are placeholders until
captured from the live environment.
Added docs/DEMO_SCRIPT.md: 3-act, 4-5 minute recording script
covering the state surface, coordination proof (metrics + autonomy
milestone), and developer experience. Includes exact commands,
highlight points, and a screenshot capture checklist.
Restructured from single-user chat-drift framing to multi-agent
coordination as the primary story. Leads with the problem (agents
have no shared state), the solution (structured reasoning-state
backend), and the proof (56 checkpoints, 30 cross-agent handoffs,
autonomous complementary task selection). Single-user value prop
preserved as a secondary section. All claims grounded in current
reality — no future hype, no unqualified comparisons.
Three integration tests covering the recheck pattern:
- Duplicate task_id claims both visible (advisory, not rejected)
- Different task_id claims show no collision
- Full pivot flow: detect collision, abandon, re-claim on different task
Single nullable VARCHAR(100) column addition. Applied and verified
against the real local Postgres: claims with task_id round-trip
correctly, claims without task_id work unchanged.
Tasks gain an optional id field (short slug like "impl-1", "docs-arch").
Claims gain an optional task_id field referencing a specific task. The
state brief shows (id: X) on tasks and (task: X) on claims, making it
precise which task a claim covers.
Skill pack v1.9 teaches the recheck pattern: after creating a claim,
re-read state to detect if another agent claimed the same task_id in
the race window. If collision detected, abandon and pivot.
This solves the near-simultaneous start problem from the autonomy
validation where both agents picked [docs] because claims had no
task-level identity.
Cherry-picked the non-redundant section from Codex's
codex/docs-task-claim-affinity-rationale branch: "Why structured
tasks reuse the claim intent vocabulary." Dropped Codex's
open/done-status section (redundant with existing coverage).
The three structured-task decision sections now flow as:
reuse vocabulary → instead of task manager → open/done only
ARCHITECTURE.md: new section on structured tasks as the autonomy
mechanism — task shape, intent hints, status semantics, extract
prompt, rendering, and the selection logic.
DECISIONS.md: why structured tasks instead of a task manager, a
recommended-action endpoint, or richer claim semantics. Why task
status is open/done only — claims are live state, tasks are durable.
The health endpoint now returns git_sha and a capabilities list so
agents can detect when the running backend is missing features they
need (e.g., claims, structured_tasks). Skill pack v1.8 teaches the
capabilities probe: check /health when a 404 or missing section
suggests the backend is stale, tell the human to restart.
Diagnosed from the autonomy validation where Codex hit a backend
without /api/v5/claims — the backend process was running old code.
Tests the full pipeline: create checkpoint with structured task objects
via V4 commit endpoint, read back via V2 commits, verify JSONB
round-trip preserves intent_hint/blocked_by/status. Also tests mixed
string+object tasks and formatter rendering in state brief.
The V4 chat commit endpoint had tasks: list[str], which rejected
the structured task objects produced by the extract prompt. Widened
to bare list to match CommitCreate and CommitModel.
Tasks in checkpoints evolve from flat strings to objects with optional
intent_hint (implement/review/investigate/docs/test), blocked_by
(dependency label), and status (open/done). Agents reading the state
brief can now self-select complementary work by matching task intents
against active claim intent_types — no founder routing needed.
Backward-compatible: old string tasks normalize at render time. No
schema migration. JSONB handles both shapes. Skill pack v1.7 teaches
the autonomous selection reflex.