feat(spec): generate a Markdown technical spec from the canvas - #28
Conversation
The Specs tab now turns the current canvas into a Markdown technical spec that downloads automatically: an overview, key decisions highlighted as callouts, one Mermaid diagram section per group of connected components, a component reference, connections, and risks. - spec-agent Trigger task: reads the room, builds the spec graph in code, makes one structured model call for the prose (sanitised against the graph, internal refs stripped), renders the Markdown in code; aborts on an empty or oversized canvas - Stored on read like AI turns: GET /api/projects/[id]/spec uploads a finished run to private Vercel Blob and records it on Project (guarded on the run id); POST starts a run (409 while one is pending); GET .../spec/markdown downloads the file - Decisions recorded in the user's AI design sessions are included and tagged as recorded - Migration: TaskRun.kind (DESIGN or SPEC) and Project spec fields - useSpecGenerator and SpecPanel replace the placeholder Specs tab - Shared lib/ai/model.ts, lib/ai/run-failure.ts and lib/canvas-room.ts used by both agents Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Why
The Specs tab in the AI sidebar was a placeholder. This PR turns the canvas into a Markdown technical spec that downloads automatically. It highlights the major decisions, and draws every diagram and workflow on the canvas as a Mermaid diagram.
What
How it works
Start: Generate spec calls
POST /api/projects/[projectId]/spec, which returns 202 with the run id (409 with the existing run id if one is already running). It triggers the newspec-agentTrigger task and records aTaskRunwithkind: SPEC.The task (
src/trigger/spec-agent.ts):The model never adds components or connections, and anything in its output that refers to an unknown group or component is dropped. It stops with a user-facing message on an empty canvas or more than 200 components.
Storage when the status is read, like AI turns:
GET /api/projects/[projectId]/specretrieves the latest spec run. When it has finished, the route:specMdPath,specRunId,specGeneratedAtandspecStatsonProject, in an update guarded on the run idSo a spec is saved even if the tab closes, and the task never touches the database or Blob storage.
Download:
GET /api/projects/[projectId]/spec/markdownserves{project-slug}-spec.mdas an attachment. The hook downloads it automatically once the run you started is stored.The document
> [!IMPORTANT]callouts with the decision, why, alternatives, trade-offs, the components involved, and the source (recorded during AI design, stated on the canvas, or inferred). Decisions from the requesting user's AI design sessions are included.Code
lib/spec/:spec-graph.tsmermaid.tsspec-schema.ts: the model output schema,sanitizeSpecContent, and the run and status typesspec-prompt.tsspec-engine.tsrender-markdown.tsspec-store.ts: storing, starting runs and recorded decisions, with Trigger and Blob swappable for testsspec-file-name.tshooks/use-spec-generator.ts, mounted inAiSidebarso a run keeps being followed while another tab is open, andcomponents/editor/spec-panel.tsx, which replaces the placeholder tab.lib/ai/model.ts(model id, thinking settings, schema retry),lib/ai/run-failure.ts(friendly failure messages) andlib/canvas-room.ts(reading the room). Design-turn behaviour is unchanged.20260915195650_add_project_speconly adds things: aTaskRunKindenum,TaskRun.kinddefaulting toDESIGNwith an index, and four nullable spec fields onProject. It's already applied to the shared database.project-overview.md, a Spec Agent section inarchitecture-context.md, the Specs tab inui-context.md, and the tracker entry. (docs.mdis gitignored and was updated locally.)Excerpt from a live run
Generated through the local Trigger worker (
gemini-3.5-flash-lite) from the Microservices starter template, with one recorded decision:Important
API Gateway Entry Point: Route all external client traffic through a single API Gateway.
Why: Centralizes entry point concerns such as routing and token verification.
Alternatives considered: Direct client-to-service communication
Trade-offs: Introduces a potential single point of failure and bottleneck at the gateway.
Components: Web Client, API Gateway · Source: Inferred from the diagram
flowchart TD c1(["Web Client"]) c2(["API Gateway"]) c3["Auth Service"] c4["User Service"] c5["Order Service"] c6[("Session Cache")] c7[("User DB")] c8[("Order DB")] c3 -->|"sessions"| c6 c1 -->|"HTTPS"| c2 c2 -->|"verify token"| c3 c2 --> c5 c2 --> c4 c5 -->|"read / write"| c8 c5 -->|"lookup"| c4 c4 -->|"read / write"| c7Verification
pnpm typecheckandpnpm lintpass, afternext typegenfor the new routes.🤖 Generated with Claude Code