diff --git a/docs/docs-index.yaml b/docs/docs-index.yaml index fc6899f..f096187 100644 --- a/docs/docs-index.yaml +++ b/docs/docs-index.yaml @@ -62,9 +62,21 @@ docs_index: tags: [api, endpoints] anchors: - id: endpoints - summary: "REST API under /api/projects; map, actions, artifacts, cards" + summary: "REST API under /api; setup, projects, cards, orchestration, integrations" depends_on: [doc.system-architecture] - last_verified: "2026-02-18" + last_verified: "2026-03-16" + + - id: doc.api-endpoints + path: reference/api-endpoints.md + tokens_estimate: 2200 + tags: [api, endpoints, orchestration, setup, integrations] + anchors: + - id: endpoint-inventory + summary: "As-built endpoint inventory across setup, projects, cards, and orchestration" + - id: contracts + summary: "Key request/response contracts and operational constraints" + depends_on: [doc.api-reference, doc.data-contracts] + last_verified: "2026-03-16" - id: doc.planning path: domains/planning-reference.md diff --git a/docs/domains/api-reference.md b/docs/domains/api-reference.md index 14b6ec6..05c9735 100644 --- a/docs/domains/api-reference.md +++ b/docs/domains/api-reference.md @@ -1,13 +1,13 @@ --- document_id: doc.api-reference -last_verified: 2026-02-18 +last_verified: 2026-03-16 tokens_estimate: 400 tags: - api - endpoints anchors: - id: endpoints - summary: "REST API under /api/projects; map, actions, artifacts, cards" + summary: "REST API under /api; setup, projects, cards, orchestration, integrations" ttl_expires_on: null --- # API Reference @@ -16,21 +16,29 @@ ttl_expires_on: null ## Contract -- INVARIANT: All routes under `/api`; project-scoped routes use `[projectId]` -- INVARIANT: Errors return JSON `{ error, message, details? }` +- INVARIANT: All routes are under `/api`; project-scoped routes use `[projectId]` +- INVARIANT: Most routes use `{ error, message, details? }`, but setup/integration/SSE routes may use endpoint-specific envelopes +- INVARIANT: Streaming endpoints use `text/event-stream` and emit terminal `done` events ## Endpoint Groups | Group | Base Path | Purpose | |-------|-----------|---------| +| Setup | `/api/setup`, `/api/setup/status` | Configure required runtime keys and inspect readiness | +| Docs panel | `/api/docs` | List docs index entries and retrieve doc content | +| GitHub integration | `/api/github/repos` | List or create repos using configured token | | Projects | `/api/projects` | CRUD projects | | Map | `/api/projects/[id]/map` | Canonical map snapshot | | Actions | `/api/projects/[id]/actions` | Submit planning actions | +| Action preview | `/api/projects/[id]/actions/preview` | Dry-run action batch without mutation | | Chat | `/api/projects/[id]/chat`, `/chat/stream` | Planning LLM | +| Memory | `/api/projects/[id]/memory` | Inspect stored memory units for a project | | Artifacts | `/api/projects/[id]/artifacts` | Context artifacts | | Card knowledge | `/api/projects/[id]/cards/[cardId]/{requirements,facts,assumptions,questions}` | Knowledge items | | Planned files | `/api/projects/[id]/cards/[cardId]/planned-files` | Card planned files | +| Card finalize/build support | `/api/projects/[id]/cards/[cardId]/{context-artifacts,produced-files,finalize,push}` | Context links, generated files, finalize flow, branch push | | Files | `/api/projects/[id]/files` | File tree (planned or repo); `?source=repo` for produced code | +| Orchestration | `/api/projects/[id]/orchestration/*` | Build triggers, runs, checks, assignments, approvals, PR candidates | ## Related - [data-contracts-reference.md](data-contracts-reference.md) diff --git a/docs/reference/api-endpoints.md b/docs/reference/api-endpoints.md index 3b0fe12..06376dd 100644 --- a/docs/reference/api-endpoints.md +++ b/docs/reference/api-endpoints.md @@ -1,321 +1,463 @@ # 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. +As-built API surface for Dossier (`app/api/**/route.ts`). ## Base URL - Local: `http://localhost:3000` -- All routes are under `/api` +- All endpoints are under `/api` -## Error Response Format +## Response Conventions -All errors return JSON: +- Many routes use shared helpers and return: + ```json + { "error": "validation_failed|not_found|conflict|action_rejected|internal_error", "message": "...", "details": {} } + ``` +- Some endpoints intentionally return different envelopes (for example `/api/setup`, `/api/github/repos`, and SSE endpoints). Treat each endpoint contract below as source of truth. +- Streaming endpoints return `Content-Type: text/event-stream`. -```json -{ - "error": "error_code", - "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 | +## Endpoint Inventory (quick scan) + +### Setup, docs, and integrations + +- `POST /api/setup` +- `GET /api/setup/status` +- `GET /api/docs` +- `GET /api/github/repos` +- `POST /api/github/repos` +- `POST /api/dev/restart-and-open` (development-only) + +### Projects and planning + +- `GET /api/projects` +- `POST /api/projects` +- `GET /api/projects/[projectId]` +- `PATCH /api/projects/[projectId]` +- `GET /api/projects/[projectId]/map` +- `GET /api/projects/[projectId]/actions` +- `POST /api/projects/[projectId]/actions` +- `POST /api/projects/[projectId]/actions/preview` +- `POST /api/projects/[projectId]/chat` +- `POST /api/projects/[projectId]/chat/stream` +- `GET /api/projects/[projectId]/memory` +- `GET /api/projects/[projectId]/files` + +### Card context and approval + +- Artifacts: + - `GET/POST /api/projects/[projectId]/artifacts` + - `GET/PATCH/DELETE /api/projects/[projectId]/artifacts/[artifactId]` +- Knowledge: + - `GET/POST /requirements`, `PATCH/DELETE /requirements/[itemId]` + - `GET/POST /facts`, `PATCH/DELETE /facts/[itemId]` + - `GET/POST /assumptions`, `PATCH/DELETE /assumptions/[itemId]` + - `GET/POST /questions`, `PATCH/DELETE /questions/[itemId]` +- Planned files: + - `GET/POST /api/projects/[projectId]/cards/[cardId]/planned-files` + - `PATCH/DELETE /api/projects/[projectId]/cards/[cardId]/planned-files/[fileId]` +- Card execution support: + - `GET /api/projects/[projectId]/cards/[cardId]/context-artifacts` + - `GET /api/projects/[projectId]/cards/[cardId]/produced-files` + - `GET/POST /api/projects/[projectId]/cards/[cardId]/finalize` + - `POST /api/projects/[projectId]/cards/[cardId]/push` + +### Orchestration + +- Triggering: + - `POST /api/projects/[projectId]/orchestration/build` + - `POST /api/projects/[projectId]/orchestration/resume-blocked` +- Runs: + - `GET/POST /api/projects/[projectId]/orchestration/runs` + - `GET/PATCH /api/projects/[projectId]/orchestration/runs/[runId]` +- Checks: + - `GET/POST /api/projects/[projectId]/orchestration/runs/[runId]/checks` + - `GET /api/projects/[projectId]/orchestration/runs/[runId]/checks/[checkId]` +- Assignments: + - `GET/POST /api/projects/[projectId]/orchestration/runs/[runId]/assignments` + - `GET /api/projects/[projectId]/orchestration/runs/[runId]/assignments/[assignmentId]` + - `POST /api/projects/[projectId]/orchestration/runs/[runId]/assignments/[assignmentId]/dispatch` +- Approvals and PR candidates: + - `GET/POST /api/projects/[projectId]/orchestration/approvals` + - `GET/PATCH /api/projects/[projectId]/orchestration/approvals/[approvalId]` + - `GET/POST /api/projects/[projectId]/orchestration/pull-requests` + - `GET/PATCH /api/projects/[projectId]/orchestration/pull-requests/[prId]` +- Agent callback: + - `POST /api/projects/[projectId]/orchestration/webhooks/agentic-flow` --- -## Project Management +## High-Value Contracts and Constraints + +### Setup and integration endpoints -### GET /api/projects +### `POST /api/setup` -List all projects. +Save API keys to `~/.dossier/config` and inject into current process env. -**Response:** `200` — Array of project objects +Request: ```json -[ - { "id": "uuid", "name": "string", "repo_url": "string|null", "default_branch": "string", "created_at": "string", "updated_at": "string" } -] +{ + "anthropicApiKey": "optional string", + "githubToken": "optional string" +} ``` -### POST /api/projects +Rules: -Create a project. +- At least one key must be non-empty after trim. +- Returns `{ success: true, configPath }` on success. + +### `GET /api/setup/status` + +Returns setup readiness: -**Request body:** ```json { - "name": "string (required)", - "repo_url": "string|null (optional)", - "default_branch": "string (optional, default: main)" + "needsSetup": true, + "missingKeys": ["ANTHROPIC_API_KEY", "GITHUB_TOKEN"], + "configPath": "/home/.../.dossier/config" } ``` -**Response:** `201` — Created project object - -### GET /api/projects/[projectId] - -Get project details. - -**Response:** `200` — Project object | `404` — Not found +### `GET /api/github/repos` -### PATCH /api/projects/[projectId] +Lists repositories for the configured GitHub token (`env` first, then config file). -Update project. +- `503` if token is missing. +- `401` if token is invalid. -**Request body:** Same as POST, all fields optional +### `GET /api/docs` -**Response:** `200` — Updated project object +Docs panel API. ---- +- No query param: returns indexed docs from `docs/docs-index.yaml` +- `?path=`: returns `{ content }` for that document +- Normalizes and guards path traversal (`400 Invalid path`, `404 Doc not found`) -## Map & Actions +### `POST /api/github/repos` -### GET /api/projects/[projectId]/map +Creates a user repo. -Canonical map snapshot: Workflow → WorkflowActivity → Step → Card tree. +Request: -**Response:** `200` ```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": [] - } - ] - } - ] + "name": "repo-name", + "private": false } ``` -### GET /api/projects/[projectId]/actions +Constraints: -Action history for the project. +- `name` must match `^[a-zA-Z0-9._-]+$` +- `422` on invalid/existing repo names from GitHub API -**Response:** `200` — Array of PlanningAction records +### `POST /api/dev/restart-and-open` -### POST /api/projects/[projectId]/actions +Development-only helper (`NODE_ENV=development`): -Submit planning actions. Validates, applies, and persists. Rejects on first failure. +- Requires `{ projectId }` +- Starts `npm run dev` in clone path on first free port `3001..3010` +- Returns `409` when clone does not exist and `503` when no view port is available + +--- + +## Projects and planning + +### `POST /api/projects` + +Validated request schema accepts: + +- `name` (required) +- `description`, `customer_personas`, `tech_stack`, `deployment`, `design_inspiration` (optional) +- `repo_url` (optional URL/null) +- `default_branch` (optional) + +Current create behavior persists `name`, `repo_url`, and `default_branch`, and creates a default system policy profile. + +### `PATCH /api/projects/[projectId]` + +Partial updates for all fields listed above. + +### `GET /api/projects/[projectId]/map` + +Canonical map shape is: + +`project -> workflows[] -> activities[] -> cards[]` + +There is no `step` level in this response. Card nodes include build and finalization fields such as `build_state`, `last_built_at`, `last_build_ref`, and `finalized_at`. + +### `POST /api/projects/[projectId]/actions` + +Applies planning actions transactionally. + +Request: -**Request body:** ```json { "actions": [ { - "id": "uuid (optional)", - "action_type": "createWorkflow|createActivity|createStep|createCard|updateCard|reorderCard|linkContextArtifact|upsertCardPlannedFile|approveCardPlannedFile|upsertCardKnowledgeItem|setCardKnowledgeStatus", + "id": "optional uuid", + "action_type": "updateProject|createWorkflow|createActivity|createCard|updateCard|reorderCard|deleteWorkflow|deleteActivity|deleteCard|linkContextArtifact|createContextArtifact|upsertCardPlannedFile|upsertCardKnowledgeItem", "target_ref": {}, "payload": {} } - ] + ], + "idempotency_key": "optional string", + "expected_sequence": 12 } ``` -**Response:** `201` — `{ "applied": number, "results": [...] }` | `422` — Action rejected +Operational constraints: -**Supported action types:** +- `expected_sequence` mismatch returns `409`. +- Duplicate `idempotency_key` returns previous results with `idempotent: true`. +- Rejected actions return `422 action_rejected`. -| 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/preview` -Code-generation intents are rejected. +Dry-run only; does not mutate DB. ---- +### `POST /api/projects/[projectId]/chat` -## Context Artifacts +Non-streaming planning endpoint. -### GET /api/projects/[projectId]/artifacts +Modes: -List project artifacts. +- `scaffold` +- `populate` (requires `workflow_id`) +- `finalize` -**Response:** `200` — Array of ContextArtifact +Returns JSON with fields like: -### 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" + "status": "success|error", + "responseType": "clarification|actions|mixed", + "applied": 0, + "workflow_ids_created": [] } ``` -**Response:** `201` — Created artifact +### `POST /api/projects/[projectId]/chat/stream` -### GET /api/projects/[projectId]/artifacts/[artifactId] +SSE variant for scaffold/populate/finalize. Emits events including: -Get single artifact. +- `error` +- `phase_complete` +- `done` -### PATCH /api/projects/[projectId]/artifacts/[artifactId] +### `GET /api/projects/[projectId]/memory` -Update artifact. All fields optional. +Returns memory units linked to project plus storage paths (`sqlite`, `ruvector`). -### DELETE /api/projects/[projectId]/artifacts/[artifactId] +### `GET /api/projects/[projectId]/files` -Delete artifact. **Response:** `204` +Query parameters: ---- +| Param | Values | Notes | +|---|---|---| +| `source` | `planned` (default), `repo` | planned DB tree vs repository tree | +| `cardId` | uuid | card-specific repo view (assignment/worktree) | +| `content` | `1` | with `source=repo&path=...`, return `text/plain` | +| `diff` | `1` | with `source=repo&path=...`, return `text/x-diff` | +| `path` | relative path | required for `content=1` or `diff=1` | -## Card Knowledge Items +Notes: -All knowledge routes require the card to belong to the project (via workflow → activity). +- If `source=repo` and no run worktree exists, route falls back to clone tree when possible. +- If no assignment branch is selected, `diff=1` returns an empty diff body (`200`) against base branch context. -### 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]` +## Card-level endpoints -### Facts +### Artifacts -- `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]` +Artifact type enum: -### Assumptions +`doc|design|code|research|link|image|skill|mcp|cli|api|prompt|spec|runbook|test|scaffold` -- `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]` +Create requires at least one of `content`, `uri`, `integration_ref`. -### Questions +### Knowledge items -- `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 shape (requirements/facts/assumptions/questions): -**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)" + "status": "draft|approved|rejected", + "confidence": 0.8, + "position": 0 } ``` +Facts can also include `evidence_source`. + +### Planned files + +`artifact_kind`: + +`component|endpoint|service|schema|hook|util|middleware|job|config` + +`action`: `create|edit` + +`status`: `proposed|user_edited|approved` + +### `GET /cards/[cardId]/context-artifacts` + +Returns expanded artifact objects linked to the card. + +### `GET /cards/[cardId]/produced-files` + +Returns `[{ path, status }]` for `added|modified` files from latest completed card assignment. + +### `GET /cards/[cardId]/finalize` + +Returns finalization package: + +- `card` +- `project_docs` +- `card_artifacts` +- `requirements` +- `planned_files` +- `finalized_at` + +### `POST /cards/[cardId]/finalize` + +SSE endpoint. Preconditions: + +- card exists in project +- card is not already finalized +- project is finalized +- card has at least one requirement +- card has at least one planned file/folder +- planning LLM is enabled + +Emits `finalize_progress`, `phase_complete`, and `done`. + +### `POST /cards/[cardId]/push` + +Pushes completed card feature branch to remote: + +- `400` if repo is not connected +- `409` if there is no completed build for the card +- `401/502` on push failures + --- -## Card Planned Files +## Orchestration API + +### Triggering + +#### `POST /orchestration/build` -### GET /api/projects/[projectId]/cards/[cardId]/planned-files +Request: + +```json +{ + "scope": "workflow|card", + "workflow_id": "required when scope=workflow", + "card_id": "required when scope=card", + "trigger_type": "card|workflow|manual", + "initiated_by": "string" +} +``` -List planned files for a card. +Returns `202` with `{ runId, assignmentIds, outcome_type }` on success. -### POST /api/projects/[projectId]/cards/[cardId]/planned-files +#### `POST /orchestration/resume-blocked` -Create planned file. +Request: -**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_id": "uuid", + "actor": "optional string" } ``` -### PATCH /api/projects/[projectId]/cards/[cardId]/planned-files/[fileId] +Returns `202` with resumed assignment/run identifiers. -Update or approve planned file. Use `{ "status": "approved" }` for approval. +### Runs -### DELETE /api/projects/[projectId]/cards/[cardId]/planned-files/[fileId] +#### `GET /orchestration/runs` -Delete planned file. +Query: `scope?`, `status?`, `limit?` ---- +#### `POST /orchestration/runs` -## Project Files (Planned + Repository) +Creates run directly; requires `repo_url`, `base_branch`, `run_input_snapshot`, and scope-specific IDs. -### GET /api/projects/[projectId]/files +#### `PATCH /orchestration/runs/[runId]` -File tree for the project. Two modes via `source` query param. +Allowed status transitions: -**Query params:** +- `queued -> running|cancelled` +- `running -> blocked|failed|completed|cancelled` +- `blocked -> running|failed|cancelled` +- `failed -> queued` +- `completed` and `cancelled` are terminal -| 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) | +### Checks -**Default (`source=planned`):** Returns hierarchical file tree built from `card_planned_file.logical_file_name`. +- `POST /orchestration/runs/[runId]/checks` requires `check_type` and `status` +- check types: `dependency|security|policy|lint|unit|integration|e2e` +- statuses: `passed|failed|skipped` -**`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`. +### Assignments -**`source=repo&content=1&path=...`:** Returns raw file content. `404` if file not found. +`POST /orchestration/runs/[runId]/assignments` requires: -**`source=repo&diff=1&path=...`:** Returns `git diff base...feature -- path`. `404` if file unchanged or not found. +- `card_id` +- `agent_role` (`planner|coder|reviewer|integrator|tester`) +- `agent_profile` +- `feature_branch` +- `allowed_paths` (non-empty) +- optional `forbidden_paths`, `worktree_path`, `assignment_input_snapshot` -**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" } - ] - } -] -``` +`POST /.../dispatch` accepts optional `{ actor }` and returns `202` with execution IDs. + +### Approvals and PR candidates + +- `GET /orchestration/approvals` requires `run_id` query param. +- `POST /orchestration/approvals` requires `run_id`, `approval_type` (`create_pr|merge_pr`), `requested_by`. +- `PATCH /orchestration/approvals/[approvalId]` requires `status` and `resolved_by`. +- `GET /orchestration/pull-requests` requires `run_id`. +- `POST /orchestration/pull-requests` requires `run_id`, `base_branch`, `head_branch`, `title`, `description`. +- `PATCH /orchestration/pull-requests/[prId]` requires `status`, optional `pr_url`. + +### Agent webhook + +`POST /orchestration/webhooks/agentic-flow` requires: -**Response (content/diff):** `200` — `text/plain` or `text/x-diff` body. `404` — Error JSON if no build or file not found. +- `event_type` +- `assignment_id` + +Allowed `event_type` values: + +- `execution_started` +- `commit_created` +- `execution_completed` +- `execution_failed` +- `execution_blocked` --- +## Operational Pitfalls + +- **Different error envelopes by route:** do not hardcode one global error parser for all endpoints. +- **SSE consumers:** finalize and stream routes require event-stream handling (`done` event indicates completion). +- **Build output visibility:** `produced-files` and `files?source=repo` depend on run/assignment/worktree state; empty responses can be valid. +- **Setup dependence:** GitHub and planning workflows depend on configured `GITHUB_TOKEN` and `ANTHROPIC_API_KEY`. + ## 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 to map data flow through validated actions and mutation pipeline. +- No auth/RLS layer in this single-user deployment mode. +- SQLite is the default runtime datastore for API flows.