Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ You'll need:
3. `bun test`, `cargo test`, and `go test -race` must pass before review.
4. Open a PR with a clear summary. CI runs `ci.yml` on each push.

For changes that ship or unship a public surface, update the status contract in the same PR:

- `README.md` "What ships today"
- `docs/status.md`
- Any affected guide/reference page under `docs/guide/` or `docs/reference/`

## Reporting issues

- **Bugs / feature requests:** open a GitHub issue at <https://github.com/openagentlock/OpenAgentLock/issues>.
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,15 @@ For agents that need to **author** new rules from natural-language intent, see [
| Surface | Status |
|---|---|
| `agentlock detect` | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| `agentlock install` (Claude Code, Codex CLI, Cursor) | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| `agentlock install` (Claude Code, Codex CLI, Cursor, Gemini CLI) | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| `agentlock install --tier {unattested,software,totp}` | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| `agentlock install` (OpenCode, Cline, Gemini CLI, Continue, VS Code Copilot) | ![not yet](https://img.shields.io/badge/-not%20yet-f59e0b?style=flat-square) |
| `agentlock install` (OpenCode, Cline, Continue, VS Code Copilot) | ![not yet](https://img.shields.io/badge/-not%20yet-f59e0b?style=flat-square) |
| Five baseline gates in monitor mode | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| Tamper-evident Merkle ledger | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| Local web dashboard | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| Software + TOTP signers (with `signer enroll` + session mint) | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| OS keychain signer, hardware-key (YubiKey PIV / FIDO2) | ![not yet](https://img.shields.io/badge/-not%20yet-f59e0b?style=flat-square) |
| OS keychain signer (macOS) | ![shipped](https://img.shields.io/badge/-shipped-16a34a?style=flat-square) |
| Hardware-key signer (YubiKey PIV / FIDO2) | ![not yet](https://img.shields.io/badge/-not%20yet-f59e0b?style=flat-square) |
| OIDC SSO + RBAC + LDAP | ![not yet](https://img.shields.io/badge/-not%20yet-f59e0b?style=flat-square) |
| Signed PDF audit report | ![not yet](https://img.shields.io/badge/-not%20yet-f59e0b?style=flat-square) |

Expand All @@ -87,7 +88,7 @@ The complete shipped/not-yet matrix lives at <https://openagentlock.github.io/Op
```mermaid
flowchart LR
subgraph host["Your host"]
H["Agent harness<br/><i>Claude Code · Codex CLI · Cursor</i>"]
H["Agent harness<br/><i>Claude Code · Codex CLI · Cursor · Gemini CLI</i>"]
CLI["agentlock CLI<br/><i>owns long-lived signing key</i>"]
end
subgraph docker["Docker (127.0.0.1)"]
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ agentlock --help
agentlock detect
```

This prints a table of every agent harness it found on your machine. Today, end-to-end hooks are wired for **Claude Code**, **Codex CLI**, and **Cursor**; other harnesses are detected but the installer flags them as not yet implemented. See [Status](../status.md).
This prints a table of every agent harness it found on your machine. Today, end-to-end hooks are wired for **Claude Code**, **Codex CLI**, **Cursor**, and **Gemini CLI**; other harnesses are detected but the installer flags them as not yet implemented. See [Status](../status.md).

Then pick a signer tier and run `install`. Two recommended paths:

Expand Down Expand Up @@ -124,4 +124,4 @@ Open the dashboard at <http://127.0.0.1:7879/> to watch live activity.

Out of the box, the control plane runs in **monitor mode**: every tool call is logged but nothing is blocked. Use the dashboard to review activity, then flip rules to enforce when you're confident. See [Policies and the five gates](policies.md).

OS-keychain and hardware-key (YubiKey) signers are stronger than TOTP and are on the roadmap; today TOTP is the strongest signer that ships. See [Signers](signers.md).
For stronger local signing, macOS can use the shipped OS-keychain signer. Hardware-key signers (YubiKey PIV / FIDO2), Linux Secret Service, and Windows DPAPI remain roadmap. See [Signers](signers.md).
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ hide:
![OpenAgentLock](assets/banner.svg){ .oal-banner .no-zoom }

<p class="lede" markdown>
Detect local agent harnesses, gate risky tool calls with a deterministic YAML policy, and anchor every decision in a tamper-evident Merkle ledger. Install once and keep working in **Claude Code, Codex CLI, and Cursor** as normal — your workflow does not change.
Detect local agent harnesses, gate risky tool calls with a deterministic YAML policy, and anchor every decision in a tamper-evident Merkle ledger. Install once and keep working in **Claude Code, Codex CLI, Cursor, and Gemini CLI** as normal — your workflow does not change.
</p>

[Get started](guide/getting-started.md){ .oal-cta .primary }
Expand All @@ -36,7 +36,7 @@ Eight harness detectors registered: Claude Code, Codex CLI, Cursor, OpenCode, Cl
#### Install plan / apply
<span class="gate-id">`agentlock install`</span>

Interactive multi-select. Posts to `/v1/install/plan`, renders the diff, applies on confirm. Real install paths live for **Claude Code** (HTTP hooks) and **Codex CLI** (TOML hooks).
Interactive multi-select. Posts to `/v1/install/plan`, renders the diff, applies on confirm. Real install paths live for **Claude Code**, **Codex CLI**, **Cursor**, and **Gemini CLI**.
</div>

<div class="gate-card" markdown>
Expand Down
6 changes: 5 additions & 1 deletion docs/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Returns the list of currently active gates with their per-gate status (matched c
Synchronous verdict for a single tool call. Request body:

- `session_id` — required, string. From `POST /v1/sessions/create`.
- `source` — required, string. Harness id (`claude-code`, `codex`, `cursor`, `mcp-proxy`).
- `source` — required, string. Harness id (`claude-code`, `codex`, `cursor`, `gemini`, `mcp-proxy`, or another detected source).
- `tool` — required, string. The tool name being checked (`Bash`, `Read`, `Write`, `mcp__<server>__<method>`).
- `input` — required, object. The tool's input shape (e.g. `{ "command": "rm -rf foo" }` for Bash).
- `cwd` — optional, string. Working directory if relevant to the rule.
Expand Down Expand Up @@ -79,6 +79,10 @@ The first time a new MCP server fingerprint is seen, it's queued for pinning. Ac

`POST /v1/hooks/codex/<event>`

`POST /v1/hooks/cursor/<event>`

`POST /v1/hooks/gemini/<event>`

`POST /v1/hooks/<harness>/<event>` (other harnesses; not yet implemented in the installer)

The hook event names mirror the harness's own naming. See [Hooks](hooks.md).
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The result is a small struct with `name`, `present`, `surfaces`, `configPaths`,

## Wiring vs detection

A harness being **detected** is independent of whether the installer will **wire it up**. Today, `agentlock install` wires Claude Code, Codex CLI, and Cursor. The other detectors land in the picker but the installer flags them as not yet implemented and skips writing hook entries.
A harness being **detected** is independent of whether the installer will **wire it up**. Today, `agentlock install` wires Claude Code, Codex CLI, Cursor, and Gemini CLI. The other detectors land in the picker but the installer flags them as not yet implemented and skips writing hook entries.

## Adding a new harness detector

Expand Down
13 changes: 10 additions & 3 deletions docs/reference/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ When the daemon is unreachable, the shim never writes user-visible text into std
- **Claude Code — live `statusLine`** (best UX). The installer writes a `statusLine` entry in `~/.claude/settings.json` pointing at a tiny health-check script at `<agentlockHome>/bin/agentlock-status`. Claude Code re-runs that script on every UI render and shows the result as a persistent element under the chat: `OpenAgentLock ✓` when the daemon is up, `OpenAgentLock ⚠ daemon offline` when it's not. The output is pure UI — never seen by the model.
- **Codex CLI — silent fail-open**. Codex has no `statusLine` analog and hides hook stderr on exit-0 (it only surfaces hook output as a red `(failed)` banner when the hook exits non-zero, which is the wrong channel for a status nudge). There is no in-Codex UI surface available for an indicator that won't either look like an error or pollute the model's input. The shim stays silent on every event when the daemon is unreachable.
- **Cursor — silent fail-open**. Cursor's hook spec has no UI surface that's outside the model's input stream and no statusLine equivalent. On daemon failures the shim emits a plain `{"permission":"allow"}` envelope and stays silent. A live indicator for Cursor would need a real Cursor extension; tracked separately.
- **Gemini CLI — silent fail-open**. Gemini hooks have no status-line equivalent. On daemon failures the shim stays silent and lets the tool call continue.

All three harnesses share the wrapper-stability fix: the hook command Claude Code / Codex / Cursor spawn points at `<agentlockHome>/bin/agentlock` (e.g. `~/Library/Application Support/OpenAgentLock/bin/agentlock` on macOS), written by `agentlock install`. The path lives in our state dir, not in the package manager's `node_modules` tree, so package upgrades don't strand the wired path. The same applies to `agentlock-status`. Both paths are shell-quoted in the wired command string so spaces (`Application Support`) survive `/bin/sh -c` parsing.
All four harnesses share the wrapper-stability fix: the hook command that Claude Code / Codex / Cursor / Gemini spawn points at `<agentlockHome>/bin/agentlock` (e.g. `~/Library/Application Support/OpenAgentLock/bin/agentlock` on macOS), written by `agentlock install`. The path lives in our state dir, not in the package manager's `node_modules` tree, so package upgrades don't strand the wired path. The same applies to `agentlock-status`. Both paths are shell-quoted in the wired command string so spaces (`Application Support`) survive `/bin/sh -c` parsing.

## Codex CLI

Expand All @@ -59,9 +60,15 @@ Cursor (≥1.7) uses **command hooks** in `~/.cursor/hooks.json`. The installer

Daemon-down behavior is documented in the **Daemon-down UX** section above — Cursor gets silent fail-open on transport errors. We never set `agent_message` on those, since that field lands in the model's input stream and would register as a prompt-injection attempt.

## Gemini CLI

Gemini CLI uses command hooks in `~/.gemini/settings.json`. The installer wires the `agentlock hook gemini <event>` shim for the same lifecycle shape as the Gemini settings file exposes, including pre-tool and post-tool events. The shim emits Gemini's permission-decision response shape on stdout.

Daemon-down behavior is documented in the **Daemon-down UX** section above — Gemini gets silent fail-open on transport errors.

## Other harnesses

OpenCode, Cline, Gemini CLI, Continue.dev all expose a hook surface but **the installer does not yet write to them**. The detectors find the harness, the picker shows it, and the install plan flags it as not yet implemented. Wiring is a follow-up tracked in the public roadmap.
OpenCode, Cline, and Continue.dev expose a hook surface but **the installer does not yet write to them**. The detectors find the harness, the picker shows it, and the install plan flags it as not yet implemented. Wiring is a follow-up tracked in the public roadmap.

VS Code Copilot has no general-purpose pre-tool hook surface; we cannot harden it from outside.

Expand All @@ -84,4 +91,4 @@ Ledger leaves use the same shape plus `verdict`, `reason`, `policy_rule_id`, and

## Nudges in deny replies

When a matched rule carries a `nudge:` hint (see [Policies → Nudges](../guide/policies.md#nudges)) and the final verdict is `deny`, every harness shim — Claude Code, Codex, Cursor — appends the hint to the deny reason it forwards to the model. The format is the literal string `"<reason>\n\n→ Suggested: <nudge>"` — arrow `→`, capital `S`, colon-space — and is intentionally stable so external tools can grep for `→ Suggested: ` to spot the hint. Allow, monitor-suppressed, and non-matching paths drop the field; the reason flows through unchanged.
When a matched rule carries a `nudge:` hint (see [Policies → Nudges](../guide/policies.md#nudges)) and the final verdict is `deny`, every harness shim — Claude Code, Codex, Cursor, Gemini — appends the hint to the deny reason it forwards to the model. The format is the literal string `"<reason>\n\n→ Suggested: <nudge>"` — arrow `→`, capital `S`, colon-space — and is intentionally stable so external tools can grep for `→ Suggested: ` to spot the hint. Allow, monitor-suppressed, and non-matching paths drop the field; the reason flows through unchanged.
Loading