From 683f2efd76f12f10c779bb5bf855e7210725e626 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Sun, 25 Oct 2026 11:54:40 -0400 Subject: [PATCH 1/3] fix(harness-ops): state the permission posture of every unattended claude -p The restart consumer's scheduled `claude -p` now passes `--permission-mode auto`, plus `--permission-prompts none` from Claude Code 2.1.259, as lane-launcher.sh does, instead of inheriting the user's defaultMode. The run-claude-cli pin test now walks every workflow, so a pin bump in pr-verify.yml or pr-unblock.yml fails until its launcher is checked. Co-Authored-By: Claude Opus 5.5 --- .../actions/resolve-config/callers.test.mjs | 24 +++++++++-------- .../skills/lanes/context/restart-consumer.md | 6 ++++- .../skills/lanes/scripts/restart-consumer.sh | 26 +++++++++++++++---- .../lanes/scripts/restart-consumer.test.sh | 20 ++++++++++++++ 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/.github/actions/resolve-config/callers.test.mjs b/.github/actions/resolve-config/callers.test.mjs index 2677718790..1cd1433cf4 100644 --- a/.github/actions/resolve-config/callers.test.mjs +++ b/.github/actions/resolve-config/callers.test.mjs @@ -1596,19 +1596,21 @@ const PERMISSION_PROMPTS_NONE_LAUNCHERS = new Set([ "d02b8697e092705153f0996549b05f95a446bb52", ]); -test("pr-run-activity-read.yml: every run-claude-cli pin is a launcher checked to pass --permission-prompts none", () => { - const pins = []; - for (const [id, job] of Object.entries(workflow("pr-run-activity-read.yml").jobs ?? {})) { - for (const step of job.steps ?? []) { - const uses = String(step.uses ?? ""); - if (!uses.includes("/run-claude-cli@")) continue; - const sha = uses.slice(uses.indexOf("@") + 1); - pins.push(sha); - assert.match(sha, /^[0-9a-f]{40}$/, `${id} ${step.id} pins a full SHA`); - assert.ok(PERMISSION_PROMPTS_NONE_LAUNCHERS.has(sha), `${id} ${step.id}: ${sha} is not checked to pass --permission-prompts none`); +test("every workflow's run-claude-cli pin is a launcher checked to pass --permission-prompts none", () => { + const files = new Set(); + for (const file of workflowFiles()) { + for (const [id, job] of Object.entries(workflow(file).jobs ?? {})) { + for (const step of job.steps ?? []) { + const uses = String(step.uses ?? ""); + if (!uses.includes("/run-claude-cli@")) continue; + const sha = uses.slice(uses.indexOf("@") + 1); + files.add(file); + assert.match(sha, /^[0-9a-f]{40}$/, `${file} ${id} ${step.id} pins a full SHA`); + assert.ok(PERMISSION_PROMPTS_NONE_LAUNCHERS.has(sha), `${file} ${id} ${step.id}: ${sha} is not checked to pass --permission-prompts none`); + } } } - assert.ok(pins.length >= 2, pins.join(", ")); + for (const file of ["pr-run-activity-read.yml", "pr-verify.yml", "pr-unblock.yml"]) assert.ok(files.has(file), [...files].join(", ")); }); // Each launcher leg is followed by a check that the CLI's init message diff --git a/plugins/harness-ops/skills/lanes/context/restart-consumer.md b/plugins/harness-ops/skills/lanes/context/restart-consumer.md index 4734f20ab1..ff0a2189d9 100644 --- a/plugins/harness-ops/skills/lanes/context/restart-consumer.md +++ b/plugins/harness-ops/skills/lanes/context/restart-consumer.md @@ -133,7 +133,11 @@ from cmd.exe. Two scheduled forms, different trade-offs: -- **Headless skill form**: `claude -p "/harness-ops:lanes consume-restarts run"`. +- **Headless skill form**: `claude -p "/harness-ops:lanes consume-restarts run" + --permission-mode auto --permission-prompts none`. The mode is stated, never + inherited from user settings; `--permission-prompts none` is printed only when + the CLI that runs `print-schedule` accepts it, so regenerate the schedule after + upgrading from an older CLI. Survives plugin updates (the skill resolves `${CLAUDE_PLUGIN_ROOT}` freshly at each invocation, so the task never embeds a plugin cache path that rots), but each tick is a paid model turn. Bound the spend: `claude` supports `--model` diff --git a/plugins/harness-ops/skills/lanes/scripts/restart-consumer.sh b/plugins/harness-ops/skills/lanes/scripts/restart-consumer.sh index 80100a8f9d..7b48489c71 100755 --- a/plugins/harness-ops/skills/lanes/scripts/restart-consumer.sh +++ b/plugins/harness-ops/skills/lanes/scripts/restart-consumer.sh @@ -217,6 +217,9 @@ CONSUMER_MARKER="harness-ops:restart-consumer" CONSUMER_LANE="restart-consumer" SENTINEL_PREFIX="