Skip to content

Repository files navigation

Gatekeeper

You are not optimizing Copilot — you are controlling what you allow yourself to send into it.

Gatekeeper is a VS Code extension that acts as a prompt discipline layer in front of GitHub Copilot. It intercepts every @gatekeeper chat request, trims and structures the context before it leaves your machine, and routes low-complexity questions to a local model entirely — so Copilot only ever sees the minimum signal it needs.


How It Works

User Action
   │  (Ctrl+Shift+G · right-click "Gatekeeper: Run" · @gatekeeper chat · //gk: ghost text)
   ▼
┌──────────────────────────────────────────────┐
│  Smart Run  (gatekeeper.run)                  │
│  extension.ts                                 │
│  · Cursor on //gk: line → ghost-text trigger  │
│  · Selection active    → inline edit flow     │
│  · Otherwise           → contextual QuickPick │
└──────────────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────────────┐
│  Gatekeeper Command / Chat Participant        │
│  extension.ts · chatParticipant.ts            │
└──────────────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────────────┐
│  Context Extractor                            │
│  contextExtractor.ts                         │
│  · Active file text & language               │
│  · Cursor selection / highlighted range      │
│  · Scored related open files                 │
│  · Workspace diagnostics (errors/warnings)   │
│  · Token usage estimates                     │
└──────────────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────────────┐
│  Context Trimmer                              │
│  contextTrimmer.ts                           │
│  · Extract enclosing function (AST-aware)    │
│  · Strip block & line comments               │
│  · Remove unreferenced import statements     │
└──────────────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────────────┐
│  Prompt Optimizer                             │
│  promptOptimizer.ts                          │
│  · Detect intent (fix/refactor/test/…)       │
│  · Scope breadth check — block if too broad  │
│  · Select intent-specific system prompt      │
│  · Compile structured Context/Task/Constraints│
│  · Inject diff-first instruction if enabled  │
└──────────────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────────────┐
│  Ollama Pre-filter  (optional, Feature E)     │
│  modelRouter.ts                              │
│  · Ping local Ollama at 127.0.0.1:11434      │
│  · Classify complexity (low/medium/high)     │
│  · Answer directly if low-complexity         │
│  · Fall through to Copilot otherwise         │
└──────────────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────────────┐
│  Copilot LM API                               │
│  vscode.lm.selectChatModels + sendRequest()  │
│  · Receives the trimmed, structured prompt   │
│  · Streams response back token-by-token      │
└──────────────────────────────────────────────┘
   │
   ▼
┌──────────────────────────────────────────────┐
│  Rollback Snapshot · Audit Log                │
│  snapshotStore.ts · auditLog.ts              │
│  · Save pre-edit file state to disk           │
│  · Append JSONL audit entry (hash/intent/…)  │
└──────────────────────────────────────────────┘
   │
   ▼
Response streamed to chat  /  Unified diff patch applied to editor

Features

A · Smarter Context Trimming

Instead of sending the entire active file, Gatekeeper extracts only the function containing your cursor. It also strips block/line comments and removes import statements that are never referenced in the file body.

  • gatekeeper.focusCurrentFunction — extract only the enclosing function (default: true)
  • gatekeeper.stripComments — remove comments before sending (default: true)
  • gatekeeper.stripUnusedImports — drop unreferenced imports (default: true)

The optimization report shows exactly how many lines were trimmed and why.

B · Intent Scope Enforcer

Requests that are too broad (e.g. "refactor the entire codebase", "redesign the architecture") are detected before they reach Copilot. Broad requests show a warning but proceed. Architectural-scope requests are blocked with an explanation to narrow the scope.

Scope levels: targetedmoderatebroadarchitectural

C · Structured Prompt Compiler

Raw user input is transformed into a structured format that eliminates ambiguity:

Context:
- file: auth.ts
- function: validateToken()

Task:
Fix the null-check so it handles undefined without throwing.

Constraints:
- State the root cause in one sentence
- Patch only the affected lines
- Do not introduce unrelated refactoring

Constraints are intent-specific — fix, explain, refactor, test, document, implement, and review each have a tailored constraint set.

D · Diff-First Workflow

When enabled, Gatekeeper appends a system-level instruction telling the model to respond with unified diffs instead of full files for fix, refactor, and review tasks. This eliminates wall-of-code responses.

  • gatekeeper.diffFirstMode — enable diff output (default: false)

Example response format:

--- a/src/auth.ts
+++ b/src/auth.ts
@@ -14,7 +14,7 @@
-  if (token == null) throw new Error('missing');
+  if (token == null || token === undefined) throw new Error('missing token');

E · Local Model Pre-Filter

Low-complexity questions that require no code context (general knowledge, syntax questions, concept explanations) are answered by a local Ollama model without ever reaching Copilot.

  • gatekeeper.useLocalModelPreFilter — enable local routing (default: false)
  • gatekeeper.ollamaModel — Ollama model to use (default: "llama3")

The pre-filter performs a two-step check: first classifies complexity, then either answers locally or escalates. The report shows Pre-filter: ollama/llama3 when Ollama answered.


Usage

Open the GitHub Copilot Chat panel (Ctrl+Alt+I or View → Chat) and invoke @gatekeeper:

@gatekeeper explain what this function does
@gatekeeper fix the null-check on line 42
@gatekeeper refactor this to reduce nesting
@gatekeeper write unit tests for validateToken()
@gatekeeper review this for security issues

For best results: place your cursor inside the function you want to work with before sending the prompt. The context trimmer will extract that function as the primary context.


Optimization Report

Every response is preceded by a report showing what was done:

> Gatekeeper Optimization Report
>
> | Metric            | Value              |
> |-------------------|--------------------|
> | Intent            | `fix`              |
> | Raw context       | ~3,498 tokens      |
> | Optimized prompt  | ~890 tokens        |
> | Reduction         | ↓ 75%              |
> | Output format     | unified diff       |
>
> Applied:
> - Applied "fix" system-prompt template
> - Focused on function (lines 42–67, was 312 lines)
> - Stripped comments (−31 lines)
> - Removed 4 unused imports
> - Diff-first mode enabled
> - Structured prompt compiled (Context / Task / Constraints)

Disable the report with gatekeeper.showOptimizationReport: false.


Commands

Single entry point — gatekeeper.run

You no longer need to remember which command does what. One action auto-routes based on context:

Editor state when triggered What happens automatically
Cursor is on a //gk: … line Fires the inline ghost-text suggestion
Text is selected Opens the inline edit flow (prompt → patch → confirm → apply)
Nothing selected Opens a contextual QuickPick with all available actions

Trigger it via:

  • Keyboard: Ctrl+Shift+G / Cmd+Shift+G
  • Right-click context menu → Gatekeeper: Run
  • Command Palette → Gatekeeper: Run

QuickPick actions (when nothing is selected)

Action Description
$(edit) Optimize & Preview Extract context, score files, compile structured prompt — inspect before sending
$(history) Rollback Last Edit Pick a pre-edit snapshot for the active file
$(graph) Show Stats Token savings, intent breakdown, model usage
$(output) View Audit Log JSONL audit of every inline edit attempt
$(trash) Reset Stats Wipe accumulated stats

Direct commands (still available for custom keybindings)

Command Description
@gatekeeper <prompt> Chat participant — optimized prompt via chat panel
Gatekeeper: Inline Edit Selection Direct inline edit (requires selection)
Gatekeeper: Optimize & Preview Direct preview (any open file)
Gatekeeper: Show Optimization Stats WebView stats panel
Gatekeeper: Reset Stats Clear saved statistics
Gatekeeper: Show Audit Log Markdown table of all edits
Gatekeeper: Rollback Last Edit Restore snapshot for active file
//gk: <instruction> (ghost text) Type in any file, pause 600 ms → suggestion appears

Settings

Setting Type Default Description
gatekeeper.focusCurrentFunction boolean true (A) Send only the function at the cursor
gatekeeper.stripComments boolean true (A) Strip comments from source context
gatekeeper.stripUnusedImports boolean true (A) Remove unreferenced imports
gatekeeper.diffFirstMode boolean false (D) Request unified diff output for fix/refactor/review
gatekeeper.useLocalModelPreFilter boolean false (E) Route simple requests to Ollama first
gatekeeper.ollamaModel string "llama3" (E) Ollama model name
gatekeeper.enableInlineEdits boolean true Enable the Inline Edit Selection command
gatekeeper.inlinePreviewBeforeApply boolean true Show diff preview and confirm before applying patches
gatekeeper.enableAuditLog boolean true Write audit entries to .gatekeeper/audit.jsonl
gatekeeper.maxRollbackSnapshots number 5 Max pre-edit snapshots kept per file
gatekeeper.enableInlineCompletions boolean false Enable //gk: ghost-text completions
gatekeeper.compressStackTraces boolean true Compress stack traces in diagnostics and chat messages to top 3 frames
gatekeeper.maxContextLines number 150 Max lines from the active file
gatekeeper.maxRelatedFiles number 3 Max number of related open files to include
gatekeeper.relevanceThreshold number 0.3 Minimum relevance score for related files (0–1)
gatekeeper.preferredModelFamily string "" Copilot model family (leave empty for any available)
gatekeeper.usePromptTemplates boolean true Use intent-specific system prompts
gatekeeper.showOptimizationReport boolean true Show the token-reduction report above responses

Testing

Quickest path — Extension Development Host

  1. Open the project folder in VS Code.
  2. Press F5 — a new Extension Development Host window opens with Gatekeeper live-loaded.
  3. In the host window, open any source file and run through the scenarios below.

After any code change: press Ctrl+Shift+F5 (restart) or Ctrl+R in the host window — no packaging needed.


Test the smart gatekeeper.run routing

Route 1 — ghost-text trigger

  1. Open any .ts / .js / .py file.
  2. Enable inline completions: gatekeeper.enableInlineCompletions: true in Settings.
  3. Type // gk: sort this array by date descending and pause ~600 ms.
  4. Expected: ghost-text suggestion appears inline. Press Tab to accept.
  5. Alternative trigger: place cursor on that line and press Ctrl+Shift+G. The ghost-text engine fires without waiting for the debounce.

Route 2 — inline edit (selection)

  1. Open any source file and select 3–10 lines of code.
  2. Press Ctrl+Shift+G.
  3. Expected: an input box appears immediately asking what edit to apply — no QuickPick shown.
  4. Type add null-check before first use → confirm → a diff preview opens → click Apply.
  5. Check the file is patched and .gatekeeper/audit.jsonl has a new entry.

Route 3 — contextual QuickPick

  1. Open a file, ensure no text is selected, cursor is not on a //gk: line.
  2. Press Ctrl+Shift+G.
  3. Expected: the QuickPick appears with 5 actions (Optimize & Preview, Rollback, Stats, Audit Log, Reset Stats).
  4. Choose Optimize & Preview → enter a prompt → a Markdown preview opens in a side panel.

Test stack-trace compression

  1. Open the Copilot Chat panel and type:
    @gatekeeper fix this error:
    TypeError: Cannot read property 'id' of null
        at UserService.find (user.service.ts:42:18)
        at AuthController.login (auth.controller.ts:88:12)
        at Layer.handle [as handle_request] (express/lib/router/layer.js:95:5)
        at next (express/lib/router/route.js:137:13)
        at Route.dispatch (express/lib/router/route.js:112:3)
        at Layer.handle [as handle_request] (express/lib/router/layer.js:95:5)
    
  2. Expected: Gatekeeper reports compressed an embedded stack trace (−3 lines) and sends only the error message + top 3 frames to the model.
  3. Disable with gatekeeper.compressStackTraces: false and repeat — full trace passes through unchanged.

Test rollback

  1. Select code, apply an inline edit via Ctrl+Shift+G (Route 2 above).
  2. Press Ctrl+Shift+G again with nothing selected → choose Rollback Last Edit.
  3. Expected: a snapshot QuickPick appears; select the pre-edit entry → file reverts.

Test the @gatekeeper chat participant

@gatekeeper explain what this function does
@gatekeeper fix the null-check on line 42
@gatekeeper write unit tests for validateToken()

Every response opens with a Gatekeeper Optimization Report table showing token reduction, intent, and applied rules.


Test Ollama local routing (optional)

  1. Start Ollama: ollama serve (requires Ollama installed).
  2. Set gatekeeper.useLocalModelPreFilter: true and gatekeeper.ollamaModel: "llama3" in Settings.
  3. In chat: @gatekeeper what is a closure in JavaScript?
  4. Expected: the report shows Pre-filter: ollama/llama3 and no Copilot request is made.

Requirements

  • VS Code ^1.90.0
  • GitHub Copilot and GitHub Copilot Chat extensions — signed in
  • Node.js ^20 (bundled with VS Code 1.90+)
  • Ollama (optional, for Feature E) — running at http://127.0.0.1:11434

Installation

From .vsix (local build)

git clone <repo>
cd gatekeeper
npm install
npm run compile
npx @vscode/vsce package --no-dependencies --allow-missing-repository
code --install-extension gatekeeper-0.1.0.vsix

Development mode (F5)

Open the project folder in VS Code and press F5. This launches an Extension Development Host with the extension loaded live — no packaging needed. Reload the host window after any source change.


Architecture

src/
├── extension.ts                 # Activation, smart-run command, all wiring
├── chatParticipant.ts           # @gatekeeper chat handler, request lifecycle
├── contextExtractor.ts          # Active file, selection, related files, diagnostics
├── contextTrimmer.ts            # (A) Comment stripping, import pruning, function extraction
├── promptOptimizer.ts           # (B+C) Intent detection, scope check, structured prompt builder
├── modelRouter.ts               # (E) Ollama availability check, local routing, pre-analysis
├── logCompressor.ts             # Regex-based stack trace summariser (Node/Java/Python/.NET)
├── unifiedDiff.ts               # Unified diff parser, hunk validator, patch applicator
├── inlineCompletionProvider.ts  # Ghost-text provider triggered by //gk: comments
├── snapshotStore.ts             # Pre-edit rollback snapshots (ring-buffer, disk-persisted)
├── auditLog.ts                  # JSONL audit log per inline edit (hash · intent · outcome)
├── statsTracker.ts              # Persistent token-savings statistics, WebView report
└── types.ts                     # Shared TypeScript interfaces

Data written to disk

<workspace>/
└── .gatekeeper/
    ├── audit.jsonl          # One JSON line per inline edit event
    ├── snapshots/           # Pre-edit file snapshots (auto-pruned)
    └── .gitignore           # Auto-created — excludes audit + snapshots from git

Design Philosophy

Most AI cost-control tools try to optimize what happens inside the model. Gatekeeper controls what you allow into the model in the first place.

Three concrete enforcement points:

  1. ContextTrimmer — the active file shrinks from N lines to the enclosing function. You never send what the model doesn't need.
  2. PromptCompiler — structured format eliminates ambiguity; the model doesn't waste tokens hedging or re-interpreting scope.
  3. ModelRouter — questions requiring no code context never reach Copilot at all.

The scope enforcer is the most direct expression of this: it blocks a request before it leaves your machine, not after tokens have been consumed.

About

It's a prompt optimizer that sits between you and Copilot

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages