9703eb2b6b
Worldtree Conversation API debug TUI. Multi-pane observability dashboard: chat transcript + persona/Vili affect log + tool events + admin events + Bifrost state + tool inventory + (opt-in) raw server log. Design locked at docs/design-brief.md (originated as brokkr-smithy/docs/ratatoskr-design-brief.md). Operator-locked decisions: - Textual application-shell framework (multi-pane dashboard, not REPL). - Separate repo + separate dev team (no Worldtree-source imports). - httpx-sse for SSE consumption (reference Python SSE-resume impl). - Triple version-skew mitigation: spec-pin in pyproject.toml + recorded SSE snapshot tests + conformance smoke. Initial pin: Worldtree v0.19.0 at 55101e909abcd2219833266b6f905c5bc956e0f0. - Persona pane: label-don't-refuse PII posture. - Server-log pane: opt-in via --server-log <path>. - Two-stage Ctrl-C (cancel then exit). - Markdown rendering default-on; --raw opt-out. In the box: - docs/design-brief.md — the locked design with full rationale. - docs/SPEC-PIN.md — Worldtree spec pin + bump procedure. - docs/conversation-api-spec.md + docs/conversation_api.contract.md — vendored Worldtree spec snapshots at the pinned SHA. - pyproject.toml — Python 3.12, hatchling, uv-managed, deps locked. - src/ratatoskr/ — stub package (cli.py raises NotImplementedError). - tests/test_no_worldtree_imports.py — boundary smoke test PASSING. - tests/snapshots/README.md — recording convention for SSE snapshot tests. Not in the box yet: - Gitea remote (operator/infra-ops to register at vh/ratatoskr). - Implementation — the dev team owns this; design brief is the spec. Origin: althing thread 01KS3R34XD3N6HMK91VXESHGW7 (worldtree-dev → brokkr-smithy-dev, 2026-05-20). Volva consulted via thread 01KS3VF6W33N3V5FNMGQ91YNVD.
373 lines
17 KiB
Markdown
373 lines
17 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Principles
|
|
|
|
`PRINCIPLES.md` at the repo root carries the four Corviduo engineering
|
|
principles (Excellence over uniqueness · Explicit over implicit ·
|
|
Elegance is a byproduct · Action-relevance over thoroughness). These
|
|
are *what to optimize for* across all work — distinct from this file's
|
|
behavioral guidelines (*how to operate session-to-session*) and the
|
|
workflow mechanics below (*project-level mechanics*). The principles
|
|
also live at `~/.claude/CLAUDE.md` § Core principles; this repo copy
|
|
is the load-bearing version when human contributors or non-Claude-Code
|
|
AI tooling read the codebase.
|
|
|
|
## Canonical Corviduo specifications
|
|
|
|
This project depends on cross-cutting Corviduo specifications that
|
|
live canonically at `~/development/corviduo-project-template/` (the
|
|
spec-stewardship repository, Brokkr-managed as of 2026-05-15). When
|
|
this file is read inside the template repository itself, the
|
|
canonicals live here directly; when seeded into a derivative project,
|
|
pinned copies of the canonicals live in the derivative.
|
|
|
|
### What lives canonically in the template
|
|
|
|
| Spec | Canonical path | Covers |
|
|
|---|---|---|
|
|
| `CONTRACT-FORMAT.md` | `docs/contracts/CONTRACT-FORMAT.md` | Format spec for `.contract.md` files (v2.x). |
|
|
| `contract_parser.py` | `docs/contracts/contract_parser.py` | Validator/extractor for `.contract.md`. Python ≥3.11, stdlib only. |
|
|
| `contract_drift_check.py` | `scripts/contract_drift_check.py` | Verifies issue-scoped contracts' `prd:` block hashes match live tracker state. |
|
|
| `PRINCIPLES.md` | `PRINCIPLES.md` | Four engineering principles. |
|
|
| `methodology.md` | `docs/methodology.md` | The Corviduo preferred development pipeline ((optional) Vor → (required) Contract → branch (direct or AFK TDD) → verify → merge/commit). |
|
|
| `PRACTICES.md` | (to migrate from `galdrabok/conventions/`) | Engineering practices (contract-first, TDD, no-backwards-compat, atomic commits). |
|
|
| `CONTEXT-FORMAT.md` | (to migrate from `galdrabok/conventions/`) | Format spec for `CONTEXT.md` glossary files. |
|
|
| `ADR-FORMAT.md` | (to migrate from `galdrabok/conventions/`) | Format spec for Architecture Decision Records. |
|
|
|
|
### What to seed into a new project, by stack
|
|
|
|
When you seed a new Corviduo project from this template, copy the
|
|
canonical files that apply to your target stack. The drift-check
|
|
mechanism (below) keeps consumer copies in sync as canonicals evolve.
|
|
|
|
**Every project (cross-language baseline):**
|
|
|
|
- `CONTRACT-FORMAT.md`, `PRINCIPLES.md`, `PRACTICES.md` — applies
|
|
regardless of implementation language.
|
|
- `contract_parser.py`, `contract_drift_check.py` — Python
|
|
meta-tooling. Invoke via `uv run python scripts/...` in non-Python
|
|
projects.
|
|
|
|
**Python projects** (Worldtree, Sleipnir, Brokkr-Smithy, Skaldsong,
|
|
Vor backend):
|
|
|
|
- All baseline files.
|
|
- `env.sh.template` (Python-shape: `PYTHONPATH`, uv-managed venv
|
|
expectations).
|
|
- `.gitignore` (Python-shape: `__pycache__/`, `.venv/`, ruff /
|
|
mypy / pytest / uv caches).
|
|
- **Preferred tooling**: `uv` exclusively (`uv venv`, `uv pip
|
|
install`, `uv run`, `uv tool install`). Ruff for lint. Mypy for
|
|
types. Pytest for tests. No `pip` / `pipx` / `poetry` unless
|
|
the project clearly already uses something else.
|
|
|
|
**TypeScript / Bun projects** (Mead Hall, Vor UI, future client
|
|
apps):
|
|
|
|
- All baseline files. `CONTRACT-FORMAT.md` applies cross-language —
|
|
`.contract.md` files describe code regardless of implementation
|
|
language.
|
|
- `env.sh.template` (TS/Bun-shape: project-name-uppercase root,
|
|
per-app env vars, no Python venv references).
|
|
- `.gitignore` (TS/Bun-shape: `node_modules/`, `dist/`,
|
|
`bun.lockb` is committed; no Python caches).
|
|
- **Preferred tooling**: Bun exclusively (no npm / yarn / pnpm).
|
|
Bun's native bundler. Bun's native test runner (`bun test`).
|
|
TypeScript strict mode. React + Vite for UI projects where
|
|
applicable.
|
|
|
|
**Mixed-stack projects** (Python backend + TypeScript frontend in
|
|
one repo): take both stacks' files; document which directory is
|
|
which in `docs/architecture.md`.
|
|
|
|
### Keeping canonicals in sync
|
|
|
|
Two tools at `scripts/` handle drift detection and sync for
|
|
cross-cutting Corviduo canonicals. Both Python ≥3.11 stdlib-only;
|
|
invoke via `uv run python scripts/...` in non-Python projects.
|
|
|
|
- **`scripts/canonical_sync.py`** — operator-triggered. Fetches each
|
|
pinned canonical from `~/development/<canonical_source>/<canonical_path>`,
|
|
writes the consumer copy, bumps the pin's `pinned_sha256_16` +
|
|
`pinned_at` in the manifest. Reports per-pin: `OK` / `SYNCED` /
|
|
`WOULD` (dry-run) / `ERROR`. Run after the architect broadcasts a
|
|
canonical update on althing.
|
|
- **`scripts/canonical_drift.py`** — read-only verifier suitable for
|
|
CI gating. Detects drift between pinned canonicals and their
|
|
sources, and consumer-copy divergence from the pinned hash. Exits
|
|
non-zero on staleness, divergence, or missing canonical.
|
|
|
|
Each consumer carries a `.corviduo-canonicals.toml` manifest at the
|
|
repo root pinning each canonical:
|
|
|
|
```toml
|
|
[[pins]]
|
|
id = "contract-format-v2"
|
|
canonical_source = "corviduo-project-template"
|
|
canonical_path = "docs/contracts/CONTRACT-FORMAT.md"
|
|
consumer_path = "docs/contracts/CONTRACT-FORMAT.md"
|
|
pinned_sha256_16 = "..."
|
|
pinned_at = "2026-05-15T..."
|
|
```
|
|
|
|
The pattern generalises beyond template-only canonicals. Same shape
|
|
handles Worldtree's `conversation-api-client-spec-v2.md`, Bifrost's
|
|
protocol spec, and any future cross-cutting canonical — set
|
|
`canonical_source` to whichever `~/development/<repo>/` directory
|
|
hosts the truth.
|
|
|
|
Optional per-pin `tolerate_drift = true` makes `canonical_drift.py`
|
|
warn-only for that pin when `--allow-warn` is set (useful for pins
|
|
the consumer deliberately allows to lag).
|
|
|
|
## Persistent memory
|
|
|
|
`persistent-memory.md` at the repo root captures durable intent and
|
|
supporting evidence (goals, decisions, foot-gun warnings, in-flight
|
|
state) across context resets. Read it at session start; treat it as
|
|
one input alongside this CLAUDE.md and the auto-memory system, not
|
|
as the single source of truth. When durable state shifts enough to
|
|
warrant capture, run `/snapshot` and commit alongside the next commit.
|
|
|
|
## Architecture map
|
|
|
|
`docs/architecture.md` is the top-level module map (dependency graph,
|
|
session-load boundaries, execution order). Each core module gets its own
|
|
`CLAUDE.md` at `core/{module}/CLAUDE.md` once it grows past trivial.
|
|
When a development session focuses on one module, load that module's
|
|
`CLAUDE.md` plus the stable-infrastructure dependencies listed there.
|
|
|
|
## BEHAVIORAL GUIDELINES
|
|
|
|
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
|
|
|
### 1. Think Before Coding
|
|
|
|
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
|
|
|
Before implementing:
|
|
- State your assumptions explicitly. If uncertain, ask.
|
|
- If multiple interpretations exist, present them — don't pick silently.
|
|
- If a simpler approach exists, say so. Push back when warranted.
|
|
- If something is unclear, stop. Name what's confusing. Ask.
|
|
|
|
### 2. Simplicity First
|
|
|
|
**Minimum code that solves the problem. Nothing speculative.**
|
|
|
|
- No features beyond what was asked.
|
|
- No abstractions for single-use code.
|
|
- No "flexibility" or "configurability" that wasn't requested.
|
|
- No error handling for impossible scenarios.
|
|
- If you write 200 lines and it could be 50, rewrite it.
|
|
|
|
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
|
|
|
### 3. Surgical Changes
|
|
|
|
**Touch only what you must. Clean up only your own mess.**
|
|
|
|
When editing existing code:
|
|
- Don't "improve" adjacent code, comments, or formatting.
|
|
- Don't refactor things that aren't broken.
|
|
- Match existing style, even if you'd do it differently.
|
|
- If you notice unrelated dead code, mention it — don't delete it.
|
|
|
|
When your changes create orphans:
|
|
- Remove imports/variables/functions that YOUR changes made unused.
|
|
- Don't remove pre-existing dead code unless asked.
|
|
|
|
The test: Every changed line should trace directly to the user's request.
|
|
|
|
### 4. Goal-Driven Execution
|
|
|
|
**Define success criteria. Loop until verified.**
|
|
|
|
Transform tasks into verifiable goals:
|
|
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
|
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
|
- "Refactor X" → "Ensure tests pass before and after"
|
|
|
|
For multi-step tasks, state a brief plan:
|
|
```
|
|
1. [Step] → verify: [check]
|
|
2. [Step] → verify: [check]
|
|
3. [Step] → verify: [check]
|
|
```
|
|
|
|
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
|
|
|
---
|
|
|
|
## Project conventions
|
|
|
|
### Naming hierarchy
|
|
|
|
```
|
|
Corviduo.ai (company)
|
|
└─ ratatoskr (project / repo — this codebase)
|
|
└─ ... (modules, agents, components — fill in as the project grows)
|
|
```
|
|
|
|
Sibling Corviduo projects: `Worldtree` (multi-agent framework), `Skaldsong` (story-generation engine), `vastai-app` (Vast Blue SEA — multi-agent web app), `sleipnir` (AFK orchestrator), `Vor` (pre-contract design partner UI), `Galdrabok` (Sleipnir-preflight skill author), `task-board` (per-session web UI), `althing`.
|
|
|
|
Norse / Germanic naming convention is the house style for Corviduo projects. Module and agent names follow the same vein.
|
|
|
|
### No backwards compatibility until v1.x
|
|
|
|
This project is pre-release. When something is redesigned, everything gets updated and everything old gets ripped out. **No shims, no compat layers, no deprecation periods.** If a new approach replaces an old one, the old code is deleted and all references are updated in the same commit. This keeps the codebase clean and avoids accumulating dead paths.
|
|
|
|
### Contract-first workflow
|
|
|
|
Contracts at `docs/contracts/` are machine-parseable architectural pseudocode specs. They serve as unambiguous work specifications: a planning pass writes the contract, then the implementation pass translates it to code, then an audit pass verifies compliance.
|
|
|
|
**Workflow: contracts come before code.** When implementing a new module or making non-trivial changes to an existing one, write or update the `.contract.md` file first. The contract captures function signatures, preconditions, postconditions, error handling, steps, and invariants — settling design questions before writing code. Contracts are not documentation of existing code; they are the source of truth that code is written to satisfy.
|
|
|
|
- Format spec: [`docs/contracts/CONTRACT-FORMAT.md`](docs/contracts/CONTRACT-FORMAT.md) (v2.1 is current; v2.0 and v1 contracts remain accepted)
|
|
- Parser: [`docs/contracts/contract_parser.py`](docs/contracts/contract_parser.py) — `--validate` checks required fields; `--list` shows function signatures; `--dir` batch processes
|
|
- Drift checker: [`scripts/contract_drift_check.py`](scripts/contract_drift_check.py) — verifies issue-scoped contracts' `prd:` block hashes match the live tracker state
|
|
- File convention: `docs/contracts/{module_name}.contract.md` for module contracts; `docs/contracts/issues/{N}.contract.md` for issue-scoped contracts
|
|
|
|
When to write a contract:
|
|
- **New module** — always write a contract before implementation
|
|
- **Complex changes** — new function blocks, new error handling, new state transitions
|
|
- **Cross-module interfaces** — when the change affects `depends_on` / `used_by` relationships
|
|
|
|
When a contract is not needed:
|
|
- Bug fixes that don't change function signatures or behavior
|
|
- Trivial helpers, one-liners, config changes
|
|
- Documentation-only changes
|
|
|
|
### Issue → AFK dispatch hygiene (Sleipnir)
|
|
|
|
Before marking any issue `ready-for-agent` (the label that gates AFK
|
|
dispatch via Sleipnir), it MUST have an issue-numbered contract at
|
|
`docs/contracts/issues/<N>.contract.md` AND that contract MUST carry
|
|
a `prd:` block in its YAML frontmatter pinning it to:
|
|
|
|
- the issue body (SHA-256, first 16 hex chars)
|
|
- the lock-in comment id + content SHA (or `null` if the issue body
|
|
alone is the spec)
|
|
- a `pinned_at` timestamp
|
|
|
|
This is hard policy, not a suggestion. Without the contract Sleipnir's
|
|
gate refuses dispatch with `blocked-needs-contract`. Without the `prd:`
|
|
block PRD-↔-ship drift becomes invisible — the audit infrastructure
|
|
that detects it is a no-op.
|
|
|
|
Verify before applying the label:
|
|
|
|
- contract file exists at the expected path
|
|
- frontmatter has a populated `prd:` block
|
|
- `python scripts/contract_drift_check.py --contract <path>` returns clean
|
|
|
|
The full convention — frontmatter shape, required fields, reasoning
|
|
behind the four drift entry points — lives in
|
|
[`docs/contracts/CONTRACT-FORMAT.md`](docs/contracts/CONTRACT-FORMAT.md).
|
|
|
|
### TDD development cycle
|
|
|
|
Contract → failing test → minimal code to pass → run test. Tests written
|
|
before/alongside code, never deferred. Vertical slices (tracer bullet first,
|
|
then incremental loop), not horizontal slices (don't write all tests then all
|
|
code — that produces tests of *imagined* behavior).
|
|
|
|
### Persistent-memory + housekeeping commit-along rule
|
|
|
|
When committing changes, also commit `persistent-memory.md` if it's dirty.
|
|
Same applies to housekeeping files (`HANDOFF-SUMMARY.md`, `NEXT-STEPS.md`,
|
|
`README.md`, `State-Of-Development.md`) where they exist. The repo state
|
|
should always be coherent across these files at every commit.
|
|
|
|
---
|
|
|
|
## Tooling conventions
|
|
|
|
### Issues
|
|
|
|
For Worldtree-and-friends Gitea-tracked issues, prefer `python -m core.issues`
|
|
(the project's own CLI wrapping the Gitea API) over `gh` or `tea`. Until
|
|
this project grows its own `core/issues/` adapter, fall back to `tea`
|
|
(local Gitea CLI at `/usr/local/bin/tea`, v0.14.0) for simple operations.
|
|
|
|
### Tea CLI
|
|
|
|
`tea` is the local Gitea CLI. Use for PRs, releases, branch/repo ops. For
|
|
issues prefer `python -m core.issues` when it exists. **Note:**
|
|
`tea issues edit <N> --add-labels <label>` is the bucket-2 ergonomic
|
|
(client-side add-semantics, doesn't clobber other labels) — Gitea's HTTP
|
|
label endpoint is replace-semantics. For comment-edits, use direct HTTP
|
|
against the Gitea API (`tea` v0.14.0 has no comment-edit subcommand).
|
|
|
|
### Sleipnir AFK orchestration
|
|
|
|
If this project uses Sleipnir for AFK dispatch:
|
|
- `~/.config/sleipnir/config.yaml` carries user-global config
|
|
- `.sleipnir/config.yaml` (this repo) carries per-project overrides; gitignored per-checkout
|
|
- Default convention: `dispatch.dependency_aware: true` for INV-029 dependency-aware dispatch
|
|
- Skills: `/sleipnir-scaffold <N>` to bootstrap a contract; `/sleipnir-preflight <N>` to apply `ready-for-agent`
|
|
|
|
### Task-board status reporting
|
|
|
|
If the user runs the task-board plugin, the session card on the web UI shows
|
|
at-a-glance status. The plugin's auto-hook fires `task_update` on
|
|
UserPromptSubmit and `task_wait` on Stop. You should also call `task_start`
|
|
and `task_update` proactively to set what the session is working on:
|
|
|
|
- **`task_start`** — at the start of a distinct piece of work (new feature,
|
|
investigation, phase, bug hunt). Sets the card's activity subheader.
|
|
- **`task_update`** — at mid-task inflection points (issue filed/closed,
|
|
branch merged, QA verdict, blocker hit, milestone). One per inflection.
|
|
- **`task_set_shells`** — when starting a `Bash run_in_background: true`,
|
|
pass an array of one short description per *currently active* background
|
|
shell. Update when shells finish; clear with `[]` when the last completes.
|
|
|
|
**SID derivation** (post-v0.1.5):
|
|
|
|
```bash
|
|
SID="$(cat "${XDG_CACHE_HOME:-$HOME/.cache}/claude-task-board/$(basename "$PWD").sid" 2>/dev/null)"
|
|
LABEL="${TASK_BOARD_SESSION:-$(basename "$PWD")}"
|
|
```
|
|
|
|
If `$SID` is empty (no hook has fired yet this Claude Code restart),
|
|
**skip the explicit task-board call for this turn**. Subsequent turns
|
|
can call freely. Re-derive at the start of every turn — do NOT cache.
|
|
Do NOT fall back to JSONL-mtime guess (that was the source of duplicate-
|
|
card bugs).
|
|
|
|
---
|
|
|
|
## Project Overview
|
|
|
|
_Author this section once the project's purpose, modules, and conventions
|
|
solidify. Mirror the shape of `Worldtree/CLAUDE.md` § Project Overview when
|
|
the project grows enough surface to need module-level documentation._
|
|
|
|
### What this project does
|
|
|
|
_TODO — one paragraph._
|
|
|
|
### Module structure
|
|
|
|
_TODO — once modules exist, list them here with one-line descriptions._
|
|
|
|
### Development setup
|
|
|
|
_TODO — typical pattern: `source .venv/bin/activate && source env.sh` before
|
|
running anything. Mirror Worldtree's pattern when relevant._
|
|
|
|
---
|
|
|
|
## Development Notes
|
|
|
|
- **No backward compatibility until v1.x** (see above).
|
|
- **Contracts before code** for non-trivial work (see above).
|
|
- **Persistent-memory + housekeeping commit-along** (see above).
|
|
- The `.gitignore` is configured for Python projects using tools like
|
|
ruff, pytest, mypy, and uv/poetry/pdm. Adjust if this is not a Python
|
|
project.
|
|
- Build, lint, and test commands will be documented here as the project
|
|
grows.
|