diff --git a/docs/SYSTEM_ARCHITECTURE.md b/docs/SYSTEM_ARCHITECTURE.md index 06783d3..806aa27 100644 --- a/docs/SYSTEM_ARCHITECTURE.md +++ b/docs/SYSTEM_ARCHITECTURE.md @@ -1,6 +1,6 @@ --- document_id: doc.system-architecture -last_verified: 2026-03-06 +last_verified: 2026-03-23 tokens_estimate: 950 tags: - architecture @@ -106,7 +106,7 @@ Full schema details: [data-contracts-reference.md](domains/data-contracts-refere ## Data Flow (Summaries) ### Planning -`User chat → Anthropic streaming API → stream-action-parser → PlanningAction[] → validate → apply → SQLite` +`User chat → planning SDK query()/stream wrapper → stream-action-parser → PlanningAction[] → validate → apply → SQLite` Detail: [planning-reference.md](domains/planning-reference.md) @@ -138,12 +138,12 @@ Two distinct connection patterns exist. | Concern | Planning LLM | Build Agent | |---------|-------------|-------------| -| Auth | `ANTHROPIC_API_KEY` | `ANTHROPIC_API_KEY` | -| SDK | `@anthropic-ai/sdk` (Messages API) | `@anthropic-ai/claude-agent-sdk` | -| Call style | `messages.create` / `messages.stream` | `query()` — async iterator | -| Streaming | Optional (non-streaming for simple calls, streaming for chat) | Always streaming (`for await` over messages) | -| Tools | None (text output only) | Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch | -| CWD | N/A | `worktree_path` (repo clone) | +| Auth | `ANTHROPIC_API_KEY` (env/config) or Claude CLI credential (`~/.claude/settings.json`) | `ANTHROPIC_API_KEY` (env/config) | +| SDK | `@anthropic-ai/claude-agent-sdk` via planning wrapper | `@anthropic-ai/claude-agent-sdk` | +| Call style | `query()` wrapper (non-streaming and streaming paths) | `query()` — async iterator | +| Streaming | Optional (chat stream uses streaming path) | Always streaming (`for await` over messages) | +| Tools | `WebSearch` always; `Read/Glob/Grep` when repo clone (`cwd`) is available | Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch | +| CWD | Optional clone path when repo connected | `worktree_path` (repo clone) | | Lifecycle | Request-response per chat turn | Fire-and-forget; result via in-process webhook callback | | Model | `claude-haiku-4-5-20251001` (configurable) | `claude-sonnet-4-5-20250929` (configurable) | diff --git a/docs/domains/planning-reference.md b/docs/domains/planning-reference.md index 34afdf5..c6f56a5 100644 --- a/docs/domains/planning-reference.md +++ b/docs/domains/planning-reference.md @@ -1,6 +1,6 @@ --- document_id: doc.planning -last_verified: 2026-03-06 +last_verified: 2026-03-23 tokens_estimate: 750 tags: - planning @@ -41,28 +41,55 @@ ttl_expires_on: null | scaffold | Map empty or no workflows | updateProject + createWorkflow only | | populate | Workflows exist, activities/cards sparse | createActivity, createStep, createCard | | full | Map has structure | All action types; refinements, links, planned files | -| finalize | Map fully planned; user triggers | createContextArtifact (project docs + card e2e tests) | +| finalize | User triggers approval/finalize | createContextArtifact (project docs, scaffold docs, and card e2e tests) | Mode selected by `lib/llm/planning-prompt.ts` based on map state. ### Flow ``` User message → POST /chat/stream - → buildPlanningSystemPrompt() | buildScaffoldSystemPrompt() | buildPopulateSystemPrompt() | buildFinalizeSystemPrompt() - → Claude API (streaming) + → buildScaffoldSystemPrompt() | buildPlanningSystemPrompt() | finalize prompts + → claude-client -> planning-sdk-runner (Agent SDK query()) → stream-action-parser (parse JSON blocks) → PlanningAction[] emitted - → POST /actions (validate + apply) + → validatePlanningOutput() + pipelineApply() inside chat route ``` +Planning uses read-only tools: +- Always: `WebSearch` +- When repo is connected and cloned: `Read`, `Glob`, `Grep`, `WebSearch` (cwd set to clone path) + +Auth resolution for planning: +1. `ANTHROPIC_API_KEY` from env +2. `ANTHROPIC_API_KEY` from `~/.dossier/config` +3. Claude CLI settings (`~/.claude/settings.json`, respecting `CLAUDE_CONFIG_DIR`): + - `env.ANTHROPIC_API_KEY`, or + - `env.ANTHROPIC_AUTH_TOKEN` (also mapped to `CLAUDE_CODE_OAUTH_TOKEN`) + ### Per-Card Finalize Flow ``` User clicks "Finalize" on card → POST /cards/[cardId]/finalize - → Assemble: project-wide docs + card context + e2e tests - → Return finalization package for review - → User edits (optional) - → POST /cards/[cardId]/finalize/confirm - → Set card.finalized_at → card is build-ready + → Validate prerequisites: + project.finalized_at exists + card has requirements + card has planned files + card not already finalized + → Link project docs to card (doc/spec/design) + → Generate required test artifact + optional card-specific docs + → Set card.finalized_at + → Best-effort memory ingestion for card context +``` + +### Project Finalize Flow (chat mode=finalize) +``` +POST /chat or /chat/stream with mode=finalize + → runFinalizeMultiStep() executes FINALIZE_DOC_SPECS in parallel + → each doc emits createContextArtifact + → failure if any required doc missing + → parse root folders from architectural-summary + → ensure clone and create root folders + scaffold files in base branch + → push base branch + → set project.finalized_at ``` ### Key Files @@ -71,8 +98,10 @@ User clicks "Finalize" on card → POST /cards/[cardId]/finalize | `lib/llm/planning-prompt.ts` | System prompts; mode selection | | `lib/llm/stream-action-parser.ts` | Parse streaming JSON → actions | | `lib/llm/build-preview-response.ts` | Preview response before apply | -| `lib/llm/claude-client.ts` | Planning LLM client (Messages API) | -| `lib/llm/planning-credential.ts` | Resolves ANTHROPIC_API_KEY from env or ~/.dossier/config | +| `lib/llm/claude-client.ts` | Planning LLM client; auth routing + timeouts | +| `lib/llm/planning-sdk-runner.ts` | Agent SDK query wrapper for planning (final result only) | +| `lib/llm/planning-credential.ts` | Resolves env/config/CLI credentials | +| `lib/llm/run-finalize-multistep.ts` | Project finalize doc generation (parallel sub-steps) | | `app/api/projects/[id]/chat/route.ts` | Non-streaming chat | | `app/api/projects/[id]/chat/stream/route.ts` | Streaming chat (scaffold, populate, finalize) | | `app/api/projects/[id]/cards/[cardId]/finalize/route.ts` | Per-card finalize endpoint | diff --git a/docs/reference/api-endpoints.md b/docs/reference/api-endpoints.md index 3b0fe12..7c6ff41 100644 --- a/docs/reference/api-endpoints.md +++ b/docs/reference/api-endpoints.md @@ -1,321 +1,279 @@ # API Endpoints Reference -REST API for the Dossier planning and build system. All routes under `/api`. SQLite (default) stores data in `~/.dossier/dossier.db`. Migrations run automatically on first use. - -## Setup - -1. Copy `.env.example` to `.env.local` and set `ANTHROPIC_API_KEY` and `GITHUB_TOKEN`. -2. Database: SQLite (default) stores data in `~/.dossier/dossier.db`. Migrations run automatically on first use. +REST API for the Dossier planning/build system. All routes are under `/api`. ## Base URL - Local: `http://localhost:3000` -- All routes are under `/api` +- All endpoints: `/api/...` -## Error Response Format +## Error Shapes (As Built) -All errors return JSON: +Most routes use the shared error helper: ```json { - "error": "error_code", + "error": "validation_failed|not_found|conflict|action_rejected|internal_error", "message": "Human-readable description", "details": { "field": ["specific issue"] } } ``` -| HTTP Status | Error Code | When | -|-------------|------------------|-------------------------------------------| -| 400 | validation_failed | Malformed payload, schema mismatch | -| 404 | not_found | Resource doesn't exist | -| 409 | conflict | Referential integrity error | -| 422 | action_rejected | Action rejected (e.g. code-gen intent) | -| 500 | internal_error | Database or unexpected error | +Some orchestration/setup/repo utility routes return simpler JSON like: ---- +```json +{ "error": "message string" } +``` -## Project Management +Common statuses in current handlers: `400`, `401`, `404`, `409`, `422`, `500`, `502`, `503`. -### GET /api/projects +--- -List all projects. +## Setup & Environment -**Response:** `200` — Array of project objects +### GET /api/setup/status +Returns setup readiness for Anthropic planning credentials and GitHub token. + +**Response (`200`):** ```json -[ - { "id": "uuid", "name": "string", "repo_url": "string|null", "default_branch": "string", "created_at": "string", "updated_at": "string" } -] +{ + "needsSetup": true, + "missingKeys": ["ANTHROPIC_API_KEY", "GITHUB_TOKEN"], + "configPath": "/home//.dossier/config", + "anthropicViaCli": false +} ``` -### POST /api/projects +Notes: +- Anthropic is considered satisfied when either: + - `ANTHROPIC_API_KEY` resolves from env or `~/.dossier/config`, or + - Claude CLI is installed/authenticated (`anthropicViaCli: true`). +- `GITHUB_TOKEN` is still required for push/sync flows. + +### POST /api/setup -Create a project. +Saves one or both keys to `~/.dossier/config` and injects saved values into `process.env` for immediate use. **Request body:** ```json { - "name": "string (required)", - "repo_url": "string|null (optional)", - "default_branch": "string (optional, default: main)" + "anthropicApiKey": "sk-ant-... (optional)", + "githubToken": "ghp_... (optional)" } ``` -**Response:** `201` — Created project object +**Constraints:** +- At least one key is required (`400` otherwise). -### GET /api/projects/[projectId] +--- -Get project details. +## Project Management -**Response:** `200` — Project object | `404` — Not found +### GET /api/projects +List projects. -### PATCH /api/projects/[projectId] +### POST /api/projects +Create project + default system policy profile. + +**Request body (subset):** +```json +{ + "name": "required", + "repo_url": "https://github.com/org/repo (optional)", + "default_branch": "main (optional)" +} +``` -Update project. +### GET /api/projects/[projectId] +Get project. -**Request body:** Same as POST, all fields optional +### PATCH /api/projects/[projectId] +Update mutable project fields (name/description/personas/tech/deployment/design/repo/default_branch). -**Response:** `200` — Updated project object +**Constraint:** `finalized_at` is intentionally not writable through this endpoint. --- -## Map & Actions +## Planning Chat -### GET /api/projects/[projectId]/map +### POST /api/projects/[projectId]/chat +Non-streaming planning endpoint. -Canonical map snapshot: Workflow → WorkflowActivity → Step → Card tree. +**Modes:** +- `scaffold` -> scaffold prompt; only `updateProject` + `createWorkflow` are applied. +- `populate` (+ `workflow_id`) -> add activities/cards in one workflow. +- `finalize` -> generate required project-level context artifacts (multi-step finalize flow). +- omitted -> scaffold if map is empty, otherwise full planning mode. -**Response:** `200` +**Request body:** ```json { - "project": { "id", "name", "repo_url", "default_branch" }, - "workflows": [ - { - "id", "project_id", "title", "description", "build_state", "position", - "activities": [ - { - "id", "workflow_id", "title", "color", "position", - "steps": [{ "id", "title", "position", "cards": [...] }], - "cards": [] - } - ] - } - ] + "message": "string", + "mode": "scaffold|populate|finalize (optional)", + "workflow_id": "uuid (required when mode=populate)", + "mock_response": "test-only optional" } ``` -### GET /api/projects/[projectId]/actions - -Action history for the project. +### POST /api/projects/[projectId]/chat/stream +SSE variant of planning endpoint. -**Response:** `200` — Array of PlanningAction records +**SSE events used by current handlers:** +- `message` +- `action` +- `error` +- `finalize_progress` +- `phase_complete` +- `done` -### POST /api/projects/[projectId]/actions +**Response type:** `text/event-stream` -Submit planning actions. Validates, applies, and persists. Rejects on first failure. +--- -**Request body:** -```json -{ - "actions": [ - { - "id": "uuid (optional)", - "action_type": "createWorkflow|createActivity|createStep|createCard|updateCard|reorderCard|linkContextArtifact|upsertCardPlannedFile|approveCardPlannedFile|upsertCardKnowledgeItem|setCardKnowledgeStatus", - "target_ref": {}, - "payload": {} - } - ] -} -``` +## Map & Actions -**Response:** `201` — `{ "applied": number, "results": [...] }` | `422` — Action rejected +### GET /api/projects/[projectId]/map +Canonical map snapshot (project -> workflows -> activities -> steps -> cards). -**Supported action types:** +### GET /api/projects/[projectId]/actions +Project action history. -| Action | Description | -|--------|-------------| -| `createWorkflow` | Create a new workflow in the project | -| `createActivity` | Create a workflow activity | -| `createStep` | Create a step within an activity | -| `createCard` | Create a card in a step or activity | -| `updateCard` | Update card title, description, status, or priority | -| `reorderCard` | Move card to new step/position | -| `linkContextArtifact` | Link a context artifact to a card | -| `upsertCardPlannedFile` | Create or update a planned file for a card | -| `approveCardPlannedFile` | Approve or revert a planned file | -| `upsertCardKnowledgeItem` | Create or update a requirement, fact, assumption, or question | -| `setCardKnowledgeStatus` | Set status (draft/approved/rejected) on a knowledge item | +### POST /api/projects/[projectId]/actions +Validate + apply action batch. -Code-generation intents are rejected. +### POST /api/projects/[projectId]/actions/preview +Dry-run preview; computes action summaries/deltas without DB writes. --- ## Context Artifacts ### GET /api/projects/[projectId]/artifacts - List project artifacts. -**Response:** `200` — Array of ContextArtifact - ### POST /api/projects/[projectId]/artifacts - Create artifact. Requires at least one of: `content`, `uri`, `integration_ref`. -**Request body:** -```json -{ - "name": "string", - "type": "doc|design|code|research|link|image|skill|mcp|cli|api|prompt|spec|runbook", - "title": "string|null", - "content": "string|null", - "uri": "string|null", - "locator": "string|null", - "mime_type": "string|null", - "integration_ref": "object|null" -} -``` - -**Response:** `201` — Created artifact - ### GET /api/projects/[projectId]/artifacts/[artifactId] - -Get single artifact. +Get artifact. ### PATCH /api/projects/[projectId]/artifacts/[artifactId] - -Update artifact. All fields optional. +Update artifact. ### DELETE /api/projects/[projectId]/artifacts/[artifactId] +Delete artifact (`204`). + +--- -Delete artifact. **Response:** `204` +## Card Approval / Finalization + +### GET /api/projects/[projectId]/cards/[cardId]/finalize +Returns card finalization package: +- card +- project docs (`doc/spec/design`) +- linked card artifacts +- requirements +- planned files +- current `finalized_at` + +### POST /api/projects/[projectId]/cards/[cardId]/finalize +SSE finalize flow for a single card. + +Current step sequence: +1. Link project-wide docs to card +2. Generate card e2e test artifact (+ optional card-specific docs) +3. Stamp `card.finalized_at` +4. Attempt memory ingestion for the card (best-effort when memory plane enabled) + +**Validation constraints (returns `400 validation_failed`):** +- Card must belong to project +- Card must not already be finalized +- Project must already be finalized +- Card must have at least one requirement +- Card must have at least one planned file/folder --- ## Card Knowledge Items -All knowledge routes require the card to belong to the project (via workflow → activity). +All routes verify the card belongs to the project. ### Requirements - -- `GET /api/projects/[projectId]/cards/[cardId]/requirements` -- `POST /api/projects/[projectId]/cards/[cardId]/requirements` -- `PATCH /api/projects/[projectId]/cards/[cardId]/requirements/[itemId]` -- `DELETE /api/projects/[projectId]/cards/[cardId]/requirements/[itemId]` +- `GET|POST /api/projects/[projectId]/cards/[cardId]/requirements` +- `PATCH|DELETE /api/projects/[projectId]/cards/[cardId]/requirements/[itemId]` ### Facts - -- `GET /api/projects/[projectId]/cards/[cardId]/facts` -- `POST /api/projects/[projectId]/cards/[cardId]/facts` -- `PATCH /api/projects/[projectId]/cards/[cardId]/facts/[itemId]` -- `DELETE /api/projects/[projectId]/cards/[cardId]/facts/[itemId]` +- `GET|POST /api/projects/[projectId]/cards/[cardId]/facts` +- `PATCH|DELETE /api/projects/[projectId]/cards/[cardId]/facts/[itemId]` ### Assumptions - -- `GET /api/projects/[projectId]/cards/[cardId]/assumptions` -- `POST /api/projects/[projectId]/cards/[cardId]/assumptions` -- `PATCH /api/projects/[projectId]/cards/[cardId]/assumptions/[itemId]` -- `DELETE /api/projects/[projectId]/cards/[cardId]/assumptions/[itemId]` +- `GET|POST /api/projects/[projectId]/cards/[cardId]/assumptions` +- `PATCH|DELETE /api/projects/[projectId]/cards/[cardId]/assumptions/[itemId]` ### Questions - -- `GET /api/projects/[projectId]/cards/[cardId]/questions` -- `POST /api/projects/[projectId]/cards/[cardId]/questions` -- `PATCH /api/projects/[projectId]/cards/[cardId]/questions/[itemId]` -- `DELETE /api/projects/[projectId]/cards/[cardId]/questions/[itemId]` - -**Create payload (e.g. requirements):** -```json -{ - "text": "string", - "status": "draft|approved|rejected (optional)", - "source": "agent|user|imported", - "confidence": "number 0-1 (optional)", - "position": "number (optional)" -} -``` +- `GET|POST /api/projects/[projectId]/cards/[cardId]/questions` +- `PATCH|DELETE /api/projects/[projectId]/cards/[cardId]/questions/[itemId]` --- -## Card Planned Files - -### GET /api/projects/[projectId]/cards/[cardId]/planned-files - -List planned files for a card. - -### POST /api/projects/[projectId]/cards/[cardId]/planned-files - -Create planned file. - -**Request body:** -```json -{ - "logical_file_name": "string", - "module_hint": "string|null", - "artifact_kind": "component|endpoint|service|schema|hook|util|middleware|job|config", - "action": "create|edit", - "intent_summary": "string", - "contract_notes": "string|null", - "status": "proposed|user_edited|approved (optional)", - "position": "number (optional)" -} -``` +## Card Planned Files & Context Links -### PATCH /api/projects/[projectId]/cards/[cardId]/planned-files/[fileId] +### Planned files +- `GET|POST /api/projects/[projectId]/cards/[cardId]/planned-files` +- `PATCH|DELETE /api/projects/[projectId]/cards/[cardId]/planned-files/[fileId]` -Update or approve planned file. Use `{ "status": "approved" }` for approval. - -### DELETE /api/projects/[projectId]/cards/[cardId]/planned-files/[fileId] - -Delete planned file. +### Context links for a card +- `GET|POST /api/projects/[projectId]/cards/[cardId]/context-artifacts` --- -## Project Files (Planned + Repository) +## Repo Views & Sync ### GET /api/projects/[projectId]/files +Unified file API: +- `source=planned` (default): card planned files tree +- `source=repo`: actual cloned repo tree (+ git status) +- `source=repo&content=1&path=...`: file content (`text/plain`) +- `source=repo&diff=1&path=...`: diff vs base (`text/x-diff`) -File tree for the project. Two modes via `source` query param. +### GET /api/projects/[projectId]/cards/[cardId]/produced-files +Returns added/modified files detected for the card's completed assignment branch. -**Query params:** +### POST /api/projects/[projectId]/cards/[cardId]/push +Pushes this card's feature branch to origin. -| Param | Values | Description | -|-------|--------|-------------| -| `source` | `planned` (default) | Planned files from `card_planned_file` (intent, not produced code) | -| `source` | `repo` | Actual files from cloned repo (after build); includes diff status | -| `content` | `1` | With `source=repo` and `path`: return file content as `text/plain` | -| `diff` | `1` | With `source=repo` and `path`: return unified diff vs base branch as `text/x-diff` | -| `path` | `src/foo.ts` | Required when `content=1` or `diff=1`; file path (with or without leading slash) | +Common non-200s: +- `400`: repo not connected +- `401`: missing/invalid GitHub token +- `409`: no completed build for that card +- `502`: push failed upstream -**Default (`source=planned`):** Returns hierarchical file tree built from `card_planned_file.logical_file_name`. +### POST /api/projects/[projectId]/repo/sync +Sync local base branch (usually `main`) to `origin/` in Dossier's clone. -**`source=repo`:** Returns file tree from the latest build's cloned repo (feature branch). Requires at least one completed or running build with `worktree_root` set. Nodes include optional `status`: `added`, `modified`, `deleted`. +Common non-200s: +- `400`: repo not connected +- `401`: auth/token issue +- `502`: git sync failure -**`source=repo&content=1&path=...`:** Returns raw file content. `404` if file not found. +--- -**`source=repo&diff=1&path=...`:** Returns `git diff base...feature -- path`. `404` if file unchanged or not found. +## Orchestration Endpoints (Build Runs) -**Response (tree):** `200` — Array of `FileNode`: -```json -[ - { - "name": "src", - "type": "folder", - "path": "/src", - "status": "modified", - "children": [ - { "name": "index.ts", "type": "file", "path": "/src/index.ts", "status": "added" } - ] - } -] -``` +See `app/api/projects/[projectId]/orchestration/**` for full route set, including: +- build trigger +- run/assignment/check lifecycle +- approvals +- PR candidate endpoints +- webhook ingestion -**Response (content/diff):** `200` — `text/plain` or `text/x-diff` body. `404` — Error JSON if no build or file not found. +Primary domain doc: `docs/domains/orchestration-reference.md`. --- ## As-Built Notes -- **Mutations**: All map changes go through the actions endpoint; no direct writes. -- **Auth**: No auth/RLS; endpoints use anon access (single-user desktop app). -- **Database**: SQLite only; no Supabase or Postgres. +- **Mutations**: Map edits are mediated via action pipeline (`/actions`) or planning chat routes that internally apply validated actions. +- **Auth model**: Single-user local app; no user auth/RLS layer in API routes. +- **Database runtime**: SQLite is implemented; `DB_DRIVER=postgres` currently throws "not yet implemented." diff --git a/docs/reference/configuration-reference.md b/docs/reference/configuration-reference.md index f5197b8..58ad2ac 100644 --- a/docs/reference/configuration-reference.md +++ b/docs/reference/configuration-reference.md @@ -1,7 +1,7 @@ --- document_id: doc.configuration -last_verified: 2026-02-18 -tokens_estimate: 600 +last_verified: 2026-03-23 +tokens_estimate: 700 tags: - configuration - env @@ -10,9 +10,9 @@ anchors: - id: precedence summary: "process.env > .env.local > ~/.dossier/config" - id: required - summary: "ANTHROPIC_API_KEY, GITHUB_TOKEN" + summary: "Anthropic planning credential + GITHUB_TOKEN" - id: optional - summary: "DB_DRIVER, DOSSIER_DATA_DIR, feature flags" + summary: "DB pathing, model selection, runtime tuning, feature flags" ttl_expires_on: null --- # Configuration Reference @@ -21,44 +21,56 @@ ttl_expires_on: null ## Contract -- INVARIANT: Config precedence: `process.env` > `.env.local` > `~/.dossier/config` -- INVARIANT: Self-deploy uses `~/.dossier/config`; dev uses `.env.local` -- Anthropic credential: we accept **API key** first (env, then `~/.dossier/config`). If none is set, we use your **installed Claude CLI** config: `~/.claude/settings.json` (or `CLAUDE_CONFIG_DIR`/settings.json). We read `env.ANTHROPIC_API_KEY` or `env.ANTHROPIC_AUTH_TOKEN` from that file so you don’t need to paste a key if Claude Code is already configured. +- INVARIANT: Config precedence is `process.env` > `.env.local` > `~/.dossier/config` +- INVARIANT: `/setup` writes to `~/.dossier/config` and updates `process.env` for immediate use +- INVARIANT: Planning credential resolution is env/config first, then Claude CLI settings + +Planning credential resolution order: +1. `process.env.ANTHROPIC_API_KEY` +2. `~/.dossier/config` -> `ANTHROPIC_API_KEY` +3. Claude CLI settings (`~/.claude/settings.json`, or `CLAUDE_CONFIG_DIR/settings.json`): + - `env.ANTHROPIC_API_KEY`, else + - `env.ANTHROPIC_AUTH_TOKEN` (also mapped to `CLAUDE_CODE_OAUTH_TOKEN`) --- ## Required -Anthropic credential (API key or Claude CLI config) and GitHub token: +| Variable | Required for | Notes | +|----------|--------------|-------| +| `ANTHROPIC_API_KEY` | Planning/build LLM access | Optional if Claude CLI credential is available via settings.json | +| `GITHUB_TOKEN` | Push/sync branch operations | Required by `/api/projects/[projectId]/cards/[cardId]/push` and `/api/projects/[projectId]/repo/sync` | -| Variable | Purpose | -|----------|---------| -| ANTHROPIC_API_KEY | Planning LLM and build (set in env or `~/.dossier/config`; or we use your Claude CLI `~/.claude/settings.json` when no key is set) | -| GITHUB_TOKEN | Push branches, create PRs; [github.com/settings/tokens](https://github.com/settings/tokens) `repo` scope | +Token guidance: +- Classic token: `repo` scope +- Fine-grained token: repository `Contents` write permission --- -## Optional +## Optional Runtime Variables | Variable | Default | Purpose | |----------|---------|---------| -| DB_DRIVER | sqlite | `sqlite` or `postgres` | -| DATABASE_URL | — | Postgres connection string (when DB_DRIVER=postgres) | -| DOSSIER_DATA_DIR | ~/.dossier | Data directory | -| SQLITE_PATH | ~/.dossier/dossier.db | Override SQLite path | -| EMBEDDING_MODEL | all-MiniLM-L6-v2 | RuVector embedding model | -| PLANNING_LLM_MODEL | claude-haiku-4-5-20251001 | Planning LLM model | -| DOSSIER_STALE_RUN_MINUTES | 0 | Minutes before marking stuck runs as failed. 0 = disabled (no timeout). | +| `DB_DRIVER` | `sqlite` | Database driver selector; `postgres` currently not implemented at runtime | +| `DATABASE_URL` | — | Checked when `DB_DRIVER=postgres`; runtime throws if postgres selected | +| `DOSSIER_DATA_DIR` | `~/.dossier` | Base data directory | +| `SQLITE_PATH` | `~/.dossier/dossier.db` | Explicit SQLite path override | +| `PLANNING_LLM_MODEL` | `claude-haiku-4-5-20251001` | Planning model override | +| `COMPLETION_MODEL` | `claude-sonnet-4-5-20250929` | Build execution model override | +| `EMBEDDING_MODEL` | `all-MiniLM-L6-v2` | Memory embedding model | +| `DOSSIER_STALE_RUN_MINUTES` | `0` | Stale run timeout; `0` disables timeout | +| `DOSSIER_PRE_AUTOCOMMIT_DELAY_MS` | `2000` | Delay before webhook/auto-commit after execution completion | +| `PLANNING_DEBUG` | unset | Extra planning diagnostics when set to `1` | --- -## Feature Flags (NEXT_PUBLIC_*) +## Feature Flags | Variable | Default | Purpose | |----------|---------|---------| -| NEXT_PUBLIC_PLANNING_LLM_ENABLED | true | Planning chat | -| NEXT_PUBLIC_BUILD_ORCHESTRATOR_ENABLED | true | Build triggers | -| NEXT_PUBLIC_MEMORY_PLANE_ENABLED | true | Memory ingestion/retrieval | +| `NEXT_PUBLIC_PLANNING_LLM_ENABLED` | `true` | Enables chat/chat-stream planning endpoints | +| `NEXT_PUBLIC_BUILD_ORCHESTRATOR_ENABLED` | `true` | Enables orchestration/build routes | +| `NEXT_PUBLIC_MEMORY_PLANE_ENABLED` | `true` | Enables memory ingestion/retrieval flows | --- @@ -66,26 +78,56 @@ Anthropic credential (API key or Claude CLI config) and GitHub token: | Variable | Purpose | |----------|---------| -| PLANNING_MOCK_ALLOWED | 1 = mock LLM in planning tests | +| `PLANNING_MOCK_ALLOWED` | `1` enables mock LLM payload support in planning routes/tests | --- ## Config File Format -`~/.dossier/config` or `.env.local`: +Both `.env.local` and `~/.dossier/config` use: -``` +```bash KEY=value KEY="value with spaces" # comments ignored ``` +`/api/setup` accepts: + +```json +{ + "anthropicApiKey": "optional string", + "githubToken": "optional string" +} +``` + +At least one key must be present. + +--- + +## Troubleshooting + +### Setup loop redirects back to `/setup` +Check `/api/setup/status`: +- `missingKeys` includes `GITHUB_TOKEN` -> add token via `/setup` or config file +- `missingKeys` includes `ANTHROPIC_API_KEY` and `anthropicViaCli=false` -> provide key or ensure Claude CLI is installed/authenticated + +### Push/sync returns 401 or auth error +- Ensure `GITHUB_TOKEN` is present in env or `~/.dossier/config` +- Verify token scope/permissions for target repo + +### `DB_DRIVER=postgres` fails at runtime +- Current runtime implementation supports SQLite only +- Use default `DB_DRIVER=sqlite` + --- ## Verification -- [ ] Required vars set before running -- [ ] /setup writes to ~/.dossier/config +- [ ] `/api/setup/status` reports expected `needsSetup` and `missingKeys` +- [ ] `/api/setup` persists values to `~/.dossier/config` +- [ ] Push/sync routes succeed with configured `GITHUB_TOKEN` ## Related - [.env.example](../../.env.example) - [lib/config/data-dir.ts](../../lib/config/data-dir.ts) +- [lib/llm/planning-credential.ts](../../lib/llm/planning-credential.ts)