Workspace

.handoff/ Runtime State

What Handoff stores in the workspace's local .handoff/ directory, and why it's gitignored.

.handoff/ is where the CLI keeps everything that's local-machine state rather than version-controlled content. It should always be gitignored.

PathPurpose
.handoff/cli-auth.jsonSaved OAuth device-flow credentials (remoteUrl, accessToken, expiresAtMs) written by handoff-app login / mcp-init, read by push/pull/sync-status/mcp-token so you don't have to re-authenticate on every command. Removed by handoff-app logout.
.handoff/sync-state.jsonThe last sync cursor (lastSyncVersion, lastSyncAt) and a per-entity fingerprint map, used by push (to skip unchanged components) and pull/sync-status (to compare local vs. remote state).
.handoff/conflicts/Where pull writes files it couldn't cleanly merge into the workspace, for manual resolution.
.handoff/.cache/build-cache.jsonComponent build cache: per-component source/template file states plus a global-deps state (the token snapshot, global SCSS, global JS). Tokens are one invalidation input, not the key — the cache is what lets start and the build commands skip components whose sources haven't changed.
.handoff/app/Where the Next.js app is materialized under the default materialization_layout: 'legacy'. The other two layouts put it elsewhere: 'runtime'<workingPath>/handoff-runtime, 'root' → the workspace root itself. (.handoff/runtime/ is a separate, ephemeral CI root used by the deprecated prepare-runtime/vercel-build per-project deploy path, not a materialization_layout value.)

Always gitignore .handoff/

It holds a bearer token (cli-auth.json) and machine-local cache/state, never commit it. mcp-init --embed also writes into a project's .mcp.json, not .handoff/, but adds that file to .gitignore for you when it embeds a literal token; do the same for .handoff/ if your workspace template doesn't already ignore it.

None of this is required for a workspace to function from scratch, delete .handoff/ at any time and the CLI will recreate what it needs (you'll just need to login again and push without the unchanged-file skip optimization on the next run).