Obvious/Help Center

Writing a Technical Spec

Published May 22, 2026 · Last updated May 22, 2026 · 3 min read

The technical spec is the third and final phase of the spec pipeline. By the time you write it, the product outcome is decided and the UX is concrete. The technical spec translates both into a precise implementation plan grounded in the current codebase — naming exact files, services, schemas, and interfaces rather than describing them in the abstract.

Ground everything in actual code

The most important rule: cite what you've read, not what you assume. Every service, file path, schema, and route you reference must be something you've looked at. Not "the API layer" — name apps/api/src/routes/notifications.ts. Not "the existing auth middleware" — name apps/api/src/middleware/auth.ts and explain what it does that's relevant. A spec that says "the WebSocket service probably lives in..." is about to produce a PR targeting the wrong file. Read the code. Run grep. Name the actual paths.

Every component in the data flow is a piece of code that needs to exist. The spec traces each hop from event source to UI:

Comment Created → comment.service.ts
  → Inngest Event: comment/created
  → Notification Service (create · markRead): notification.service.ts
  → Postgres: notifications table
  → WebSocket Push → SSE channel
  → UI badge (React, async push, < 5s)

Every arrow in that chain is a piece of code the agent will need to write or call. Name them all.

Write interface contracts, not pseudocode

TypeScript interfaces, Zod schemas, API route shapes, and database migration scripts belong in the technical spec — not pseudocode approximations of them. The agent implements these literally, so write the actual type definitions you want it to produce.

Architecture decisions need rationale: where new code goes, which existing services it calls, how data flows from event to storage to UI. When there are multiple valid approaches, name the alternatives and explain why you chose this one. The agent won't second-guess a decision that has a rationale attached.

Capture data flow and state transitions

Describe where the event originates, how it reaches the service, and how the UI learns about it. Data flow is not optional context — it's the sequence of code that must exist. A diagram or ordered list is more useful than prose, because each step maps to a concrete implementation requirement.

Plan migration and rollout

Database migrations, feature flags, and backward compatibility constraints belong here. If the notifications table needs to exist before the service can write to it, that's a sequencing constraint. These constraints become the dependency graph in the execution plan — without them, the agent can't sequence the work.

Be explicit about:

  • Migrations — any schema changes that must run before new code deploys

  • Feature flags — whether the feature ships behind a flag and under what conditions it activates

  • Backward compatibility — what existing behavior must be preserved during rollout

What a strong technical spec contains

  • Named files, services, routes, and schemas — not descriptions of them

  • Actual TypeScript types or Zod schemas the agent can copy directly into implementation

  • Architecture decisions with rationale for each choice

  • A complete data flow from event origin to UI

  • Sequencing constraints that become the dependency DAG in the execution plan

  • A "what not to build" section derived from the product spec's scope boundaries

The technical spec is where the implementation becomes deterministic. An agent working from a precise technical spec — one grounded in evidence, with typed contracts and explicit data flow — produces a PR that hits the target. An agent left to discover the architecture at build time makes decisions you never approved.

Was this helpful?