tessera plan — What is the AI about to do?
You're about to ask an AI to write hundreds of files for you. It will burn tokens, run for 5–30 minutes, and might do something you didn't expect.
tessera plan lets you look at the recipe before cooking it. No AI is invoked — these commands just compile, print, and compare the plan that tessera new would otherwise execute.
If this is your first day on Tessera, run these three commands at least once before you trust a real tessera new run.
The three subcommands
tessera plan compile <yaml> [-o <out.json>]
Reads a stack manifest (YAML) and writes a versioned, hash-anchored plan.json.
$ tessera plan compile stacks/static.yaml
✓ Compiled plan: /home/me/proj/.tessera/plan.json
stack: static
steps: 3
plan hash: a53a0aa050046435...
compiled: 2026-04-28T18:53:05ZWant it written somewhere else? Pass -o:
$ tessera plan compile stacks/static.yaml -o /tmp/before.jsonCompile is pure — it reads YAML, hashes prompts, validates dependencies, writes JSON. No network, no AI. Safe to run anytime.
tessera plan show [<plan.json>]
Pretty-prints the plan. With no argument, shows .tessera/plan.json from the current directory.
$ tessera plan show
Plan: ./.tessera/plan.json
Stack: static
Steps: 3
Hash: a53a0aa050046435a6a080477f981de3...
Compiled: 2026-04-28T18:53:05Z (compiler v1.0)
Steps (topological order):
[1] scaffold — [1/3] Creating website
complexity: complex
adapter: (router) model: (default)
deps: -
fingerprint: e468b96d03e9...
gates: exists_any
[2] polish — [2/3] Validating and polishing
complexity: medium
adapter: (router) model: (default)
deps: scaffold
fingerprint: ccf069e24b8a...
[3] setup_md — [3/3] Generating setup instructions
complexity: simple
adapter: (router) model: (default)
deps: polish
fingerprint: dbfa1ba8e029...
gates: exists_anyThis is exactly what tessera new will dispatch — three steps, in this order, with these prompt fingerprints.
tessera plan diff <a.json> <b.json>
Compares two plans semantically — not as raw JSON. It tells you what changed about the work, ignoring noise like the compiled_at timestamp.
$ tessera plan diff /tmp/before.json /tmp/after.json
Plan diff
before: /tmp/before.json hash a53a0aa05004…
after: /tmp/after.json hash 7b91f3e2d840…
Prompt body changed:
- scaffold
Complexity changed:
- polishExit codes — these matter for CI:
| Code | Meaning |
|---|---|
0 | Plans semantically identical (you can ship the change) |
1 | Usage error (bad path, broken JSON) |
2 | Differences exist (not necessarily bad — review them) |
A non-zero diff is a signal, not an error. Use it like git diff: a CI job that runs tessera plan diff origin/main HEAD will trip on every prompt edit, prompting human review.
What is plan_hash?
Every compiled plan carries a plan_hash — a SHA-256 over the deterministic serialisation of every step's fingerprint, complexity, and dependencies, in execution order.
Think of it as a fingerprint of the whole recipe:
- Same hash → same plan. Identical work will be dispatched.
- Different hash → different plan. Something changed: a prompt, a step order, a dependency, a complexity hint.
Cosmetic edits (renaming a step's human-readable name field) do not change the hash. Bumping a prompt_version field does, even if the prompt body is byte-identical — that's the whole point of prompt_version: a way to force a re-render without text edits.
Why you should care
You commit static.yaml. CI compiles it. Six months later, an AI build behaves weirdly. You want to know: is the recipe the same?
$ tessera plan compile stacks/static.yaml -o /tmp/today.json
$ diff <(jq -r .plan_hash /tmp/yesterday.json) <(jq -r .plan_hash /tmp/today.json)If those hashes match, the recipe didn't drift. The bug is somewhere else — adapter version, AI model behaviour, runtime environment. If they don't match, run tessera plan diff to see exactly what shifted.
When you'll reach for these commands
| Situation | Command |
|---|---|
| "I tweaked a prompt in YAML — what does that actually change?" | tessera plan diff before.json after.json |
| "What is the AI going to do once I hit enter?" | tessera plan show |
| "Is tomorrow's build the same recipe as today's?" | Compare plan_hash values |
| "Is my new YAML even valid?" | tessera plan compile path.yaml (it'll error loudly if not) |
| "I added a step — is the dependency wired right?" | tessera plan show (look at deps: line) |
Common mistakes
Hand-editing plan.json. Don't. The executor recomputes the hash on read; if your edits desync it, the next tessera new --execute will refuse the plan. Edit the YAML, recompile.
Forgetting to bump prompt_version. If you "fix a typo" in a prompt template but the AI's behaviour shouldn't change, you still want a new fingerprint so plan diff flags the edit for review. Always bump prompt_version when you touch a prompt body, even cosmetically.
Reading the long hash. Nobody compares 64 hex chars by eye. Use tessera plan diff, or jq -r .plan_hash plan.json | head -c 12 for a 12-char prefix (collision-free in practice for any one project).
See also
- YAML stack manifests — how stacks describe themselves
- Build trace & events — what gets recorded once you actually run the plan
- Troubleshooting — when
plan compileerrors out