{
  "markdown": "# ArmorGemini\n\nArmorIQ intent-based security enforcement plugin for the Gemini CLI. Enforces that Gemini declares what it intends to do before doing it, and every action is checked against that declared intent.\n\n**Status:** v0.3.2. Intent-plan enforcement via a bundled MCP server, local-first policy activation (`/armor:yes` is the only confirmation), backend policy layer on top for org-wide rules. Requires an ArmorIQ API key. See [CHANGELOG](CHANGELOG.md) for what changed.\n\n## Design\n\nArmorGemini is **backend-authoritative for policy** and **local-first for intent drift**. Every enforcement decision that catches drift fires client-side without waiting on the network; every policy decision flows through the ArmorIQ IAP backend. If the plugin is not configured with an API key, hooks fail closed and every tool call is denied with a clear \"not configured\" message.\n\n```\nUser Prompt ──► SessionStart hook             (banner: ENFORCING)\n                       │\n                       ▼\n                BeforeAgent hook               (inject \"declare your plan first\" directive)\n                       │\n                       ▼\n                Model calls register_intent_plan (armorgemini-policy MCP tool)\n                       │\n                       ▼\n                BeforeToolSelection hook        (no-op today, see Hook lifecycle)\n                       │\n                       ▼\nTool Call ──► BeforeTool hook  ──► 1. is tool in plan?          (drift check, local, no network)\n                                    2. is plan still fresh?      (TTL)\n                                    3. local policy match?       (${dataDir}/policy.json, no network)\n                                    4. POST /iap/enforce         (backend policy check)\n                       │\n                       ▼\n                allow | deny\n                       │\n                       ▼\nTool Result ──► AfterTool hook  ──► POST /iap/audit (best-effort)\n                       │\n                       ▼\n                SessionEnd hook                 (clear the plan file)\n```\n\n## Install\n\nOne-command install (writes global Gemini CLI settings, installs the ArmorIQ SDK/CLI, and prompts you to sign in):\n\n```bash\ncurl -fsSL https://armoriq.ai/install_armorgemini.sh | bash\n```\n\nThe installer:\n\n1. Installs `@armoriq/sdk` globally (adds the `armoriq` CLI to your PATH)\n2. Downloads the plugin into `~/.armoriq/armorGemini`\n3. Wires the six ArmorGemini hooks into `~/.gemini/settings.json`\n4. Wires the `armorgemini-policy` MCP server via `gemini-extension.json`\n5. Registers the `/armor:*` slash commands in `~/.gemini/commands/armor/`\n6. Runs `armoriq login --product armorgemini` which opens your browser, mints an API key, and writes it to `~/.armoriq/credentials.json`\n7. Verifies the hooks fire\n\nAfter that first run there is nothing more to do. The plugin picks up the key from `~/.armoriq/credentials.json` on every subsequent Gemini CLI session.\n\n### Manual credential controls (dev / advanced)\n\nEnd users should not need these. For local dev or CI:\n\n| Variable | Purpose |\n|---|---|\n| `ARMORIQ_API_KEY` | Override the credentials.json key. Precedence: env > credentials.json. |\n| `ARMORIQ_BACKEND_ENDPOINT` | Override backend URL. Default `https://api.armoriq.ai`. |\n| `ARMORIQ_ORG_ID` | Scope the plugin to a specific ArmorIQ org. |\n| `ARMORGEMINI_TIMEOUT_MS` | Per-request timeout to the backend (default 8000). |\n| `ARMORGEMINI_DATA_DIR` | Where per-session plan files live. Default `~/.gemini/armorgemini`. |\n| `ARMORGEMINI_INTENT_REQUIRED` | Set to `false` to disable intent-plan enforcement and fall back to policy-only mode (v0.2 behavior). |\n| `ARMORGEMINI_PLAN_TTL_SECONDS` | Age (in seconds) after which a stored plan is treated as stale. Default 600. |\n\n### Reconnecting or switching accounts\n\n```bash\narmoriq login --product armorgemini    # re-runs the browser auth, overwrites credentials.json\narmoriq logout                          # clears credentials.json\n```\n\n## The `armorgemini-policy` MCP server\n\nBundled with the plugin, declared in `gemini-extension.json` under `mcpServers`. Gemini CLI launches it automatically on session start. Three tools:\n\n| Tool | Purpose |\n|---|---|\n| `register_intent_plan` | Declare your plan for the current turn. Must be called before any other tool when `ARMORGEMINI_INTENT_REQUIRED=true` (the default). |\n| `reset_intent_plan` | Clear the current plan explicitly. The next tool call will be denied until a fresh plan is registered. |\n| `get_intent_plan` | Read the currently registered plan for a session. Informational. |\n\nThe plan shape:\n\n```json\n{\n  \"goal\": \"One-line summary of the task\",\n  \"steps\": [\n    { \"action\": \"read_file\", \"description\": \"Peek at the top of README\" },\n    { \"action\": \"list_directory\", \"description\": \"See what else is in the dir\" }\n  ]\n}\n```\n\nTools listed in `steps[].action` are allowed for the rest of the turn. Anything else is denied at BeforeTool as intent drift.\n\n## The `/armor` slash commands\n\nInstalled alongside the hooks. `/armor:add` and `/armor:template` stage the policy locally with a YAML preview; `/armor:yes` activates it and enforcement kicks in immediately on this session. No dashboard round-trip.\n\n| Command | Purpose |\n|---|---|\n| `/armor:list` | Show the current active local policy. |\n| `/armor:add <verb> <target> [note]` | Stage a rule change (verb: `allow`, `deny`, or `hold`). Shows a YAML preview. |\n| `/armor:template <name>` | Stage a named policy template (`lockdown`, `strict-read-only`, `balanced`). Shows a YAML preview. |\n| `/armor:yes` | Confirm the currently staged proposal. Writes it to `${dataDir}/policy.json` (`BeforeTool` picks it up immediately) and fire-and-forgets the same policy to the ArmorIQ backend for audit. |\n| `/armor:no` | Discard the currently staged proposal. |\n| `/armor:help` | Show help. |\n\nExample flow:\n\n```\n/armor:add deny web_fetch external network not allowed here\n    (YAML preview appears, nothing sent anywhere)\n/armor:yes\n    (local policy.json written, enforcement live, backend audit push best-effort)\n/armor:list\n    (shows the new rule)\n```\n\n## Hook lifecycle\n\n| Hook | What ArmorGemini does |\n|---|---|\n| `SessionStart` | Logs session_id, cwd, and configured state. Prints the ENFORCING banner. |\n| `BeforeAgent` | Injects a directive telling the model to call `register_intent_plan` (armorgemini-policy MCP) before any other tool. |\n| `BeforeToolSelection` | No-op today. Gemini API rejects `allowedFunctionNames` with `mode: \"AUTO\"`, and `mode: \"ANY\"` forces tool calls on every turn. Enforcement stays in `BeforeTool`. |\n| `BeforeTool` | Layered enforcement: (1) intent-drift check against the registered plan, (2) local policy check against `${dataDir}/policy.json` (source of truth for enforcement, written by `/armor:yes`), (3) backend `POST /iap/enforce` for org-wide policy. Any layer denying → deny. |\n| `AfterTool` | Sanitizes input (redacts obvious secret-shaped keys, truncates long strings), then best-effort `POST /iap/audit`. Never blocks. |\n| `SessionEnd` | Clears the session's plan file. |\n\n## Tests\n\n```bash\nnode --test tests/*.test.mjs\n```\n\nTests stub `globalThis.fetch` per case to simulate backend responses (allow, deny, 401, network error), and use a scratch data dir to exercise the intent-plan path without touching real state. No real network is hit.\n\n## Provenance\n\nPorts the ArmorClaude enforcement model to Gemini CLI. Gemini CLI's hook set is a superset of what Claude Code exposes: `BeforeAgent` is the per-turn hook (equivalent of Claude's `UserPromptSubmit`), `BeforeToolSelection` is a bonus tightening layer that Claude Code doesn't have (structurally hides off-plan tools from the model). The plugin bundles a stdio MCP server declared via `mcpServers` in the `gemini-extension.json` manifest, so intent-plan capture works natively without shell-side hacks.\n\n## License\n\nMIT\n",
  "bytes": 7879,
  "sha": "ba60257cf8f1a912e72690d3117413720a89276fcda68381a265cd5ad12c8d3e",
  "repo_slug": "armoriq/armorgemini",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_armoriq_armorgemini_39227aaa/readme"
}