Evidence-backed intent,
ready for any coding agent.
IntentSpec is the open format for the work upstream of code — the outcomes, edge cases, and evidence that define done. Write it by hand. Or let Pathmode build it from your product evidence.
---
id: "INT-EXPORT-JSON-001"
status: "approved"
objective: "Allow users to export filtered data to JSON"
evidence:
- type: "quote"
source: "support-ticket-4421"
excerpt: "I can't tell what's in my export before I download it."
anchors: ["outcome:0", "edgeCase:0"]
- type: "friction"
source: "session-replay-a3f9"
excerpt: "User re-exported full dataset 3 times trying to find filtered subset."
anchors: ["objective"]
outcomes:
- "User clicks Export → JSON file downloads to device"
- "Export contains only the currently filtered dataset"
- "No PII fields are included in the output"
constraints:
- "Must run client-side only (no server round-trip)"
- "File size must not exceed 10MB"
edgeCases:
- scenario: "Empty dataset"
expectedBehavior: "Show toast: 'Nothing to export' — no file created"
- scenario: "10k+ rows"
expectedBehavior: "Stream to file, show progress indicator"
healthMetrics:
- "Page load time must not increase"
- "Existing CSV export must continue to work"
---Try it: validate a spec
Edit the spec on the left. It's validated against the same JSON Schema your CI uses.
Uses ajv against /intentspec.schema.json — the same schema the GitHub Action enforces.
The problem: specs without evidence
A spec that doesn't trace back to evidence is just opinion. When the agent asks "why this outcome?", the answer is "because someone said so." That's how scope creeps, agents drift, and PRs get rejected after the work is done.
The solution: judgment, carried
Intent is judgment under evidence, not a contract you compile from a prompt — that's Intent Engineering. IntentSpec is the form that judgment takes: outcomes anchored to quotes, friction, and observations, and validated in CI like any spec. The evidence-anchored whyand the machine-checkable spec are one artifact, not two — there's no separate spec format to hand off to. Agents execute against it; humans review against the evidence that produced it.
Intent Engineering
The practice of maintaining explicit, evidence-backed product intent upstream of code — so agents have concrete criteria for done, not vague requirements that get interpreted differently every sprint. IntentSpec is the portable format that carries that intent from discovery to deployment.
How It Works
Three steps to go from vibe coding to spec-driven development.
Write an intent.md
Define the objective, expected outcomes, constraints, and edge cases in a Markdown file with YAML frontmatter. Commit it alongside your code.
your-repo/ ├── src/ ├── intent.md ← your spec └── package.json
Drop it into any agent
One rule line in your agent's config file points at intent.md. The agent now has concrete success criteria — not a vague prompt.
Works with Claude Code, Cursor, Windsurf, GitHub Copilot, Aider, and any LLM — see the config snippets below.
Validate in CI
Add the GitHub Action to enforce schema compliance on every PR. Prevent drift before it reaches main.
- uses: JanneL/validate-
intentspec-action@v1
with:
file: intent.mdHow it differs from what you already use
Tickets, agent rule files, and design docs all describe work — but none of them carry evidence in a form an AI agent can read.
| Linear / Jira ticket | AGENTS.md / .cursorrules | RFC / design doc | IntentSpec | |
|---|---|---|---|---|
| Format | Free-form fields | Free-form Markdown | Prose | Markdown + YAML + JSON Schema |
| Machine-validated | No | No | No | Yes |
| Enforceable in CI | No | No | No | Yes |
| Defines "Done" | Sometimes | No | Sometimes | Always |
| Carries evidence | No | No | Sometimes | Yes |
| Designed for AI agents | No | Yes | No | Yes |
| Scope | Per-task | Per-repo | Per-system | Per-feature |
IntentSpec is complementary, not a replacement — link from your ticket, reference from your AGENTS.md, derive from your RFC.
Drop it into any agent
Hand-author intent.md, or build it from your evidence in Pathmode. Either way, one rule line in your agent's config points at it.
Claude Code
CLAUDE.mdAlways read intent.md before implementing any feature.
Cursor
.cursor/rules/intentspec.mdc--- description: IntentSpec alwaysApply: true --- Read intent.md before generating code.
Windsurf
.windsurfrulesRead intent.md before implementing any feature.
GitHub Copilot
.github/copilot-instructions.mdReference intent.md for feature requirements.
Aider
bash$ aider --read intent.mdAny LLM
System promptTreat the attached intent.md as the source of truth for "done".
Frequently Asked Questions
What is IntentSpec?
How is IntentSpec different from AGENTS.md or CLAUDE.md?
Which AI coding agents work with IntentSpec?
Do I need Pathmode to use IntentSpec?
Can IntentSpec be validated automatically?
How does IntentSpec prevent AI agent drift?
How is IntentSpec different from spec-driven development tools and GitHub spec-kit?
Specs in the wild
Real intent.md files — built from evidence or hand-authored, validated in CI, consumed by AI agents.
T3 Stack Showcase
Full-stack Todo — TRPC + Zod + Tailwind
---
id: "showcase-todo-feature"
status: "approved"
objective: "Full-stack Todo with
TRPC + Zod + Tailwind"
evidence:
- type: "friction"
source: "user-feedback-q3"
excerpt: "Todos disappear on
refresh — users expect
persistence."
anchors: ["outcome:3"]
outcomes:
- "User can create a Todo item"
- "User can toggle completion"
- "User can delete a Todo item"
- "All changes persist via TRPC"
constraints:
- "Must use TRPC for all API calls"
- "Must use Zod for validation"
---GitHub OAuth
Hand-authored alongside existing email auth
---
id: "INT-AUTH-OAUTH-003"
status: "approved"
objective: "Add GitHub OAuth as
a sign-in option"
evidence:
- type: "quote"
source: "beta-feedback-nov"
excerpt: "I'd use this but I
don't want another password."
anchors: ["objective",
"outcome:0"]
outcomes:
- "User can sign in with GitHub
in one click"
- "Existing users can link
their account"
edgeCases:
- scenario: "GitHub email matches
existing account"
expectedBehavior: "Prompt to
link — never auto-merge"
---