Wrap any command. If it dies, a headless Claude Code session diagnoses the bug, writes a failing test, patches it on a separate branch, verifies the fix independently, and leaves a post-mortem. Your branch is never touched.
the ninety seconds
Phantom runs your command untouched and stays out of the way. Your exit code passes through unchanged, so it is safe inside && chains and in CI. Scroll to watch a recovery happen.
phantom/fix-* branch is cut from HEAD. Nothing before this point has changed your tree.unfixed, whatever the suite says.The spinner lines are live: the guard hook sees every file the session touches, so it tells you what is happening rather than only that something is.
the part you actually care about
Letting an agent loose in your repo is the objection, and it should be. Every rail below is a mechanism, not a promise — and each one is there because the alternative was tried and written down.
A phantom/fix-* branch is cut from HEAD before any edit, and you are checked back out when it finishes — success or failure. The fix exists only as a branch to diff, merge, or delete.
.env, *.pem, *.key, secrets/** are enforced three ways: permission deny rules, a PreToolUse guard hook on every call, and a post-session audit that hard-reverts the branch on any hit.
No WebFetch, no curl, no git push. There is no push code path to configure.
Phantom re-runs your tests itself, outside the session, and then re-runs the command that crashed. A session that claims success without changing anything is reported unfixed.
maxIterations, maxMinutes, and a real spend ceiling — maxTokens or maxCostUsd — checked before each additional attempt.
Kills the process tree, rescues untracked work into a stash, resets the fix branch, checks your branch back out, exits 130. SIGTERM and SIGHUP do the same.
The session runs node — it has to, to run your tests — so a one-liner can read what your user can read. The guard is lexical: an audit found four ways past it in one afternoon. All four are fixed and pinned by tests, and the honest lesson is that a lexical guard is a speed bump. Branch isolation and the post-session audit are the real backstops. Need hard isolation? Run it in a container.
Output, and the command line phantom displays, are scrubbed before the model, the report, the notification or the webhook ever see them — KEY=value, Authorization headers, URL credentials, PEM blocks, well-known token shapes. Unusual formats get through. It is a safety net, not a guarantee.
the surface
Wrap anything. Flags go before the command; everything after it passes through verbatim, so phantom never has an opinion about your arguments.
Run this before your first crash. Checks that claude is installed and logged in, that this is a git repo with a commit, what test command it would run, and whether notifications can reach you.
This repo's fix branches, crash captures and post-mortems. Writes to stdout; --json for the whole state.
Prunes them. Merged branches only by default — deletion goes through git branch -d, so a stale plan fails instead of destroying work.
Replays a crash phantom already captured, without waiting for it to happen again.
--dry-run diagnoses and proposes a diff with no branch and no edits. The CI-safe mode — and phantom now checks afterwards that the session really did change nothing.
--commit, --prompt, --no-notify, --verify. A setting in your config file can be turned off for a single run without editing it.
.phantomrc, a package.json field, or fourteen PHANTOM_* variables. Precedence: flags > environment > file > defaults.
what it is not
Nothing here is a caveat buried in a footnote. If one of these is a dealbreaker, better you find out now than after a recovery.
Outside a repo, phantom passes the command through and says why it is not recovering. There is no way to undo a bad session without git.
Claude may fail. You get unfixed or timeout, your branch untouched, and a report saying what was tried.
Patching works anywhere Claude Code can edit, but verification needs a test command and the crash heuristics are tuned for Node traces first.
Every recovery is a genuine session on your plan or API key. Set maxCostUsd if that matters — the dollar figure phantom shows is an estimate from published rates, not your bill.
A child that never closes stdout keeps phantom waiting. Wrap foreground processes.
why trust it
Phantom is a tool that edits your code while you are not watching. That only deserves trust if the thing itself is held to a standard, so it is: every fix ships with a regression test, and every test is broken on purpose to prove it fails before it is allowed to pass.
The release notes name what was broken rather than burying it — including the release where following phantom's own printed recovery instructions could destroy your uncommitted work. That bug is fixed, pinned by a test that executes the printed advice verbatim, and written up in full in the changelog.
questions
No. It is a denied tool, there is no network tool, there is no push code path, and there is no flag. Not configurable.
.env?No — enforced as permission deny rules, by the guard hook on every call, and by a post-session audit that hard-reverts the branch on any hit. Watch your own log output though: the redactor is pattern-based.
Phantom refuses on a dirty tree. --allow-dirty stashes a snapshot first and restores it after — including on Ctrl+C — and the command it prints to restore it names the stash by full sha, so a stash pushed meanwhile by another shell cannot be popped by mistake.
One to three headless turns plus test runs — roughly a short interactive debugging session. maxIterations and maxMinutes bound how often it asks and how long it waits; for an actual ceiling on spend, set maxTokens or maxCostUsd.
Use --dry-run: diagnosis and a proposed diff land in .phantom/reports/ with no branch and no edits. Upload .phantom/ as an artifact. Full mode works, but the branch dies with the runner since nothing is pushed.
Yes, and it does the right thing: a tool call times out long before a recovery finishes, so phantom captures the crash and hands it to /phantom:recover instead of starting a session that would be killed halfway. The recovery session also never inherits the parent session's environment.
A child-process spawn with piped stdio and a bounded buffer. A 50 MB log flood is in the test suite.
Then run phantom doctor once, before your first crash.
Also installable as a Claude Code plugin — /plugin marketplace add waazy-w/claude-phantom