Skip to content

feat: ArmorCopilot for GitHub Copilot CLI — initial port from ArmorCodex#3

Merged
Harihara04sudhan merged 7 commits into
mainfrom
feat/armorcopilot-gh-port
May 28, 2026
Merged

feat: ArmorCopilot for GitHub Copilot CLI — initial port from ArmorCodex#3
Harihara04sudhan merged 7 commits into
mainfrom
feat/armorcopilot-gh-port

Conversation

@Harihara04sudhan

@Harihara04sudhan Harihara04sudhan commented May 25, 2026

Copy link
Copy Markdown
Contributor

TL;DR

ArmorCopilot for GitHub Copilot CLI, ported from ArmorCodex with ~85% verbatim code reuse. Replaces the previously-explored Microsoft Copilot Studio direction (which couldn't carry our intent-capture wedge).

Why GitHub Copilot CLI (not Microsoft Copilot Studio)

Microsoft Copilot Studio GitHub Copilot CLI
Where it runs Microsoft cloud (SaaS) Developer's laptop (local CLI)
Pre-tool interception Webhook AFTER LLM picks tool Real preToolUse hook BEFORE tool fires
Intent capture possible No (degraded) YES — same wedge as Claude/Codex
Plugin model None (webhook only) First-class plugin runtime
Effort 3-4 weeks + new infra + degraded wedge ~1 week, 85% reuse from ArmorCodex

Per the CTO meeting brief and product principle "intent is the main product — if not, don't do it" — we pivot.

The previous MS work is preserved as tag stash/armorcopilot-ms-2026-05-22 for future revival if a customer asks.

What landed in this PR

Final layout matches armorCodex / armorClaude (plugin at plugins/<name>/ with repo-level .claude-plugin/marketplace.json at root):

armorCopilot/
├── .claude-plugin/marketplace.json     repo-level marketplace (publisher: ArmorIQ)
├── .agents/plugins/marketplace.json    mirror for non-Copilot agent runtimes
├── install_armorcopilot.sh             curl-pipe installer (mirrors armorCodex)
├── README.md                           top-level docs
└── plugins/armorcopilot/                ← the plugin itself
    ├── .claude-plugin/plugin.json      plugin manifest
    ├── .mcp.json                       MCP server config (armorcopilot-policy)
    ├── hooks/hooks.json                8 events wired (sessionStart, userPromptSubmitted,
    │                                   preToolUse, permissionRequest, postToolUse,
    │                                   postToolUseFailure, agentStop, sessionEnd)
    ├── package.json                    @armoriq/armorcopilot, v0.1.0
    ├── README.md                       plugin-level docs
    ├── assets/armoriq-logo.png
    └── scripts/                        bootstrap + hook-router + policy-mcp + 12 lib modules

Code reuse from armorCodex (~85% verbatim)

  • engine.mjs, hook-output.mjs, audit-wal.mjs, iap-service.mjs, policy.mjs, crypto-policy.mjs, fs-store.mjs, runtime-state.mjs, common.mjs, intent-schema.mjs, intent.mjs, policy-mcp.mjs — copied verbatim or with comment-only renames
  • config.mjs — env prefix ARMORCODEX_ARMORCOPILOT_, data dir ~/.codex/armorcodex~/.copilot/armorcopilot, llmId openai-codexgithub-copilot, mcpName/agentId/userId rebranded
  • hook-router.mjs — added normalizer that maps Copilot's camelCase payload (sessionId, toolName, toolArgs JSON-string) to the snake_case shape engine.mjs already expects

Phase 0 research findings

  • Plugin manifest at .claude-plugin/plugin.json (4 alternate paths checked; this is canonical and matches github/copilot-plugins)
  • 13+ hook events available (sessionStart/sessionEnd/userPromptSubmitted/preToolUse/postToolUse/permissionRequest/preCompact/errorOccurred/agentStop/subagentStart/...)
  • Hook payload: stdin JSON, both snake_case and camelCase variants — Copilot sends camelCase, our normalizer maps to snake_case
  • Block mechanism: stdout JSON {"permissionDecision":"deny","permissionDecisionReason":"...","modifiedArgs":{}} — matches our existing hook-output.mjs ZERO-DIFF
  • Hook command env: Copilot CLI sets $CLAUDE_PLUGIN_ROOT (we use this in hooks.json for absolute-path resolution)
  • Plugin install: copilot plugin install owner/repo or owner/repo:path
  • Two default marketplaces: github/copilot-plugins (official) + github/awesome-copilot (community)

How to install (once merged)

Via the marketplace flow (the repo's root .claude-plugin/marketplace.json resolves the plugin source automatically):

copilot plugin marketplace add armoriq/armorCopilot
copilot plugin install armorcopilot@armorcopilot

Or via the curl-pipe installer (handles plugin install + npm deps + armoriq-dev CLI + device-code login):

curl -fsSL https://armoriq.ai/install_armorcopilot.sh | bash

The plugin runtime auto-discovers .claude-plugin/plugin.json at plugins/armorcopilot/ and registers hooks + MCP servers.

Companion PRs (must all merge for the curl-pipe flow to work end-to-end)

Repo PR What
armoriq/conmap-auto #251 Add 'armorcopilot' to ProductSlug allowlist (backend)
armoriq/armorIQ-Frontend #213 DeviceApproval product-aware branding for ArmorCopilot
armoriq/armoriq-landing #58 Serve install_armorcopilot.sh from armoriq.ai

Local install + smoke test (verified)

The plugin was installed end-to-end via local marketplace path and tested against a real copilot CLI session:

  • ✅ Plugin install via marketplace.json
  • ✅ All 5 hooks load + fire on the right events (now 8 with postToolUseFailure / agentStop / sessionEnd added)
  • ✅ MCP server registers register_intent_plan, policy_update, policy_read tools
  • ✅ Payload normalization (camelCase → snake_case) working
  • ✅ Hook stdout JSON shape accepted by Copilot
  • ✅ Directive injection via UserPromptSubmit reaches Copilot's planner
  • ✅ Backend roundtrip works (intent token issued against staging-api)
  • ✅ Banner now correctly spells ARMORCOPILOT (was inherited ARMORCODEX art)

Copilot review fixes (latest commit 59da8a2)

Six review-driven fixes addressed:

  1. config.mjs — 3-way switch on envMode (production/staging/local) replacing the confusing 2-way ternary that mapped useProduction → staging
  2. iap-service.mjs verify-step — fail closed on non-2xx (was silently allowing through with data.allowed default)
  3. engine.mjs safe-tools — dropped websearch + webfetch from the early-exit list (network egress must go through enforcement)
  4. audit-wal.mjs — capped readBatch at 4MiB to prevent OOM if the backend is down and the WAL grows large
  5. policy-mcp.mjs + intent-schema.mjs — added optional session_id to plan; MCP writes per-session pending-plan.<sessionId>.json (with global mirror for legacy reader compat). Eliminates concurrent-session clobbering.
  6. hooks.json — added the 3 missing event registrations (postToolUseFailure, agentStop, sessionEnd) — engine had handlers but Copilot never invoked them
  7. README.md — corrected "synchronous audit log" to reflect the actual WAL-backed async batched pipeline; updated install command to show marketplace add + curl-pipe flow

Test plan

  • Local install via copilot plugin marketplace add /Users/...armorCopilot + copilot plugin install armorcopilot@armorcopilot
  • Verify hook firing (debug log shows Loaded 5 hook(s) from 1 plugin(s) → now 8)
  • Verify MCP tool registration (armorcopilot-policy-policy_update, _read, register_intent_plan)
  • Verify backend roundtrip (intent token issued, audit row enqueued)
  • Pending companion PRs: end-to-end curl-pipe install + device-code login (needs #251, #213, #58)
  • Pending companion PRs: deny-rule block path (needs #251 deployed so the customer's API key passes the staging product-allowlist check)

Closes #1, parks #2 (the previous Microsoft Copilot Studio skeleton — preserved as tag stash/armorcopilot-ms-2026-05-22 for future revival).

🤖 Generated with Claude Code

ArmorCopilot is the GitHub Copilot CLI counterpart of ArmorClaude
(Claude Code) and ArmorCodex (OpenAI Codex). Same wedge — intent
capture before action, policy enforcement on every tool call, audit to
ArmorIQ backend — applied to the local-CLI agentic harness that has
real preToolUse/postToolUse hooks. Pivoted to GitHub Copilot CLI after
Microsoft Copilot Studio research showed it lacks pre-action intent
visibility (only post-LLM-decision webhook), which would degrade us
to a policy-only product comparable to Check Point + Zenity. GitHub
Copilot CLI is local + hooks + MCP, identical model to Claude/Codex.

Phase 0 PoC questions answered from docs (no code experiment needed):
- Plugin manifest at .claude-plugin/plugin.json (canonical)
- Hook payload via stdin JSON (snake_case + camelCase variants)
- Block via stdout JSON {permissionDecision:"deny",permissionDecisionReason}
- MCP config at .mcp.json or .github/mcp.json
- 13+ hook events available (sessionStart/Pre/Post/userPromptSubmitted/etc)
- Plugin install via `copilot plugin install owner/repo`
- 2 default marketplaces: github/copilot-plugins + github/awesome-copilot

Phase 1 port — 22 files, ~85% verbatim from armorCodex/plugins/armorcodex:

  packages/armorcopilot-gh/
  ├── .claude-plugin/plugin.json   plugin manifest (canonical path)
  ├── .mcp.json                    MCP server config
  ├── hooks/hooks.json             5 hooks: sessionStart, userPromptSubmitted,
  │                                preToolUse, permissionRequest, postToolUse
  ├── package.json                 npm deps + name @armoriq/armorcopilot-gh
  ├── README.md                    install + config + architecture
  ├── assets/armoriq-logo.png
  └── scripts/
      ├── bootstrap.mjs            entry point (mcp / router)
      ├── hook-router.mjs          dispatches hook events to engine
      ├── policy-mcp.mjs           MCP server (3 tools)
      └── lib/                     12 modules
          ├── engine.mjs           ZERO-DIFF from armorCodex
          ├── hook-output.mjs      ZERO-DIFF (snake_case + permissionDecision
          │                        shapes already match GH Copilot's spec)
          ├── audit-wal.mjs        VERBATIM
          ├── iap-service.mjs      VERBATIM
          ├── policy.mjs           VERBATIM + tool whitelist expanded for GH
          ├── crypto-policy.mjs    VERBATIM
          ├── fs-store.mjs         VERBATIM
          ├── runtime-state.mjs    VERBATIM
          ├── common.mjs           VERBATIM
          ├── intent-schema.mjs    VERBATIM
          ├── intent.mjs           VERBATIM
          └── config.mjs           env prefix ARMORCODEX_ → ARMORCOPILOT_,
                                   data dir ~/.codex/armorcodex →
                                   ~/.copilot/armorcopilot, llmId
                                   openai-codex → github-copilot,
                                   mcpName/agentId/userId rebranded

All Codex identifier references swept from code AND comments. Plugin
runtime auto-discovers .claude-plugin/plugin.json on
`copilot plugin install armoriq/armorCopilot:packages/armorcopilot-gh`.

Refs #1, parks #2 (the previous Microsoft Copilot Studio skeleton —
preserved as tag stash/armorcopilot-ms-2026-05-22 for future revival).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 25, 2026 07:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports ArmorCopilot’s intent-plan + policy enforcement model into a GitHub Copilot CLI plugin, wiring Copilot hooks to a local enforcement engine and exposing an MCP server for plan registration and policy management.

Changes:

  • Added Copilot CLI plugin manifests (hooks + MCP server) and a bootstrap entrypoint for dependency setup.
  • Implemented hook routing + enforcement engine (intent-plan capture/verification, policy evaluation, audit logging).
  • Added local persistence primitives (policy state, runtime state, audit WAL) and backend integrations (intent capture + verify-step + audit batch ship).

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/armorcopilot-gh/scripts/policy-mcp.mjs MCP server exposing register_intent_plan, policy_read, policy_update, plus audit WAL flusher
packages/armorcopilot-gh/scripts/lib/runtime-state.mjs Runtime state persistence (sessions + discovered tools)
packages/armorcopilot-gh/scripts/lib/policy.mjs Policy model, parsing (“Policy …” commands), and evaluation (incl. anyParam matchers + data class detection)
packages/armorcopilot-gh/scripts/lib/planner.mjs Plan markdown/JSON extraction helpers and plan file path resolution
packages/armorcopilot-gh/scripts/lib/intent.mjs Intent capture + token/plan parsing + plan/tool matching + CSRG proof extraction
packages/armorcopilot-gh/scripts/lib/intent-schema.mjs Zod schema + normalization for Copilot intent plans
packages/armorcopilot-gh/scripts/lib/iap-service.mjs Backend calls for verify-step / CSRG verify / audit enqueue & batch ship
packages/armorcopilot-gh/scripts/lib/hook-output.mjs Hook response helpers for deny/block/additional context
packages/armorcopilot-gh/scripts/lib/fs-store.mjs Atomic JSON read/write utilities
packages/armorcopilot-gh/scripts/lib/engine.mjs Core enforcement pipeline for hooks (policy + intent + CSRG + audit)
packages/armorcopilot-gh/scripts/lib/crypto-policy.mjs Optional crypto-bound policy token flow and local cached state
packages/armorcopilot-gh/scripts/lib/config.mjs Plugin/env configuration resolution
packages/armorcopilot-gh/scripts/lib/common.mjs Shared utilities (matching, sanitization, redaction, HTTP helpers)
packages/armorcopilot-gh/scripts/lib/audit-wal.mjs Durable on-disk audit WAL with offset tracking + rotation
packages/armorcopilot-gh/scripts/hook-router.mjs Routes hook events from stdin JSON to engine handlers
packages/armorcopilot-gh/scripts/bootstrap.mjs One-time dependency install + stdio safety (stdout hygiene) + dispatch
packages/armorcopilot-gh/README.md User-facing install/config/architecture docs
packages/armorcopilot-gh/package.json Package metadata and runtime dependencies
packages/armorcopilot-gh/hooks/hooks.json Copilot hook registration to the router
packages/armorcopilot-gh/.mcp.json MCP server registration (stdio node command)
packages/armorcopilot-gh/.claude-plugin/plugin.json Plugin manifest (hooks, MCP servers, and userConfig surface)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +42 to +50
// dev branch — points at staging-api for pre-release testing.
// main branch keeps "https://api.armoriq.ai" (prod). When promoting a
// feature from dev → main, resolve the URL conflict in favor of main.
const backendEndpoint =
env.ARMORCOPILOT_BACKEND_ENDPOINT?.trim() ||
env.BACKEND_ENDPOINT?.trim() ||
(useProduction
? "https://staging-api.armoriq.ai"
: "http://127.0.0.1:3000");
Comment on lines +81 to +88
const response = await postJson(endpoint, payload, headers, timeoutMs);
if (!response.ok && !isPlainObject(response.data)) {
throw new Error(
response.text || `IAP verify-step failed with status ${response.status}`
);
}

const data = isPlainObject(response.data) ? response.data : {};
Comment on lines +221 to +247
const pendingPath = path.join(config.dataDir, "pending-plan.json");
await writeJson(pendingPath, {
plan,
tokenRaw: "",
allowedActions: Array.from(extractAllowedActions(plan)),
expiresAt: undefined,
registeredAt: Date.now()
});

let backendWillIssue = false;
if (config.intentEndpoint || (config.useSdkIntent && config.apiKey)) {
backendWillIssue = true;
// Kick off the SDK call. When it resolves with a signed token, update
// pending-plan.json so PreToolUse picks up the token on subsequent
// calls. Errors are logged to stderr and otherwise swallowed.
(async () => {
try {
const policyState = await loadPolicyState(config.policyFile);
const result = await requestIntent(config, {
prompt: parsed.data.goal,
plan,
session_id: "mcp",
policy_hash: computePolicyHash(policyState.policy),
policy: policyState.policy,
validitySeconds: config.validitySeconds,
metadata: { source: "copilot", planning: "copilot-registered" }
});
Comment on lines +120 to +124
const st = await fh.stat();
if (offset >= st.size) return { rows: [], endOffset: offset };
const length = st.size - offset;
const buf = Buffer.alloc(length);
await fh.read(buf, 0, length, offset);
Comment thread plugins/armorcopilot/README.md Outdated
Comment on lines +14 to +20
## Install

```bash
copilot plugin install armoriq/armorCopilot
```

The plugin runtime auto-discovers `.claude-plugin/plugin.json` and registers hooks + MCP servers.
Comment thread plugins/armorcopilot/README.md Outdated
Comment on lines +11 to +12
- Optional CSRG cryptographic proofs for tamper detection
- Synchronous audit log to ArmorIQ backend
Comment on lines +18 to +38
"preToolUse": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap.mjs\" router",
"timeoutSec": 30
}
],
"permissionRequest": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap.mjs\" router",
"timeoutSec": 30
}
],
"postToolUse": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap.mjs\" router",
"timeoutSec": 30
}
]
Harihara04sudhan and others added 2 commits May 25, 2026 13:32
Mirrors the established ArmorIQ plugin repo layout:
  /
  ├── .claude-plugin/marketplace.json    repo-level marketplace
  ├── .agents/plugins/marketplace.json   mirror
  ├── plugins/<plugin-name>/             actual plugin tree
  └── README.md

Changes:
- Renamed packages/armorcopilot-gh/ → plugins/armorcopilot/
  (drop the "-gh" suffix; the brand is just ArmorCopilot, GitHub Copilot
   CLI is the only target. If we ever ship for another harness, that
   gets its own plugin directory under plugins/.)
- Added .claude-plugin/marketplace.json at repo root with publisher
  "ArmorIQ" (matches armorCodex#22 convention — the "Built by..." filter
  groups plugins by company, not product)
- Mirror to .agents/plugins/marketplace.json
- package.json name: @armoriq/armorcopilot-gh → @armoriq/armorcopilot
- README.md rewritten for the new layout
- Removed PLAN_GH_COPILOT.md + CTO_MEETING_BRIEF.md
  (planning docs for this work — preserved in this branch's commit
   history if needed; no value at repo root after the port lands)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After installing into the real `copilot` CLI and capturing what it sends
to hooks, two adapter changes were needed:

1. hooks.json — pass COPILOT_HOOK_EVENT via env per event
   Copilot CLI does NOT include `hook_event_name` in the hook payload
   (unlike Claude Code's snake_case variant). Our engine routes by
   event name, so we set it via the `env` field per hook.

2. hook-router.mjs — normalize Copilot's camelCase payload
   Copilot sends `sessionId / toolName / toolArgs (string-encoded)`
   where the engine expects `session_id / tool_name / tool_input (obj)`.
   Added a normalizer that copies camelCase → snake_case, parses
   `toolArgs` JSON string to object, and sets `hook_event_name` from
   the env var.

3. marketplace.json — fix `source` shape
   Copilot's marketplace schema rejected `{source:"local",path:"./..."}`.
   Changed to plain string `"./plugins/armorcopilot"` matching the
   format the official github/copilot-plugins marketplace uses.

4. README.md — fixed leftover `packages/armorcopilot-gh` path

Verified end-to-end with `copilot plugin marketplace add` + install:
  Marketplace "armorcopilot" added successfully.
  Plugin "armorcopilot" installed successfully.
  [DEBUG] Loaded 5 hook(s) from 1 plugin(s)
  [DEBUG] Adding tool: armorcopilot-policy-policy_update
  [DEBUG] Adding tool: armorcopilot-policy-policy_read
  [DEBUG] Adding tool: armorcopilot-policy-register_intent_plan
  [hook stderr] [armorcopilot] session started: ..., mode=enforce
  [hook stdout] {"hookSpecificOutput":{"hookEventName":"UserPromptSubmit",
                  "additionalContext":"ArmorCopilot active. Call
                  register_intent_plan first..."}}

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 25, 2026 10:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated 6 comments.

Comment on lines +45 to +50
const backendEndpoint =
env.ARMORCOPILOT_BACKEND_ENDPOINT?.trim() ||
env.BACKEND_ENDPOINT?.trim() ||
(useProduction
? "https://staging-api.armoriq.ai"
: "http://127.0.0.1:3000");
Comment on lines +264 to +274
const safeInternalTools = new Set([
"toolsearch",
"todowrite",
"listmcpresourcestool",
"readmcpresourcetool",
"read",
"grep",
"glob",
"websearch",
"webfetch"
]);
// SDK round-trip, even cold-start latency) eats into that budget.
// Awaiting nothing on the network path keeps the MCP response under
// ~100ms regardless of backend conditions.
const pendingPath = path.join(config.dataDir, "pending-plan.json");
Comment thread plugins/armorcopilot/README.md Outdated
- Verifies every tool call against the registered plan — out-of-plan tools are blocked even if policy would allow them
- Lets you set policies in natural language ("Block any commands that fetch URLs") via the `policy_update` MCP tool
- Optional CSRG cryptographic proofs for tamper detection
- Synchronous audit log to ArmorIQ backend
Comment thread README.md
## Install

```bash
copilot plugin install armoriq/armorCopilot
Comment thread plugins/armorcopilot/README.md Outdated
## Install

```bash
copilot plugin install armoriq/armorCopilot
Harihara04sudhan and others added 2 commits May 25, 2026 15:58
The relative `bash: "node scripts/bootstrap.mjs router"` only worked
when Copilot CLI happened to chdir to the plugin root before invoking
the hook. From other working directories the hook crashed with:

  Error: Cannot find module '/<user-cwd>/scripts/bootstrap.mjs'

Switched all 5 hook commands to expand \$CLAUDE_PLUGIN_ROOT (set by
Copilot CLI for every plugin hook). Now the bash command is:

  node "\$CLAUDE_PLUGIN_ROOT/scripts/bootstrap.mjs" router

This is the same pattern Claude Code uses and is what Copilot CLI
expects for plugins shipping scripts under their own plugin root.

Verified end-to-end: running `copilot` from /Users/<user>/Armoriq
(any non-plugin CWD) no longer hits the MODULE_NOT_FOUND error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
End-user flow:
  curl -fsSL https://armoriq.ai/install_armorcopilot.sh | bash

What it does (in order):
  1. Checks prereqs: copilot CLI, node>=20, npm, git
  2. Clones armoriq/armorCopilot to ~/.armoriq/armorCopilot
  3. npm install --omit=dev for plugin runtime deps
  4. npm install -g @armoriq/sdk-dev@latest (installs `armoriq-dev` CLI)
  5. copilot plugin marketplace add armoriq/armorCopilot
  6. copilot plugin install armorcopilot@armorcopilot
  7. armoriq-dev login --product armorcopilot  (device-code auth)

Idempotent — re-running pulls latest, refreshes deps, reinstalls plugin.

Flags:
  --uninstall    remove plugin + marketplace registration
  --skip-login   don't prompt for ArmorIQ login at the end

Overrides (testing):
  ARMORCOPILOT_MARKETPLACE_REPO  override marketplace source
  ARMORCOPILOT_GIT_URL           override clone source
  ARMORCOPILOT_GIT_REF           branch / tag (default main)
  ARMORCOPILOT_INSTALL_HOME      where to clone

Also commits the plugin's package-lock.json (generated by the local
npm install during PoC testing) for reproducible installs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 26, 2026 10:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Harihara04sudhan and others added 2 commits May 28, 2026 18:14
…art)

The ASCII art block in install_armorcopilot.sh was copy-pasted from
install_armorcodex.sh and never updated, so the banner that flashed
during install said ARMORCODEX instead of ARMORCOPILOT. Replaced with
ANSI Shadow font output for the correct 'ARMORCOPILOT' wordmark.

Verified by running the installer locally — banner now reads correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six review-driven fixes, in priority order:

1. config.mjs — endpoint resolution is now a 3-way switch on envMode
   (production/staging/local) instead of a confusing 2-way ternary that
   mapped useProduction → staging-api. Production users now correctly
   resolve to api.armoriq.ai unless overridden.

2. iap-service.mjs verify-step — fail closed on non-2xx. Previously a
   non-2xx response with a JSON body skipped the throw and fell through
   to defaulting `allowed=true`. Now any non-ok response throws.

3. engine.mjs safe-tools whitelist — dropped `websearch` and `webfetch`
   from the early-exit list. Network egress tools must go through full
   policy + intent enforcement; they were previously bypassing all
   guardrails.

4. audit-wal.mjs readBatch — capped per-read size at 4MiB to prevent
   OOM if the backend is down and the WAL grows large. Plenty of room
   for `maxRows=100` audit rows (40KB worst case each).

5. policy-mcp.mjs register_intent_plan + intent-schema.mjs — added
   optional `session_id` field to the plan. When the caller passes it,
   the pending plan is written to `pending-plan.<sessionId>.json`
   (per-session, matches what engine.mjs already reads). We also
   mirror to the legacy global path so older readers still work.
   Eliminates concurrent-session clobbering.

6. hooks/hooks.json — added the 3 missing registrations
   (postToolUseFailure, agentStop/Stop, sessionEnd). Engine had
   handlers for all of these but Copilot CLI never invoked them
   because they weren't registered. Failed tool executions and
   session cleanup now route through ArmorCopilot.

7. README.md — corrected the "synchronous audit log" claim to reflect
   the actual WAL-backed async batched pipeline, and updated the
   install command to show the marketplace add + install flow
   (plus the curl-pipe installer alternative).

Refs Copilot review on PR #3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 28, 2026 12:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 27 changed files in this pull request and generated 6 comments.

Files not reviewed (1)
  • plugins/armorcopilot/package-lock.json: Language not supported

Comment thread README.md
Comment on lines +7 to +13
## Install

```bash
copilot plugin install armoriq/armorCopilot
```

The plugin runtime auto-discovers `.claude-plugin/plugin.json` inside `plugins/armorcopilot/` and registers hooks + MCP servers.
Comment on lines +187 to +197
inputSchema: {
goal: z.string().min(1).optional()
.describe("One-line summary of what the plan accomplishes"),
steps: z.union([
z.array(PLAN_STEP_SCHEMA).min(1),
z.string().min(1)
]).optional()
.describe("Ordered list of tool calls (array, or JSON-stringified array)"),
plan: z.union([INTENT_PLAN_ZOD, z.string().min(1)]).optional()
.describe("Alternative: pass the whole plan as an object or JSON string")
}
Comment on lines +258 to +266
const result = await requestIntent(config, {
prompt: parsed.data.goal,
plan,
session_id: "mcp",
policy_hash: computePolicyHash(policyState.policy),
policy: policyState.policy,
validitySeconds: config.validitySeconds,
metadata: { source: "copilot", planning: "copilot-registered" }
});
"interface": {
"displayName": "ArmorCopilot",
"shortDescription": "Intent-based security policy and audit for GitHub Copilot CLI.",
"longDescription": "ArmorIQ intent-based security enforcement for GitHub Copilot CLI. Hooks into preToolUse / postToolUse / sessionStart / userPromptSubmitted events. Provides plan registration through MCP, intent-plan matching, permission gating, and synchronous audit on every tool invocation. Block tools by name, by argument pattern, or by intent drift — all configured from natural language via the policy_update MCP tool.",
Comment on lines +1 to +10
{
"name": "@armoriq/armorcopilot",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@armoriq/armorcopilot",
"version": "0.1.0",
"dependencies": {
Comment thread install_armorcopilot.sh
Comment on lines +4 to +29
# ArmorCopilot installer for GitHub Copilot CLI.
#
# Usage:
# curl -fsSL https://armoriq.ai/install_armorcopilot.sh | bash
#
# Works two ways:
# A. curl-pipe (no clone): fetches the plugin into ~/.armoriq/armorCopilot
# B. From an existing checkout: cd armorCopilot && bash install_armorcopilot.sh
#
# What it wires:
# 1. clones the plugin to ~/.armoriq/armorCopilot
# 2. npm install --omit=dev for plugin runtime deps
# 3. installs @armoriq/sdk-dev globally (for the `armoriq-dev` CLI)
# 4. registers the marketplace + installs the plugin in Copilot CLI:
# copilot plugin marketplace add armoriq/armorCopilot
# copilot plugin install armorcopilot@armorcopilot
# 5. runs `armoriq-dev login --product armorcopilot` for device-code auth
#
# Idempotent: re-running pulls the latest, reinstalls deps, refreshes marketplace.
#
# Flags:
# --uninstall remove the plugin + marketplace registration
# --skip-login don't prompt for ArmorIQ login at the end
#
# Non-interactive overrides:
# ARMORCOPILOT_MARKETPLACE_REPO override marketplace source (testing)
@Harihara04sudhan Harihara04sudhan merged commit f9379bb into main May 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tracking: ArmorCopilot (GitHub Copilot CLI plugin)

3 participants