Copilot Guard
track copilot. warn before wall. keep using brain.

Status bar shows Copilot: 142 / 1900. Turns yellow, orange, red as you approach your company cap.
Warns you before GitHub does. No network interception, no private APIs, no root CAs.
Install · Get your count · Commands · Settings · Skills · Limitations · Troubleshooting · Development
What it does
| Feature |
Detail |
| Status bar |
$(copilot) Copilot: 142 / 1900 (estimated) — colored by state, click for dashboard |
| Limit engine |
Green → Yellow → Orange → Red, driven by two configurable thresholds |
| Notifications |
VS Code toast at each state transition — dismissable, opt-out in settings |
| Soft gate |
Best-effort warning when you hit Red on a keybinding-triggered send. A deterrent, not a block |
| Cost estimate |
$1.42 / $19.00 in the status bar tooltip and dashboard — derived from the credit total, always tagged estimated (GitHub publishes no fixed credit-to-USD rate) |
| Skills |
Reusable instruction presets written as real .github/copilot-instructions.md and *.instructions.md files |
| Sync |
Pull official usage totals from GitHub's billing API — personal accounts only, see below |
| Workspace defaults |
Ship .vscode/extensions.json + .vscode/settings.json in a repo to recommend the extension and pin org thresholds for everyone who opens it |
Every displayed number carries a confidence tag: exact, synced, or estimated. Never shown as official when it isn't.
Getting your count
VS Code exposes no API that lets a third-party extension read what the native Copilot Chat panel sends or receives. These are the real options, from most to least accurate:
Option 1 — GitHub PAT sync (most accurate, delayed 24 h)
Works only if Copilot is billed to your personal GitHub account (Copilot Individual / legacy setup). If your company pays for your Business seat, skip to Option 2 — the API will return empty data.
Create the token:
- Go to github.com/settings/tokens/new (pre-fills the scope below) → Generate token
- Confirm
manage_billing:copilot is ticked (under Billing) — that's the only scope needed
- Click the copy-icon next to the new token to copy it in full — you won't see it again once you navigate away
Connect it:
Cmd+Shift+P → Copilot Guard: Sync Usage from GitHub
- Paste the token when prompted (stored in VS Code's encrypted secret storage, never in settings files)
- Run the same command any time to refresh — data lags up to ~24 h since GitHub aggregates daily
Paste gotcha: the token box is password-masked (dots, not text), so a bad paste is invisible. Copy the whole token from GitHub with the copy-icon button, not a manual selection — trailing newlines/spaces from a manual copy are trimmed automatically, but a truncated token will fail. Valid tokens start with ghp_, github_pat_, or gho_; the box warns inline if what you pasted doesn't match.
If you're on a Business/org-managed seat the sync will show a warning: "Personal billing data unavailable — this seat is managed by an org or enterprise." That's correct behavior, not a bug — GitHub's billing endpoint returns this for org-managed seats as either an HTTP 403 or an HTTP 404, both handled the same way. Your only option then is to ask your org admin for usage data (GitHub org Copilot usage docs), or use Option 2. If your admin wants a dashboard instead of raw numbers, point them at copilot-metrics-viewer — an open-source org/enterprise usage dashboard built on the org-level Copilot Metrics API (admin access required, not something an individual seat holder can self-serve).
┌─────────────────────────────────────────────────┐
│ accuracy ████████████████████████ exact │
│ freshness ████░░░░░░░░░░░░░░░░░░░░ ~24 h │
│ setup ███░░░░░░░░░░░░░░░░░░░░░ PAT req │
│ seat types personal accounts only │
└─────────────────────────────────────────────────┘
Option 2 — Keybinding shadow (semi-automatic, zero ongoing effort)
Bind the copilotGuard.gated.chatSubmit command to your Copilot Chat send key. Every submit fires it first — Copilot Guard logs +1 (with model multiplier if you set a default model), then passes through.
Set it up:
Cmd+Shift+P → Preferences: Open Keyboard Shortcuts
- Search
Copilot Guard: Gated Chat Submit
- Bind it to
Enter with when: inChatInput (or whatever key you use to send)
Not bound by default — binding the wrong key silently breaks your Copilot Chat send, so this is deliberate opt-in.
┌─────────────────────────────────────────────────┐
│ accuracy ████████████░░░░░░░░░░░░ ±1/turn │
│ freshness ████████████████████████ live │
│ setup ████░░░░░░░░░░░░░░░░░░░░ keybind │
│ seat types all │
└─────────────────────────────────────────────────┘
Counts sends, not responses. No token data. GPT-4.5 and Claude Opus turns count the same as GPT-4o unless you manually set a default model in settings.
Option 3 — Manual log (always works)
Cmd+Shift+P → Copilot Guard: Log Copilot Request
Prompts for a model name (optional). Applies the current per-model rate read from GitHub's own model catalog when available (falls back to a bundled table otherwise — see src/usage/estimator.ts). Status bar updates immediately.
Bind it to a key for speed:
{ "key": "ctrl+alt+l", "command": "copilotGuard.logRequest" }
┌─────────────────────────────────────────────────┐
│ accuracy ████████████░░░░░░░░░░░░ weighted │
│ freshness ████████████████████████ live │
│ setup ██░░░░░░░░░░░░░░░░░░░░░░ none │
│ seat types all │
└─────────────────────────────────────────────────┘
Nothing else works — why
| What you might expect |
Why it doesn't exist |
| Intercept native Copilot Chat turns |
VS Code fires no event another extension can listen to |
| Read the Copilot status bar number |
No inter-extension API; the value is internal to github.copilot |
| Count tokens per response |
vscode.lm.countTokens() only works on messages you construct yourself |
| Org/Business seat REST API |
Requires org owner or billing_manager — not available to a regular seat holder |
| Network interception |
Requires root CA install + MITM proxy; outside extension scope |
Full research in docs/feasibility.md and docs/quota-read-research.md.
Commands
| Command |
What it does |
Copilot Guard: Log Copilot Request |
Manually record a request — asks for model (optional), applies multiplier |
Copilot Guard: Sync Usage from GitHub |
Pull official usage totals via GitHub billing API (personal accounts, PAT required) |
Copilot Guard: Reset GitHub Token |
Clear the stored PAT — use if you pasted a wrong/expired token; Sync Usage from GitHub will then re-prompt |
Copilot Guard: Gated Chat Submit |
Bind to your send key — logs +1 and passes through |
Copilot Guard: Reset Usage Counter |
Clear all recorded usage events |
Copilot Guard: Apply Skill |
Quick-pick a preset and write it to the correct instructions file |
Copilot Guard: Open Settings |
Jump to copilotGuard.* settings |
Copilot Guard: Open Dashboard |
Webview showing live status plus one-click Sync/Reset Token/Log/Reset Usage — same actions as the commands above, in one place |
AI Workspace: Quick Switch |
Cmd+Alt+A — switch active skill/profile |
Settings
| Setting |
Default |
What it does |
copilotGuard.maxCredits |
1900 |
Monthly cap — Red state fires at or above this value |
copilotGuard.warningAt |
[1800, 1850] |
Ascending list of thresholds; each entry adds a warning band and notification |
copilotGuard.enableBlocking |
true |
Show modal warning at Red on gated sends |
copilotGuard.showStatusBar |
true |
Show/hide the status bar item |
copilotGuard.notifications |
true |
Toast notifications on state transitions |
copilotGuard.skills.enabled |
true |
Enable the Skills system |
copilotGuard.skills.defaultSkill |
"" |
Auto-apply this skill on activation |
copilotGuard.maxCostUsd |
19 |
Estimated monthly spend cap in USD — same Red/warning-band logic as maxCredits, shown separately |
copilotGuard.usdPerCredit |
0.01 |
Assumed USD value of one credit, used only to turn the credit total into a dollar estimate — GitHub publishes no fixed rate |
copilotGuard.costWarningAt |
[] (derives from warningAt) |
USD warning bands; leave empty to scale automatically from warningAt |
Skills
Skills are reusable Copilot instruction presets. Applying one writes a real
.github/copilot-instructions.md or *.instructions.md file — no hooks, no private APIs,
just files Copilot Chat natively reads.
Built-in presets: Backend Review, Security Audit, Refactoring, Bug Hunter, Performance, Code Explainer, Documentation Writer, and more. See resources/skills/builtin/.
Cmd+Shift+P → Copilot Guard: Apply Skill → pick from the list.
Rolling out org-wide defaults
If your org has a verbal or written cap ("don't go over 1900 credits / $19"), pin it at the workspace level so every member gets it automatically on open — no per-person setup.
Drop these two files in the repo(s) your org works in:
.vscode/extensions.json
{ "recommendations": ["setdarbinyan.copilot-guard"] }
.vscode/settings.json
{
"copilotGuard.maxCredits": 1900,
"copilotGuard.maxCostUsd": 19,
"copilotGuard.warningAt": [1800, 1850],
"copilotGuard.showStatusBar": true,
"copilotGuard.notifications": true
}
VS Code prompts to install the recommended extension on open, and workspace settings override personal ones for that repo. This repo ships both as a working example — see .vscode/extensions.json and .vscode/settings.json.
Two honest limits: install still needs a click (VS Code never silently installs extensions), and this only applies to whichever repo carries these files — copy them into each org repo, or into one shared workspace root everyone opens.
Limitations
- Cannot count native Copilot Chat turns automatically — no VS Code API exposes them to third-party extensions. Use Option 1, 2, or 3 above.
- Cannot force-block Copilot — the gate is a warning/deterrent. VS Code has no API to cancel another extension's command.
- GitHub sync is personal-account-only — Business/org seats get no data from the personal billing endpoint.
- Model multipliers drift —
estimator.ts has the table; update it when GitHub changes pricing.
Troubleshooting
| Symptom |
Cause |
Fix |
sync failed (GitHub API /users/…/settings/billing/usage?… returned 404) |
Business/org-managed Copilot seat — GitHub's billing endpoint doesn't expose personal data for these, and returns 404 instead of 403 depending on plan |
Expected. Use Option 2 or Option 3, or ask your org admin |
sync failed (GitHub API /user returned 401) |
Token missing, expired, or corrupted on paste |
Now auto-clears the bad token and offers to re-prompt. If it doesn't, run Copilot Guard: Reset GitHub Token then Sync Usage from GitHub again |
| Pasted a wrong token and now can't get the prompt back |
Old versions stored the bad token permanently — sync silently kept reusing it since a stored token (even invalid) skipped the prompt |
Fixed: 401s now auto-clear and re-prompt. Or run Copilot Guard: Reset GitHub Token manually any time |
sync failed (GitHub API /user returned 403) on a personal account |
Token missing the manage_billing:copilot scope |
Regenerate the token with the scope ticked |
| Token box shows a warning while typing |
Pasted value doesn't start with ghp_/github_pat_/gho_, or has stray whitespace |
Re-copy the full token from GitHub; whitespace is trimmed automatically, a wrong prefix means the paste was incomplete |
| Status bar missing |
copilotGuard.showStatusBar is false |
Open Settings and re-enable it |
Still stuck? Open an issue with the exact error text (never paste your token) at the GitHub repo.
Development
npm install
npm run watch # esbuild watch
npm run lint
npm run test:unit # plain Node, no extension host needed
npm run test:integration # @vscode/test-electron, needs a display
F5 in VS Code → Extension Development Host.
Testing the warning bands
Set a low cap in your settings.json so you can hit every band by logging a handful of requests:
"copilotGuard.maxCredits": 10,
"copilotGuard.warningAt": [2, 4, 6, 8]
Then run Copilot Guard: Log Copilot Request repeatedly and watch the status bar step through:
| Count |
State |
Color |
| 0–1 |
green |
— |
| 2–3 |
w1 |
electric blue #00b4ff |
| 4–5 |
w2 |
teal #00d4aa |
| 6–7 |
w3 |
gold #ffd700 |
| 8–9 |
w4 |
orange #ff9500 |
| 10+ |
red |
error background |
A VS Code notification fires at each band crossing. Restore your real values when done:
"copilotGuard.maxCredits": 1900,
"copilotGuard.warningAt": [1500, 1700, 1800, 1850]
docs/feasibility.md · docs/quota-read-research.md · docs/usage-engine.md
MIT — free like untracked tokens on an open plain.