Workspace preflight
Workspace preflight checks your Git checkout before an agent works on it. If the checkout has local edits or is not at the expected commit, it creates a separate worktree so the agent never touches your files. Today it is used by CI recovery in the PR review app.
What it checks
packages/robos-lib/workspace-preflight.js exports two functions.
inspect(workspace, revision, expectedBranch) runs git status --porcelain=v1 -z, git rev-parse HEAD and git branch --show-current. It returns the changed files (status code and path, plus the old path for renames and copies) and needsIsolation, which is true when any of these hold:
| Condition | reason text |
|---|---|
| The status lists any staged, unstaged or untracked change | Your working copy has local edits. |
HEAD is not the given revision | Your working copy differs from the failed PR revision. |
expectedBranch is given and the current branch is different | Your working copy is on another branch. |
prepare(workspace, revision, { root, expectedBranch }) does the following:
- Rejects the revision unless it is a 40 to 64 character hexadecimal Git object name (“A verified Git revision is required.”).
- Runs
inspect. When no isolation is needed, it returns the inspection result withisolated: falseand stops. - Otherwise it confirms the commit exists with
git cat-file -eand runsgit worktree add --detachto createci-repair-<uuid>underroot. The default root is~/.robos/agent-workspaces, created with mode0700. - It writes
ci-repair-<uuid>.jsonnext to the worktree (mode0600) withversion,originalWorkspace,workspace,revision,createdAtandisolated: true.
A detached worktree has its own index and files, so your branch, staged changes and untracked files stay as they were. The unit test workspace-preflight.test.js checks that a repair commit leaves staged, unstaged and untracked files untouched.
const { inspect, prepare } = require('../robos-lib/workspace-preflight');
const info = inspect('/path/to/checkout', failedCommitSha, 'my-feature-branch');
if (info.needsIsolation) {
const repair = prepare('/path/to/checkout', failedCommitSha, { expectedBranch: 'my-feature-branch' });
// repair.workspace is a detached worktree at failedCommitSha
}
The preflight element
workspace-preflight-ui.js defines the custom element <robos-workspace-preflight>. Assign the inspect result to its value property. The element stays hidden unless needsIsolation is true. When shown, it displays “Keep your work. Repair in a clean workspace.”, the reason, a collapsible “Existing local changes” list of status and path, and a note that the worktree starts at the failed commit and is kept so you can return to it.
In the PR review app
CI recovery (packages/pr-review/lib/ci-recovery.js) is available to the author of an open pull request whose CI has failed.
- In the CI banner, click Get CI back to green. A dialog titled “Back to green” opens.
- Choose the repair agent. Only Codex is supported, and it needs a configured Codex
execagent. - If the preflight reports that isolation is needed, the primary button reads Use clean workspace & fix. Otherwise it reads Investigate & fix. If you start a repair that needs isolation without confirming it, the app refuses with “Use a clean repair workspace to preserve your existing work.”
- The agent works in the repair worktree. Its prompt tells it to commit there, not to switch branches, edit the original checkout or push, and never to push, force-push, merge or open another PR.
- When the agent has produced a verified commit, the button changes to Push fix & watch CI. Until then the dialog states “Your branch stays local until you push.”
The recovery state, including the repair workspace path, is saved to disk. Reopening the dialog continues in the same workspace, and answers you give to the agent’s questions are applied there. Your original index, branch and files are not changed by the repair itself.
Not verified: pushing the repair commit when the repair ran in a separate worktree. CI recovery calls ReviewPRState.push with workspace and expectedHead, but that method in packages/pr-review/lib/review-pr-state.js takes no arguments and runs in the original checkout. There it requires the PR branch to be checked out and a clean tree, and it runs a plain git push without --force. The tests replace push with a stub, so this path has no test.