HANDOFF.md: what it is and a copy-paste template

HANDOFF.md is a plain markdown file at the repo root or in a task folder. It records the goal, current state, decisions, next steps and open questions so another AI agent or person can continue the work. Below: a template, an example and how to share it.

Updated

Copy-paste HANDOFF.md template

Paste this into a new file, or ask your agent to fill it in at the end of a session.

# HANDOFF: <task name>

## Goal
What "done" means, in one or two sentences. What must not change.

## Current state
Where the work stands right now. Branch, last commit, what runs and what does not.

## What changed
- ...

## Decisions and why
- Chose X over Y because ...

## Next steps
1. ...
2. ...

## Open questions / blockers
- ...

## How to verify
```
npm test
```

## Files touched
- path/one.ts (new)
- path/two.ts (modified)

Where do you put HANDOFF.md and how do agents use it?

  • Repo root for one stream of work. The next session finds it without being told.
  • Per task (for example tasks/login-fix/HANDOFF.md) when several agents or branches run in parallel.

Agents such as Claude Code, Cursor or Codex can read any file in the repo, so the simplest setup is a line in your instructions: "At the end of a session, update HANDOFF.md. At the start, read it first." Nothing here depends on a built-in feature; it is an ordinary file and an ordinary instruction.

HANDOFF.md vs AGENTS.md, CLAUDE.md and README

HANDOFF.md holds session state: what happened and what comes next. It changes every session and is retired when the work ends. AGENTS.md and CLAUDE.md hold standing instructions for agents: build commands, code style, rules. README holds project docs for humans. Do not put session notes in the standing files; they go stale and mislead later runs.

Why does an agent handoff need a document at all?

Context windows end, sessions get closed, and the assistant that started the work is not the one that finishes it. What survives is whatever was written down. A handoff document is a compact, honest account of the state of a task: what was done, what was verified, what is still broken, and what to do next. It is not a transcript, and it deliberately does not carry repository access, credentials, or the previous conversation — only text.

What should an agent handoff document contain?

The template above is the short form. This longer nine-section version suits larger tasks and adds the commit and the commands already run.

# Agent handoff: <task name>

## Objective
One paragraph: what "done" means, and what must not change.

## Repository and branch
- Repo:
- Branch:
- Base:

## Relevant commit
<hash> — <subject>. Everything below describes the tree at this commit.

## Completed changes
- ...

## Files affected
```
path/one.ts   (new | modified)
```

## Commands run and results
```
npm test  → 14 passed
```

## Unresolved problems
1. ...

## Decisions and constraints
- ...

## Next steps
1. ...

Two of these do most of the work. Commands run and results saves the next agent from re-running a ten-minute test suite to learn what you already know. Relevant commit lets it check git log -1 and see immediately whether the summary still matches the branch.

What does a filled-in handoff look like?

A fictional but realistic one: an agent moved session storage to Redis behind a feature flag, ran the tests, and stopped before the CI and staging work. Everything the next agent needs is in the document, including the pre-existing lint warning it should not waste time on.

agent-handoff.md

2,790 characters · fictional example, same file as the download

Agent handoff: migrate session storage to Redis

Objective

Move acme/shop-web session storage from the in-process memory store to Redis so sessions survive deploys and work across multiple instances. Keep the public cookie format unchanged.

Repository and branch

  • Repo: github.com/acme/shop-web
  • Branch: chore/redis-sessions (pushed)
  • Base: main at 4f2c9a1

Relevant commit

b71e0d3 — "Add Redis session store behind SESSION_STORE flag". Everything below describes the tree at this commit. If git log -1 on the branch shows a different hash, this document is stale.

Completed changes

  • Added lib/session/redis-store.ts implementing the SessionStore interface (get, set, touch, destroy) with a 7-day TTL.
  • lib/session/index.ts picks the store from SESSION_STORE=memory|redis (default memory, so nothing changes until the flag flips).
  • docker-compose.yml gains a redis:7-alpine service for local dev.
  • .env.example documents REDIS_URL and SESSION_STORE.

Files affected

lib/session/redis-store.ts      (new)
lib/session/index.ts            (modified)
lib/session/memory-store.ts     (unchanged, still default)
docker-compose.yml              (modified)
.env.example                    (modified)
tests/session/redis-store.test.ts (new)

Commands run and results

npm test -- session         → 14 passed, 0 failed
npm run type-check          → clean
npm run lint                → 1 warning (unused import in memory-store.ts, pre-existing)
docker compose up redis     → healthy on :6379
SESSION_STORE=redis npm run dev → login/logout works; cart persists across a server restart

Unresolved problems

  1. Session touch on every request doubles Redis round-trips. Left as is; measure before optimizing.
  2. tests/session/redis-store.test.ts needs a live Redis. It is skipped in CI (describe.skipIf(!process.env.REDIS_URL)). CI has no Redis service yet.
  3. Not tested: concurrent logins from two instances. Needs the staging environment.

Decisions and constraints

  • Cookie name and signing stay identical, so a rollout does not log anyone out.
  • No session data migration: memory-store sessions are lost on the first deploy with SESSION_STORE=redis. Product agreed (deploy at low traffic, Tuesday 04:00 UTC).
  • Do not add ioredis; the project already uses redis@4.

Next steps

  1. Add a Redis service to .github/workflows/ci.yml and unskip the store test.
  2. Set REDIS_URL and SESSION_STORE=redis in staging; run the two-instance login check.
  3. Open the PR from chore/redis-sessions → main with this document as the description; request review from the platform team.
  4. After merge: flip the flag in production during the agreed window, watch session_store_errors for one hour.

How do I publish the handoff and pass the link on?

From Claude Code or Cursor with the Docs MD MCP server connected, at the end of the session:

Write an agent-handoff.md for the work in this session using the nine-section
template, then share it with a 7-day expiry and give me both links.

You get a rendered URL and a raw URL. Paste the raw URL into the next session's first message, or into the issue the teammate will pick up. Without MCP, the same thing from a shell:

curl -s -X POST https://docs-md.com/api/share \
  -H "Content-Type: application/json" \
  --data-binary @<(jq -Rs '{content: ., filename: "agent-handoff.md", expiry: "7d"}' agent-handoff.md) \
  | jq -r '.rawUrl'

How does the next agent or person read it?

  • A person opens the rendered link: headings, the file list as a code block, the results table, and a table of contents in the sidebar.
  • An assistant with an HTTP tool fetches https://docs-md.com/raw/<id> and gets the markdown as text/markdown. A first message such as "Read https://docs-md.com/raw/… and continue from its next steps" is enough.

Before acting on the summary, the next agent should compare the commit in the document with the branch head. If they differ, someone worked after the handoff was written, and the document is a starting point rather than the truth.

What are the limits?

  • 120,000 characters per share; a handoff should be far shorter than that.
  • The link is public to anyone who has it. Never include tokens, keys, or customer data.
  • Expiry removes the page at its URL; it does not recall copies already fetched.
  • The next agent needs its own repository access. The handoff carries a summary, not permissions.

To build the file from a form instead of by hand, use the HANDOFF.md generator: it emits the same sections with a live preview, a download, and a share link.

See also: share an implementation plan for review and the REST API.

FAQ

What is HANDOFF.md?

HANDOFF.md is a plain markdown file, usually at the repo root or in a task folder, that records the goal, current state, decisions, next steps and open questions of a piece of work. An AI coding agent or a developer writes it at the end of a session so the next agent or person can continue without the old conversation.

Where should HANDOFF.md go?

Put it at the repo root for a single piece of ongoing work. For several tasks in parallel, use one file per task, such as tasks/<name>/HANDOFF.md. Commit it on the task branch, or keep it out of git if it holds scratch notes, and delete or archive it when the work merges.

Is HANDOFF.md a standard?

No. It is a community convention, not a formal spec. No tool requires the name or the sections. Teams pick the headings that fit and tell their agents to read and update the file. The template on this page is one workable layout.

How do I hand off a coding task to another AI agent?

Have the current agent write a handoff document: objective, repo and branch, the commit its summary describes, completed changes, files touched, commands it ran with their results, unresolved problems, decisions, and next steps. Publish it as a link. The next agent reads the raw markdown URL; a human reads the rendered page.

What should an agent handoff document contain?

The nine sections in the template on this page. The two that are most often missing and most valuable are "commands run and results" (so the next agent does not repeat them) and "relevant commit" (so it can tell whether the summary is stale).

How can another coding assistant read my markdown progress report?

Give it the raw URL, https://docs-md.com/raw/<id>, which returns plain text/markdown. Any assistant that can fetch a URL — Claude Code, Cursor, Codex, a custom agent with an HTTP tool — can read it directly. The rendered URL without /raw/ is for people.

Does the handoff transfer repository access or conversation history?

No. It transfers a written summary only: no repo access, no credentials, no files, no chat state. The next agent still needs its own checkout and permissions. That is why the document names the branch and commit explicitly.

How long should a handoff link live?

Match the expiry to the task: 1 day for a same-day session switch, 7 days for a task that waits on a teammate. Use "never" only for handoffs you will link from a README or an issue for the long term. The link is public to anyone who has it.