Files
ThothII/CLAUDE.md
T
marcopanandClaude Fable 5 c4951e2aa5 chore: hygiene pass — ruff clean, docs storage-model truth, replay /me, failSession log
Audit findings 6.1-6.4 + the audit's remediation plan itself
(docs/superpowers/plans/2026-07-20-full-audit-remediation-plan.md).

- ruff: 34 → 0 (unused imports/f-strings auto-fixed; E702 semicolon lines
  split in test files; one unused local dropped). Suite still 819 green.
- CLAUDE.md + PROJECT_STATE.md no longer claim "no database / settings in
  settings.json": the harness selects filesystem OR PostgreSQL session
  storage (repository.py, server mode), and settings flow through harness
  preferences with the JSON file as fallback only.
- tools/replay: stub /me (SPA boot was parsing the SPA's own HTML as JSON)
  and /runtime/prewarm.
- failSession best-effort persistence now logs its failure server-side
  instead of vanishing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 01:55:41 +02:00

5.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Start here

Read PROJECT_STATE.md for the current-state snapshot: what was last built, pending manual gates, workspace/secret layout, and design-doc locations. This file holds the stable commands + architecture mental model; PROJECT_STATE.md holds the evolving detail. Design history lives in docs/superpowers/specs/ and docs/superpowers/plans/.

Commands

The repo has three independently-built layers. Run the full stack (real Pi + DWH, needs VPN + harness/.env + pi on PATH) with ./scripts/run-stack.sh (frontend :5173 → backend :8787).

harness/ (Python tht CLI + Pi gate extension)

  • Install: cd harness && python -m venv .venv && pip install -e ".[dev]" (puts tht on PATH)
  • Test: .venv/bin/pytest -q — l2 (real GLM + remote DB) is opt-in via addopts = -m 'not l2'; l0 (testcontainers) needs Docker
  • Single test: .venv/bin/pytest tests/test_session_mutations.py::test_set_name -v (or -k <pattern>); include e2e with -m l2
  • Lint: .venv/bin/ruff check . (line-length 100)

backend/ (Fastify + TypeScript, vitest)

  • Dev: npm run dev (tsx watch src/server.ts) · Build: npm run build (tsc → dist/)
  • Test: npx vitest run · Single: npx vitest run test/routes-sessions.test.ts -t "rename"
  • Typecheck: npx tsc --noEmit -p . (vitest does NOT type-check — run this before committing)

frontend/ (React 18 + Vite + vitest)

  • Dev: npm run dev (Vite; set VITE_BACKEND_URL) · Build: npm run build
  • Test: npx vitest run · Single: npx vitest run src/shell/NavSessions.test.tsx
  • Typecheck: npx tsc -b · E2E: npm run e2e (Playwright)

No ESLint on the TS layers — tsc is the gate. Tests use vitest + MSW (no network).

Architecture (the parts that need multiple files to see)

frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → DWH (read-only)
  • The harness owns the workflow and all persistence. tht (Python) is a deterministic CLI; harness/.pi/extensions/tht-gate.js is a Pi extension that drives an 8-phase NL→SQL workflow. The single source of workflow truth is harness/workflow.yaml; the orchestration rules the model must follow are harness/.pi/skills/tht-sessione/SKILL.md. "Current phase" is computed by folding the decision ledger (harness/tht/phase.py), not stored — read it before reasoning about phase logic.

  • Persistence = phase documents, NOT chat. A session is a directory under the workspace's sessions/ path: session_manifest.yaml + per-phase artifacts (question.md, schema_linking.json, sql_final.sql, …) + review_decisions.jsonl. The contract (SKILL.md): "the persisted state is the truth — what is not recorded did not happen." There is no verbatim transcript store. A resumed Pi process rebuilds context from tht session show <id> + the on-disk artifacts.

  • The backend is a thin bridge with no database of its own. ThtRunner shells tht subcommands; PiProcessManager runs one Pi child per session and bridges its RPC stream; SessionBridge maps Pi RPC events → client events (ui_request/text_delta/info); SseHub fans them out over SSE to the browser. Persistence belongs to the HARNESS, which selects the session repository from the workspace config (harness/tht/session/repository.py): filesystem by default, PostgreSQL when session_storage is configured (server/portable deployment). Settings flow through harness preferences (tht session preferences) with backend/data/settings.json only as the file fallback for injected runners/tests.

  • Human-in-the-loop gate contract. The model proposes; a human reviewer decides at gates via widgets (reviewer_select = single pick — a chosen option carrying a decision payload auto-confirms/persists directly, an option without one only asks; reviewer_decide = multiselect, each choice IS a decision; reviewer_confirm = artifact/phase gate). The frontend renders these widget-descriptors (src/widgets/ registry) and the live transcript is rebuilt in-memory from the SSE stream (src/store/sessionStore.ts) — it is not persisted.

Project-specific gotchas

  • tht's -c/--config is a PER-COMMAND option — it must follow the subcommand, never precede it (ThtRunner.buildArgv enforces this; prepending caused live 500s).
  • --json output must be pristine (only valid JSON on stdout) — used as a machine contract.
  • UI strings are English; document content stays the workspace language (Italian for psd) because it's the real data. Only chrome/labels are English.
  • Workspaces (harness/workspaces/*.yaml) set the DB target and absolute paths.sessions/artifacts/indexes — for psd these point at a separate, uncommitted repo (tht-workspace-psd/). Secrets live ONLY in harness/.env (gitignored).
  • Settings are global (workspace/provider/model/thinking, persisted via harness preferences — backend/data/settings.json is only the fallback); the New-session form is question-only.
  • Resume: a resumable session re-enters at its last incomplete phase. The backend refuses resume with 409 when finalized or archived, and PiProcessManager.spawnFor must send /riprendi-sessione <id> (resume mode) vs /nuova-domanda (new) — sending the wrong prompt silently turns a resume into a new question.