GitHub Copilot AI Credits Optimization — Optional Module 4: Agent Fleet Efficiency and Cost Governance — Hands-On Lab Guide
Duration: ~77 minutes of hands-on exercises within the 170-minute module; the optional runnable appendix adds 45 minutes
Format: Design and review exercises with worksheets and answer keys, plus one optional runnable appendix
Audience: Platform and DevEx engineers, automation and SRE-adjacent engineers, Copilot program owners
Repository: No repository is required for the core labs. The optional appendix requires a personal or non-production sandbox repository you own
Lab Overview
This lab guide contains the hands-on work for Optional Module 4 of the GitHub Copilot AI Credits Optimization curriculum. Each lab maps to one workshop section and to one learning objective. Complete them in order — Lab 6 consumes the outputs of Labs 1–5.
Important: Labs 1–6 require no paid AI request, no Copilot license, and no live product access. They are completed with the supplied scenarios, worksheets, and answer keys. Appendix A is optional, bounded, and spends AI credits; it is not required for any learning objective.
Important: All scenarios in this guide are synthetic. Do not use customer repositories, production identities, production queues, or real incident data in any exercise.
Prerequisites
| Requirement | Applies to | Details |
|---|---|---|
| Module 2 and Module 3 concepts | Labs 1–6 | AI credits, token categories, cached input, budgets, durable accepted outcomes |
| Printed or shared templates | Labs 1–6 | Printable copies are inlined in Appendix B of this guide; editable sources are in templates/ beside this guide |
| Pen, worksheet, or text editor | Labs 1–6 | No product access needed |
| Copilot CLI installed | Appendix A only | Verify with copilot --version — this proves installation only |
| Copilot CLI authenticated | Appendix A only | Separate step: authenticate with copilot login, or supply COPILOT_GITHUB_TOKEN / GH_TOKEN / GITHUB_TOKEN (that precedence) |
| Copilot license you are authorized to spend from | Appendix A only | Appendix A makes a small number of bounded paid calls |
| Non-production sandbox repository you own | Appendix A only | Never a customer, production, or shared repository |
| Approval to spend a small number of AI credits | Appendix A only | Confirm your budget owner is aware before running |
| A shell you can copy commands into | Appendix A only | Appendix A gives PowerShell (Windows-first) commands with a bash alternative for each step |
Setup
- Open the four templates. Printable copies are inlined in Appendix B of this guide; the editable sources live in the
templates/folder beside it:lane-profile-worksheet.mdcache-key-review-worksheet.mdfailure-taxonomy-worksheet.mdcanary-scorecard.md
- Form pairs or groups of three. Each group needs one person who can describe a real automated workload from their own environment in general terms — no customer names, repository names, or internal figures.
- Agree on a shared vocabulary before starting: lane, lane profile, session tax, pre-spend gate, fingerprint, lease, outcome, durable accepted outcome.
Setup Checkpoint
- ✅ Every group has all four templates available
- ✅ Every group has one anonymized real workload to reason about
- ✅ Everyone agrees that no exercise in Labs 1–6 will call a model
- ✅ If Appendix A will be delivered, everyone has confirmed a sandbox repository and spend authorization
Lab Summary
| Lab | Workshop section | Exercise | Time |
|---|---|---|---|
| 1 | 1 — Measure the Fixed Session Tax | Session-tax inventory and baseline design | 10 min |
| 2 | 2 — Lane Profiles | Design three lane profiles | 15 min |
| 3 | 3 — Isolation and Ownership | Two-watcher fleet review | 10 min |
| 4 | 4 — Pre-Spend Gates and Caching | Unsafe cache-key review | 15 min |
| 5 | 5 — Runtime Governance | Dispatcher outcome taxonomy | 15 min |
| 6 | 6 — Landing, Telemetry, and Rollout | Capstone: checklist and canary scorecard | 12 min |
| A | Optional | Runnable bounded Copilot CLI probes | 45 min |
| B | Reference | Printable copies of the four templates | Not timed |
Core hands-on total: 77 min (inside the 170-minute module). Optional appendix A: +45 min. Appendix B is reference material and adds no time.
Lab 1: Session-Tax Inventory and Baseline Design (10 min)
Workshop Section: 1 — Measure the Fixed Session Tax
Objective: Identify what a programmatic invocation pays for before it starts working, and design a baseline experiment that could prove it.
Starting State
You are handed the following lane description. Nothing has been measured.
LANE: nightly-dependency-audit
Runs: 1 invocation per repository per night, 240 repositories
Invocation: copilot -p "$PROMPT" --allow-all-tools
Working dir: /home/automation/workspaces/monorepo-parent/<repo>
Discovered: AGENTS.md at the monorepo parent (human onboarding guide, long)
.github/copilot-instructions.md in each repository (short, mechanical)
3 MCP servers configured at user scope (issue tracker, wiki, code search)
2 skills installed at user scope
Model: not specified
Effort: not specified
Memory: not specified
Output: plain text captured to a log file
Task: list dependencies with known advisories and open one issue per finding
Steps
- (3 min) List every contributor to this lane's session tax. For each, mark it
REQUIRED,OPTIONAL, orUNKNOWNfor this task, and name the instrument you would use to inspect it. - (3 min) List every unbounded or unspecified element that could change cost from night to night.
- (4 min) Write a baseline experiment for one single factor. Specify: probe prompt, pinned configuration, number of repetitions, recorded fields, and the one variable that changes between arms.
Expected Result
A one-page inventory plus a baseline experiment that a colleague could run without asking you a question.
Answer Key
Session-tax contributors
| Contributor | Verdict | Instrument |
|---|---|---|
| System prompt and built-in tool definitions | REQUIRED |
/context — System Prompt and System Tools rows |
Parent AGENTS.md (human onboarding guide) |
OPTIONAL — almost certainly not needed by this task |
/context — Custom Instructions row; copilot plugins list --kind instruction |
Repository copilot-instructions.md |
UNKNOWN — may carry dependency conventions |
Same as above, plus a quality comparison |
| Wiki MCP server | OPTIONAL — no obvious role in a dependency audit |
copilot plugins list --kind mcp |
| Issue-tracker MCP server | UNKNOWN — the task opens issues, so it may be the intended path |
Same |
| Code-search MCP server | UNKNOWN |
Same |
| Two user-scope skills | UNKNOWN |
copilot plugins list --kind skill |
| Memory | OPTIONAL — disabled by default in prompt mode; confirm the harness does not enable it |
Lane profile review |
Unbounded or unspecified elements
- No
--model, so the lane inherits a default that can change without review. - No
--effort, so reasoning depth is unpinned. --allow-all-toolsgrants full tool permission; there is no visibility restriction at all.- No
--max-ai-credits, so a single pathological repository has no per-run ceiling. - No
--no-ask-user, so an unattended run can stall waiting for input. - Working directory sits under a parent that carries a long human-oriented instruction file.
- Advisory output size per repository is unbounded.
- Plain-text output makes per-run accounting hard;
--output-format=jsonwould be machine-readable.
Baseline experiment (example)
- Probe prompt:
Reply with the single word OK. - Pinned: one model,
--effort low, one working directory, fresh session per run,--no-ask-user,--output-format=json. Do not add-s— it prints only the agent response and suppresses the stats you are trying to measure. - Arms: (A) current discovery as-is; (B) identical, plus
--disable-builtin-mcps. - Repetitions: at least 5 runs per arm; report median and range.
- Recorded fields: AI credits, input/cached-input/output tokens, latency, outcome, exit status.
- Second experiment, run separately: repeat the same design with
--no-custom-instructionsas the single variable. One arm, one variable — never both in the same comparison. - Follow-up arm: repeat with 3 representative real repositories to check quality parity before adopting arm B.
Success Criteria
- ✅ Every contributor is classified
REQUIRED,OPTIONAL, orUNKNOWNwith a named instrument - ✅ At least four unbounded or unspecified elements are identified, including the missing model pin
- ✅ The baseline experiment changes exactly one variable and specifies repetitions
- ✅ The plan includes a real-task quality check, not only the trivial probe
- ✅ No token or credit figure is invented from memory
Lab 2: Design Three Lane Profiles (15 min)
Workshop Section: 2 — Lane Profiles
Objective: Build least-context, least-tool, least-permission profiles and state the evidence required before adopting each reduction.
Starting State
Use the Lane Profile Worksheet (templates/lane-profile-worksheet.md, printable copy in Appendix B). Your fleet has three lanes:
| Lane | Description |
|---|---|
| A — Repository audit | Read a repository and produce a findings report. Must not modify anything |
| B — Bounded test fix | One failing test named in the work item; a deterministic test command proves success |
| C — Release-note synthesis | Convert a supplied structured changelog into a formatted release note. No repository access required |
Steps
- (9 min) Complete one worksheet per lane. Fill every field; write
UNKNOWN — measurerather than guessing. - (3 min) For each reduction you propose (fewer tools, no MCP servers, no custom instructions, lighter model, lower effort), write the evidence you would require before adopting it in production.
- (3 min) Identify the one field in each lane most likely to cause a silent failure if you get it wrong.
Expected Result
Three completed worksheets where every restriction is enforced by a flag, not by prompt wording.
Answer Key
Lane A — Repository audit (read-only)
| Field | Answer |
|---|---|
| Tool visibility | Read and search tools only, using the tool names your installed CLI reports (verify; do not copy a list) |
| Tool permission | Deny write; deny shell (deny always wins) — this is the enforcement that makes the lane read-only |
| MCP servers | None required; --disable-builtin-mcps unless a finding must be filed through an MCP tool |
| Custom instructions | Only if the report format depends on repository conventions |
| Model and effort | Lighter model, low effort |
| Credit cap | --max-ai-credits set above the CLI minimum of 30 |
| Output | --output-format=json plus --share for audit trail (leave -s off anything you measure) |
| Silent-failure risk | A read-only rule stated only in the prompt, or a visibility list whose tool names do not match this version — enforce with --deny-tool |
Lane B — Bounded test fix
| Field | Answer |
|---|---|
| Tool visibility | Read, search, edit, and the specific shell commands the test run needs |
| Tool permission | Allow scoped shell and write; deny shell(git push); deny writes outside the target path |
| MCP servers | Only servers the fix path uses |
| Custom instructions | Yes — the fix must follow repository conventions |
| Model and effort | Mid-tier with a coded escalation rule tied to the deterministic check (one escalation step per fingerprint, recorded in the ledger) |
| Credit cap | Moderate --max-ai-credits (above the CLI minimum of 30); a run that exhausts it is run_cap_exhausted, not an automatic retry |
| Isolation | Isolated worktree or clone per worker, with cleanup |
| Silent-failure risk | Escalation by habit instead of by measured signal; also unverified "fixed" claims without running the test |
Lane C — Release-note synthesis
| Field | Answer |
|---|---|
| Tool visibility | Minimal or none — this is text-to-text |
| Tool permission | Deny write and shell |
| MCP servers | None |
| Custom instructions | Usually none |
| Model and effort | Mid-tier, low effort |
| Prompt budget | Hard cap on changelog size with a visible truncation marker and a context_too_large outcome |
| Silent-failure risk | Unbounded input growth as the changelog accumulates |
Evidence required before adopting any reduction
- A baseline and a reduced arm measured on the same representative task mix.
- Durable acceptance and human correction time compared, not just tokens or credits.
- A canary lane, a rollback trigger, and an owner (Lab 6).
Success Criteria
- ✅ All three worksheets have every field completed or explicitly marked
UNKNOWN — measure - ✅ Every read-only claim is enforced by a visibility or permission flag
- ✅ Each proposed reduction has named evidence attached
- ✅ Lane B specifies an escalation rule that lives in code, not in operator habit
- ✅ Each lane names its most likely silent-failure field
Lab 3: Two-Watcher Fleet Review (10 min)
Workshop Section: 3 — Isolation, Worktrees, and Concurrent Ownership
Objective: Find inheritance and ownership defects that cause duplicate or misconfigured spend.
Starting State
WATCHER 1: "failing-tests" — scans all repositories every 10 minutes for failing tests
WATCHER 2: "flaky-tests" — scans the same repositories every 15 minutes for flaky tests
Both watchers:
- run as the same automation identity
- share one checkout at /srv/agents/workspace
- build the prompt, then invoke Copilot CLI with --allow-all
- delete the queue item as soon as the CLI exits with status 0
- have no attempt limit per target
- were recently moved from /srv/monorepo/tools to /srv/agents to "reduce inherited context"
Steps
- (4 min) List every defect you can find. Group them as inheritance, ownership, isolation, or landing defects.
- (3 min) For each ownership defect, specify the fingerprint, lease, and dedupe rule that fixes it.
- (3 min) Specify the verification step that proves the move to
/srv/agentsdid not silently remove needed configuration.
Expected Result
A defect list with a concrete fix for each, including one verification command.
Answer Key
| Defect | Category | Fix |
|---|---|---|
| Both watchers can select the same failing test as a target | Ownership | Fingerprint on target plus error signature; single-owner time-bounded lease; disjoint scope by construction |
| No attempt limit per target | Ownership | Attempt ledger keyed by fingerprint with a hard cap and a parked state |
| Shared checkout allows workers to corrupt each other's working tree | Isolation | One worktree or clone per worker with guaranteed cleanup |
--allow-all grants full permission for both lanes |
Isolation / security | Replace with explicit --deny-tool rules for everything mutating that the lane must not do, then narrow visibility with --available-tools using tool names verified in this CLI version |
| The move may have dropped needed MCP servers, instructions, or skills | Inheritance | Run copilot plugins list from the exact working directory the harness uses and compare against the expected inventory; pass MCP configuration explicitly if it is required |
| Saved interactive approvals may leak into automation running as the same identity | Inheritance | Isolate per-lane configuration state (for example, a dedicated COPILOT_HOME per lane — a harness pattern to verify in your environment) and pass permissions per invocation |
| Deleting the queue item on exit status 0 | Landing | Acknowledge only after validated, persisted, and consumed output (Section 6); use a distinct signal for "nothing to do" |
| No per-run credit cap | Governance | Add --max-ai-credits per lane (minimum 30 in CLI v1.0.79), remembering it is a soft limit in public preview |
| Shared worktrees or checkouts left behind by killed runs | Isolation | Unique worktree or clone name per run, cleanup on exit, and a recovery step (git worktree list → git worktree remove → git worktree prune) |
Success Criteria
- ✅ At least six defects identified and categorized
- ✅ A fingerprint, lease, and dedupe rule specified for the overlap
- ✅ Per-worker workspace isolation with cleanup specified
- ✅ The verification step names running the inventory from the harness's actual working directory
- ✅ The premature acknowledgment defect is identified as a landing problem, not a cost problem
Lab 4: Unsafe Cache-Key Review (15 min)
Workshop Section: 4 — Pre-Spend Gates, Cache Correctness, and Prompt Budgets
Objective: Find cache-key omissions and name the specific wrong result each one can produce.
Starting State
Use the Cache-Key Review Worksheet (templates/cache-key-review-worksheet.md, printable copy in Appendix B). A team ships this cache to avoid re-scoring unchanged files:
CACHE DESIGN v1
key = sha256(file_contents)
value = { score: int, rationale: string }
ttl = none
negative cache = yes, failures cached like successes
bypass = none
provenance = none
invalidation = manual, by deleting the cache directory
NOTES
- The scoring rubric lives in prompts/rubric.md and is edited about twice a month
- The lane recently changed from a lighter model to a mid-tier model
- Reasoning effort was raised from low to high last week
- Some entries were written before the team added a "severity" field to the value
Steps
- (6 min) List every missing key component and, for each, the specific wrong outcome it can produce.
- (5 min) Rewrite the cache design: key components, value schema, provenance, TTL, invalidation, negative-result policy, and bypass.
- (4 min) Decide what the system should do when it encounters an entry written before the schema change.
Expected Result
A corrected cache design that a reviewer could approve without further questions.
Answer Key
| Missing component | Wrong outcome it produces |
|---|---|
| Fully rendered prompt (including rubric text) | After a rubric edit, every unchanged file keeps its old rubric's verdict forever — the most dangerous omission here |
| Model identifier | Verdicts produced by the previous lighter model are served as if produced by the current model |
| Reasoning effort | Low-effort verdicts are served after the lane moved to high effort |
| Context tier | default and long_context results are treated as interchangeable |
| Tool visibility and permission set | A verdict produced without repository access is served for a lane that now has it |
| MCP configuration | Capability differences are invisible in the key |
| Repository state beyond the single file | Verdicts that depend on neighboring files or configuration go stale silently |
| Harness and CLI version | Behavior changes across versions are invisible |
| TTL | Nothing ever expires, so staleness is unbounded |
| Provenance | You cannot audit which configuration produced a stored verdict |
| Negative-result policy | A transient outage is cached as a permanent failure |
| Bypass | No safe way to force a re-run during an incident |
Corrected design (example)
CACHE DESIGN v2
key = sha256(
rendered_prompt # includes rubric and template text
+ rubric_version
+ model_id
+ reasoning_effort
+ context_tier
+ tool_visibility_set
+ tool_permission_set
+ mcp_config_hash
+ input_state_hash # file contents plus relevant neighbors/config
+ harness_version
+ cli_version )
value = { schema_version, score, severity, rationale, produced_at, run_id }
provenance = { key_components, lane, profile_hash, accepted_later: bool }
ttl = 30 days, plus immediate invalidation on any profile change
negative = cache deterministic refusals only; never cache service_unavailable
bypass = harness --no-cache flag (your runner, not a Copilot CLI option), logged every time it is used
migration = entry missing any key component or schema_version -> treat as MISS
Old-schema entries: treat as a miss and re-run. Never infer a missing field, and never serve a value whose schema version is unknown.
Success Criteria
- ✅ At least eight missing components identified
- ✅ The rendered-prompt/rubric omission is identified as the highest-severity defect
- ✅ The corrected key includes model, effort, context tier, tool sets, and versions
- ✅ Negative caching distinguishes deterministic refusals from transient failures
- ✅ Missing or unknown key components are treated as a cache miss
Lab 5: Dispatcher Outcome Taxonomy (15 min)
Workshop Section: 5 — Runtime Governance
Objective: Map real run results to outcomes, retry behavior, breaker counting, and queue action.
Starting State
Use the Failure Taxonomy and Breaker Worksheet (templates/failure-taxonomy-worksheet.md, printable copy in Appendix B). Today the dispatcher has exactly two outcomes: ok (exit status 0) and failed (anything else). Failures are retried immediately up to 10 times, and 5 consecutive failures trip a breaker that parks the lane for 7 hours.
Steps
- (8 min) Classify each of the nine run results below: outcome name, retry behavior, whether it counts toward the breaker, and queue action.
- (4 min) Identify which current behaviors cause a retry storm, a breaker misfire, or silent work loss.
- (3 min) Propose the backoff schedule, park window, breaker rule (including how long the breaker stays open), and dead-letter policy you would ship instead.
Run results to classify
- The test named in the work item already passes before any model call.
- The model edited a file, but the deterministic test still fails.
- The CLI returned a permission error because the lane denies
writeand the task requires it. - The prompt assembler found the diff exceeds the lane's input budget.
- The service returned a transient network error after 40 seconds.
- The harness budget module refused the call before it was made: the lane's window envelope was already spent.
- The lane profile references a model name the CLI does not recognize.
- The run succeeded and the report was written, but the consumer directory does not exist.
- The run started, consumed nearly all of its per-run
--max-ai-creditscap, and stopped mid-task without producing a usable result.
Answer Key
| # | Outcome | Retry | Counts toward breaker | Queue action |
|---|---|---|---|---|
| 1 | already_green |
No | No | Acknowledge with reason; record as a free success |
| 2 | model_failure |
Yes, bounded by the attempt ledger | Yes | Retain, increment attempt |
| 3 | policy_denied |
No | No | Retain and alert an owner — the profile or the task is wrong |
| 4 | context_too_large |
No — fix the input first | No | Retain and flag for prompt-budget redesign |
| 5 | service_unavailable |
Yes, with exponential backoff and jitter | No | Retain |
| 6 | budget_refused (pre-spend, no credits used) |
Not immediately — park the worker | No | Retain; retry unchanged after the park window; do not increment the attempt counter |
| 7 | invalid_config |
No | No | Halt the lane and alert; an unrecognized model name is a configuration error to fix, not a condition to retry |
| 8 | landing_failed |
Yes, after the path is resolved | No | Retain — never acknowledge; this is paid work that did not land |
| 9 | run_cap_exhausted (post-spend) |
Not automatically | No | Retain; record the spend, increment the attempt counter, and require task decomposition or an explicit reviewed cap decision before another attempt |
Current behaviors that break
- Retry storm: immediate retries with no backoff, plus retrying
policy_denied,context_too_large, andinvalid_config, which can never succeed on retry. - Most expensive retry storm: retrying
run_cap_exhaustedunchanged — every attempt pays close to the whole cap and lands nothing. - Breaker misfire: counting every non-zero exit toward the streak lets routing, budget, and configuration errors trip the breaker and take down a healthy lane.
- Silent work loss: treating exit status 0 as success acknowledges case 8, where nothing landed.
- Attempt-ledger corruption: counting case 6 as an attempt eventually dead-letters work that was never actually tried.
- Throughput loss: a 7-hour park is far longer than most incidents last.
Recommended replacement
- Backoff: 10m → 20m → 40m with jitter, capped at 40m; maximum 3 attempts per fingerprint.
- Park on
budget_refusedfor a fixed window (30 minutes is a reasonable start); log one summary line, not one line per item; leave the attempt counter untouched. - On
run_cap_exhausted: record the spend against the lane, increment the attempt counter, and block further attempts on that fingerprint until the work item is decomposed or the cap is changed by a named owner. - Breaker: 5 consecutive
model_failureoutcomes only; open for 20 minutes, then half-open with exactly one probe item — close on success, reopen for another 20 minutes on failure; alert the lane owner on every trip. - Dead-letter after the attempt cap with last outcome, profile hash, and transcript pointer retained.
Success Criteria
- ✅ All nine results classified with outcome, retry, breaker, and queue action
- ✅
already_greenandcontext_too_largeare excluded from breaker counting - ✅ Case 6 and case 9 are given different outcomes, and only case 9 records spend and increments the attempt counter
- ✅ Case 8 is retained rather than acknowledged
- ✅ Retry storm, breaker misfire, and silent work loss are each identified with a cause
- ✅ The proposed backoff, park window, breaker rule (including open duration), and dead-letter policy are specific
Lab 6: Capstone — Fleet Lane Optimization Checklist and Canary Scorecard (12 min)
Workshop Section: 6 — Durable Landing, Telemetry, Canary Rollout, and Capstone
Objective: Produce a canary-ready plan for one real lane, with a quality gate, a rollback trigger, and an owner.
Starting State
Each group picks one anonymized real lane from a member's environment (or Lane A, B, or C from Lab 2 if no real lane is available). You will need your Lab 1–5 outputs.
Steps
- (6 min) Complete the Fleet Lane Optimization Checklist section of the canary scorecard (
templates/canary-scorecard.md, printable copy in Appendix B) for that lane: profile, gates, governance, landing, telemetry. - (4 min) Complete the Canary Scorecard: the single variable you will change, the baseline you will capture, the quality-parity gate, the cost metric, the rollback trigger, and the owner.
- (2 min) Each group reports one line: "Our canary lane is X, our single variable is Y, and we roll back if Z."
Expected Result
One completed scorecard per group, ready to take back to a real backlog.
Answer Key — Model Response
A complete scorecard names all of the following:
- Canary lane: highest volume with the lowest blast radius and a clear acceptance signal.
- Single variable: exactly one profile element (for example, disabling two MCP servers that the audit lane never uses).
- Baseline: median and range for credits, latency, retries, and durable acceptance over a stated window before the change.
- Quality-parity gate: durable acceptance and human correction time must not regress beyond an agreed tolerance.
- Cost metric: full cost per durable accepted outcome — not tokens saved.
- Adversarial review: integration seams, cache-key completeness, flag spelling, exit-code blast radius.
- Rollback trigger: a specific, pre-agreed threshold and a named person allowed to pull it without a meeting.
- Deployment verification: restart the worker and confirm the new behavior in live logs.
Success Criteria
- ✅ The checklist is complete for one specific lane, with unknowns marked
UNKNOWN — measure - ✅ Exactly one variable is changed in the canary
- ✅ A quality-parity gate is stated in measurable terms
- ✅ The cost metric is full cost per durable accepted outcome
- ✅ A rollback trigger and a named owner are recorded
- ✅ Deployment verification in live logs is included
Backup Path: Sample Inventory Output (No Product Access)
Use this when the facilitator cannot run copilot plugins list live — no CLI installed, no network, restricted machine, or a demo that failed once. It supports Lab 1 (session-tax inventory) and Lab 3 (verifying what a working directory contributes).
Important: The listing below is illustrative and synthetic. It was written for teaching and is not captured from any customer, production, or personal environment. Real output differs by machine, repository, version, and configuration — never quote counts, names, or costs from it as fact.
Command (illustrative)
$ copilot plugins list
Sample output (illustrative — synthetic, not a real environment)
MCP servers:
User:
✓ issue-tracker -- http transport
✓ wiki-search -- stdio transport
✓ code-search -- http transport
Built-in:
✗ github-mcp-server -- stdio transport (disabled for this directory)
Skills:
User:
✓ release-notes-formatter -- Format a structured changelog into release notes.
✓ dependency-advisories -- Summarize dependency advisories for a repository.
Repository:
✓ run-unit-tests -- Run the repository's unit test command and report failures.
Built-in:
✓ github-pr-media -- Upload media and embed it in a pull request or comment.
Instructions:
Repository:
✓ .github/copilot-instructions.md
Working Directory:
✓ AGENTS.md
✓ team-onboarding.instructions.md
Language servers:
Repository:
✓ typescript-language-server
Plugins:
User:
✓ internal-platform-tools
How to use it in the room
| Question to ask | What the sample shows |
|---|---|
| Which of these would a nightly dependency audit actually use? | dependency-advisories and possibly issue-tracker; wiki-search, release-notes-formatter, and team-onboarding.instructions.md are candidates for removal |
| What is grouped by scope, and why does it matter? | User scope follows the identity; repository and working-directory scope follow the checkout — moving a worker changes the second group, not the first |
| What is missing from this inventory? | Custom agents and session-scoped hooks are not covered by plugins list; they require a live session |
| What can this output tell you about cost? | Only what is present. It shows no token or credit figures — those must be measured with /context and /usage in your own environment |
Note:
copilot plugins listperforms discovery only and makes no model call, so running it costs nothing when the environment does allow it.
Core Lab Cleanup
Labs 1–6 create no product state. Before leaving:
- ✅ Confirm no worksheet contains customer names, repository names, identities, or internal figures
- ✅ Decide who keeps the completed scorecard and where it will live
- ✅ Record any claim your group could not verify as a follow-up item for the technical accuracy owner
Core Lab Troubleshooting
| Symptom | Cause | Recovery |
|---|---|---|
| A group has no real lane to analyze | Audience is pre-automation | Use Lane A, B, or C from Lab 2 as the capstone subject |
| A group argues about exact token overhead numbers | Those numbers are environment-specific and unpublished | Redirect to the baseline experiment in Lab 1: the answer is measured, not quoted |
| A group wants to reuse a flag from another agent CLI | Different products, different flags | Use the "Translating Playbooks From Other Agent CLIs" table in the workshop Appendix |
| A group finishes early | Scenario is smaller than their real system | Ask them to add a second lane to the capstone and compare rollback triggers |
| Disagreement about a flag's current behavior | Documentation changes | Record it as a verification item; do not settle it by assertion |
| No CLI, no network, or a live inventory demo fails | Environment restriction | Switch to Backup Path: Sample Inventory Output above after one attempt; state clearly that the sample is synthetic |
Appendix A: Optional Runnable Copilot CLI Probes (45 min)
Optional. Not required for any learning objective. This appendix spends AI credits.
⚠️ Safety and Scope
| Rule | Why |
|---|---|
| Use a personal or non-production sandbox repository you own | Prevents any change to customer, production, or shared code |
| Never use a production automation identity | Spend and permissions must be attributable to you for this exercise |
| Confirm spend authorization first | This appendix makes a small number of paid calls |
Keep every run bounded with --max-ai-credits |
The cap is a soft limit in public preview — actual usage may slightly exceed it. CLI v1.0.79 rejects values below 30, and GitHub's documentation advises setting limits above 30 because most model calls cost more than 20 AI credits. This appendix uses 40 for every run |
Do not grant --allow-all or --yolo |
These are session-wide permission grants intended for isolated environments only |
| Treat transcripts as sensitive | Session transcripts can contain repository content; store them locally and delete them at cleanup |
Do not run --share-gist |
It publishes a transcript to GitHub.com and is unavailable to EMU and *.ghe.com users |
| Stop after Exercise A5 | The comparison is the objective; do not extend it into real work |
Important: Command syntax reflects GitHub documentation verified on 2026-08-12 and
copilot helpoutput from CLI v1.0.79. Verify option spellings and values againstcopilot helpfor your installed version before running. An unknown option is rejected — the CLI printserror: unknown option '<flag>'and exits non-zero without making a model call. The fail-open risk is a valid flag carrying a wrong or unverified value, which parses cleanly and silently restricts nothing.
Shell note: Commands are given PowerShell-first (Windows), with a bash alternative under each step. Run one or the other consistently — do not mix them in a single run. In PowerShell, output is captured with
| Set-Content -Encoding utf8rather than>so the file encoding is predictable.
Prerequisites Check
Step 1 — Version (proves the CLI is installed; it does not prove authentication)
copilot --version
copilot --version
Step 2 — Authentication (a separate check)
CLI v1.0.79 exposes no non-interactive "auth status" subcommand, so authentication is confirmed either by an interactive login or by the first real run in Exercise A2 failing or succeeding. If you have not authenticated on this machine, do it now:
copilot login
copilot login
Automation-style alternative: export a supported token instead of logging in. The CLI reads COPILOT_GITHUB_TOKEN, then GH_TOKEN, then GITHUB_TOKEN. Never paste a token into a command line that will be captured in a transcript or shell history.
Step 3 — Sandbox repository and clean tree
Set-Location <PATH-TO-YOUR-SANDBOX-REPOSITORY>
git status
cd <PATH-TO-YOUR-SANDBOX-REPOSITORY>
git status
Step 4 — Scratch directory for outputs
New-Item -ItemType Directory -Force -Path .\.module4-probe | Out-Null
mkdir -p ./.module4-probe
Confirm you are in a sandbox repository you own with a clean working tree before continuing.
Setup Checkpoint
- ✅
copilot --versionprints a version (installation confirmed) - ✅ You have either completed
copilot loginor exported a supported token (authentication addressed separately from version) - ✅ You are inside a non-production sandbox repository you own, and
git statusshows a clean tree - ✅ You have spend authorization and know your credit cap for this exercise
- ✅ The scratch directory
./.module4-probeexists
Exercise A1 — Establish the Zero-Cost Inventory (8 min)
Objective: See exactly what this working directory would contribute to a session, without making a model call.
Run the inventory from the directory your automation would use:
copilot plugins listcopilot plugins listCapture a machine-readable copy:
copilot plugins list --json | Set-Content -Encoding utf8 .\.module4-probe\inventory-before.jsoncopilot plugins list --json > ./.module4-probe/inventory-before.jsonInspect only MCP servers and instruction sources:
copilot plugins list --kind mcp --kind instructioncopilot plugins list --kind mcp --kind instruction
Expected result: A grouped listing by kind and configuration scope. copilot plugins list performs discovery and does not make a model call. If you cannot run it, use the Backup Path: Sample Inventory Output section earlier in this guide — the sample is illustrative and synthetic.
Checkpoint: You can name every MCP server, skill, plugin, and instruction source this directory would contribute — and identify at least one your automation would not need.
Note: Custom agents and session-scoped hooks are not covered by
copilot plugins list; they require a live session. Do not treat this inventory as complete evidence of everything a session loads.
Success criteria
- ✅ Inventory captured to
inventory-before.json - ✅ At least one discovered resource identified as unnecessary for a hypothetical audit lane
- ✅ No model call was made in this exercise
Exercise A2 — Run a Bounded Baseline Probe (12 min)
Objective: Measure a minimal invocation with everything pinned and bounded.
Warning: This step spends AI credits. The cap is set to 40: CLI v1.0.79 rejects anything below 30, and GitHub's documentation advises setting session limits above 30 because most model calls cost more than 20 AI credits. Do not raise it if the run stops — a stop is the control working.
Note:
-s(--silent) is deliberately omitted. It prints only the agent response and suppresses run stats, which is the opposite of what a measurement probe needs. Add it only in a production lane where you have proven the JSONL channel carries the fields you depend on.
Run the baseline probe:
copilot -p "Reply with the single word OK." ` --no-ask-user ` --model claude-haiku-4.5 ` --max-ai-credits 40 ` --output-format=json ` --share .\.module4-probe\baseline-transcript.md | Set-Content -Encoding utf8 .\.module4-probe\baseline.jsonlcopilot -p "Reply with the single word OK." \ --no-ask-user \ --model claude-haiku-4.5 \ --max-ai-credits 40 \ --output-format=json \ --share ./.module4-probe/baseline-transcript.md \ > ./.module4-probe/baseline.jsonlInspect the JSONL output:
Get-Content .\.module4-probe\baseline.jsonl -TotalCount 5head -n 5 ./.module4-probe/baseline.jsonlInspect the transcript:
Get-Content .\.module4-probe\baseline-transcript.md -TotalCount 40head -n 40 ./.module4-probe/baseline-transcript.mdRecord what your version actually reports: which fields exist, and whether any of them expose per-call cost.
Expected result: A completed run, a JSONL file, and a Markdown transcript.
Checkpoint: You can state, from evidence rather than assumption, which usage fields your installed CLI emits.
Note:
--modelvalues change over time and differ by plan and host. If the model string above is not available in your environment, substitute a lightweight model you know is available and record the substitution. Treat an unrecognized model name as a configuration error to fix — do not assume the CLI substitutes another model for you; that behavior is unverified and sits in the workshop's claim ledger.
Success criteria
- ✅ The run completed within the credit cap
- ✅
baseline.jsonlexists and was inspected - ✅ A transcript was written locally (not to a gist)
- ✅ You recorded which usage fields are present, rather than assuming
Exercise A3 — Run a Single-Variable Comparison (12 min)
Objective: Change exactly one factor and observe the difference.
The only difference between this arm and Exercise A2 is --disable-builtin-mcps. Everything else — prompt, model, credit cap, and output format — stays identical, which is what makes the two runs comparable.
Run the same probe with built-in MCP servers disabled:
copilot -p "Reply with the single word OK." ` --no-ask-user ` --model claude-haiku-4.5 ` --max-ai-credits 40 ` --disable-builtin-mcps ` --output-format=json ` --share .\.module4-probe\reduced-transcript.md | Set-Content -Encoding utf8 .\.module4-probe\reduced.jsonlcopilot -p "Reply with the single word OK." \ --no-ask-user \ --model claude-haiku-4.5 \ --max-ai-credits 40 \ --disable-builtin-mcps \ --output-format=json \ --share ./.module4-probe/reduced-transcript.md \ > ./.module4-probe/reduced.jsonlCompare the first 60 lines of each transcript. Write both extracts to files first — no process substitution, so the same approach works in both shells:
Get-Content .\.module4-probe\baseline-transcript.md -TotalCount 60 | Set-Content -Encoding utf8 .\.module4-probe\baseline-head.txt Get-Content .\.module4-probe\reduced-transcript.md -TotalCount 60 | Set-Content -Encoding utf8 .\.module4-probe\reduced-head.txt Compare-Object (Get-Content .\.module4-probe\baseline-head.txt) (Get-Content .\.module4-probe\reduced-head.txt)head -n 60 ./.module4-probe/baseline-transcript.md > ./.module4-probe/baseline-head.txt head -n 60 ./.module4-probe/reduced-transcript.md > ./.module4-probe/reduced-head.txt diff ./.module4-probe/baseline-head.txt ./.module4-probe/reduced-head.txtRecord credits, latency, and any visible context differences for both arms.
Expected result: Two runs that differ by exactly one configuration element.
Checkpoint: You can state what changed between arms and what you still cannot see from this evidence.
Important: This comparison measures session tax on a trivial prompt only, and one run per arm is an anecdote — the workshop's baseline design calls for repetitions with median and range. It is not evidence that the reduced profile solves real tasks. Adopting it in production requires the quality-parity gate from Lab 6.
Note: Testing a second reduction (for example
--no-custom-instructions) requires another arm run separately. Changing two things at once produces a result nobody can attribute — that is the defect this exercise exists to prevent. If time allows and you have spend authorization, run it as an additional arm and record it separately; otherwise write it down as a follow-up.
Success criteria
- ✅ Exactly one factor changed between the A2 and A3 arms
- ✅ Both runs used identical model, cap, and output format
- ✅ Both runs stayed within their credit caps
- ✅ Differences recorded as observations, not conclusions
- ✅ You stated explicitly what this evidence does not prove
Exercise A4 — Verify a Permission Restriction Empirically (8 min)
Objective: Prove that a restriction you configured is actually in effect — using permission denial, which uses identifiers the CLI itself documents.
The run below keeps the same model, cap, and output format as A2 and A3 so its output is comparable with them. Reasoning effort remains a lane-profile decision, but this probe does not set it because support varies by model.
Ask the agent to describe its tools while
writeandshellare denied:copilot -p "List the names of the tools you can use. Do not use any tool to answer." ` --no-ask-user ` --model claude-haiku-4.5 ` --max-ai-credits 40 ` --deny-tool 'write' --deny-tool 'shell' ` --output-format=json ` --share .\.module4-probe\exclusion-transcript.md | Set-Content -Encoding utf8 .\.module4-probe\exclusion.jsonlcopilot -p "List the names of the tools you can use. Do not use any tool to answer." \ --no-ask-user \ --model claude-haiku-4.5 \ --max-ai-credits 40 \ --deny-tool 'write' --deny-tool 'shell' \ --output-format=json \ --share ./.module4-probe/exclusion-transcript.md \ > ./.module4-probe/exclusion.jsonlCompare the response and transcript against your intent.
Optional, visibility layer: if you want to test
--available-tools, first discover the tool names your installed version actually uses (from this run's output or an interactive session), then add--available-tools '<NAME>,<NAME>'with those exact names. Do not copy a tool list from a slide or another product — an unmatched name parses fine and restricts nothing.
Expected result: Evidence about which tools the model reports as available under your restriction.
Checkpoint: You have first-hand evidence rather than a belief about your restriction.
Important: A model's self-report is corroborating evidence, not proof. The authoritative check is the enforcement behavior itself: a denied tool cannot run, and deny always wins over allow,
--allow-all, and saved approvals. Treat any mismatch between intent and observation as a configuration bug to investigate, and verify option spelling and values withcopilot help.
Success criteria
- ✅ The run completed within its credit cap
- ✅ The run used the same model, effort, cap, and output format as A2 and A3
- ✅ You compared the observed tool list against your intended restriction
- ✅ Any tool name you used with
--available-toolscame from your own environment, not from a copied list - ✅ Any mismatch was recorded as a follow-up, not explained away
Exercise A5 — Record Findings and Stop (5 min)
- Write four lines in your notes:
- What the inventory showed that you did not expect.
- What the baseline arm cost and how long it took.
- What changed in the reduced arm.
- What you still cannot determine without a real-task comparison.
- Add any documentation mismatch you found to your team's verification backlog.
- Stop here. Do not extend these probes into real work in this session.
Success criteria
- ✅ Four findings recorded
- ✅ At least one open verification question written down
- ✅ No further paid runs started
Appendix A Cleanup
Remove local transcripts and outputs:
Remove-Item -Recurse -Force .\.module4-proberm -rf ./.module4-probeConfirm no repository changes were made:
git statusgit statusCheck for stray Git worktrees. These exercises do not create any, but a killed run in your own automation can, and worktrees are shared Git state that outlives the process:
git worktree list Get-ChildItem -Directory -Filter "*.worktrees" -Path .. -ErrorAction SilentlyContinuegit worktree list ls -d ../*.worktrees 2>/dev/nullIf an abandoned worktree appears, remove it and prune the metadata (add
--forceonly when you are certain no process is using it):git worktree remove <PATH-TO-WORKTREE> git worktree prunegit worktree remove <PATH-TO-WORKTREE> git worktree pruneConfirm no session artifacts were published externally (you did not run
--share-gist).Confirm your total spend against your authorized cap.
Cleanup success criteria
- ✅
./.module4-proberemoved - ✅
git statusshows a clean working tree - ✅
git worktree listshows only the worktrees you expect - ✅ No gist or external share was created
- ✅ Spend reconciled against the cap you agreed before starting
Appendix A Troubleshooting
| Symptom | Likely cause | Recovery |
|---|---|---|
copilot: command not found / The term 'copilot' is not recognized |
CLI not installed or not on PATH |
Install Copilot CLI, or skip the appendix — it is optional |
| The run stops citing the credit limit | The soft cap was reached | This is the control working. Do not raise the cap; record the observation as run_cap_exhausted and note that credits were spent |
Use at least 30 AI credits |
A --max-ai-credits value below the CLI minimum |
Use the appendix value of 40; the minimum accepted by CLI v1.0.79 is 30 |
| Authentication error | Not logged in, or the wrong host for your enterprise | Run copilot login (add --host https://<your-host> for data residency), or export COPILOT_GITHUB_TOKEN; never paste a token into a command line |
error: unknown option '<flag>' |
Option names differ in your installed version | The CLI rejects unknown options and makes no model call. Run copilot help, use the current spelling, and record the discrepancy as a documentation-drift finding |
| The restriction appears to have no effect | A valid flag with an unmatched value (tool name, pattern, or server name) | Re-check the value against your environment, not the documentation alone; prefer --deny-tool 'write' / --deny-tool 'shell' for enforcement and record the mismatch |
| Error or unexpected behavior when pinning reasoning effort | Configurable reasoning is available only for supported models | Remove --effort, or choose a model documented to support configurable reasoning; record which model you used |
| Model string not available | Model availability changes over time and by plan and host | Substitute a lightweight model available to you and record the substitution; treat an unrecognized model name as a configuration error, not as something the CLI will silently work around |
| The run reports it cannot use tools in non-interactive mode | Non-interactive runs need an explicit tool-permission grant in some versions | These probes need no tool. If your version requires a grant, use --allow-all-tools together with --deny-tool 'write' --deny-tool 'shell' (deny always wins) — never --allow-all or --yolo |
| Output file is empty | Redirection, encoding, or format mismatch | Re-run without redirection to see the output in the terminal, then re-add flags one at a time. In PowerShell prefer | Set-Content -Encoding utf8 <path> over > |
| PowerShell reports a parsing error on a multi-line command | Backtick line continuations require no trailing spaces | Paste the command as a single line, or re-copy it; do not mix bash \ continuations into PowerShell |
| The agent asks a clarifying question | --no-ask-user omitted |
Cancel, add --no-ask-user, and re-run |
| A worktree or scratch directory is left behind after a cancelled run | Cleanup did not execute | Follow the cleanup steps above: remove ./.module4-probe, then git worktree list → git worktree remove → git worktree prune |
Appendix B: Printable Templates
Why this appendix exists: the published site renders this lab guide but does not publish the
templates/folder. The four worksheets are therefore reproduced here in full so that every learner — including anyone reading the published lab without repository access — can print or copy them. The files intemplates/remain the editable sources; the copies below must be kept identical to them.
| Template | Used in | Source file |
|---|---|---|
| B1 — Lane Profile Worksheet | Lab 2 | templates/lane-profile-worksheet.md |
| B2 — Cache-Key Review Worksheet | Lab 4 | templates/cache-key-review-worksheet.md |
| B3 — Failure Taxonomy and Breaker Worksheet | Lab 5 | templates/failure-taxonomy-worksheet.md |
| B4 — Fleet Lane Optimization Checklist and Canary Scorecard | Lab 6 capstone | templates/canary-scorecard.md |
Note: Appendix B is reference material. It adds no time to the 77-minute core lab total or to the optional 45-minute Appendix A.
B1 — Lane Profile Worksheet
Used in: Lab 2 — one copy per lane. Source file:
templates/lane-profile-worksheet.md.
Complete one worksheet per lane. Write UNKNOWN — measure rather than guessing. Every restriction must be enforced by a flag or harness control, never by prompt wording alone.
Lane name: ___________________________________
Owner: ___________________________________ Review date: _______________
Verified against Copilot CLI docs on: _______________
1. Purpose
| Field | Value |
|---|---|
| Task shape (one shape per lane) | |
| Definition of done (stop condition) | |
| Deterministic check that proves success | |
| Invocation volume per window | |
| Blast radius if this lane misbehaves |
2. Model and Reasoning
| Field | Control | Value | Justification |
|---|---|---|---|
| Model | --model / COPILOT_MODEL (auto carries a documented 10% model-cost discount on paid plans) |
||
| Reasoning effort | --effort / --reasoning-effort (none, minimal, low, medium, high, xhigh, max in CLI v1.0.79) |
||
| Context window tier | --context (default | long_context) |
||
| Escalation rule (in code, on a measured signal) | Harness | ||
| Escalation ceiling (steps per fingerprint) and where it is recorded | Harness ledger |
3. Tools and Permissions
Visibility (
--available-tools/--excluded-tools) controls what the model can choose from, and its values are version- and configuration-specific — verify the tool names in your own environment. Permission (--allow-tool/--deny-tool) controls what may run. Deny always wins, and it is the enforcement layer for any "must not modify" rule.
| Field | Control | Value |
|---|---|---|
| Tools visible to the model (names verified in this CLI version ☐) | --available-tools |
|
| Tools excluded | --excluded-tools |
|
| Tools permitted without prompting | --allow-tool |
|
| Tools denied outright | --deny-tool |
|
| Directory scope | -C, --add-dir |
|
| URL scope | --allow-url, --deny-url |
|
| Temp directory | --disallow-temp-dir |
Read-only claim check: Is every "must not modify" statement enforced by a flag? ☐ Yes ☐ No
4. Context Sources
| Field | Control | Value | Evidence it is needed |
|---|---|---|---|
| MCP servers enabled | --disable-builtin-mcps, --disable-mcp-server, --additional-mcp-config |
||
| GitHub MCP tool scope | --add-github-mcp-toolset, --add-github-mcp-tool |
||
| Custom instructions | --no-custom-instructions, COPILOT_CUSTOM_INSTRUCTIONS_DIRS |
||
| Memory | --enable-memory (off by default in prompt mode) |
||
| Discovered inventory verified from the harness working directory | copilot plugins list |
☐ Yes ☐ No |
5. Spend and Fan-Out Controls
| Field | Control | Value |
|---|---|---|
| Per-run credit cap (soft limit, public preview; minimum 30 in CLI v1.0.79) | --max-ai-credits |
|
| Subagent concurrency cap | Harness scheduler (no supported CLI environment variable listed in v1.0.79 help) | |
| Subagent depth cap | Harness scheduler | |
| Run wait timeout / watchdog | Harness | |
| Parallel workers per lane | Harness | |
| Attempts per fingerprint | Harness attempt ledger | |
Behavior when a run exhausts its cap (run_cap_exhausted) |
Harness — record spend, increment attempt, require decomposition or a reviewed cap change |
6. Isolation
| Field | Control | Value | Status note |
|---|---|---|---|
| Working directory | -C |
Documented | |
| Configuration/state directory | COPILOT_HOME |
Documented variable; per-lane use is a harness pattern | |
| Worktree isolation | --worktree |
Experimental (not listed in v1.0.79 top-level help) — fallback: | |
| Shell sandbox | --sandbox |
Experimental — fallback (generic engineering practice, not a Copilot control): | |
| Secret redaction | --secret-env-vars |
Documented | |
| Cleanup rule and owner | Harness | ||
Stray-worktree recovery step (git worktree list → remove → prune) |
Runbook |
7. Output and Interaction Contract
| Field | Control | Value |
|---|---|---|
| Output format | --output-format=json (-s suppresses stats — keep it off measurement runs) |
|
| Transcript capture and retention | --share=PATH |
|
| External sharing (default: none) | --share-gist — avoid; unavailable to EMU and *.ghe.com |
|
| No clarifying questions | --no-ask-user |
|
| Exit-status contract (success / no-op / failure) | Harness |
8. Reduction Log
Record every reduction from the current profile and the evidence required before adoption.
| Reduction | Expected saving | Evidence required | Canary lane | Decision |
|---|---|---|---|---|
9. Sign-Off
| Check | Status |
|---|---|
Every field completed or marked UNKNOWN — measure |
☐ |
| Every restriction enforced by a control, not prompt text | ☐ |
| Flag values (tool names, patterns, server names) verified in this environment, not copied | ☐ |
| Preview/experimental controls have a stated fallback | ☐ |
| Permission changes reviewed as security changes | ☐ |
| Profile committed with the code that references it | ☐ |
Reviewer: ___________________________________ Date: _______________
B2 — Cache-Key Review Worksheet
Used in: Lab 4 — one copy per cache. Source file:
templates/cache-key-review-worksheet.md.
A cache that omits an input which can change the answer will confidently serve a wrong result, and the failure looks like a saving in cost reporting. Review every cache in front of a paid call with this worksheet.
Cache name: ___________________________________
Lane(s) served: ___________________________________
Reviewer: ___________________________________ Date: _______________
1. Key Completeness
| Component | Included? | If missing, the specific wrong result it can produce |
|---|---|---|
| Fully rendered prompt (template, rubric, and instruction text) | ☐ | |
| Instruction / rubric version | ☐ | |
| Model identifier | ☐ | |
| Reasoning effort | ☐ | |
Context window tier (default / long_context) |
☐ | |
| Tool visibility set | ☐ | |
| Tool permission set | ☐ | |
| MCP server configuration | ☐ | |
| Relevant repository/input state (commit SHA or content hash) | ☐ | |
| Harness version | ☐ | |
| Copilot CLI version | ☐ | |
| Other lane-specific inputs: ____________________ | ☐ |
Highest-severity omission found: ___________________________________
2. Value and Provenance
| Field | Present? | Notes |
|---|---|---|
| Value schema version | ☐ | |
| Result payload fully specified | ☐ | |
| Produced-at timestamp | ☐ | |
| Run ID | ☐ | |
| Lane and profile hash | ☐ | |
| Later accepted / rejected flag | ☐ |
3. Lifecycle Policy
| Policy | Decision |
|---|---|
| TTL | |
| Invalidation triggers (profile change, rubric change, version bump) | |
| Behavior when a key component is missing from an old entry | Must be cache miss — confirm ☐ |
| Behavior when the value schema version is unknown | Must be cache miss — confirm ☐ |
| Negative-result policy: deterministic refusals | |
| Negative-result policy: transient failures (must not be cached) | Confirm ☐ |
| Documented bypass flag (implemented in your harness, not a Copilot CLI option) | |
| Bypass usage logged every time | Confirm ☐ |
4. Gate Ladder Placement
Where does this cache sit relative to the other pre-spend gates?
| Order | Gate | Present in this lane? | Notes |
|---|---|---|---|
| 1 | Configuration validation | ☐ | |
| 2 | Ownership lease | ☐ | |
| 3 | Skip-if-done | ☐ | |
| 4 | Baseline probe | ☐ | |
| 5 | Attempt ledger | ☐ | |
| 6 | Result cache | ☐ | |
| 7 | Budget check (pre-spend — refusal is budget_refused, no credits spent) |
☐ |
Is any gate optimistic (assumes done when uncertain)? ☐ Yes ☐ No — if yes, fix it to fail toward spending.
5. Prompt Budget Review (same input path)
| Check | Status |
|---|---|
| Every growing field has a hard cap | ☐ |
Truncation is visible in the prompt (...[truncated]) |
☐ |
| Trim-to-budget drops sections in a defined priority order | ☐ |
Oversized input produces a distinct context_too_large outcome instead of a call |
☐ |
| Files are referenced by path rather than inlined where the lane can read them | ☐ |
| Tool-output size behavior reviewed (documented default: output over 20 KiB is written to a file and previewed) | ☐ |
| Harness-level input caps defined, independent of any CLI threshold variable | ☐ |
6. Corrected Design
CACHE DESIGN v__
key =
value =
provenance =
ttl =
negative =
bypass =
migration =
7. Sign-Off
| Check | Status |
|---|---|
| Every key component reviewed with a stated failure mode | ☐ |
| Missing or unknown components treated as a miss | ☐ |
| Transient failures excluded from negative caching | ☐ |
| Bypass exists and is logged | ☐ |
| Change reviewed as a correctness change, not an optimization | ☐ |
B3 — Failure Taxonomy and Breaker Worksheet
Used in: Lab 5 — one copy per lane. Source file:
templates/failure-taxonomy-worksheet.md.
Most dispatcher defects come from one mistake: treating every non-success as "the model failed." Use this worksheet to classify outcomes and to size retries, parking, breakers, and dead-lettering.
Lane name: ___________________________________
Owner: ___________________________________ Date: _______________
1. Outcome Map
Fill one row per outcome your dispatcher can produce. The first ten are the recommended baseline set. Note that a pre-spend refusal and a post-spend cap exhaustion are different outcomes with different consequences.
| Outcome | Detected by | Retry? | Backoff | Counts toward breaker? | Attempt counter | Queue action | Alert? |
|---|---|---|---|---|---|---|---|
success |
No | — | No | — | Acknowledge and remove | No | |
already_done / already_green |
No | — | No | — | Acknowledge with reason | No | |
model_failure |
Bounded | Exponential + jitter | Yes | Increment | Retain, increment attempt | On breaker trip | |
context_too_large |
No | — | No | — | Retain, flag for redesign | Yes | |
policy_denied |
No | — | No | — | Retain, alert owner | Yes | |
service_unavailable |
Yes | Exponential + jitter | No | — | Retain | On sustained failure | |
budget_refused (pre-spend; no credits used) |
After park window | Fixed park | No | Do not increment | Retain | One summary line | |
run_cap_exhausted (post-spend; credits used) |
Not automatically — requires decomposition or a reviewed cap change | Blocked, not timed | No | Increment | Retain, blocked until the work or cap changes | Yes — to the lane owner | |
invalid_config |
No | — | No | — | Halt lane | Yes | |
landing_failed |
Yes, after fix | Exponential | No | Increment | Retain — never acknowledge | Yes | |
| Other: ______________ |
Spend accounting check: does every run_cap_exhausted outcome record the credits actually consumed against the lane? ☐ Yes ☐ No
2. Retry and Backoff Design
| Parameter | Value | Rationale |
|---|---|---|
| Maximum attempts per fingerprint | ||
| Backoff schedule | ||
| Jitter | ||
| Backoff cap | ||
| Park window on budget refusal (pre-spend) | ||
Required change before retrying after run_cap_exhausted (decompose / re-lane / reviewed cap change) |
||
| Log volume per park event (target: one summary line) |
3. Breaker Design
| Parameter | Value |
|---|---|
Outcomes counted toward the streak (should be model_failure only) |
|
| Consecutive failures to trip | |
| Open duration (a defensible default is 20 minutes — long enough to clear a blip, short enough to protect throughput) | |
| Half-open probe policy (exactly one item; close on success, reopen for another full window on failure) | |
| Reset condition | |
| Who is alerted when it trips |
Check: Could a routing, policy, budget, cap-exhaustion, configuration, or already-done outcome trip this breaker? ☐ Yes ☐ No If yes, the breaker will punish the model for the dispatcher's mistakes — fix before shipping.
4. Dead-Letter Policy
| Field retained with a dead-lettered item | Present? |
|---|---|
| Last outcome and error detail | ☐ |
| Attempt history | ☐ |
| Lane and profile hash | ☐ |
| Transcript pointer | ☐ |
| Fingerprint and lease history | ☐ |
| Owner responsible for triage | ☐ |
Rule: an item that exhausts its attempts is moved, never deleted. Confirm ☐
5. Layered Budget Check
| Layer | Control | Configured value | Enforced by |
|---|---|---|---|
| Enterprise / organization / cost center | Spending budgets, user-level budgets | GitHub | |
| Fleet envelope | Credits per lane per window | Harness check() before every paid call |
|
| Run | --max-ai-credits (soft, public preview, minimum 30 in CLI v1.0.79) |
Copilot CLI | |
| Fan-out | Subagent concurrency and depth caps | Harness scheduler (no supported CLI environment variable in v1.0.79 help) | |
| Worker concurrency | Parallel workers per lane | Scheduler | |
| Retries | Attempts per fingerprint | Attempt ledger |
Honest accounting check: when one task fans out into N model calls, does the ledger record N? ☐ Yes ☐ No
6. Failure-Mode Review
| Risk | Present today? | Mitigation |
|---|---|---|
| Retry storm (immediate retries, or retrying non-retryable outcomes) | ☐ | |
Automatic retry after run_cap_exhausted (pays the cap again and lands nothing) |
☐ | |
| Breaker misfire (non-model outcomes counted) | ☐ | |
| Attempt-ledger corruption (pre-spend refusals counted as attempts) | ☐ | |
| Silent work loss (acknowledging on ambiguous success) | ☐ | |
| Refusal log flood (per-item refusal logging) | ☐ | |
| Invisible spend (a lane that bypasses the budget module) | ☐ | |
| Park window longer than typical incident duration | ☐ |
B4 — Fleet Lane Optimization Checklist and Canary Scorecard
Used in: Lab 6 capstone — one copy per lane. Source file:
templates/canary-scorecard.md.
Use Part 1 to confirm a lane is ready to change. Use Part 2 to run the change like a production deployment.
Lane name: ___________________________________
Owner: ___________________________________ Date: _______________
Part 1 — Fleet Lane Optimization Checklist
1.1 Measurement
| Check | Status | Evidence |
|---|---|---|
| Session tax contributors inventoried for the harness working directory | ☐ | |
| Baseline captured with median and range (not a single run) | ☐ | |
| Baseline includes a representative real-task arm, not only a trivial probe | ☐ | |
| Recorded fields include credits, tokens, latency, retries, outcome | ☐ |
1.2 Lane Profile
| Check | Status |
|---|---|
| Model, effort, and context tier pinned explicitly | ☐ |
| Tool visibility restricted to what the lane needs | ☐ |
| Tool permissions least-privilege; deny rules present for anything the lane must never do | ☐ |
| MCP servers and instruction sources justified or disabled | ☐ |
| Memory intentionally decided (off by default in prompt mode) | ☐ |
| Per-run credit cap set (soft limit, public preview; minimum 30 in CLI v1.0.79) | ☐ |
--no-ask-user set for unattended runs |
☐ |
| Flag values (tool names, patterns, MCP server names) verified in this environment | ☐ |
| Preview/experimental controls have a documented fallback | ☐ |
1.3 Isolation and Ownership
| Check | Status |
|---|---|
| Working directory and configuration paths resolved relative to the harness | ☐ |
| Per-worker workspace isolation with a unique name, a cleanup rule, and an owner | ☐ |
| Work fingerprint defined | ☐ |
| Single-owner lease with expiry | ☐ |
| Scopes disjoint by construction | ☐ |
| Attempt ledger with a hard cap | ☐ |
1.4 Pre-Spend Gates
| Check | Status |
|---|---|
| Configuration validation before spend | ☐ |
| Skip-if-done with an explicit force override | ☐ |
| Baseline probe runs before the paid call | ☐ |
| Cache key complete and reviewed | ☐ |
Prompt budget enforced with visible truncation and a context_too_large outcome |
☐ |
| Gates fail toward spending when uncertain | ☐ |
1.5 Runtime Governance
| Check | Status |
|---|---|
Every paid call passes through one budget check() and record() |
☐ |
| Fan-out recorded honestly (N calls recorded as N) | ☐ |
Outcome taxonomy implemented, including separate budget_refused (pre-spend) and run_cap_exhausted (post-spend) outcomes |
☐ |
Backoff with jitter; no immediate retries; no automatic retry after run_cap_exhausted |
☐ |
| Breaker counts model failures only, with a stated open duration and single-probe half-open | ☐ |
| Refusals park the worker and log one summary line | ☐ |
| Dead-letter retains context | ☐ |
1.6 Landing and Telemetry
| Check | Status |
|---|---|
| Output validated before acknowledgment | ☐ |
| Atomic write or verified merge | ☐ |
| Distinct signal for success, no-op, and failure | ☐ |
| Exit-code changes traced through every caller | ☐ |
| Downstream consumer confirmed to read the output | ☐ |
| Provenance recorded (lane, run ID, profile hash, model, cache status) | ☐ |
| Durable acceptance recorded after the stabilization period | ☐ |
| Worker restarted and new behavior confirmed in live logs | ☐ |
Part 2 — Canary Scorecard
2.1 Change Definition
| Field | Value |
|---|---|
| Canary lane (highest volume, lowest blast radius, clear acceptance signal) | |
| Single variable being changed | |
| Everything explicitly held constant | |
| Expected effect and mechanism | |
| Reviewer for the change |
2.2 Baseline (before the change)
| Metric | Median | Range | Window |
|---|---|---|---|
| AI credits per invocation | |||
| Latency per invocation | |||
| Retries per accepted outcome | |||
| Human correction time per accepted outcome | |||
| Durable acceptance rate | |||
| Full cost per durable accepted outcome |
2.3 Canary Result (after the change)
| Metric | Median | Range | Delta vs. baseline |
|---|---|---|---|
| AI credits per invocation | |||
| Latency per invocation | |||
| Retries per accepted outcome | |||
| Human correction time per accepted outcome | |||
| Durable acceptance rate | |||
| Full cost per durable accepted outcome |
2.4 Gates
| Gate | Pass condition | Result |
|---|---|---|
| Baseline captured | Median and range recorded before the change | ☐ Pass ☐ Fail |
| Single variable | Exactly one profile element changed | ☐ Pass ☐ Fail |
| Quality parity | Durable acceptance and human correction do not regress beyond tolerance: ______ | ☐ Pass ☐ Fail |
| Cost improvement | Full cost per durable accepted outcome improves | ☐ Pass ☐ Fail |
| Adversarial review | Integration seams, cache-key completeness, flag spelling and flag values, exit-code blast radius all reviewed | ☐ Pass ☐ Fail |
| Deployed and verified | New behavior confirmed in live logs after restart | ☐ Pass ☐ Fail |
2.5 Rollback
| Field | Value |
|---|---|
| Rollback trigger (specific, pre-agreed threshold) | |
| Person allowed to roll back without a meeting | |
| Rollback procedure and expected time to restore | |
| How the rollback is verified |
2.6 Expansion
| Field | Value |
|---|---|
| Next lane to receive the change | |
| Minimum observation window before expanding | |
| Who signs off on expansion | |
| Re-verification date for preview/experimental controls used |
Report line: "Our canary lane is __________, our single variable is __________, and we roll back if __________."
Lab guide for GitHub Copilot AI Credits Optimization — Optional Module 4: Agent Fleet Efficiency and Cost Governance (optional; not counted in the 7-hour-10-minute core curriculum)