Bookings[email protected] San Antonio · Texas
Obsidian guide · Building with AI

Specs an AI coding tool can actually follow.

Many “the AI built the wrong thing” problems start before the first prompt. A short written spec, and a rule that the tool plans before it codes, prevents most of them. Here’s the template and workflow we use.

Updated October 2026 · Tested in Obsidian 1.14 · No plugins

Why AI tools build the wrong thing

An AI coding tool is fast and confident, and it fills every gap in your request with a guess. Ask for “CSV export” and it has to decide which columns, which dates, who may export, and what happens with 10,000 rows. Each guess can be reasonable and still not what you meant.

A short written spec turns those guesses into decisions you make once. It gives you something to check the work against, and something to paste into the next session when the tool has forgotten everything.

The one-page spec

Nine headings. Most specs fit on one screen; if yours doesn’t, it’s probably two features.

Templates/Spec.md
---
type: spec
project:
status: Drafting
priority: Medium
---
## Problem
What's broken or missing, for whom?

## Goal
One sentence: what's true when this ships?

## Users
Who uses it, in what situation?

## Acceptance criteria
- [ ]
- [ ]
- [ ]

## Not in scope
-

## Data
New tables, columns or fields:

## Edge cases
-

## Security notes
Who may see or change this? What must be validated?

## Test plan
-
  • Acceptance criteria are checkboxes a stranger could test. “Fast” isn’t one; “the export finishes in under 10 seconds for 5,000 invoices” is. They become your tests.
  • Not in scope stops the tool from helpfully adding things you didn’t ask for, and stops you from asking for them halfway through.
  • Edge cases are where generated code tends to break: empty lists, huge lists, odd characters, time zones, two people editing at once.
  • Security notes are the most-skipped heading and the most expensive to skip. Write down who may see and change the data, and that the server checks it.

A filled-in example

Specs/CSV export.md
## Problem
Owners copy invoice data by hand every quarter for their accountant.

## Goal
An owner can download their invoices for a date range as a CSV file.

## Acceptance criteria
- [ ] "Export CSV" button on the Invoices page
- [ ] Date range defaults to last quarter
- [ ] Columns: number, client, issued, due, amount, status
- [ ] Only the signed-in owner's invoices are included
- [ ] An empty range downloads a file with just the header row

## Not in scope
- PDF export, scheduled exports, choosing columns

## Edge cases
- Client names with commas, quotes or line breaks
- 10,000+ invoices
- Dates near midnight in other time zones

## Security notes
- The server checks the owner on every request; hiding the button isn't enough
- Cells starting with = + - @ are escaped so spreadsheets don't run them as formulas

## Test plan
- Two test accounts: B can't export A's invoices, even by editing the request
- A client named =1+1 exports as plain text

Notice what the AI no longer has to guess: the columns, the default dates, what to leave out, and the two security checks it would most likely miss.

Make it plan before it codes

The most useful habit: no code until the tool has told you its plan and you’ve agreed. Paste this with your spec:

Prompt: plan before you code
Before writing any code, read the relevant files and give me a plan:
1. What you understand the task to be, in two sentences.
2. The files you'll change or create, and why each one.
3. The steps, in order. Each step should leave the app working.
4. Risks, open questions, and anything in the spec that seems wrong.
Don't change any files yet. Wait for my OK on the plan.

Task / spec:
<paste the spec>

Push back on plans that touch lots of files; ask for the smallest version. Then have it split the work into steps that each leave the app working:

Prompt: turn a spec into small steps
Split this spec into steps that can each be built, tested and committed on their own.
For each step: what changes, how to test it, and roughly how many lines it touches.
No step should take more than about 30 minutes or 200 changed lines.

<paste the spec>

Build one step, run the tests, commit, then move on. If a step goes wrong, you lose one step, not an afternoon.

Write down decisions, so the AI doesn’t undo them

AI tools don’t remember why you chose something. A month later you ask for a change, and the tool switches your file storage back to the approach you moved away from. Two small notes prevent that:

  • A decision note for anything you’d hate to argue about twice: the context, the options, what you picked and why.
  • A two-minute session log after each AI coding session: what changed, what’s half-done, and what to tell the tool next time.

Rules that apply to every session go in the file your tool reads automatically: CLAUDE.md for Claude Code, AGENTS.md for tools that follow that convention, or your Cursor project rules. Keep it short, and point to the decision notes for the reasons.

Keep it in Obsidian, next to your code

Specs, decisions, bugs and session logs are just Markdown, so Obsidian is a natural home. Keep the vault in its own folder beside your project rather than inside a public repository, so private notes don’t get published by accident.

Give each spec a status (Drafting, Ready, Building, Shipped) and a priority, and this Base shows them as cards grouped in workflow order, plus a ranked list of what to build next. (New to Bases? See our Bases recipes.)

Specs.base
filters:
  and:
    - type == "spec"
    - '!file.inFolder("Templates")'
formulas:
  step: if(status == "Drafting", "1 Drafting", if(status == "Ready", "2 Ready", if(status == "Building", "3 Building", if(status == "Shipped", "4 Shipped", "0 No status"))))
  rank: if(priority == "High", 1, if(priority == "Medium", 2, 3))
views:
  - type: cards
    name: Board
    groupBy:
      property: formula.step
      direction: ASC
    order:
      - file.name
      - project
      - priority
  - type: table
    name: Build next
    filters:
      and:
        - status == "Ready"
    order:
      - file.name
      - project
      - priority
    sort:
      - property: formula.rank
        direction: ASC

Groups sort by name, which would put Building before Drafting; the numbered step formula keeps them in order.