The State Branch
Overdeck records everything durable about your pipeline — plans, per-issue records, review verdicts, PRD drafts, and xBRIEF task state — in git, so it survives reinstalls and travels between machines. That state lives on a dedicated branch calledoverdeck-state, not on main.
Your code history and your pipeline history share one repository but never
share a branch, a commit, or a merge.
Why a separate branch
Overdeck writes state constantly — every plan, verdict, and task update lands a commit. When that state lived onmain, those commits made up most of the
branch’s history. The churn buried real code changes in git log, triggered
CI on every state write, and forced feature branches to rebase over commits
that never touched code. Moving state to its own branch removes all three
problems at once: main shows only code, CI runs only on code, and feature
branches rebase only when code actually changes.
What you see on GitHub
The default view of your repository showsmain: source code, docs, and one
Overdeck-owned directory, .overdeck/context/, which holds your hand-written
project guidance (see Context Layers). No
plans, no records, no task database.
Switch the branch dropdown to overdeck-state and the file listing changes
completely:
A PRD is browsable at
github.com/<owner>/<repo>/blob/overdeck-state/drafts/<issue>.md — useful for
linking plans in issues and chat.
Where the files live on your machine
Overdeck checks the state branch out to a state worktree at~/.overdeck/state/<project>/. A worktree is a second checkout of the same
repository: the same file is drafts/pan-123.md on the branch and
~/.overdeck/state/<project>/drafts/pan-123.md on disk. Every state commit
Overdeck makes happens there — never in your project checkout.
You never create this worktree yourself. pan install, pan doctor, and the
migration all create or repair it automatically, on any machine.
Two directories share the .overdeck name; they are different things:
This mirrors the convention tools like Cargo use:
~/.cargo/ for the machine,
./.cargo/ for the project.
What happens when you clone
A plaingit clone checks out code only. Your working directory contains
main’s files — no records/, specs/, or other pipeline-state directories. Git does download the state
branch’s history into .git/ (that is how the state reaches new machines),
but none of it appears on disk unless you check the branch out.
Want a lighter clone? git clone --single-branch fetches main alone.
Cloning the state branch directly (git clone -b overdeck-state <url>)
gives you a working directory that starts at records/, specs/, and so on
— occasionally useful for inspecting pipeline state without Overdeck, in the
same way people clone a gh-pages branch.
The branches never merge
main and overdeck-state have no common ancestor — overdeck-state is an
orphan branch, like gh-pages. GitHub cannot even open a pull request between
them; the compare page reports “nothing to compare.” You may still see
GitHub’s “recent pushes — Compare & pull request” banner after state activity.
Ignore it: it appears for any recently pushed branch and leads nowhere here.
Overdeck also enforces the separation mechanically:
- A CI guard fails any code-branch change that adds state paths, and any state-branch change that adds code.
- The same guard rejects a branch whose history contains the state branch’s
root commit, so even a file-less
git merge --allow-unrelated-historiesis refused at push time. - If something forced past all of that ever lands, it is one
git revertfrom undone — a merge commit destroys nothing.
How a project starts using the state branch
Overdeck migrates every registered project automatically duringpan sync and
before the dashboard starts its pipeline coordinator. Commands that start work
also enforce the same gate, so an incomplete migration cannot create fresh
legacy .pan/ state or task exports. If a safety prerequisite blocks automation,
Overdeck reports the exact reason and leaves both branches untouched.
The administrative command remains available for previewing or resuming a
blocked cutover:
overdeck-state branch,
removes it from main in one ordinary commit, and publishes both branches in
a single atomic push. The final commit on the state branch adds
migration-complete.json — the marker. Overdeck treats a project as
migrated only when a valid marker is present at the branch tip’s history, so a
half-finished or interrupted migration leaves every reader safely on the old
layout. The command is resumable: run it again after a failure and it
continues where it stopped.
The migration includes tracked and untracked permanent-state artifacts. If an
agent already committed legacy .pan/ state or task exports on main, the cutover uses ordinary
forward commits to copy those files onto overdeck-state and remove them from
main; it never rewrites published history.
Migration is per project and per repository. Each project is reconciled
independently, and the mechanism is plain git — GitHub and GitLab remotes
behave identically.
Polyrepo projects
A polyrepo project can designate one of its sub-repositories as the state-host repo, even when the project root is not itself a Git repository. Setpan_records.repo to the sub-repository’s name from workspace.repos:
infra repository hosts overdeck-state and its remote
stores the durable pipeline state. Migration reads existing legacy .pan/ state and task exports from the project root, publishes them to the state-host
repo’s orphan branch, and removes the legacy root copies. The host repo’s
main branch remains unchanged. GitHub and GitLab host remotes use the same
migration flow.
Record writes hold a bounded per-issue lock
Every per-issue record write (records/<issue>.json) runs under a cross-process
lock so two writers can’t lose each other’s updates. The lock is held while the
write commits and pushes from the state worktree — and that hold is bounded:
if the commit-and-push doesn’t finish within
OVERDECK_RECORD_DURABILITY_BUDGET_MS (default 30 seconds), the writer
releases the lock and reports a durability timeout instead of starving other
writers for minutes. A stalled remote can no longer block verdict writes the
way it did before this bound existed.
A timeout does not lose your update:
- The mutation stays in the local record file — Overdeck never rewinds it, because the slow push may still land in the background.
- Review and test verdicts that can’t take the lock in time fall back to a
workspace-local
pipeline-verdict.json, which is drained proactively: it is folded back into the canonical record after the next successful journal write for the issue, or automatically within about two and a half minutes (retrying at 5s, 30s, and 120s), without waiting for anyone to read the issue’s status.
OVERDECK_DASHBOARD_SPAWNED_BY (used only by the port-override guard), and
the server’s own record writes appear as process-<pid>@<hostname>.
What changes day to day
Almost nothing, by design. Plans finalize, records update, and task state flow exactly as before — Overdeck resolves every read and write to the state worktree automatically. The visible differences:git log mainshows code changes only. State activity appears onoverdeck-stateinstead.- State pushes no longer trigger your CI.
- PRD links in issues point at
blob/overdeck-state/drafts/...instead of in-repo.pan/paths. pan taskreads and updates the issue record’s xBRIEF task state through the canonical state door; you do not need to change directories.
Frequently asked questions
Does deleting my project checkout lose pipeline state? No. State lives on theoverdeck-state branch on your remote and in the
state worktree under ~/.overdeck/. Re-cloning the repo and running
pan doctor restores everything.
Can I edit state files by hand?
Read them freely. For edits, prefer pan commands — Overdeck assumes it is
the only writer, and hand edits can race it. Operator notes in notes/ are
the exception; they are yours.
Why does my repository’s total clone size include state history?
Both branches share one git object store. The weight is the same as before
the migration — it used to live on main — but if it ever grows
uncomfortable, git clone --single-branch or --filter=blob:none skips it.
What if I accidentally merge overdeck-state into main?
You almost can’t: GitHub refuses the pull request, and the CI guard plus the
local pre-push hook reject the merge commit. If one is ever forced through,
git revert -m 1 <merge-commit> restores main completely.
Can the overdeck-state branch be deleted?
Protect it like main — it is the only home of your pipeline state, and no
code branch can restore it. Add a rule on your remote that blocks deletion
and force pushes of overdeck-state (GitHub: a repository ruleset targeting
the branch; GitLab: a protected-branch entry). Locally, git already refuses
to delete the branch while the state worktree has it checked out, and
Overdeck’s bundled agent rules forbid agents from deleting it in any form.