| name | kilroy:land |
| description | Land a completed Kilroy pipeline run — merge the worktree branch back into this repo, run smoke tests, and push. |
| user-invocable | true |
Land a completed Kilroy pipeline run by merging the run branch into this repo, running smoke tests, and pushing.
Step 1: Discover the run
Resolve this repo's absolute path, then scan all runs in ~/.local/state/kilroy/attractor/runs/ and read each manifest.json to find runs whose repo_path matches. From the matching runs, select the most recent one (highest run ID, which is a ULID and sorts chronologically).
If no matching runs are found, stop and tell the user. Suggest /kilroy:run to start a run.
If the user passed a specific run ID instead of using the default, use it directly.
Step 2: Verify run completed successfully
Read ~/.local/state/kilroy/attractor/runs/<run_id>/final.json. It must exist and contain "status": "success". If the run did not succeed, stop and tell the user. Suggest /kilroy:status to inspect, or /kilroy:run to re-run.
Step 3: Read run metadata
Read ~/.local/state/kilroy/attractor/runs/<run_id>/manifest.json and extract:
base_sha — the commit the run branched from
repo_path — absolute path to this repo
run_branch — the branch name (e.g. attractor/run/<run_id>)
run_id
Report these to the user so they know what's about to happen.
Step 4: Ensure the repo is clean
Check for uncommitted changes:
git status --porcelain
If there are uncommitted changes (output is non-empty), prompt the user:
"The repo has uncommitted changes. These must be stashed before landing. Stash all changes now?"
If the user agrees, stash:
git stash push -m "kilroy-land: stash before landing run <run_id>"
If the user declines, stop.
Step 5: Rebase if HEAD has moved
Check whether the local branch has moved forward since the pipeline forked:
current_sha=$(git rev-parse HEAD)
If current_sha equals base_sha, no rebase is needed — skip to Step 6.
If current_sha does NOT equal base_sha (HEAD has moved forward), rebase the run branch onto the current HEAD so the pipeline's changes land on top of any new commits:
git rebase --onto HEAD <base_sha> <run_branch>
This replays only the commits between base_sha and the tip of <run_branch> onto the current HEAD.
If the rebase encounters conflicts, stop and report them to the user. Do NOT force or skip — the user must resolve conflicts manually. The run branch is untouched in the worktree so no work is lost.
If the rebase succeeds, update base_sha to current_sha for the commit message context (so the summary accurately reflects what happened), and note that a rebase was performed for the final report.
Step 6: Squash-merge the run branch
Squash-merge the (possibly rebased) run branch into the current branch. This collapses the entire pipeline run into a single commit, avoiding the clutter of empty per-node checkpoint commits on main:
git merge --squash <run_branch>
If the merge fails, stop and report the error.
After the squash, build a summary of which pipeline nodes produced file changes. Inspect the run branch commits between base_sha and the tip of <run_branch>:
git log --oneline <base_sha>..<run_branch> --format="%h %s" --reverse
For each commit, check if it changed files:
git diff-tree --no-commit-id --name-only -r <commit_hash>
Collect the node names from commits that had actual file changes (non-empty diff-tree output).
Before committing, remove any gitignored files that were pulled in by the squash-merge:
ignored=$(git ls-files -ic --exclude-standard)
if [ -n "$ignored" ]; then
echo "Removing gitignored files from staging area:"
echo "$ignored"
echo "$ignored" | xargs git reset HEAD --
fi
Then commit the squashed changes:
git commit -m "attractor(<run_id>): landed pipeline run
Squash-merged from <run_branch>
Nodes with file changes:
- <node_name_1>
- <node_name_2>
..."
If the squash results in no changes at all (every node was empty), skip the commit and warn the user that the pipeline run produced no file changes.
Step 7: Run smoke tests
Run the smoke test suite:
script/smoke-test-suite-full
If the smoke tests fail, stop and report. Do NOT push. The user can inspect failures and decide what to do. The squashed changes are already committed on the local branch, so no work is lost.
Step 8: Holdout scenario verification (optional)
Ask the user:
"Would you like to run holdout scenario verification before pushing?"
If the user says yes, invoke the verify:run-holdout-scenarios skill, and report the result.
If all holdout scenarios pass, proceed to Step 9.
If there were failures, triage each failure into one of three categories:
- Spec gap — the specification does not define the expected behavior. The spec needs revision before the next pipeline run can succeed.
- Unimplemented spec — the specification clearly defines the behavior (pseudocode, algorithm, data format) but the implementation does not follow it. The next pipeline run can fix this immediately.
- Both — the spec is partially there but incomplete. Include in both artifacts.
Then produce the appropriate artifacts:
-
If there are spec gaps: Invoke spec:critique (existing behavior, unchanged). Report the path to the critique versioned file.
-
If there are unimplemented specs: Write .ai/unimplemented_specifications.md with a structured entry for each unimplemented-spec failure. Each entry must include:
- A descriptive title
- Specification reference: exact file path, section number, and algorithm/pseudocode name
- What the spec requires: the specific behavior defined in the spec
- What the implementation does: the observed incorrect behavior
- Holdout scenario(s) affected: which scenarios failed due to this
- Evidence: screenshot filename or error message
- Implementation fix required in: the file(s) and function(s) that need to change
Format:
# Unimplemented Specifications
Source: holdout scenario verification during landing of run <run_id>
Date: <date>
## Unimplemented: <title>
**Specification reference:** `<file_path>`, <Section> — `<algorithm_name>`
**What the spec requires:** <description>
**What the implementation does:** <description>
**Holdout scenarios affected:** <list>
**Evidence:** <screenshot or error>
Report both artifacts to the user, explaining what each addresses:
- Critique → needs spec revision before the next run (invoke
spec:revise or spec:critique-revise-loop)
- Unimplemented specs → the next pipeline run (
/kilroy:run) can fix these immediately because the spec already defines the correct behavior
If holdout scenario verification fails, stop and report. Do NOT push. The user can inspect failures and decide what to do. The squashed changes are already committed on the local branch, so no work is lost.
Step 9: Push
Ask the user:
"Smoke tests and holdout scenario verification passed. Push to origin?"
If holdout scenarios were skipped, adjust the prompt accordingly:
"Smoke tests passed (holdout scenarios skipped). Push to origin?"
If the user agrees:
git push
Step 10: Clean up
After a successful push, clean up the worktree and run branch:
git worktree remove ~/.local/state/kilroy/attractor/runs/<run_id>/worktree --force
git branch -D <run_branch>
Report that the run has been landed and cleaned up.
Summary
At the end, report:
- Run ID that was landed
- Whether a rebase was performed (and from which SHA onto which SHA)
- The single squash commit hash
- How many pipeline nodes ran vs. how many produced file changes
- Smoke test result
- Holdout scenario verification result (or skipped)
- Whether changes were pushed