Files
tatlock/CLAUDE.md
T
jpmschweitzerandClaude 99569e786e docs: correct stale tooling and model references
Three migrations left their documentation behind:

wakeup.sh was replaced by the Makefile during the project structure
consolidation, but AGENTS.md and the e2e README still tell you to run it.
The log path moved to build/logs/server.log at the same time.

The local model moved to gemma4:e2b, but the e2e prerequisites and the
benchmark recommendation still name mistral-nemo.

The benchmark figures in CLAUDE.md predate the current model. Measured
2026-08-07: ~95 tok/s, full flow ~10-13s for simple turns, cold model load
~36s rather than ~8s. A turn costs three sequential Ollama calls and ~710
generated tokens regardless of how trivial the question is.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 15:07:10 +02:00

3.5 KiB
Raw Permalink Blame History

CLAUDE.md

Claude Code-specific notes for this project. For general development instructions, architecture, coding standards, and deployment — see AGENTS.md.

Setup & Commands

make setup          # Create venv and install all dependencies
make test           # Unit tests (no external services)
make test-integration  # Integration tests (needs Claude/Ollama)
make test-contracts # Wire-level contract tests against live service boundaries
make run            # Start dev server on port 8777
make lint           # Ruff linter + formatter check
make typecheck      # Mypy
make clean          # Remove caches and build artifacts

Dependencies are in pyproject.toml ([project.dependencies] and [project.optional-dependencies.dev]).

Critical Gotchas

ASGITransport does NOT trigger FastAPI lifespan events. The session-scoped _initialize_app fixture in tests/conftest.py calls initialize_application() explicitly via asyncio.run(). Without this, the Ollama/Claude health checks never run: _ollama_available stays None (treated as available, so requests go to Ollama) and _claude_available stays None (treated as unavailable, so the Claude fallback never engages).

AsyncIO scope mismatch. asyncio_default_fixture_loop_scope = function is set in pyproject.toml. Session-scoped async fixtures cause ScopeMismatch errors. The fix is to use a sync fixture with asyncio.run() for session-scoped initialization.

The butler persona prompt suppresses local-model tool calling. With TATLOCK_SYSTEM_PROMPT attached, gemma4 reasons about calling the calculator, then answers from memory with wrong arithmetic (a different wrong product each run). orchestrate_tool_calls() therefore uses the terse TATLOCK_ORCHESTRATION_PROMPT; the persona is applied in synthesize_from_results(). Do not reattach the persona prompt to a tool-phase agent. tool_choice: "required" via extra_body does NOT force Ollama to call tools — it is advisory at best.

Claude Sonnet 5+ rejects sampling parameters. temperature/top_p/top_k return a 400. Use get_sampling_settings() from the model selector instead of passing ModelSettings(temperature=...) directly to agents that can run on the Claude fallback. The contract test suite pins this (make test-contracts).

Integration test timeouts. Set to 120s to match OLLAMA_TIMEOUT config (300s for the pure-Ollama fallback test, which cannot be rescued by Claude). Current GPU-resident numbers (measured 2026-08-07, gemma4:e2b at ~95 tok/s): full Steward → orchestrate → synthesize flow ~1013s for simple turns; librarian-routed queries ~20-25s (not re-measured). A single turn costs 3 sequential Ollama calls and ~710 generated tokens even for "what is 61 plus 12?" — most of it the model's own reasoning, paid three times. Cold model load is ~36s, avoided while the model is pinned with keep_alive: -1; the OLLAMA_KEEP_ALIVE=2h default otherwise reintroduces it. The old "~35s steward / ~2 min flow" and "1125s flow" figures are superseded — do not plan against them. STEWARD_TIMEOUT defaults to 60s.

get_benchmark_store does not exist. The benchmarking module (src/core/benchmarks.py) was never implemented. scripts/benchmark_analysis.py also references it and is broken. Do not add mocks for it in tests.

Steward tests need household registry. Use register_household_members() (sync) in fixtures, not initialize_application() (async). The steward extracts capabilities from the registry.