Claude Code has amnesia. So do PRs, changelogs, and your future self.
β‘ TL;DR
Every Claude Code session is much like a good intern: earnest, but temporary.
Thoughtful documentation can help make the next session feel like a continuation rather than a restart. It also serves three readers most “amnesia cure” articles ignore: the reviewer of your PR (who wants the why, not just the diff), the engineer writing the changelog at release time, and whoever inherits this code years from now.
The recipe:
- Start a new feature or bug spelunking in “plan” mode. Wait for
claudeto cook. - Once the plan is ready, hit escape, and run
/coding:handoff. - Start the next session with
/coding:tpp $pathToTPP, which reads the TPP and picks up where things left off. - When context runs low, run
/coding:handoffagain. - Repeat until the TPP is complete.
- Move the finished TPP to
_done/for future reference.
The examples below use Claude Code, but the pattern works with Codex, Gemini CLI, and any other coding agent that can read repo files and follow a short workflow.
Want to skip the explanation? Jump to the setup prompt for Claude, Codex, or Gemini.
(Disclaimer: Claude edited the grammar in this document, but a human wrote the content. You can wrestle my emoji-prefixed headers that I’ve been using for the last decade out of my cold, dead hands–or tap the β¨ in the header to de-mojify)
β οΈ The problem
Claude Code is good, and sometimes excellent, at small, well-defined tasks. You show it the problem, it asks questions, tries things, and progress happens.
The catch: all LLM conversations have a “context window,” a bounded amount of text the model can consider at one time. When the context fills up before the work is done, the intern ceases to exist–the context is lost–and you’re left with a partially-completed mess.
If the work requires multiple sessions, you need a way to hand off what one session learned to the next. Otherwise, every session starts from scratch.
Amnesia is the loudest version of this context-loss problem–but not the only one. Three other readers want the why behind every decision:
- The reviewer of your PR
- The engineer writing release notes
- You, looking at the code N months (days?) from now
They’re all asking the same question–why is it like this?–and they need somewhere to look it up.
β But… bigger context windows!
On March 13, 2026, Anthropic made 1 million token contexts generally available for Opus 4.6 and Sonnet 4.6, and for many plans, is now the default!
1M tokens! π¦ and π!
Big context windows ease range anxiety–some hairy issues really do need that much room to be tractable.
But big context windows come with downsides:
- Money. Every interaction is more expensive on average, and the long ones are much more expensive. I regularly catch myself in 300k+ token sessions, and with Anthropic’s recent prompt-cache changes, quota limits arrive faster. I’ve leaned hard on
claudesince the day the Max 20x plan was introduced and never hit quota limits until 1M shipped. - Speed and accuracy. Anthropic’s Opus 4.7 system card (Β§8.7.2, figs AβB) reports MRCR v2 dropping from 59% at 256k to 32% at 1M. In practice, the model gets lost in the weeds, misses details, and gaslights you as sessions grow.
And big context windows do nothing for the other three readers. The PR reviewer, the changelog writer, and whoever inherits this code years from now are not in the session, no matter how large you size it. TPPs are for them too.
β But… /compact!
Claude Code and other coding assistant harnesses have /compact commands that try to continue sessions.
It’s… not great. When claude was new, I tried auto-compact and watched the next session act lobotomized. So I rolled my own: export the full transcript, summarize it with Haiku, and feed the summary to the next session. Call it haiku-compact. Better than auto-compact–but it still dropped the design discussions, the rejected approaches–the whys.
The lesson: any post-hoc compaction misses what a human would have curated while the work was happening. TPPs are curation as you go.
β But… MEMORY.md!
Claude Code has a memory feature that persists notes in a MEMORY.md file across sessions. In theory, this bridges the amnesia gap.
In practice, it’s write-only general guidance. In my experience, Claude writes to it enthusiastically but rarely seems to reference it in meaningful ways–and it’s specifically not relevant for planning or session-specific details.
Memory is better than nothing, but it’s not a substitute for structured handoff documents where a human can curate what matters.
Plan mode: think before acting
Claude Code has two different “plan” features that are easy to confuse: plan mode and plan files. They share a name and almost nothing else.
Plan mode (accessed by pressing Shift+Tab twice) tells Claude to explore, analyze, and write down a plan before doing anything.
It’s “due diligence mode.” Instead of jumping straight into implementation, Claude takes a step back to understand the problem, explore the codebase, and consider approaches before writing a line of code.
You should try plan mode for refactoring, new feature work, and even for non-trivial bug fixes.
Plan files: a stochastic scratchpad
Plan files are markdown documents in ~/.claude/plans/ that Claude will compose at the conclusion of a “plan mode” session.
The model reads and updates these files as it works, and /compact can use them for continuity between sessions, but they have limitations: there doesn’t seem to be a consistent format.
Plan files regularly omit:
- Clear success criteria for the next session
- A list of prerequisite files to read before starting
- Design decisions and tradeoffs that led to the chosen approach
- Gotchas and edge cases that tripped up previous sessions
Plan files seem to miss the point: they are not handoff documents for the next engineer, human or robot.
β The “clear context and auto-accept” trap
When plan mode finishes, Claude presents this prompt:

A most dangerous default.
Option 1 (“Yes, clear context and auto-accept edits”) is tempting. It sounds efficient. It is a trap. π¦
“Clear context” means exactly what it says: Claude discards the entire planning conversation: every file it read, every design tradeoff you discussed, every gotcha it discovered. All that research vanishes. The only thing that survives is the plan file in ~/.claude/plans/, and as we just established, those files don’t always contain the information future-Claude needs to actually succeed.
So now you have a robot with partial amnesia, auto-accepting its own edits, confidently vandalizing your codebase as it works from a plan that may or may not be tangentially relevant.
What you need is a way to capture everything the planning session learned before context gets cleared–an engineer’s notebook for whoever picks this up next.
That’s what TPPs are for.
π Introducing Technical Project Plans (TPPs)
I’ve been using and iterating on this system for over six months. I call them Technical Project Plans (TPPs), deliberately avoiding terms like PRD, “tech spec,” or “design doc” and their historical baggage. (And a unique three-letter acronym means I can type less.)
A good TPP reads like having the previous engineer sitting next to you. It doesn’t just say “fix the query”; it tells you which query, why it’s broken, what was already tried, and which test file reproduces the problem (or what a failing test would look like if it doesn’t exist yet).
Bad TPPs accumulate filler. Good ones accumulate insight.
Four readers, not one
A TPP earns its keep by briefing four different readers, only one of whom is the next AI session.
The next session. The most obvious reader. When context fills up or you switch models, the TPP carries the work forward: every gotcha, every rejected option, every “we tried X and it broke Y” survives the handoff.
The reviewer of your PR. A diff shows what changed. A TPP shows why–which alternatives were considered, which constraints ruled them out, which tests were chosen and why. Reviewers can evaluate the design decisions, not just the code.
The engineer writing the changelog. Release notes drafted from commit messages tend to read like “fixed bug in importer.” Release notes drafted from a _done/ folder of TPPs read like “previously, importing 50k+ libraries blocked the UI for ~30 seconds; we now batch in chunks of 500 and yield between batches.” The rationale section feeds the prose directly.
The engineer who inherits this code years from now. This is the long-tail reader, the one most articles forget about. When a bug surfaces in code written by someone who has long since left, the completed TPP is institutional memory: what was tried, what was rejected, which edge cases were already discovered. Lore, in the section name we use in the template.
Switching agents is painless
Sessions are throwaway. The TPP is the contract that survives them all.
You can switch agents mid-feature without losing progress: start in Opus (catches architectural concerns), pause when context gets thin, resume in Sonnet (simplifies what Opus over-engineers), hand the TPP to Codex for a different opinion, finish in whatever’s cheapest. The work continues; only the running session changes.
Better still, you can put agents in conversation with each other. Hand a TPP to a different model with “our intern wrote this, poke holes in it” (details). Each agent reads the same file, leaves discoveries in the same lore section, updates the same task list. Different training, different blind spots, same artifact.
TPPs are also an in-session checkpoint
The four readers above are the durable benefits. There’s a fifth, immediate one: a TPP lets you reach into the robot’s brain and verify you’re on the same page before implementation starts.
Before Claude writes a line of code, you can read the TPP and verify it understood the problem and that the proposed approach is sane. Catching a misunderstanding in a document is cheap; catching it after three sessions of implementation is not.
The TPP that emerges from plan mode becomes the contract. “Here’s what we’re building, here’s how it fits with existing code, here’s why we rejected the alternatives.” Future sessions (and future you) start with that context already established.
π What a TPP looks like
Store TPPs wherever you like. Make the path and filename carry signal for the next session.
Pick one primary backlog layout:
- Simple:
_todo/for unfinished,_done/for completed. Enough for most projects. - Priority:
_active/,_p1/…_p4/,_done/. Use when the backlog is large enough that priority matters; moving a file between folders changes its priority. No extra database, no stale labels.
For a large feature whose plans must merge together, overlay either layout with a
temporary _feat-<name>/ integration queue, such as _feat-search/ or
_feat-billing/. Each queue pairs with a feature branch, ideally checked out in
its own git worktree (a second working
copy of the same repo), so sessions can grind through the queue without
disturbing work on main. The queue’s README.md records the owning branch or
worktree, dependency and merge order, completion gate, and cleanup. The prefix
makes these queues easy for agents and tools to discover without turning the
feature name into a new priority level.
Date-prefix filenames (20260208-feature-name.md) so they sort chronologically. Each TPP carries YAML frontmatter so backlog tools can read structured fields like title, section, priority, issue links, and demand signals (votes, views).
Lower-priority ideas can start as placeholders: frontmatter plus a short description. The copy-pasteable guide below has the full template.
π§ Example TPP-GUIDE.md
The TPP guide is the instruction manual the tpp and handoff skills read
before touching the plan. Keep it short, concrete, and project-specific.
This is a generalized version of the one I use:
# Technical Project Plan (TPP) Guide
## What is a TPP?
A TPP is a living handoff document for complex work that may span multiple agent
sessions or multiple engineers.
Each engineer reads it, does work, documents discoveries, and updates the file
so the next engineer can continue without starting over.
Every bit of context in the TPP should help the next engineer succeed.
## Golden rule
A good TPP transfers expertise, not just instructions.
It should explain:
- What problem we are solving for users
- Which approaches were considered
- Which approaches failed, and why
- Which tests and edge cases reveal the problem
- How to adapt if nearby architecture changes
These same answers serve four readers: the next session, the reviewer of the PR, the engineer drafting release notes, and whoever inherits this code years from now. Write once; serve all four.
## Typical process
1. An issue is raised, initial design and research is done, and a TPP is created.
2. Engineer A works on the TPP and updates it with discoveries, challenges, and
next steps.
3. Engineer B picks up where Engineer A left off, using the TPP to continue the
work.
4. The cycle continues until the TPP is complete.
5. The completed TPP moves to `_done/`.
Update the TPP as progress is made. The file is the handoff.
## Where TPPs live
Choose one primary backlog layout for this project. A temporary feature
integration queue may overlay either layout.
### Simple layout
- `_todo/`: unfinished TPPs
- `_done/`: completed TPPs
### Priority layout
- `_active/`: actively being worked on or targeting the next release
- `_p1/`: high-impact work that should become active soon
- `_p2/`: planned near-term work
- `_p3/`: worthwhile but not imminent
- `_p4/`: nice-to-have work with no timeline
- `_done/`: completed TPPs
Filenames should be date-prefixed:
```text
YYYYMMDD-feature-name.md
```
If using priority folders, moving a file between folders changes its priority.
The filesystem location is the source of truth.
### Feature integration queues
Use `_feat-<name>/` when several TPPs must be coordinated on a feature branch
(often checked out in its own git worktree) and merged together, for example
`_feat-search/` or `_feat-billing/`. This is a temporary integration queue, not
another priority level.
Each feature queue must contain a `README.md` defining its purpose, owning
branch or worktree, dependency and merge order, completion gate, and the
priority/frontmatter policy for its TPPs. Remove the queue after its completed
plans move to `_done/` and the feature merges.
## Frontmatter
Use YAML frontmatter when scripts, dashboards, issue trackers, or backlog tools
need structured data.
```yaml
---
title: Full-text search
section: Search
priority: p1
issue: https://github.com/example/project/issues/122
votes: 42
---
```
Adapt the fields to this project. Common fields:
- `title`: human-readable task title
- `section`: product area or subsystem
- `priority`: `p1`, `p2`, `p3`, or `p4` if using priority folders
- `issue`, `forum`, `discord`: links to discussion
- `votes`, `views`: demand signals
- `shelved: true`: evaluated and deferred indefinitely
If using priority folders, `priority` must match the folder. For a TPP in a
`_feat-<name>/` queue, follow the effective priority documented by the
project-specific guide or that queue's `README.md`.
## Placeholder TPPs
Lower-priority work may start as a placeholder TPP: frontmatter plus a short
description. Do not add phases, alternatives, or task breakdowns until the work
is close enough to need real scoping.
```markdown
---
title: "On this day" gallery
section: UX & Viewer
priority: p3
issue: https://github.com/example/project/issues/232
votes: 17
---
# TPP: "On this day" gallery
Show assets from the same calendar date in prior years. Natural companion to tag
galleries; likely needs date-aware aggregation and a viewer entry point.
```
## Full TPP structure
```markdown
---
title: Feature name
section: Product area
priority: p1
---
# TPP: Feature name
## Summary
Short description of the problem, under 10 lines.
## Current phase
Next: the one thing the next session does first.
- [x] Research β finding, or a pointer to where it landed
- [x] Breaking tests β `test/foo.test.ts:"rejects empty tag"`
- [ ] Design settled β Option A, pending B's perf numbers
- [ ] Implementation
- [ ] Integration verified β `npm run test:integration`
- [ ] Reviewed
These are independent state, not a sequence: work loops back. Re-open a box when
new information invalidates it and say why in Lore.
## Required reading
YOU MUST study these before continuing. Work may be rejected if you skip them.
- **[AGENTS.md](../AGENTS.md)**: project structure, local rules, test commands
- **[CLAUDE.md](../CLAUDE.md)** (when present): additional Claude Code instructions
- **[TPP-GUIDE.md](./TPP-GUIDE.md)**: this workflow
- Add project-specific design, testing, API, and architecture docs here
- Add source files that define the subsystem
## Description
Detailed context about the problem, under 20 lines.
## Lore
- Non-obvious details that will help the next engineer
- Prior gotchas that tripped up previous sessions
- Relevant functions, classes, constraints, and historical context
## Solutions
It is OK to be unsure. Mark uncertainty clearly so the next engineer knows what
to verify.
### Option A (preferred)
Describe the preferred approach. Include pros, cons, code snippets, and why this
approach is preferred when useful.
### Option B (alternative)
Describe any serious alternative and why it was rejected or deferred.
## Tasks
Each task names its deliverable and the **acceptance test that proves it** β the
test file and case, or the exact command to run. A runnable test is a shorter
and stricter spec than a paragraph of implementation notes. Add prose only for
integration points a test can't express.
```
## Keeping TPPs useful
Every line must be something the next session could not cheaply rediscover. Cut
anything the code, the tests, or `git log` already say.
**Prefer a pointer to prose.** Name the test that pins the behavior, the commit
that broke it, the file that defines the constraint β don't describe them.
**Never record a count that drifts.** Record the command that produces the
number, not the number.
The high-value sections are **Lore** and the failed approaches under
**Solutions**. Everything else is scaffolding β keep it thin.
Length is a symptom; the rule is **focus**. One TPP, one coherent piece of work
β say what it does in a sentence with no "and". Never pad, and never trim
reasoning to hit a number. When the work really is bigger, don't shred it into
siblings that must coordinate: promote it to a **feature arc**, one coordination
TPP over focused children that are each independently testable and mergeable.
## Handoff rules
When context is running low or the session is ending:
1. Re-read the TPP.
2. Mark completed tasks.
3. Update the current phase.
4. Add discoveries, gotchas, and failed approaches.
5. Clarify exactly what remains.
6. Trim redundancy before saving.
The next session should be able to invoke the `tpp` skill with the plan path,
read the TPP, and continue without asking what happened last time.
π Review TPPs before and during work
Don’t just write TPPs and forget them. Read them before starting work. Read them while work is in progress.
Claude will add details to TPPs that never appeared in chat: design decisions, architectural notes, constraints, rejected approaches. Sonnet especially likes to do “extra work” you didn’t ask for.
Sometimes this is helpful. Claude noticed something you missed and documented it. Sometimes it’s wrong. Claude misunderstood a requirement and is now planning to implement the wrong thing.
The only way to catch this is to read the TPP. Before implementation starts, verify the plan matches your intent. While implementation is running, spot-check that new discoveries make sense. When you run /coding:handoff, read what got added.
TPPs are not append-only logs. If Claude adds something wrong, fix it. If it adds something obvious, delete it. You’re the editor. The TPP should reflect the actual plan, not a transcript of what Claude thought about.
β Re-analysis and validation pass
After the initial TPP is written, especially if it’s complex, high-priority, or risky, consider running a validation pass with a different model. If Opus wrote the TPP, use Sonnet for validation. If Sonnet wrote it, try Opus.
Start a new session in plan mode with a prompt like this:
/tpp _todo/20260213-fix-recall.md
Our intern wrote this TPP. Treat it as a rough draft
that needs validation:
- Re-research the problem from scratch
- Question every assumption in the analysis
- Verify and improve the task breakdown
- Add missing lore
Why “our intern”? Models from 2025-2026 tend to be sycophantic. They’ll read a TPP and assume it’s correct. Tell them it was written by an intern, and suddenly they’re allowed to be critical. They’ll spot gaps in analysis, question assumptions, improve task breakdowns, and strengthen the lore section.
The fresh model brings different strengths. Opus might catch architectural concerns Sonnet missed. Sonnet might simplify what Opus over-engineered. Either way, you get a second opinion before implementation starts.
This works best when the TPP is complete but before coding begins. Once implementation is underway, validation becomes harder. The code and the plan need to stay synchronized.
βοΈ Keeping TPPs under control
TPPs tend to grow. Each session adds context, discoveries, and notes. After several handoffs, you end up with thousands of lines of redundant observations that waste context window space.
I used to enforce this with a line budget: stay under 400. That number was doing the wrong job. A line cap tells a session how much to cut, not what, so it trims whatever is easiest to trim β usually the reasoning, which is the one thing worth keeping.
The better test is: could the next session cheaply rediscover this? If the
answer is yes, it doesn’t belong in the plan. The code says what the code does.
git log says when it changed. The test says what’s pinned. What a fresh
session cannot recover is why you rejected the obvious approach, which
stateful API bit you at 2am, and which edge case looks like a bug but isn’t.
That’s the lore section, and it should survive every trim.
So: prefer a pointer to prose. Name the test, the commit, the file. Don’t describe them β descriptions go stale and the real thing doesn’t.
The same rule kills a specific irritant: counts. “36 tests passing.” “12
files changed.” Coverage percentages. All of them are stale one commit later,
and a wrong number is worse than no number, because it reads as a finding. A
reviewer spots the mismatch and spends their attention establishing that the
count is off by one, which is time not spent on whether the design is right.
Record the command, not its output. npm test -- tag-gallery passes stays true;
“36 tests pass” is a hostage to the next commit.
I’ve since stopped quoting a number at all, and that took a second try to get right. Dropping 400 to 250 didn’t fix anything, because the problem was never the value. Any number in a style guide becomes a target: sessions pad up to it, or worse, mutilate a plan to get under it β and the first thing that goes is the reasoning, which is the one part worth keeping.
The number was standing in for something real, though. What I actually wanted was focus. A TPP covers one coherent piece of work, and the test is whether you can say what it does in a sentence with no “and” in it. Length is how that shows up, not what’s wrong.
The reason to care isn’t tidiness. Every line you leave in a plan is paid for out of the next engineer’s attention and context window β a budget they can’t top up, spent on your notes instead of the actual problem. Be respectful of the engineers of tomorrow. Writing a tome spends someone else’s scarcest resource.
So the guidance is now: never pad, never trim reasoning to hit a number, and treat a plan that’s getting long as a prompt to re-read it rather than a limit you’ve breached. Usually the answer is bloat. Occasionally it’s something else.
I tried cutting the phase checklist too, and had to put it back. The argument for cutting it was that newer models don’t need an eight-item ceremony to know they’re mid-implementation β replace it with one line saying where the work stands. That’s wrong, and the reason is worth spelling out: a checklist is a bitmask, and one line is a cursor. Six boxes encode six independent bits, any combination legal. One line forces you to name a single position on a line. Real state β tests written, implementation half-done, design reopened after benchmarking β has no honest one-line encoding. You write “in implementation” and the reopened design silently disappears.
Phase state is also exactly the thing the “could the next session rediscover this?” test says to keep. Nothing in the repo tells you the design was settled but the integration check never ran.
What the old checklist actually deserved was a different fix. It was eight fixed items, identical across every plan, and it shipped with both “Review & Refinement” and “Review” β a duplicate nobody noticed for months, which is what unread ceremony looks like. So the boxes are now plan-specific, each one carries a pointer, and the guide says out loud that they’re unordered and re-openable.
When the work really is bigger
Sometimes a plan is long because you bit off too much, and no amount of trimming fixes that. The tempting move is to shred it into two or three sibling plans. Don’t β that just relocates the complexity into the gaps between files, where nobody owns it. Two plans mean duplicated required reading, lore that lands in one file when both sessions needed it, and an ordering constraint recorded nowhere.
Promote it to a feature arc instead: one coordination TPP over several focused children. The arc owns the shape of the work β dependency and merge order, the completion gate, the lore every child needs, and the one-sentence purpose. The children own the work itself: their own tasks, tests, and gotchas. The arc stays short precisely because its children are focused, and an arc that starts accumulating implementation detail has quietly become a tome with extra steps.
In the layouts above, the arc is the feature queue’s README.md β I’d been
writing those for a while before noticing they were a distinct kind of document
rather than administrative overhead.
Children need real boundaries: each independently testable and independently mergeable. If one child can’t be verified without its sibling’s code, that isn’t a boundary, it’s one plan wearing two filenames.
ποΈ Why keep completed TPPs
Step 4 says to move finished TPPs to _done/. Don’t skip this.
_done/ is the cheapest institutional memory you’ll ever build. When a bug surfaces months later, a completed TPP tells the next engineer what was tried, what was rejected, and which edge cases were already discovered. When you’re extending a subsystem, the lore section can save a session’s worth of wrong turns.
It also helps with release notes and onboarding. At release time, walk _done/ since the last release and draft from intent instead of commit messages. For a new engineer, human or model, the completed TPPs are dated, scoped, and tied to actual code.
βοΈ Automating the workflow with skills
The canonical TPP skills live in our plugin marketplace: photostructure/coding-skills. Install the coding plugin in either product:
# Claude Code
/plugin marketplace add photostructure/coding-skills
/plugin install coding@photostructure
# Codex
codex plugin marketplace add photostructure/coding-skills
codex plugin add coding@photostructure
tpp: start or resume
At the beginning of a new task when the prior one did not finish, run
/coding:tpp path/to/plan.md in Claude Code or
$coding:tpp path/to/plan.md in Codex. The coding agent reads the TPP, figures
out which phase it is in, and does that phase’s work. The TPP and
TPP-GUIDE.md carry the details: required reading, tests, alternatives, tasks,
review, and handoff notes. The skill itself is short. Most of the intelligence
comes from the TPP document.
handoff: wrap up
When context is running low (check your Claude Code status line), run
/coding:handoff in Claude Code or $coding:handoff in Codex. The agent updates
the TPP with everything it learned during the task: completed work, failed
approaches, new gotchas, and clear next steps. The next task invokes tpp and
continues without asking you what happened last time.
You shouldn’t have to remember to do this. The tpp skill tells the agent to
invoke handoff itself when context runs low, “rather than letting the session
end silently.” That instruction lives in the skill’s prose rather than in
Claude-only frontmatter, so it works the same in Codex.
tpp-orchestrate: drive a queue
If you have a whole queue of plans to execute, tpp-orchestrate works through
them serially, parallelizing only when the plans provably touch disjoint files.
Each plan gets delegated to an implementer working test-first. The resulting diff
then goes through the second-opinion gate:
your own read plus a review from the other vendor’s model, with every finding
empirically verified before it’s accepted or vetoed. Each plan becomes one
coherent commit. The skill picks model and reasoning strength by risk, using
whatever the host offers.
Adapting the Required Reading list
Both tpp and handoff read AGENTS.md, honor CLAUDE.md when present, and
read the project’s docs/TPP-GUIDE.md, falling back to a bundled reference.
List other high-value docs in AGENTS.md: design principles, TDD guidelines,
API conventions, or architecture decisions. Keep the list short because every
file gets re-read each call.
π§ Encouraging TPP use with durable project guidance
Earlier versions of this article told you to wrap the claude binary in a shell
function that injected TPP instructions via --append-system-prompt. That advice
is gone. It worked, but only on one product, and only for people willing to keep
a claude.sh in every repo and an alias in their ~/.bashrc (aliased to cla,
so the wrapper wouldn’t disturb the VSCode extension or claude update). That’s
a lot of machinery for a rule the repository can carry by itself.
Put the standing rule in the repository instead. Codex reads AGENTS.md, and
Claude Code honors the same file alongside CLAUDE.md. Keep the instruction
short enough to stay useful throughout a long task:
## Technical Project Plans
For work that may span tasks, create or resume a TPP under the documented plan
directories before implementation. Follow `docs/TPP-GUIDE.md`.
At the start of a task, use the installed `tpp` skill to continue the active
plan. Before context is lost, use the installed `handoff` skill to record
progress, discoveries, failed approaches, and exact next steps.
If your coding environment supports hooks or task automation, add a reminder
that points back to this repository guidance. A reminder should reinforce the
workflow, not duplicate the full TPP guide. The explicit invocations are
/coding:tpp and /coding:handoff in Claude Code, or $coding:tpp and
$coding:handoff in Codex.
π Setting this up in your project
Install the plugin:
# Claude Code
/plugin marketplace add photostructure/coding-skills
/plugin install coding@photostructure
# Codex
codex plugin marketplace add photostructure/coding-skills
codex plugin add coding@photostructure
Then start a new task in your coding agent, use its planning mode when available, and paste this prompt:
We installed the `coding` plugin from
photostructure/coding-skills, which provides
the tpp, handoff, and tpp-orchestrate skills.
Now set up the rest of the TPP system described at
https://photostructure.com/coding/claude-code-tpp/index.md
for this project.
Implement ALL components exactly as described. Do not
skip or simplify any part based on your assessment of
project complexity. Every component exists because the
defaults (MEMORY.md, /compact, plan files) have documented
failure modes that this system addresses. See the "I don't
need this" section of the article for specifics.
This includes:
1. Before creating directories, asking me whether to use the simple layout (`_todo/` and `_done/`) or priority folders (`_active/`, `_p1/`, `_p2/`, `_p3/`, `_p4/`, and `_done/`), then setting up the chosen directories
2. Documenting `_feat-<name>/` as the reserved convention for temporary feature integration queues, without creating one until a feature actually needs it
3. Creating docs/TPP-GUIDE.md if it doesn't exist, adapted to the chosen layout and this project's conventions
4. Adding concise AGENTS.md guidance that this repo uses TPPs, while preserving CLAUDE.md guidance when present
5. Asking me for any fundamental project-specific documents that belong in Required Reading (e.g., DESIGN-PRINCIPLES.md, TDD.md, ARCHITECTURE.md). Do not fork the skills.
After setup, show the exact skill invocation for this product.
π§° This is not Claude-specific
TPPs are not a Claude Code feature. They are a repo convention plus two prompts:
- Start from this TPP, read the required context, and continue the current phase.
- Before context disappears, update the TPP so the next session can continue.
Claude Code, Codex, and Gemini CLI can use the same documents.
Codex
Codex installs these skills natively from the same marketplace:
codex plugin marketplace add photostructure/coding-skills
codex plugin add coding@photostructure
Use /plugins to browse installed plugins. Start a new task after installation
or an update, then invoke $coding:tpp path/to/tpp.md, $coding:handoff, or
$coding:tpp-orchestrate. Type $ in the composer to browse available skills.
Keep the standing repository rule in AGENTS.md; the plugin supplies the
repeatable workflow, so you do not need to copy its skills into the project.
Codex setup prompt
Open Codex in the project directory and paste this:
Set up the TPP system described at
https://photostructure.com/coding/claude-code-tpp/index.md
for Codex in this project.
The native `coding` plugin from photostructure/coding-skills is already
installed. Use its `$coding:tpp`, `$coding:handoff`, and
`$coding:tpp-orchestrate` skills. Do not copy or fork them.
This includes:
1. Before creating directories, asking me whether to use the simple layout (`_todo/` and `_done/`) or priority folders (`_active/`, `_p1/`, `_p2/`, `_p3/`, `_p4/`, and `_done/`), then setting up the chosen directories
2. Documenting `_feat-<name>/` as the reserved convention for temporary feature integration queues, without creating one until a feature actually needs it
3. Creating `docs/TPP-GUIDE.md` if it doesn't exist, adapted to the chosen layout and this project's conventions
4. Adding concise `AGENTS.md` guidance that this repo uses TPPs and that repeatable TPP work should use `$coding:tpp` and `$coding:handoff`
5. Honoring `CLAUDE.md` when present and asking which other project-specific docs belong in Required Reading
After setup, show me how to start work with `$coding:tpp path/to/tpp.md`.
Gemini CLI
Gemini CLI uses GEMINI.md for project context and supports project-local
custom commands
in .gemini/commands/. That makes the TPP workflow easy to port.
Create .gemini/commands/tpp.toml:
description = "Work on a Technical Project Plan."
prompt = """
Read @{docs/TPP-GUIDE.md}, then read the TPP referenced here: {{args}}
Determine the current phase, do the work for that phase, and update the TPP with
progress, discoveries, failed approaches, and next steps.
"""
You can create a matching .gemini/commands/handoff.toml with the same handoff
rules from TPP-GUIDE.md:
description = "Update the active TPP for handoff."
prompt = """
Re-read the active TPP and follow the handoff rules in @{docs/TPP-GUIDE.md}.
"""
Then run /tpp path/to/tpp.md at the start of a session and /handoff before
you lose context. Same discipline, different harness.
Gemini CLI setup prompt
Open Gemini CLI in the project directory and paste this:
Set up the TPP system described at
https://photostructure.com/coding/claude-code-tpp/index.md
for Gemini CLI in this project.
Implement all components. Do not skip the custom commands.
This includes:
1. Creating `.gemini/commands/tpp.toml` for `/tpp path/to/tpp.md`
2. Creating `.gemini/commands/handoff.toml` for `/handoff`
3. Before creating directories, asking me whether to use the simple layout (`_todo/` and `_done/`) or priority folders (`_active/`, `_p1/`, `_p2/`, `_p3/`, `_p4/`, and `_done/`), then setting up the chosen directories
4. Documenting `_feat-<name>/` as the reserved convention for temporary feature integration queues, without creating one until a feature actually needs it
5. Creating `docs/TPP-GUIDE.md` if it doesn't exist, adapted to the chosen layout and this project's conventions
6. Adding concise `GEMINI.md` guidance that this repo uses TPPs and that repeatable TPP work should use `/tpp` and `/handoff`
7. Asking me which project-specific docs belong in the required reading list
Use the current Gemini CLI custom command docs for TOML syntax.
After setup, show me how to start work with `/tpp path/to/tpp.md`.
π Curated knowledge beats LLMs
If you don’t already have “primer” documents for your project, like a CLAUDE.md or DESIGN-PRINCIPLES.md, ask Claude to help you write short ones. Don’t waste time with “best practices” documents unless claude doesn’t follow them already. Focus on lore: the stuff in your brain that claude can’t find with a web search.
SkillsBench (HN discussion) tested whether AI agents benefit from pre-generated procedural knowledge. Self-generated skills (where the model invents guidance from its own training data) provided no measurable benefit. But curated skills, written by humans with domain knowledge, improved performance by 16 percentage points on average. Focused documents with 2-3 modules outperformed comprehensive dumps. Smaller models with good skills matched larger models without them.
The same effect applies to humans. A new engineer joining a project doesn’t get smarter by reading the entire git log; they get smarter by reading curated docs that explain why the code looks like it does. TPPs in _done/ are exactly that.
π€ “I don’t need this” (yes, you do)
If your coding agent says “memory is fine” or “this is overkill for my project,” run these experiments before dismissing anything:
Test 1: project-instruction adherence
Pick a specific AGENTS.md or CLAUDE.md instruction. Not a simple one like
“use TypeScript,” but something behavioral, like “always write failing tests
before fixing bugs” or “never use default exports.” Start a task. Work for
15-20 turns. Check whether the agent is still following that instruction.
In many long tasks, it will drift. Project instructions compete with in-context momentum. After enough turns of implementation, behavior is shaped by what just happened, not only by what the repository said at the start.
That is why the standing rule stays short and the handoff skill records the
state before context disappears.
Test 2: MEMORY.md fidelity
After a complex session, read MEMORY.md. Now read the actual session transcript. Count the design decisions and rejected approaches from the transcript that didn’t make it into MEMORY.md. In practice, MEMORY.md captures maybe 10-20% of session-critical context. It’s a notebook, not a handoff document.
Test 3: /compact information loss
Start a session. Discuss a design tradeoff with at least three options and specific reasons for rejecting two of them. Run /compact. Then ask yourself: “Which options were rejected and why?” The answer is almost certainly gone. /compact preserves the conclusion but drops the reasoning, which is exactly what the next session needs to avoid re-exploring dead ends.
“This is overkill for my project”
Maybe! If your tasks reliably complete in a single session, you don’t need TPPs. Nobody needs a handoff document for a one-session task.
But “my project is simple” is often “my project is simple right now.” Scraper maintenance is simple until a site redesigns and you spend three sessions debugging selector changes. Price imports are simple until edge cases in currency formatting eat a week. The question isn’t whether your tasks are complex today. It’s whether you have a plan for when they become complex tomorrow.
Recall the SkillsBench result: self-generated skills provided no measurable benefit, while curated ones improved performance by 16 percentage points. MEMORY.md is self-generated. TPPs are curated.
π² Your mileage WILL vary
None of this is sacred. Models respond differently to small wording changes. Expect to tune the repository guidance and TPP template until they fit your project. Ask your coding agent to help you iterate as it missteps!
