Commit graph

143 commits

Author SHA1 Message Date
Himanshu Dongre
0c63ead534 Stop swallowing chat-title generation failures silently
Some checks failed
Deploy website to GitHub Pages / deploy (push) Has been cancelled
The /api/v4/chat/sessions/{id}/title endpoint wrapped its entire body
in a bare `except Exception: pass`. When the background LLM provider
was missing or the call failed, the endpoint silently returned the
unchanged session — clients could not tell "title not requested yet"
apart from "tried and failed because no provider." Same anti-pattern
as the extract bug (713ed9a), lower severity (titles are cosmetic).

This is the smallest correct fix:

  - Title generation is still best-effort. The endpoint always returns
    200 with the session. The chat surface is never blocked.
  - Failures are no longer silent. The bare except is replaced with
    three typed branches:
      * ProviderNotConfiguredError → WARNING log + status
        "skipped:provider_not_configured"
      * generic provider call error → WARNING log + status
        "skipped:provider_error"
      * DB write error after successful generation → ERROR log + status
        "skipped:db_error" (also rolls back the session)
  - SessionResponse gains an optional `title_generation_status: str` field
    (default None). The title endpoint sets it to one of the four enum
    values above ("ok" on success). Every other endpoint that returns
    SessionResponse continues to return null for this field — additive,
    no client-breaking change.
  - Logs carry session_id, provider, model, exception type, and message
    — enough to diagnose, no secrets (provider SDK errors do not place
    API keys in str(e); the test asserts no "sk-" / "bearer " patterns).

Chat-send is not touched. Title generation is only invoked by the
dedicated /title endpoint (verified by grep), so chat-send was already
independent of this code path and remains independent.

Tests (new file backend/tests/integration/test_chat_title.py):
  - test_title_generation_succeeds_with_provider: pins the happy path
    (status "ok", no WARNING/ERROR noise).
  - test_title_generation_fails_loud_without_provider: regression test
    for the bare-except bug — asserts 200, session title unchanged,
    status "skipped:provider_not_configured", exactly one WARNING log
    with diagnostic context, no exception bubbles.
  - test_title_generation_handles_provider_call_error: pins the generic
    provider-error branch.
  - test_title_endpoint_400_when_no_turns: pins the existing precondition
    so the typed-except rewrite doesn't accidentally swallow it.
  - test_other_session_endpoints_omit_title_generation_status: confirms
    the additive field is null on other SessionResponse endpoints.

Full backend integration suite: 170 passed locally (was 165 + 5 new).
2026-05-23 18:09:27 +05:30
Himanshu Dongre
713ed9a007 Refuse to silently extract mock content into a real Space
A fresh Smriti install with no provider configured could still run
`smriti checkpoint create --extract`, which silently returned
MockAdapter content like "Mock decision from provider". If committed,
that placeholder text became part of the user's real reasoning state.

Root cause: backend/app/api/routes/checkpoint.py:417 called
`get_adapter(cfg.background.provider, allow_mock=True)`. The
`allow_mock=True` flag means the registry quietly returns MockAdapter
when no API key is configured, rather than raising. The CLI received
the canned mock JSON and committed it without inspecting whether it
came from a real LLM.

The extract endpoint was the only route in the codebase with this
pattern — draft, review, chat title, and chat send already correctly
pass `allow_mock=False`.

The new contract:

- Core Smriti (setup, doctor, quickstart, state/current/metrics,
  claims, attach, manual JSON checkpoints) requires no API key.
- Real LLM-backed paths (`--extract`, draft, review, chat send)
  require a configured provider — OpenAI / Anthropic / OpenRouter /
  generic OpenAI-compatible (local models like Ollama).
- Mock extraction still works for tests and demos, but only when the
  caller explicitly opts in (use_mock=true on the HTTP payload).
  It is never silently the default.

Backend:
- POST /api/v5/checkpoint/extract now passes allow_mock=False and
  catches ProviderNotConfiguredError, returning HTTP 412 with a
  structured detail: error code, human message, the provider it
  tried, and a list of fix paths the CLI surfaces.
- CheckpointExtractResponse gains `provider` and `model` echo fields
  (additive, default empty) so callers can confirm what answered.

CLI:
- checkpoint create --extract catches 412 and prints the actionable
  fix list; exits 78 (EX_CONFIG). Defense in depth: even on a 200,
  refuses to commit if response.provider == "mock" on the default
  path (so any future regression in the backend is still caught).
- smriti doctor surfaces background provider state prominently:
  `ready (real LLM extraction enabled)` or `⚠ MOCK or DISABLED — …
  will fail until a provider is configured`.
- smriti doctor --strict exits 78 when the background provider is
  mock/disabled or the backend is unreachable. Safe to wire into
  CI before any --extract step.
- On a successful --extract commit, the CLI shows `extracted via
  <provider>/<model>` under the commit confirmation.

Docs:
- README: new "Provider configuration (LLM-backed features)" section
  drawing the boundary explicitly; mentions the generic provider for
  local OpenAI-compatible models; flags mock as test-only.
- .env.example: rewrote the provider section so an empty key or a
  model-without-a-key is not interpreted as "ready".
- Skill pack template: new §4.1 "Before your first --extract: verify
  the provider" telling agents to run `smriti doctor`, refuse
  --extract when background_provider is mock/disabled, and fall back
  to manual JSON checkpoints or ask the human to configure a
  provider. Re-rendered to AGENTS.md (Codex target). The Claude Code
  target (.claude/skills/smriti/SKILL.md) is gitignored per-user
  install; rerun `smriti skills install claude-code` to refresh.
- website/index.html: Try-it lede now spells out which features need
  a provider rather than gesturing at "optional LLM features".

Tests:
- test_extract_without_provider_fails_loud: regression for the bug —
  monkeypatches get_adapter to raise ProviderNotConfiguredError,
  asserts HTTP 412 with the structured detail shape, and asserts
  the response body contains neither "Mock decision from provider"
  nor "Mock Checkpoint". This test would fail on pre-fix code.
- test_extract_with_provider_echoes_provider_and_model: pins the
  green path — provider and model must be echoed and must not be
  "mock" when the real adapter answers.
- test_extract_happy_path_with_mock: unchanged, still pins the
  explicit use_mock=true contract.
- Full backend integration suite: 165 passed locally (with the
  pre-existing real-provider draft test passing under
  backend/config/providers.yaml).
2026-05-23 17:48:14 +05:30
Himanshu Dongre
15e099b67e Recut the visual design — braided agent strands, refined palette
Some checks failed
Deploy website to GitHub Pages / deploy (push) Has been cancelled
This pass replaces the v2 visual language with a more handcrafted,
signature-feeling system. Structure and copy are preserved; only the
visual + interaction layer is reworked.

Visual metaphor
---------------
The dominant motif is a braid of two agent strands (claude-code in
ember, codex in indigo) weaving over and under each other through
hexagonal "checkpoint stones." The stones carry short hashes; the
rightmost is "wet" — currently being written — and gets a soft ember
pulse. Braiding has cultural weight (DNA, rope, river confluence) and
reads as "structured intertwining," which is exactly what shared
reasoning state is. The same motif scales down to a taut, stretched
braid in the drift section.

Palette
-------
Refined to feel like a signature, not a template:
- Deeper cool-black `#070710` background (warm accents pop harder
  against blue-black than against grey-black).
- Ember `#ffb663` — warmer and more saturated than v2's `#f5c773`;
  campfire ember, not corporate gold. This is the Smriti color.
- Indigo `#7c8cff` — saturated, fresh; not v2's washed `#8ba0c7`.
- Aurora `#7be3b0` — third pole used sparingly for matches / done
  states, so the page isn't just ember + indigo.
- Warm off-white paper `#e9e7e2` for body text.
- Subtle SVG-noise grain overlay (5% opacity, overlay blend) gives
  the dark surface tooth.
- Three hand-placed ember-glow anchor regions (hero, centerpiece,
  CTA) signal hierarchy — not decorative gradient blobs.

Section redesigns
-----------------
- Hero — braid + 5 hexagonal stones replacing v2's circle-and-line
  timeline. Subtle 14s sway on the strands. The rightmost (wet)
  stone glows and pulses.
- Missing primitive — replaced the rigid 3-column-grid + connector
  gutter with a typographic glossary. Mapped rows get an ember dot;
  unmapped rows get an indigo dot and the "no equivalent" label.
  Reads like a hand-typeset comparison sheet, not a spreadsheet.
- HANDOFF.md vs structured — both panels now have a lined-paper
  background. The HANDOFF panel has a `COLLISION` (red) badge; the
  checkpoint panel has a `RESOLVED` (aurora) badge. The conflict
  line types in, gets struck through, and the resolution types in
  underneath on scroll-in.
- What Smriti is — checkpoint render becomes a parsed structured
  tree with labeled field/value pairs and intent/agent tag pills.
- Multi-agent coordination (centerpiece) — completely rebuilt.
  Three columns: claude-code panel (left) | task pool (center) |
  codex panel (right). Tasks are "packets" that fly from the
  central pool into the side panels via JS-animated transforms,
  with springy easing. Each agent has a working stack that
  populates as packets land. Plays once on scroll-in, replayable.
  Bonus: clicking any unclaimed packet fires it manually to
  whichever agent has fewer claims.
- Drift — repo timeline replaced with a tensile braid stretched
  between the checkpoint stone and the HEAD stone. On scroll-in,
  the HEAD stone nudges +14px right, gets the warning color, and
  the "+2 commits ahead" badge fades in.
- Built with Smriti — terminal panel now has traffic-light dots, a
  blinking caret, and ember underline animation on
  "67 cross-agent continuations" on scroll-in. Numbers are
  semantically colored (ember = main, indigo = codex, aurora =
  success rates).
- Try it — two terminals now sit on a very subtle skew axis (like
  an open laptop spread); hover snaps them straight.
- Brand mark — replaced the dot-grid with a hexagonal stone and two
  woven strand-threads. Soft ember pulse every ~6s.

Motion
------
Tasteful, per-section motion treatments rather than uniform fade-up.
Slow braid sway on hero. Live-typing markdown collision. Springy
packet flight. Drift stone nudge. CLI caret blink. Brand mark pulse.
SVG path draw-in. Honors `prefers-reduced-motion: reduce` — all
animations skip, every element lands in its terminal state, carets
go static.

Implementation
--------------
Still pure HTML + CSS + ~330 lines of vanilla JS. No framework, no
build step, no webfont, no third-party requests. IntersectionObserver
thresholds tuned to 0.18 so animations fire reliably on mobile (tall
stacked sections were below the previous 0.35–0.45 thresholds).
Existing GitHub Pages workflow uploads ./website unchanged.

Mobile responsive at 980 / 720 / 420 breakpoints. Theatre stacks
vertically on mobile, packets still fly to the correct positions
via computed bounding rects. Nav collapses to the GitHub CTA on
small screens.
2026-05-21 13:06:38 +05:30
Himanshu Dongre
b0bc283441 Redesign the landing page as a structured, visualized front door
Some checks are pending
Deploy website to GitHub Pages / deploy (push) Waiting to run
Replace the v1 static documentation page with a product-grade redesign
that shows what Smriti is rather than describing it.

Sections, top to bottom:
- Hero with an ambient two-agent-timeline diagram threaded through
  shared checkpoints. Single primary action.
- "The missing primitive" — Git and Smriti primitives mapped row-by-row
  with horizontal connectors, plus three Smriti rows with no Git analog.
- "Why HANDOFF.md isn't enough" — side-by-side panels: a markdown file
  with a stale-state collision next to a structured checkpoint that
  preserves decisions, task IDs, claims, and repo_state.
- "What Smriti is" — three lines of copy alongside a real-shaped
  checkpoint card with labeled structured fields.
- Centerpiece: a "protocol theatre" that animates two agents reading
  the same task pool, claiming complementary work, and routing around
  each other's claims. 5-step scripted animation, plays once on
  scroll-into-view, replayable.
- "Drift & trust" — repo-timeline SVG plus an excerpt of the
  ## Repo state section the agent reads at session start.
- "Built with Smriti" — mock CLI panel of `smriti metrics smriti-dev`
  with the current real numbers (129 checkpoints, 79+50 per agent,
  67 cross-agent continuations, 87 claims at 97% completion,
  7 milestones).
- "Try it in minutes" — two-terminal install + run blocks, links out
  to the README for the full setup ladder.
- CTA + footer.

Implementation: vanilla HTML + CSS + ~140 lines of vanilla JS. No
framework, no build step, no webfont, no third-party requests. The
existing Pages workflow keeps uploading ./website as-is. JS does two
things: IntersectionObserver-based reveal-on-scroll for sections, and
a stepwise controller for the protocol theatre. Honors
prefers-reduced-motion (animations skip, diagrams land in their final
state).

Design tokens extend the v1 dark + warm-gold palette with a second
cool indigo for state/coordination signals, plus motion + layout
tokens. Mobile responsive at 920px / 720px / 420px breakpoints. Nav
collapses to the GitHub CTA on small screens.

Remove three unused screenshot PNGs (~1MB) from website/assets/ —
v2 visualizes structures inline instead of showing wallpaper images.
The originals remain in docs/assets/ for the README.
2026-05-21 02:53:47 +05:30
Himanshu Dongre
5d00ba99f1 Add GitHub Pages deployment workflow for website/
The smallest correct path to publish the static landing page:

- `.github/workflows/pages.yml` uses the official actions/configure-pages
  + upload-pages-artifact + deploy-pages chain to upload ./website as
  the Pages site on every push to main that touches website/ or the
  workflow itself, plus a workflow_dispatch trigger for the first
  manual deploy.
- No content changes to the landing page, no framework, no build step —
  pure HTML + CSS uploaded as-is.
- Not chosen: moving website/ into docs/ to use the legacy "Deploy from
  a branch" path. docs/ already holds developer-facing API.md /
  DEMO_SCRIPT.md / assets; mixing those with the marketing landing page
  would conflate concerns and start exposing internal docs at the Pages
  URL.

One-time manual setup on GitHub (cannot be done from a workflow file):
  Settings -> Pages -> Build and deployment -> Source: GitHub Actions

After that, every push to main that touches website/ auto-publishes.
The first deploy can be triggered from the Actions tab via
workflow_dispatch. The site URL appears as the environment URL on the
workflow run and will default to https://<owner>.github.io/<repo>/.

Verified: YAML parses cleanly; the upload path ./website exists with
index.html; official action versions pinned (checkout@v4,
configure-pages@v5, upload-pages-artifact@v3, deploy-pages@v4).
2026-05-21 01:55:34 +05:30
Himanshu Dongre
6ddfc2eedf Apply the same two-terminal split to the landing page install block
The previous commit (Codex's README activation-path fix) split the
README's step-1 code block to make it clear that `make dev-local` is a
long-running foreground process that must stay in one terminal while
`source backend/.venv/bin/activate` runs in another.

The landing page at `website/index.html` had the same paste-and-get-stuck
shape in its "Try it in 5 minutes" install block. Apply the parallel
split with the exact same wording so the website and README give the
same first-run guidance — install in one block, then "Start the backend
in one terminal and keep it running", then "In a second terminal,
activate the CLI before running smriti commands".

Verified locally: page renders the split cleanly at 1280x800, no console
errors.
2026-05-21 01:43:52 +05:30
Himanshu Dongre
73914a9e1a Clarify local setup terminal flow 2026-05-21 01:41:44 +05:30
Himanshu Dongre
47d5bb0269 Add the first public landing page at website/
A self-contained static landing page — pure HTML + CSS, no JS framework,
no build step — lifting the README's positioning into a single
scrollable page a new visitor can read in about two minutes.

Sections, in order:
- Hero: "Code has Git. Multi-agent reasoning does not." + the
  version-control-for-reasoning-state framing + two CTAs.
- The problem: multi-agent collisions; markdown handoffs break.
- The Git analogy: the table from the README (commit -> checkpoint,
  branch -> fork, diff -> compare, revert -> restore, working-tree
  drift -> repo-state drift) plus the rows Git has no equivalent for
  (active claims, freshness checks, structured tasks + IDs).
- How it works: 4-beat (attach, read state, claim, checkpoint) plus
  the no-arg daily-loop snippet.
- What Smriti is not: not markdown, not memory, not orchestrator; and
  the concrete list of what markdown can't reliably provide.
- Built with Smriti: the real `smriti metrics smriti-dev` numbers and
  the strongest-proof line.
- Screenshots: dashboard, CLI, checkpoint detail (copied from
  docs/assets/ into website/assets/ so the site is self-contained).
- Try it in 5 minutes: install local-first -> smriti doctor -> smriti
  quickstart -> smriti init/attach -> no-arg daily workflow.
- CTA: star on GitHub + read the docs.

Tech: a system font stack (no webfonts), CSS variables, dark theme with
one warm accent, mobile-responsive at <=720px and <=420px. No JS. 230
lines HTML + 499 lines CSS + 3 screenshots + a .nojekyll marker.

Self-contained under website/. Existing frontend/ chat UI untouched.
Deployment is unconstrained — GitHub Pages from /website, Vercel,
Netlify, or any static host.

Verified locally via headless browser: page loads, no console errors,
no network failures, renders cleanly at desktop (1280x800) and mobile
(390x844) viewports.
2026-05-20 21:22:51 +05:30
Himanshu Dongre
e73157285c Clarify multi-project attachment in the README
Add a "Multiple projects" beat to the attach step (§4) explaining that
attachment is per-project-directory, not global — each project's
.smriti.json, SessionStart hook, and skill packs live inside that
project's directory, and a Claude Code or Codex session opened in a
project's directory automatically lands on that project's space. The
MCP server registration is machine-wide but stateless (every call
passes space="..." explicitly), so the server has no "current space"
of its own.

A clarification gap surfaced in user discussion: the README explained
`.smriti.json` but never explicitly walked through the multi-project
mental model.
2026-05-20 21:08:57 +05:30
Himanshu Dongre
3161c1a3c1 Close the skill-pack and API docs staleness before the website sprint
Skill pack (template.md -> AGENTS.md, .claude/skills/smriti/SKILL.md):
- §3.2 Repo reconciliation: lead with `## Repo state`'s automated drift
  signals; keep the manual git log checks as the documented fallback
  for checkpoints without recorded git state.
- §3.5 Backend reachability: lead with `smriti doctor` as the
  structured health check; keep `curl /health` as the raw fallback.
- Bump skill pack version 2.4 -> 2.5; re-render AGENTS.md (the
  .claude/skills/smriti/SKILL.md install is local-only and untracked).
- test_skill_pack: bump the expected version; add four single-line
  required phrases proving the new content shipped (`Repo state`,
  `smriti doctor`, "ahead of the last checkpoint", "checkpoint taken
  on a different branch").

docs/API.md:
- POST /api/v4/chat/commit: add `repo_state` to the request body
  example and a paragraph explaining its purpose (drift detection),
  persistence (`context_blob`), and read-back path (V4 state endpoint).
- DELETE /api/v2/repos/{repo_id}: add the missing section with the
  `force` query param, 204/404/409 responses, and the structured
  detail shape for the 409 refusal.

CLI suite: 253 passed. AGENTS.md and SKILL.md verified byte-identical
to fresh render(target) output.
2026-05-20 20:40:58 +05:30
Himanshu Dongre
c3fb578cfe Rewrite the README around versioned reasoning and multi-agent coordination
A public-facing positioning rewrite — the README was factually current after
the docs-truth pass but read like a backend feature list and undersold the
actual product.

- Lead with the thesis: "Code has Git. Multi-agent reasoning does not."
  Position Smriti as version control for project reasoning state.
- Add a Git analogy table (commit -> checkpoint, branch -> fork, diff ->
  compare, revert -> restore, working-tree drift -> repo-state drift) plus
  the coordination primitives Git doesn't have.
- Add a concrete "why markdown handoffs aren't enough" section listing
  what markdown can't reliably provide rather than just claiming it breaks.
- Reframe provider setup: the core coordination loop runs without API
  keys; keys are only for the LLM-assisted features (extract, draft,
  review, chat send). Previous wording over-emphasized keys.
- Rewrite the smriti init wording: cd into the project you want to
  attach; init writes project-local files in cwd; the wrong directory
  attaches the wrong project. Replaces the defensive "wire up Smriti's
  own repo by mistake" line.
- Reorder so positioning leads, then setup -> doctor -> quickstart ->
  init/attach -> no-arg daily workflow, then "What you get" details
  primitives value-framed, then "Built with Smriti" lands as evidence.
- Drop the standalone "Single-user story" section (folds into "Versioned
  reasoning") and condense the 13-item primitives list into 9
  value-framed bullets.

301 lines (was 369). Command syntax, metrics, and screenshot blocks
preserved verbatim from the docs-truth pass.
2026-05-20 20:10:58 +05:30
Himanshu Dongre
8e4138c879 Fix the stale SessionStart hook example in the README
The step-5 hook snippet showed `smriti state my-project --compact` and
claimed it was what `smriti init` generates. `smriti init` actually
generates a space-agnostic hook (`smriti state --compact`) that resolves
the space from the repo's .smriti.json attachment — verified in
`_build_session_start_hook_command`. Correct the snippet and note the
space-agnostic resolution.

Caught while integrating the cli/README.md command-reference refresh,
closing the docs truth pass as one coherent unit.
2026-05-20 00:30:47 +05:30
Himanshu Dongre
2f7e994f5e Refresh CLI command reference truth 2026-05-20 00:29:20 +05:30
Himanshu Dongre
c0ca5d1998 Refresh README and docs for the current product surfaces
A focused truth + packaging pass before the website sprint — the product
moved a lot since the last docs sync (local-first SQLite, quickstart,
doctor, attached-repo no-arg workflow, repo-state drift detection,
deletion safety).

README: refresh the stale "Built with Smriti" metrics to current numbers;
add repo-state drift detection and destructive-action guards to the
coordination/trust surfaces; add an explicit no-arg daily-workflow block
so the new-user path (setup -> doctor -> quickstart -> attach -> no-arg
state/current/metrics) routes cleanly.

ARCHITECTURE: correct the /health capabilities list (add
activation_health); document repo-state drift detection.

DECISIONS: record why drift detection is CLI-side and why destructive
Space deletion is gated, not prevented.

REPO_STRUCTURE / CONTRIBUTING: correct the CLI command list (add attach,
quickstart; 16 commands) and the skill-pack template version (2.4).

cli/README.md was already current and is unchanged. The agent skill pack
still teaches manual reconciliation and is deliberately left for its own
versioned follow-up pass.
2026-05-19 23:51:02 +05:30
Himanshu Dongre
3b6ef000dc Detect repo drift against the last checkpoint
The repo-state section added by the previous commit shows working-tree
and git-upstream drift. It does not answer the question Smriti's trust
story actually needs: has the repo moved since the last checkpoint?

Record git provenance on checkpoints and compare against it. The CLI
captures the git HEAD and branch when it creates a checkpoint; the V4
commit endpoint stores that under the commit's context_blob and returns
it on read. `smriti state` then compares the working repo against the
latest checkpoint's recorded HEAD/branch and surfaces:
  - repo unchanged since the last checkpoint
  - repo is N commit(s) ahead — recorded state may be stale
  - repo history has diverged from the last checkpoint
  - the last checkpoint was taken on a different branch

All local and read-only: no fetch, no reconciliation. Checkpoints made
before this feature (or by the MCP server) record no git state and are
simply left uncompared.
2026-05-19 23:22:22 +05:30
Himanshu Dongre
14e99a4616 Show local repo drift in state output 2026-05-19 22:43:46 +05:30
Himanshu Dongre
c65e913666 Pass force=true from the web UI space-delete confirmation
The backend now refuses DELETE /api/v2/repos/{id} with 409 for a space
that still holds checkpoints unless force=true is passed. The web UI's
delete-space request did not send it, so deleting a non-empty space from
the browser failed (it failed safe — nothing was deleted).

deleteRepo() gains an optional { force } argument, mirroring the sibling
deleteCommit()'s { cascade }. WorkspaceOverviewPage passes force=true from
the ConfirmDeleteModal's onConfirm — the point where the user has already
acknowledged the irreversible "this cannot be undone" confirmation. No
modal or UX change; only the request now carries the flag the backend
requires.
2026-05-19 20:41:33 +05:30
Himanshu Dongre
e303f7a547 Require force to delete a non-empty space at the API layer
The deletion-safety thread guarded the CLI (`--force`) and the MCP tool
(`confirm_space`), but `DELETE /api/v2/repos/{id}` itself still cascade-
deleted a fully populated space — every checkpoint, session, and turn —
with no server-side check. Any client that bypassed the CLI/MCP guards
(a direct API call, the web UI, a future client) reopened the incident
path.

Gate the route: `delete_repo` now counts the space's checkpoints and
refuses with 409 plus a structured detail (`message`, `checkpoint_count`,
`requires_force`) unless `?force=true` is passed — the same shape as the
`checkpoint delete` dependent-guard. An empty space still deletes with no
force.

Wire the existing clients through the new signal so their behavior is
unchanged: the CLI passes `force=args.force` (its own `--force` gate),
the MCP tool passes `force=true` after its `confirm_space` gate, and
quickstart passes `force=true` to tear down its own demo space.
2026-05-19 01:36:58 +05:30
Himanshu Dongre
727990d899 Require MCP confirmation for space deletion 2026-05-19 01:12:49 +05:30
Himanshu Dongre
4a1976a905 Require --force to delete a non-empty or attached space
A destructive-operations incident: `smriti space delete <space> -y`
cascade-deleted a fully populated space. `-y` skipped the only gate (the
confirmation prompt), and `cmd_space_delete` never checked how much the
space held — so one flag irreversibly deleted the space and every
checkpoint, session, and turn under it.

Gate destructive deletes in `cmd_space_delete`: a space that holds
checkpoints, or that the current repo is attached to (.smriti.json), now
requires an explicit `--force` — `-y` alone is refused, with a message
naming the reason and the flag. `--force` and `-y` stay orthogonal, the
same shape as `checkpoint delete --cascade`. Empty, unattached spaces keep
the existing `-y` convenience. CLI-side only; no backend change.
2026-05-19 00:51:33 +05:30
Himanshu Dongre
0c8f6922f4 Update skill pack for attached repo workflow 2026-05-19 00:07:52 +05:30
Himanshu Dongre
b3734f3dc3 Add durable project attachment so repos remember their Smriti space
Smriti was repo-local wiring: every command needed an explicit <space>, and
the SessionStart hook hard-coded the space name, so working across projects
and sessions meant re-stating the space constantly.

Add a `.smriti.json` attachment file at the repo root binding the repo to a
space. The CLI resolves `<space>` from it — walking up from the working
directory the way git finds `.git` — so `<space>` is now optional on the
everyday commands (state, current, metrics, claim, checkpoint, branch,
worktree). `smriti attach <space>` is the explicit binding verb (`smriti
attach` with no argument shows the current binding); `smriti init` also
writes the attachment. The generated SessionStart hook is now space-agnostic
— `smriti state --compact` resolves from the attachment, so the hook is
identical for every project and survives re-attaching.

`space delete` still requires an explicit space. No backend changes —
attach/init reuse the existing set_project_root endpoint.
2026-05-18 00:52:37 +05:30
Himanshu Dongre
ab8d6f6b6f Clarify claim completion metrics 2026-05-18 00:07:42 +05:30
Himanshu Dongre
eb60d03f4b Render list-valued blocked_by consistently in state --compact
`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.
2026-05-18 00:02:07 +05:30
Himanshu Dongre
c43310caa1 Make doctor runtime checks external-project aware 2026-05-17 19:16:56 +05:30
Himanshu Dongre
2bbb7d27bc Fix smriti current crash on list-valued blocked_by
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.
2026-05-17 16:20:32 +05:30
Himanshu Dongre
93c8ef6a4e Resolve README MCP-block overlap from the merge
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.
2026-05-17 12:31:20 +05:30
Himanshu Dongre
51a573a87d Merge external-polish-fix into the external-user cleanup sprint 2026-05-17 12:27:17 +05:30
Himanshu Dongre
76715cb1a8 Lead new users through quickstart before an empty space
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.
2026-05-17 12:17:19 +05:30
Himanshu Dongre
76f6f4c2c7 Polish external validation output and docs 2026-05-17 12:15:14 +05:30
Himanshu Dongre
2ac2abcfae Handle SQLite checkpoint timestamps in CLI formatters 2026-05-17 11:22:30 +05:30
Himanshu Dongre
98edf48a5d Merge doctor-activation and init portability into the activation sprint 2026-05-17 10:50:01 +05:30
Himanshu Dongre
1afca2bda2 Add smriti quickstart and a shipped demo space
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.
2026-05-17 10:49:52 +05:30
Himanshu Dongre
5c31d3d0f0 Preserve init API URL in hooks and MCP hints 2026-05-17 00:52:24 +05:30
Himanshu Dongre
ae9d367c08 Make init startup hooks portable 2026-05-17 00:49:44 +05:30
Himanshu Dongre
448484c4c3 Expand doctor activation diagnostics 2026-05-17 00:26:03 +05:30
Himanshu Dongre
f4062da76e Sync docs and regenerate skill pack for the current product surface
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.
2026-05-17 00:03:59 +05:30
Himanshu Dongre
8388bf8a1f Add local-first setup onboarding 2026-05-16 22:39:38 +05:30
Himanshu Dongre
f22056418d Add optional local-first SQLite mode (Phase A core)
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.
2026-05-16 22:26:05 +05:30
Himanshu Dongre
83e7aa15cb Fix pre-existing frontend TypeScript build errors
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.
2026-05-16 21:23:35 +05:30
Himanshu Dongre
704f28570c Add Project Current State CLI surface 2026-05-16 20:55:01 +05:30
Himanshu Dongre
7c8f259342 Add smriti doctor CLI diagnostics 2026-05-16 20:29:02 +05:30
Himanshu Dongre
ef8faf6e4d Add Project Current State endpoint and UI panel
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.
2026-05-16 20:01:16 +05:30
Himanshu Dongre
c470947477
Polish worktree short ids and clean finish (#5) 2026-05-04 15:28:19 +05:30
Himanshu Dongre
8c963198e1 Add canonical project root for spaces 2026-05-04 13:43:44 +05:30
Himanshu Dongre
3cb514b279 Add V3 dirty paths and skill pack v2.1 2026-05-04 13:11:20 +05:30
Himanshu Dongre
e8ce2f9de0 Merge remote-tracking branch 'origin/smriti/claude-code/555d3005' 2026-05-04 12:58:16 +05:30
Himanshu Dongre
1bab89cdea Populate worktree list probe columns 2026-05-04 12:52:35 +05:30
Himanshu Dongre
c4a21f3d7d Sync CONTRIBUTING test counts; expand DECISIONS worktree rationale
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).
2026-05-04 12:51:16 +05:30
Himanshu Dongre
432502932a README: update worktrees bullet to reflect V2 shipped
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).
2026-05-04 12:35:39 +05:30