3992a9fcb7fd0ed7fa28ba8f1124f853db59f5ad
After a codecontext overview-class tool call lands (get_codebase_overview, get_framework_analysis, get_semantic_neighborhoods), the pipeline runs a second inference pass that replaces the recursive runAssistantTurn. The synth pass auto-fetches the top-N source files referenced in the codecontext output plus project docs (BOOCHAT.md, AGENTS.md, *roadmap*.md, CONTEXT.md), applies a 32k-token budget with explicit drop-priority, and streams a structured response that grounds the model in real load-bearing code rather than relying on the codecontext summary alone. Smoke #1 (default) and #2 (Architect) both cite the correct inference/turn.ts + tool-phase.ts + stream-phase.ts files; smoke #6 (fault injection) verifies the fall-through path marks the synth message status='failed' and yields cleanly to the recursive turn. ## Truncation-aware extraction codecontext's wrapper inline-truncates results at 32k chars. Without the expansion step, the top-N file selection only saw the alphabetical head of the codebase (apps/booterm/dist/*) and auto-fetched the wrong sources. The pipeline now calls in-process readTruncation(outputPath) before extracting referenced files, so top-N selection sees the full 80k+ char output. The 32k truncated head still ships to the synth model — the expansion is reference-extraction-only, preserving the token-budget contract. Graceful degradation on readTruncation null/throw: log warn, fall back to the truncated head. ## Schema deviation from dispatch The dispatch claimed no schema migration was needed for the new 'synthesis' part kind. Reality: message_parts.kind has an explicit CHECK constraint (schema.sql:54) that would reject the new value. Added a DROP CONSTRAINT IF EXISTS + DO $$ pg_constraint idempotency-guarded re-add matching the CLAUDE.md migration pattern. The inline CREATE TABLE constraint also updated so fresh installs land with the extended enum. ## User-abort marks synth-message failed Deviation from review-time spec ("user-abort path does NOT mark the message failed"). The outer abort handler in error-handler.ts operates on the parent turn's assistantMessageId, not the new synth row that runSynthesisPass created. Without explicit marking, the synth row would sit in status='streaming' until the 5-min stale-streaming sweeper (v1.13.1-cleanup-bundle), tripping the frontend's 60s no-token-activity banner in the meantime — exactly the UX bug class the v1.13.1 sweeper was added to handle. Marking failed on every catch path (including user-abort) closes the gap. Cost: one extra DB write + one publish on the rare user-abort-during-synth path. ## Race-safe synth-tool capture tool-phase.ts uses synthEntries: Array<{tc, output, error?}> with per-callback push under Promise.all. find() picks the first non-error entry by call-order (toolCalls array index). Multiple synth-tools in one batch are uncommon but handled deterministically. ## Roadmap rebase Updated boocode_roadmap.md retrospective section + cleanup-order tracker + schema-changes summary to use the new vMAJOR.MINOR.PATCH-slug tag names per the 2026-05-22 retag (CHANGELOG.md is the canonical record). v1.13.15 listed as "this batch, tag pending"; a one-line follow-up commit will remove that qualifier after the tag lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
boocode
Self-hosted single-user developer chat app. v1: chat only.
Stack
- Node 20, Fastify, postgres (porsager/postgres), ws, zod
- React 18, Vite, TypeScript, Tailwind v4, shadcn/ui
- Postgres 16
- pnpm workspaces
Layout
apps/server— Fastify API + WebSocket + inference loop + file-read toolsapps/web— React frontend; served by Fastify in production, Vite in dev
Local dev
Requires Node 20, pnpm, Docker (for Postgres), and ripgrep.
# install
pnpm install
# bring up postgres only
cp .env.example .env
# edit POSTGRES_PASSWORD if you like; default DATABASE_URL points at the container
docker compose up -d boocode_db
# run server (port 3000) and web (port 5173) in two shells
DATABASE_URL=postgres://boocode:devpass@127.0.0.1:5500/boocode \
LLAMA_SWAP_URL=http://100.101.41.16:8401 \
pnpm dev:server
pnpm dev:web
The Vite dev server proxies /api and /api/ws/* to the Fastify backend with a
synthetic Remote-User: sam header so the Authelia auth layer can be skipped
during development.
Production
cd /opt/boocode
docker compose up --build -d
Binds to 100.114.205.53:9500 (Tailscale). Authelia is expected to gate the
upstream and inject Remote-User. Postgres binds loopback only.
What v1 has
Project sidebar, sessions per project, chat with streaming responses over
WebSocket, four file-read tools scoped to the project root (view_file,
list_dir, grep, find_files), and a model picker driven by llama-swap's
/v1/models.
What v1 does not have lives in v2 (terminal pane) and v3 (Coder pane).
Languages
TypeScript
94.1%
CSS
1.9%
JavaScript
1.1%
Shell
0.8%
PLpgSQL
0.6%
Other
1.5%