feat: add copilot CLI steering hooks for time and run budgets#30500
feat: add copilot CLI steering hooks for time and run budgets#30500
Conversation
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d69918d3-92bc-47f8-be39-1a214fbbf7cd Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d69918d3-92bc-47f8-be39-1a214fbbf7cd Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d69918d3-92bc-47f8-be39-1a214fbbf7cd Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d69918d3-92bc-47f8-be39-1a214fbbf7cd Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d69918d3-92bc-47f8-be39-1a214fbbf7cd Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d69918d3-92bc-47f8-be39-1a214fbbf7cd Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/d69918d3-92bc-47f8-be39-1a214fbbf7cd Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds Copilot CLI “steering” hook support to the Copilot harness to warn/block when the session is nearing time or run-budget exhaustion.
Changes:
- Install a runtime Copilot hook config (
.github/hooks/gh-aw-steering.json) before launching the Copilot CLI and export env vars used by the hook. - Add a new
copilot_steering_hook.cjscommand hook that persists per-session state and emits warning/critical “block” steering decisions based on remaining time/runs. - Clean up the per-run steering state file after harness completion and extend Vitest coverage for autopilot parsing and hook config generation.
Show a summary per file
| File | Description |
|---|---|
| actions/setup/js/copilot_steering_hook.cjs | New hook script that tracks session state and emits steering decisions on low time/run budgets. |
| actions/setup/js/copilot_steering_hook.test.cjs | Unit tests for config loading, state initialization, and warning/critical decision behavior. |
| actions/setup/js/copilot_harness.cjs | Installs hook config + per-run state path/env vars; parses max autopilot continues; cleans up steering state file. |
| actions/setup/js/copilot_harness.test.cjs | Tests for autopilot/run-budget helpers and hook config command quoting. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 4/4 changed files
- Comments generated: 2
| function saveState(statePath, state) { | ||
| fs.writeFileSync(statePath, JSON.stringify(state), "utf8"); | ||
| } |
| function loadState(statePath) { | ||
| try { | ||
| if (!fs.existsSync(statePath)) { | ||
| return null; | ||
| } | ||
| const raw = fs.readFileSync(statePath, "utf8"); | ||
| return /** @type {SteeringState} */ JSON.parse(raw); | ||
| } catch { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Ugh, me agree! loadState trust too much. Me caveman but me know: always validate data before use. Good catch!
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
📰 BREAKING: Report filed by Smoke Copilot · ● 18.2M
|
@copilot review all comments |
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/10b67751-6800-491f-97fd-2b102bbee5ca Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed all actionable review threads in commit
Validation passed with targeted JS tests and Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
|
|
📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing... |
|
✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟 |
|
🚀 Smoke Pi MISSION COMPLETE! Pi delivered. 🥧 |
|
🎬 THE END — Smoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨ |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal! (Run 25472644901)
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
💥 [THE END] — Illustrated by Smoke Claude · ● 254.7K
| @@ -0,0 +1,5 @@ | |||
| --- | |||
There was a problem hiding this comment.
🔍 Smoke Test Review Comment #1 (Run 25472644901): Changeset file looks good — patch type is appropriate for the steering hook additions.
| --- | ||
| "gh-aw": patch | ||
| --- | ||
|
|
There was a problem hiding this comment.
🔍 Smoke Test Review Comment #2 (Run 25472644901): Description clearly explains the feature. The steering hook pattern for time/run budget warnings is a solid approach for agent guardrails.
This comment has been minimized.
This comment has been minimized.
|
Ugh! Me caveman smoke agent! Me was HERE! All tests PASS! Me strong tester! Code good, no bugs found, me happy caveman! 🦴🔥 Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
|
✅ Smoke test PASS! GitHub MCP ✅ | MCP Scripts ✅ | Serena ✅ | Playwright ✅ | Build ✅ | Artifact ✅ | Discussion ✅ | Haiku Dispatch ✅ | PR Review ✅ | Sub-Agent ✅ | Overall: PASS | Author: app/copilot-swe-agent | Assignees: Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
There was a problem hiding this comment.
Oog! Caveman review PR. Good steering hooks! Constants clear, hook install function safe with error handling. Me happy with changes.
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
📰 BREAKING: Report filed by Smoke Copilot · ● 17.4M
| const fs = require("fs"); | ||
| const path = require("path"); | ||
|
|
||
| const DEFAULT_TIMEOUT_MINUTES = 30; |
There was a problem hiding this comment.
Oog! Me see default timeout 30 minutes. Good number. But maybe put all defaults together in config object? Easier to read for caveman brain.
| const DEFAULT_TIME_CRITICAL_MINUTES = 2; | ||
| const DEFAULT_RUN_WARNING_REMAINING = 2; | ||
| const DEFAULT_RUN_CRITICAL_REMAINING = 1; | ||
| const DEFAULT_STATE_PATH = "/tmp/gh-aw/copilot-steering-state.json"; |
There was a problem hiding this comment.
State path in /tmp good. But maybe make configurable via env var? More flexible. Me like flexibility.
There was a problem hiding this comment.
Ugh! Me agree! Configurable env var better. Flexibility good for caveman and modern dev alike!
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
📰 BREAKING: Report filed by Smoke Copilot · ● 17.7M
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
|
@copilot also set GITHUB_COPILOT_PROMPT_MODE_EXTENSIONS=true env var Extensions follow a mixed model (v1.0.41+): user-level extensions (from ~/.copilot/) load automatically in prompt mode, but project-level extensions and management tools are disabled by default — opt in with GITHUB_COPILOT_PROMPT_MODE_EXTENSIONS=true to load them. |
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/bdf49744-5d3c-48dc-9fdf-652f22b1eed5 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in I set No UI changes in this update. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
💫 TO BE CONTINUED... Smoke Claude failed to deliver outputs! Our hero faces unexpected challenges... |
|
🚀 Smoke Pi MISSION COMPLETE! Pi delivered. 🥧 |
|
📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing... |
|
✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟 |
|
|
|
Smoke Test Codex 25474180966: FAIL Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
|
💥 Smoke Test 25474180964 — PARTIAL PASS
Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
There was a problem hiding this comment.
💥 Automated smoke test review - all systems nominal! Run 25474180964 complete.
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
💥 [THE END] — Illustrated by Smoke Claude · ● 223K
| * statePath: string, | ||
| * hookLogPath: string | ||
| * }} | ||
| */ |
There was a problem hiding this comment.
Smoke test review comment #1 🔬
The loadSteeringConfig function cleanly reads steering config from environment variables with sensible defaults. Consider adding JSDoc comments to document the expected env var names and their valid value ranges for better discoverability and maintainability.
|
|
||
| await checkCommandAccessible(command); | ||
| const resolvedArgs = resolvePromptFileArgs(args); | ||
| installCopilotSteeringHooks(resolvedArgs); |
There was a problem hiding this comment.
Smoke test review comment #2 🔬
installCopilotSteeringHooks(resolvedArgs) is called after resolvePromptFileArgs, which is the right placement — hooks are installed before the agent run. The try/catch approach that logs warnings rather than failing is appropriate for a non-critical enhancement. ✅
This comment has been minimized.
This comment has been minimized.
1 similar comment
Agent Container Tool Check
Result: 12/12 tools available ✅ Overall Status: PASS
|
|
Ugh! Caveman smoke test agent was here again! Run §25474180939 complete. Me test many things. Most pass! Cave paintings better than no tests! Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
|
🎉 WOOHOO! Caveman dance around fire! Smoke test agent leave big mark here! All tools work! Build good! Playwright see GitHub! Serena find symbols! Me very happy! UGH UGH UGH! 🦴🔥 Warning Firewall blocked 6 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
|
There was a problem hiding this comment.
Caveman look at code. Steering hooks good! State path configurable via env var. Parse numbers safe. Me approve mostly. Ugh!
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.com
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "accounts.google.com"
- "android.clients.google.com"
- "clients2.google.com"
- "contentautofill.googleapis.com"
- "safebrowsingohttpgateway.googleapis.com"
- "www.google.com"See Network Configuration for more information.
📰 BREAKING: Report filed by Smoke Copilot · ● 17.7M
| const DEFAULT_STATE_PATH = "/tmp/gh-aw/copilot-steering-state.json"; | ||
| const DEFAULT_HOOK_LOG_PATH = "/tmp/gh-aw/sandbox/agent/logs/copilot-steering-hook.log"; | ||
| const MS_PER_MINUTE = 60000; | ||
|
|
There was a problem hiding this comment.
Me see hard-coded path /tmp/gh-aw/copilot-steering-state.json. Good fallback! But env var override GH_AW_COPILOT_STEERING_STATE_PATH exist - maybe document in README?
| */ | ||
| function parsePositiveNumber(rawValue, fallback) { | ||
| const parsed = parseFloat(rawValue || ""); | ||
| return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback; |
There was a problem hiding this comment.
Me like parsePositiveNumber! Safe parse. Ugh, maybe add test for NaN input too?
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤 |
Summary
.github/hooks/gh-aw-steering.jsonhook configuration before agent executionactions/setup/js/copilot_steering_hook.cjscommand hook that tracks session state and injects warning/critical steering prompts on low time or low run budgetsessionStart,sessionEnd, andagentStopcommand hookssessionEndGITHUB_COPILOT_PROMPT_MODE_REPO_HOOKS=truefrom the harness so steering hooks are loaded when prompt mode (-p) is usedGITHUB_COPILOT_PROMPT_MODE_EXTENSIONS=truefrom the harness1.0.43) and regenerate compiled workflow outputs/golden fixtures to match the new defaultmainand resolve harness merge overlap around post-run reflect/load-status behaviorValidation
make build && make fmtnpm run typecheck(inactions/setup/js)npm run lint:cjs(inactions/setup/js)npm run test:js -- copilot_harness.test.cjs copilot_steering_hook.test.cjs --no-file-parallelism(inactions/setup/js)make recompilemake update-wasm-goldenmake agent-report-progresssecret_scanningon changed filesparallel_validation(Code Review + CodeQL; Code Review passed, CodeQL reported no analyzable language changes)Notes
make agent-report-progresswas rerun when unrelated flakypkg/cliprogress-notification tests intermittently failed; final run passed.Changeset
1.0.43with regenerated compiled outputs.> Generated by Changeset Generator for issue #30500 · ◷
✨ PR Review Safe Output Test - Run 25432297510
> [!WARNING]
>
> 💥 THE END] — Illustrated by [Smoke Claude · ● 405K · ◷
✨ PR Review Safe Output Test - Run 25444740277
> [!WARNING]
>
> 💥 THE END] — Illustrated by [Smoke Claude · ● 378.9K · ◷
✨ PR Review Safe Output Test - Run 25472644901
> [!WARNING]
>
> 💥 THE END] — Illustrated by [Smoke Claude · ● 254.7K · ◷
✨ PR Review Safe Output Test - Run 25474180964
Warning
Firewall blocked 6 domains
The following domains were blocked by the firewall during workflow execution:
accounts.google.comandroid.clients.google.comclients2.google.comcontentautofill.googleapis.comsafebrowsingohttpgateway.googleapis.comwww.google.comSee Network Configuration for more information.