agentleFS
NYTC69NYTC69/review-loop/.agents/skills/paired-session/SKILL.md

paired-session

Skill3 starsChanged 6 months agoApache-2.0View on GitHub

Use in exactly four cases - the user explicitly asks for paired-session, the review-loop entry hands off because .review-loop/config.md sets `entry: paired-session`, the review-loop entry hands off because that key is absent or invalid (the default entry), or the review-pr skill hands off on its paired route; with lifecycle on, this is the plan, implementation, independent-review, finish, polish, docs, security and acceptance workflow. Generic review-loop requests go to the review-loop entry first, which routes them here.

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Run directory: default to <repo>/.review-loop/runs/<UUID>/, where <repo> is the main checkout resolved by git rev-parse …

    line 62
  2. Distinctive:

    Read a launcher log's last lines only when a polled command ends without its final coordinator line (the shared contract's Work item …

    line 74
  3. Very specific:

    Add the review-only and review-pr options below to this block as to the POSIX one.

    line 165
  4. Very specific:

    Add --auto-commit false too when the review-loop entry handed it over.

    line 176

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Paired-session workflow (Codex)

Loading the shared entry contract

First, before any stage A check or question, read <support-root>/docs/protocol/loading.md and load the shared entry contract (docs/protocol/paired-session-entry.md) as its own command, cwd in the user's workspace. The bundle must stay out of the product worktree (FIELD-18): first print a fresh bundle directory as its own command, python3 -c 'import os, tempfile, uuid; print(os.path.join(os.path.realpath(tempfile.gettempdir()), f"review-loop-protocol-{os.getuid()}", uuid.uuid4().hex[:12]))', then write that printed directory out literally as <bundle-dir>:

python3 <support-root>/scripts/read_protocol.py --runtime codex --stage entry-paired-session --output <bundle-dir>/protocol-codex-entry-paired-session.md

On native Windows Codex runs commands in PowerShell, Python is python (or py -3) and os.getuid does not exist: print the bundle directory with python -X utf8 -c "import getpass, os, re, tempfile, uuid; print(os.path.join(os.path.realpath(tempfile.gettempdir()), 'review-loop-protocol-' + (re.sub(r'[^A-Za-z0-9._-]', '_', os.environ.get('USERNAME') or getpass.getuser()) or 'user'), uuid.uuid4().hex[:12]).replace(os.sep, '/'))" (the loader names the directory after the Windows user name), then run python -X utf8 '<support-root>\scripts\read_protocol.py' --runtime codex --stage entry-paired-session --output '<bundle-dir>/protocol-codex-entry-paired-session.md'. The Windows commands in this skill are best effort; the Claude Code entry is the tested Windows path.

Resolve <support-root> to this plugin, not the task workspace. After exit 0, read the complete output file in bounded chunks and follow it; a missing, unreadable or incompletely read file is a failed stage A check, reported as stage A failure: cannot load the shared entry contract (<reason>). After compaction, reload it the same way when no coordinator command is running; while one is running, read <support-root>/docs/protocol/paired-session-entry.md directly (the stage is that whole file), which writes nothing to the workspace. This file adds only the Codex host rules:

  • Legacy pointer: none (the legacy workflow was removed in v2.13.0). Long-command execution failure: a declined or ungranted outside-sandbox approval: HOLD with the reason, on every entry and invocation (nothing falls back).

Outside-sandbox and long commands (critical)

  • Outside-sandbox execution: the coordinator spawns provider CLIs and writes to the selected $CODEX_HOME; execute each invocation below with the host's full filesystem/network permission, outside the current Codex sandbox, and never inside the sandbox.
  • Long-command form: every invocation that can dispatch model turns (run, resume, reject --expect) starts with a short nonblocking yield (about 1 second); then poll its returned command-session id until it completes. Do not cancel it or launch a duplicate while it is active, except for the lifecycle-mode backstop, which ends the polled command session.
  • Detached commands: with --detach, wait until the printed pid has exited (the printed record path then reads "exited" with the exit code), then read the last line of its log and status --brief. A report run ends in REPORTED; end the detached command only with stop (paired_session/docs/detach.md).

Run directory

  • Run directory: default to <repo>/.review-loop/runs/<UUID>/, where <repo> is the main checkout resolved by git rev-parse --path-format=absolute --git-common-dir and its parent when it ends in /.git. A lane's output therefore lives in the main checkout. Set WORKSPACE in the same Bash call that runs project_paths.py. On native Windows PowerShell, set $Workspace in the same call that runs project_paths.py. scripts/project_paths.py resolves this root and creates .review-loop/.gitignore (*, !config.md) only when missing. Not a Git repo, a bare repo or a submodule/separate-git-dir checkout: report fallback to ${XDG_STATE_HOME:-$HOME/.local/state}/review-loop (relative XDG uses $HOME/.local/state). An explicit operator-chosen run dir replaces the RUN_DIR assignment below; existing runs resume at their original --run-dir, without migration. The plugin does not create CODEX_HOME. Write launcher logs under the root's logs/. Persistent output is gitignored; scratch stays outside the repo. Do not run git clean -x on the workspace while a run is active: it would delete the run. Read a launcher log's last lines only when a polled command ends without its final coordinator line (the shared contract's Work item section).

Run invocation

There is no probe step: permission-probe and strict mode were removed in v3.7.0 (--strict only prints a NOTE). The invocation below sets up and starts the run.

Invocation (setup, then run):

set -eu
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
stage_a() { echo "stage A failure: $1"; exit 3; }
test -d "$CODEX_HOME" || stage_a "CODEX_HOME $CODEX_HOME is not an existing directory"
VERSION="$(codex plugin list --json --marketplace review-loop-marketplace | python3 -c 'import json,sys; d=json.load(sys.stdin); rows=[p for p in d.get("installed",[]) if p.get("pluginId")=="review-loop@review-loop-marketplace" and p.get("enabled")]; assert len(rows)==1, "review-loop plugin must be installed and enabled exactly once"; print(rows[0]["version"])')" || stage_a "review-loop plugin is not installed and enabled exactly once"
python3 -c 'import re,sys; v=sys.argv[1]; m=re.fullmatch(r"(\d+)\.(\d+)\.(\d+)(\.\d+)*", v); msg=None if m and tuple(map(int, m.groups()[:3])) >= (2, 10, 0) else ("installed review-loop %s predates the paired-session lifecycle (2.10.0)" % v if m else "cannot parse installed review-loop version %r" % v); msg and print("stage A failure: " + msg); sys.exit(3 if msg else 0)' "$VERSION" || exit 3
echo "VERSION=$VERSION"
PLUGIN_ROOT="$CODEX_HOME/plugins/cache/review-loop-marketplace/review-loop/$VERSION"
test -x "$PLUGIN_ROOT/bin/paired-session" || stage_a 'paired-session executable missing from installed plugin'
WORKSPACE='/absolute/path/to/the-selected-dedicated-worktree'
WORKSPACE="$(cd "$WORKSPACE" && pwd -P)" || stage_a 'selected workspace does not exist'
test "$(git -C "$WORKSPACE" rev-parse --show-toplevel)" = "$WORKSPACE" || stage_a 'selected workspace is not a Git worktree root'
TASK_ID="$(python3 -c 'import uuid; print(uuid.uuid4())')"
RUN_ROOT="$(python3 "$PLUGIN_ROOT/scripts/project_paths.py" "$WORKSPACE")" || stage_a 'cannot resolve the run root'
RUN_DIR="$RUN_ROOT/runs/$TASK_ID"
WORKITEM="$RUN_DIR/WORKITEM.md"
mkdir -p "$RUN_DIR" || stage_a 'cannot create the run directory'
cat > "$WORKITEM" <<'PAIRED_SESSION_WORKITEM' || stage_a 'cannot write the work item'
[Write the user's approved goal, acceptance criteria, scope, and verification here.]
PAIRED_SESSION_WORKITEM
echo "RUN_DIR=$RUN_DIR"
TEST_COMMAND='[verified project command, or the exact value from the profile]'
"$PLUGIN_ROOT/bin/paired-session" run \
  --workspace "$WORKSPACE" --workitem "$WORKITEM" --run-dir "$RUN_DIR" \
  --test-command "$TEST_COMMAND" --lifecycle-mode on

Exit 3 (a line printed stage A failure: …) is a failed stage A check, including the plugin-version floor (P14); report it per the entry rules, even though RUN_DIR/state.json does not exist. Any other non-zero exit from the coordinator is a refusal or HOLD: report its output verbatim (no fallback).

Replace the placeholders before running. Keep the heredoc delimiter unique and quoted.

Native Windows

Native Windows (PowerShell; best effort, the Claude Code entry is the tested Windows path): the coordinator refuses --detach. Git for Windows (Git Bash) must be installed, and the run root and the workspace stay out of OneDrive-synced folders. The invocation becomes (same placeholders, same exit 3 rule; run the coordinator and every script through python, never by shebang):

$ErrorActionPreference = 'Stop'
function Stage-A($Reason) { Write-Output "stage A failure: $Reason"; exit 3 }
$CodexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME '.codex' }
$env:CODEX_HOME = $CodexHome
if (-not (Test-Path -LiteralPath $CodexHome -PathType Container)) { Stage-A "CODEX_HOME $CodexHome is not an existing directory" }
try { $Rows = @((codex plugin list --json --marketplace review-loop-marketplace | ConvertFrom-Json).installed | Where-Object { $_.pluginId -eq 'review-loop@review-loop-marketplace' -and $_.enabled }) } catch { $Rows = @() }
if ($Rows.Count -ne 1) { Stage-A 'review-loop plugin is not installed and enabled exactly once' }
$Version = [string]$Rows[0].version
try { $Parsed = [version]$Version } catch { Stage-A "cannot parse installed review-loop version '$Version'" }
if ($Parsed -lt [version]'3.3.0') { Stage-A "installed review-loop $Version predates native Windows support (3.3.0)" }
Write-Output "VERSION=$Version"
$PluginRoot = Join-Path $CodexHome "plugins\cache\review-loop-marketplace\review-loop\$Version"
$Launcher = Join-Path $PluginRoot 'bin\paired-session'
if (-not (Test-Path -LiteralPath $Launcher -PathType Leaf)) { Stage-A 'paired-session launcher missing from installed plugin' }
$Workspace = 'C:\absolute\path\to\the-selected-dedicated-worktree'
try { $Workspace = (Resolve-Path -LiteralPath $Workspace).ProviderPath } catch { Stage-A 'selected workspace does not exist' }
$Top = git -C $Workspace rev-parse --show-toplevel
if ($LASTEXITCODE -ne 0 -or [IO.Path]::GetFullPath($Top) -ne [IO.Path]::GetFullPath($Workspace)) { Stage-A 'selected workspace is not a Git worktree root' }
if (-not $RunDir) {
  $RunRoot = python -X utf8 (Join-Path $PluginRoot 'scripts\project_paths.py') $Workspace
  if ($LASTEXITCODE -ne 0) { Stage-A 'cannot resolve the run root' }
  $RunDir = Join-Path $RunRoot ('runs\' + [guid]::NewGuid())
}
$WorkItem = Join-Path $RunDir 'WORKITEM.md'
try { New-Item -ItemType Directory -Force -Path $RunDir | Out-Null } catch { Stage-A 'cannot create the run directory' }
$WorkItemText = @'
[Write the user's approved goal, acceptance criteria, scope, and verification here.]
'@
try { [IO.File]::WriteAllText($WorkItem, $WorkItemText.Replace("`r`n", "`n") + "`n", (New-Object Text.UTF8Encoding $false)) } catch { Stage-A 'cannot write the work item' }
Write-Output "RUN_DIR=$RunDir"
$TestCommand = '[verified project command, or the exact value from the profile]'
python -X utf8 $Launcher run --workspace $Workspace --workitem $WorkItem --run-dir $RunDir --test-command $TestCommand --lifecycle-mode on
exit $LASTEXITCODE

Add the review-only and review-pr options below to this block as to the POSIX one; a second quoted here-string writes pr-pins.json the same way as the work item. Windows PowerShell 5.1 does not pass a " inside an argument intact to python: keep " out of the test command and the option values, or use PowerShell 7.3 or later.

Per-route extra arguments

A review-only request (the user asks to review an existing change, or the review-loop handoff of a code target) follows the shared contract's review-only entry: add --review-only (and --base "$BASE" only when the user named a base) to the invocation. The workspace is the worktree that holds the change (normally the current checkout). Do not create or switch to a dedicated worktree, and skip the Stage A dedicated-worktree question. Add --auto-commit false too when the review-loop entry handed it over.

A review-pr handoff (from the Codex review-pr skill, or the user asks paired-session to review a PR or ref) follows the shared contract's Review-PR entry. Resolve the run root from the operator project before switching WORKSPACE to the clone. Host rules: the run root is the resolved <repo>/.review-loop/ (or the reported state-root fallback) (the materializer's --root); the materializer reads through gh and the network, so run it as its own invocation outside the sandbox, with PLUGIN_ROOT resolved as in the invocation, before the invocation. In the invocation set WORKSPACE to the clone it printed (no input: the current worktree) and replace the RUN_ROOT resolver (PowerShell: $RunRoot) with the absolute operator-project root resolved before materialization, so runs stay beside pr/ rather than inside the clone. Skip the dedicated-worktree question, replace --test-command "$TEST_COMMAND" with --no-test-command unless the user confirmed a test command, and add --review-only --review-report --auto-commit false, --base "$BASE" (the printed merge_base; no input: only a base the user named), --review-pr-pins "$RUN_DIR/pr-pins.json" for a materialized input (the invocation writes the printed JSON there with a second quoted heredoc, like the work item) and --aspects "$ASPECTS" when aspects were given. simplify pointer: run /review-loop:code-quality-loop on the change (its POLISH-Q simplifier) (Claude Code).

When this skill is the entry

This skill is the explicit paired-session entry and the review-loop handoff target only when the config key entry is paired-session or absent and the work is fresh, an existing plan (as the work item) or a review-only code target (an invalid value counts as absent, with a warning); entry: legacy is refused by the entry, since the legacy workflow was removed in v2.13.0.

Operator commands

Operator commands (accept, reject, withdraw-findings) follow the shared entry contract. Run withdraw-findings only on the user's explicit decision naming the findings and a nonempty reason, never on the host's own judgment or in handsfree mode. Issue --intent-only --finding ID --reason TEXT first (repeat --finding for each named id), show the digest, then submit the same command with --expect <digest> instead of --intent-only. Relay the ruling, evidence, next-step hint and status; withdrawal dispatches no model turn.

Lifecycle mode

--lifecycle-mode off is the supported stop-after-gate route: PLAN -> EXEC -> GATE -> DONE (acceptance pending). The operator then handles FINISH, POLISH-Q, docs, security review and merging. Accept never commits on this route: it hands back the uncommitted tree. New runs default to on (the full lifecycle); CLI, operator/workspace profiles and Python entry points may select off, and saved off runs resume, accept, reject, note and abort normally.

For review-pr report mode, always pass --lifecycle-mode on to run. This overrides a profile's off value. For other entries, pass --lifecycle-mode on only when no operator/workspace profile sets lifecycle_mode. When a profile sets it, omit the flag (or pass the profile's value). The CLI value overrides the profile. When the user chooses off for those entries, pass --lifecycle-mode off. Compare the saved lifecycle mode with that selected mode for the backstop; saved off runs continue with off.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.