Follow writing-voice for prose tone.
A handoff prompt is a cold execution brief. The recipient has never seen this codebase, this conversation, or this context. Everything they need to execute must be in the prompt itself.
How It Differs from Specs
Spec (specification-writing) |
Handoff Prompt |
|---|---|
Planning document, lives in specs/*.md |
Communication artifact, lives in clipboard |
| Tracks progress with checkboxes | Single-shot fire-and-forget |
| Assumes the reader has repo access and can explore | Assumes the reader has zero context |
| Leaves open questions for the implementer | Closes all questions: the recipient shouldn't need to ask |
| Iterative: you come back and update it | One shot: you won't get to clarify |
A spec says "here's the plan." A handoff prompt says "here's everything you need to do it right now."
Structure
There's no rigid template. The sections you need depend on the type of handoff. Every prompt needs a task statement and enough context to execute. Everything else is judgment.
Task Statement
One or two sentences. What to build and where. Be specific about file paths.
Create an About page at `apps/opensidian/src/routes/about/+page.svelte`.
This page explains the technical architecture to visitors and is linkable from the app toolbar.
Not: "Build a page that explains the app." The recipient needs exact locations.
Context
Everything the recipient needs to understand the codebase without reading it. This is the most important section: it makes the prompt self-contained.
What to include depends on the handoff type:
For implementation tasks (building UI, adding features): paste actual code. If the data layer is 10 lines, paste those 10 lines. Include file paths for every snippet. Name the components that exist with their paths. List what's available in the UI library.
For architectural tasks (refactoring, migrations, design decisions): describe the current structure, the constraints, and the trade-offs already made. Code snippets matter less than the shape of the system and the decisions already locked in.
For debugging handoffs (fixing broken behavior): include the error output, reproduction steps, what was already tried and why it didn't work. The recipient needs to pick up where you left off, not re-diagnose from scratch.
For all types: never paraphrase when you can paste. "The workspace uses Yjs" is useless. The actual createDisposableCache((id) => { ... }).open(id) call is useful.
## Context
The entire app's data layer is this one file (`src/lib/workspace.ts`):
\`\`\`typescript
// paste the actual code
\`\`\`
The workspace API provides: Yjs CRDT table storage, per-file Y.Doc content documents,
IndexedDB persistence, and an in-browser SQLite index.
Requirements
What to build. Be exhaustive: the recipient can't ask clarifying questions.
For UI work: describe each section with what it contains, what components to use, what data it displays, and how it behaves.
For logic work: describe input/output contracts, edge cases to handle, and integration points with existing code.
If there's a choice to make (which component, which layout, which approach), make it here. Don't leave it open.
Drafting Process
-
Gather context first. Read the relevant files, understand the codebase patterns, check what components and tools are available. You can't write a self-contained prompt without knowing the details.
-
Identify the recipient's blind spots. What does someone need to know that isn't obvious? The tech stack, the import conventions, the existing patterns, the file structure.
-
Paste, don't paraphrase. Real code beats descriptions of code. Real file paths beat vague references. Real component names beat "use the UI library."
-
Close all decisions. A spec can leave open questions. A handoff prompt cannot. If there's a choice to make, make it.
-
Name the lane. Say what files, package, app, or spec the recipient should start with. A lane coordinates where to begin; it does not restrict continuation.
-
Test mentally. Read the prompt as if you've never seen this codebase. Could you execute it? If you'd need to grep for something, that information should be in the prompt.
Common Mistakes
Too abstract
## Context
The app uses a workspace API built on Yjs CRDTs for data storage.
This tells the recipient nothing actionable. Paste the workspace setup code instead.
Missing file paths
Create a new page component and link it from the toolbar.
Where? What's the toolbar file called? What's the routing convention? Be explicit.
Assuming knowledge
Use the standard shadcn components for this.
Which ones? The recipient doesn't know what "standard" means in this project. List them.
Leaving decisions open
You could use either a Card grid or an Accordion for this section: pick whichever works better.
Pick one. The recipient will waste time deliberating instead of building.
Good vs Bad
Good (self-contained, specific, closed)
Create `src/routes/about/+page.svelte`. Import `Card` from `@epicenter/ui/card`
and `Badge` from `@epicenter/ui/badge`. The page has 4 sections...
The workspace setup code is:
\`\`\`typescript
const cache = createDisposableCache((id: string) => {
const workspace = createWorkspace({
id,
tables: { files: filesTable },
kv: {},
});
const idb = attachIndexedDb(workspace.ydoc);
return { ...workspace, idb };
});
export const ws = cache.open('opensidian');
\`\`\`
Bad (vague, open-ended, assumes context)
Create an about page for the app that explains the architecture.
Use whatever components make sense. Make it look good.
The good version works cold. The bad version requires a follow-up conversation.