@openlatch/client 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +82 -257
  2. package/package.json +6 -6
package/README.md CHANGED
@@ -6,216 +6,48 @@
6
6
 
7
7
  <p align="center">
8
8
  <a href="https://github.com/OpenLatch/openlatch-client/actions/workflows/pr-checks.yml"><img src="https://github.com/OpenLatch/openlatch-client/actions/workflows/pr-checks.yml/badge.svg" alt="PR Checks" /></a>
9
- <a href="https://codecov.io/gh/OpenLatch/openlatch-client"><img src="https://codecov.io/gh/OpenLatch/openlatch-client/graph/badge.svg" alt="codecov" /></a>
10
- <a href="https://crates.io/crates/openlatch-client"><img src="https://img.shields.io/crates/v/openlatch-client.svg" alt="crates.io" /></a>
11
9
  <a href="https://www.npmjs.com/package/@openlatch/client"><img src="https://img.shields.io/npm/v/@openlatch/client.svg" alt="npm" /></a>
12
10
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License" /></a>
13
11
  <a href="https://openlatch.slack.com"><img src="https://img.shields.io/badge/Slack-join%20us-4A154B?logo=slack&logoColor=white" alt="Slack" /></a>
14
12
  </p>
15
13
 
16
- ---
17
-
18
- **[OpenLatch](https://openlatch.ai) is the agent-agnostic execution control layer for enterprise AI agents.** This repository is its open-source **capture-and-enforce adapter**: the node that runs inside a coding agent's own execution path, evaluates every covered action against that agent's Autonomy Zone before it runs, and is what gives an agent the control level **Enforced**.
19
-
20
- It is **Mode 1 — the native hook** — the first of three adapters onto one policy brain. It plugs into agents through their native lifecycle hooks, decides locally, and forwards what it sees to the control plane.
21
-
22
- **This README is for people working on the client.** If you want to *use* OpenLatch, start at [docs.openlatch.ai](https://docs.openlatch.ai) — `npx @openlatch/client init` and you are done.
23
-
24
- ---
25
-
26
- ## Where this node sits
27
-
28
- OpenLatch runs a five-step control loop around each agent's **Agent Autonomy Zone** — the operating envelope of what an agent may do, authored on the platform as intent policies across five dimensions (Quality, Economics, Security, Safety, Compliance) and compiled to deterministic rules. This client touches four of the five steps. None of the authoring happens here.
29
-
30
- | Step | What this node does | What it does not do |
31
- | ---- | ------------------- | ------------------- |
32
- | **1 · Identify** | Stamps every event with agent type, session, host and identity, so the platform's record of a sanctioned agent stays live rather than quarterly | Discovery. An agent arrives here by being installed onto, never by being found |
33
- | **2 · Define** | Nothing. It receives the compiled zone as a signed policy bundle and holds it resident | Author policy. Intent policies are written and compiled on the platform |
34
- | **3 · Detect** | Captures the actions the execution graph is built from — tool calls, commands, file changes, model calls, cost — and matches them against the resident bundle | Detection of its own. No models, no scanning, no cross-host correlation |
35
- | **4 · Act** | Returns the verdict at the hook boundary, before the action runs, from an in-process evaluation | Ask the network for it |
36
- | **5 · Improve** | Writes the local audit log and forwards every event, verdict and mode asynchronously | Report, alert, or render a dashboard |
37
-
38
- Four properties shape the code more than any feature does:
39
-
40
- | Property | What it means here |
41
- | -------- | ------------------ |
42
- | **Inside the agent, not a proxy in front of it** | The decision point is the agent's own hook lifecycle, so it sees the *action* rather than the traffic. It is not a sandbox — the threat model is a **misbehaving** agent, not an operator working to defeat it |
43
- | **Local-authoritative** | The resident bundle is the authority, not a cache of one. Evaluation reads an in-memory handle and returns, so the node keeps deciding with the network unplugged |
44
- | **Sanctioned agents only** | Depth over dragnet. This node makes the agents an enterprise has already blessed enforceable; it does not go looking for the ones it has not |
45
- | **Coverage is a deployment outcome** | An adapter in the execution path is what makes an agent **Enforced**. Without one an agent can still be **Monitored** (visible through an integration) or **Known** (identified and classified). The record always states which level applies |
46
-
47
- ### The three adapters
48
-
49
- | Mode | Surface | This repo |
50
- | ---- | ------- | --------- |
51
- | **Mode 1 — native hook** | Coding agents, including hosted ones | **Yes.** Ships first |
52
- | **Mode 2 — framework middleware** | LangChain / LangGraph | No. Ships second |
53
- | **Mode 3 — SDK + tool / MCP gate** | Bedrock, Azure AI Foundry, custom agents | No. Ships third, or on demand |
54
-
55
- ### Verdicts, and which ones this node enforces today
56
-
57
- The verdict vocabulary is **Allow, Ask, Block or Optimize**. What this binary can express is narrower than the vocabulary, and this is the honest map of it. A verdict is deterministic because an explicit policy produced it.
58
-
59
- | Verdict | On the wire / in the bundle | What this node does today |
60
- | ------- | --------------------------- | ------------------------- |
61
- | **Allow** | `allow`, `approve` | The action proceeds. `approve` is a user-confirmed allow |
62
- | **Ask** | No wire variant — an `allow` / `approve` carrying `context` | Rendered to Claude Code as `permissionDecision: "ask"`, the alert as its reason. It **allows and flags**; it does not hold the agent waiting on a human. It prevents recurrence, not the first occurrence |
63
- | **Block** | `deny` — the only action a `kind=command` rule may take | Reaches the agent as a native deny at `pre_tool_use`, naming the rule that produced it |
64
- | **Optimize** | `kind=request` rules: `prefix_reorder`, `history_trim`, `prompt_edit` | **Measurement only.** `history_trim` and `prompt_edit` are rewritten to `observe` at bundle load whatever the config says; `prefix_reorder` may act only behind `boundary.transforms_act`, which ships `false`. Out of the box the boundary observes, reports what a transform *would* have saved, and forwards the original bytes |
65
-
66
- Staging is per rule: `observe` records the match and allows the action, `enforce` applies the verdict — Monitor and Enforce in the product. Most restrictive wins across matching rules, and every rule is coerced to `observe` when the bundle's `enforcement_enabled` is false.
67
-
68
- Deny enforcement is event-scoped. Only pre-action events have somewhere to put a deny; on a post-action event it degrades to `{}` and survives in the record alone.
14
+ <p align="center">
15
+ <a href="https://openlatch.ai">Website</a> ·
16
+ <a href="https://openlatch.ai/docs/">Docs</a> ·
17
+ <a href="https://app.openlatch.ai">Dashboard</a> ·
18
+ <a href="https://openlatch.slack.com">Slack</a>
19
+ </p>
69
20
 
70
21
  ---
71
22
 
72
- ## Develop
23
+ **[OpenLatch](https://openlatch.ai) is the execution control layer for enterprise AI agents.** It turns human intent into **Agent Intent Policies** across each agent's **Autonomy Zone** — security, safety, compliance, economics and quality — and makes a deterministic decision on every covered action before it executes: allow, ask, block or optimize.
73
24
 
74
- ```bash
75
- git clone https://github.com/OpenLatch/openlatch-client && cd openlatch-client
76
- cargo build
77
- cargo test
78
- ```
25
+ This repository is its open-source **capture-and-enforce adapter**: the node that runs inside a coding agent's own execution path, evaluates every covered action against that agent's Autonomy Zone before it runs, and is what gives an agent the control level **Enforced**.
79
26
 
80
- Rust 1.88+, no other prerequisites. `cargo build` produces both binaries in `target/debug/`.
27
+ It plugs into the agent's native lifecycle hooks, decides locally and in-process, and forwards what it saw to the platform afterwards. The agent never waits on the network, and the verdict never depends on it.
81
28
 
82
- ### Work in a sandbox, not on your own machine
83
-
84
- `openlatch init` installs into `~/.openlatch`, writes `~/.claude/settings.json`, and points every live Claude Code session on the host at its boundary listener. You do not want your work-in-progress build doing that.
85
-
86
- `olbox` gives you a complete install that cannot touch your own — its own state directory, its own agent config, its own ports:
29
+ ## Quick start
87
30
 
88
31
  ```bash
89
- cargo install --path tools/sandbox --locked # once
90
-
91
- olbox enter dev # a shell inside the sandbox
92
- openlatch init # installs into the sandbox and nothing else
93
- claude # this session — and only this session — is routed
94
- exit # and you are back on your own machine
32
+ npx @openlatch/client init # installs the client, detects your agents, wires their hooks
33
+ openlatch system auth login # links this machine to your OpenLatch account (opens the browser)
34
+ claude # use your agent as usual — every tool call is now covered
35
+ codex # … and the other one, under the same policy on the same host
95
36
  ```
96
37
 
97
- It lives in [`tools/sandbox`](tools/sandbox/README.md) rather than in the client, because sandboxing is what *we* need and the client is what customers install. `olbox list`, `olbox exec dev -- <cmd>`, `olbox destroy dev`, and `eval "$(olbox env dev)"` if you would rather not use a subshell — the README covers all of it.
98
-
99
- Under the hood it is five environment variables derived from the name, which are supported client seams you can also set by hand. Getting one wrong is not a failed test — it writes your real `~/.claude/settings.json` — which is why the tool exists.
100
-
101
- | Variable | Role |
102
- | -------- | ---- |
103
- | `OPENLATCH_DIR` | State: config, token, logs, outbox |
104
- | `CLAUDE_CONFIG_DIR` | Agent config. **Claude Code's own variable**, so the daemon and the session it captures cannot end up pointed at different directories |
105
- | `OPENLATCH_PORT` | Daemon port (sandboxes: 17400–17499) |
106
- | `OPENLATCH_BOUNDARY_PORT` | Model-boundary port (sandboxes: 17600–17699) |
107
- | `OPENLATCH_BOUNDARY_OWN_WIRING` | Lets a non-default-port instance write *its own* agent config. Never inferred — see [`.claude/rules/isolated-instances.md`](.claude/rules/isolated-instances.md) |
38
+ `openlatch status` shows what is captured and enforced on this host. The [dashboard](https://app.openlatch.ai) shows the events and the verdicts. Full walkthrough: [Getting started](https://openlatch.ai/docs/getting-started/).
108
39
 
109
- `openlatch uninstall --purge` works inside a sandbox and removes the install; `olbox destroy` removes the sandbox itself.
40
+ The installer runs on Node.js. macOS, Windows and Linux are supported.
110
41
 
111
- A sandbox is never supervised: the OS unit is machine-global and carries no environment, so one installed from a sandbox shell would supervise your *real* install from your dev binary. `supervision enable` refuses there, `init` skips it, and `doctor` reports Persistence as not applicable. Use `openlatch start` — a sandbox is a session of work, not something that should survive a reboot.
112
-
113
- ### Verify before you push
114
-
115
- ```bash
116
- cargo fmt --all -- --check
117
- cargo clippy --all-targets --all-features -- -D warnings
118
- cargo test --all-features
119
- cargo test --lib --no-default-features # proves openlatch-hook links no `core`
120
- ```
121
-
122
- `tools/e2e` holds the end-to-end harness; it drives a real daemon, so run it under `olbox exec <name> --` or in its Docker mode — never straight against your own install. It enforces that itself and will refuse to start on a machine whose isolation seams are unset, printing the commands to fix it.
123
-
124
- ---
125
-
126
- ## The output contract
127
-
128
- Every command that reports health renders from one model (`src/cli/report.rs`) over the same eleven sections. Three rules decide what you see, and they are enforced by tests rather than by review:
129
-
130
- | State | Mark | Means |
131
- | ----- | :--: | ----- |
132
- | `Ok` | `✓` | Enabled **and proven working**. The only green. |
133
- | `Off` | `⚠` | Switched off deliberately. Always carries a code and a remedy. |
134
- | `Degraded` / `Pending` | `⚠` | Working, but not at full capability, or still verifying |
135
- | `Unknown` | `⚠` | Blocked by another section, which it names. One outage, one cross. |
136
- | `Failed` | `✗` | Enabled and not working |
137
- | `NotApplicable` | `·` | Absent from the build, or an exercised privacy opt-out |
138
-
139
- Eleven sections, always all reported, under three groups — the questions a reader asks in the order they ask them:
140
-
141
- | Group | Sections | Question |
142
- | ----- | -------- | -------- |
143
- | **Runtime** | Environment · Daemon · Persistence · Update | is it running, and will it keep running? |
144
- | **Coverage** | Hooks · Boundary · Policy · Inventory · Integrity | is it seeing everything, and enforcing? |
145
- | **Platform** | Cloud · Telemetry | is any of it leaving this machine? |
146
-
147
- A green section is one line. Anything else lists what needs attention, with its cause and its remedy. `-v` unfolds every check.
148
-
149
- ```
150
- Runtime
151
- Environment ✓ 3 passed, 1 not applicable
152
- Daemon ✓ 2 checks passed
153
- Persistence ⚠ Disabled at your request (user_opt_out) [OL-1513]
154
- The daemon will not restart after a logout, a reboot, or a crash.
155
- source : [supervision] disabled_reason = "user_opt_out"
156
- remedy : Run `openlatch supervision enable` to re-arm it.
157
- Update ✓ Daemon is serving the installed version (0.1.18)
158
-
159
- Platform
160
- Cloud ✓ Connected: http://localhost:5173 (0 event(s) forwarded)
161
- Telemetry · Disabled by user (opt-out honoured)
162
- ```
163
-
164
- `Policy` sits under Coverage, not Platform: the bundle arrives from the cloud but the evaluation is local and authoritative — it is about what this host enforces, not about what leaves it.
165
-
166
- ### Exit codes
167
-
168
- | Code | Meaning |
169
- | ---- | ------- |
170
- | 0 | Healthy |
171
- | 1 | Something enabled is not working |
172
- | 2 | Usage error (clap) |
173
- | 3 | Resource not found |
174
- | 4 | Permission denied |
175
- | 5 | Conflict — `OL-1501` only, because systemd's `RestartPreventExitStatus=5` keys off it |
176
- | **7** | **Degraded** — everything runs, but something is switched off or not at full capability |
177
- | 130 | Interrupted |
178
-
179
- `7` matters: `openlatch doctor && deploy` must not succeed on a host where nothing is captured or enforced.
180
-
181
- ---
182
-
183
- ## Commands
184
-
185
- | Command | Notes |
186
- | ------- | ----- |
187
- | `openlatch init` | Complete, idempotent reinstall. Reclaims the ports first — identifying the holder **by the port**, not by `daemon.pid` — then proves the daemon it started is the one serving (PID, version, `/health`). |
188
- | `openlatch status` | Dashboard plus the eleven-section verdict |
189
- | `openlatch start [--foreground] [--port N] [--boundary-port N]` | Refuses when a daemon already runs (`OL-1501`, exit 5) |
190
- | `openlatch stop` / `restart` | `stop` also removes the agent's boundary wiring, and says so |
191
- | `openlatch doctor` | Full diagnosis with causes and remedies |
192
- | `openlatch doctor --fix` | Heals what it can, backs up to `.bak` siblings + `~/.openlatch/fix-journal.json`. Never re-enables what you switched off. |
193
- | `openlatch doctor --restore` | Reverses the last `--fix`. Surgical merge preserves your non-OpenLatch hooks. |
194
- | `openlatch doctor --rescue [--since 24h] [--yes]` | Redacted diagnostic ZIP for support |
195
- | `openlatch boundary status` | Full classification, not a port probe |
196
- | `openlatch boundary {enable,disable} [-y] [--no-restart]` | Writes `[boundary] enabled`, then offers the restart that applies it |
197
- | `openlatch hooks status` | The Hooks section in detail |
198
- | `openlatch supervision {install,uninstall,enable,disable,status}` | OS-native supervisor (launchd / systemd --user / Task Scheduler), user-scope only |
199
- | `openlatch inventory {list,log,rescan,status,inspect,projects,ack}` | Configuration-plane monitoring |
200
- | `openlatch auth {login,logout,status}` · `openlatch telemetry {…}` · `openlatch update` · `openlatch logs` · `openlatch uninstall [--purge]` · `openlatch docs` | |
201
-
202
- Noun-verb aliases: `hooks install` = `init`, `daemon start` = `start`, and so on — identical arguments, pinned by test.
203
-
204
- Global flags: `--json`, `--verbose`/`-v`, `--debug`, `--quiet`/`-q`, `--no-color`. Every diagnostic's JSON carries the same `sections[]` the human rendering shows.
205
-
206
- ---
207
-
208
- ## Architecture
209
-
210
- Hooks live inside the agent, the client decides locally, the platform authors rules and runs analysis.
42
+ ## How it works
211
43
 
212
44
  ```
213
45
  ┌─────────────────────────────────────────────────────────────────┐
214
- │ Your Machine │
46
+ │ Developer's machine │
215
47
  │ │
216
48
  │ ┌──────────┐ hook event ┌──────────────────────────────┐ │
217
- │ │ Claude │──────────────▶│ OpenLatch Client │ │
218
- │ │ Code │ │ (localhost:7443) │ │
49
+ │ │ Coding │──────────────▶│ OpenLatch client │ │
50
+ │ │ agent │ │ (127.0.0.1) │ │
219
51
  │ │ │ │ │ │
220
52
  │ │ │ │ 1. Wrap in envelope │ │
221
53
  │ │ │ │ 2. Evaluate resident │ │
@@ -223,83 +55,85 @@ Hooks live inside the agent, the client decides locally, the platform authors ru
223
55
  │ │ │ ◀─ verdict ──│ 3. Redact credentials │ │
224
56
  │ └──────────┘ │ 4. Write local audit log │ │
225
57
  │ │ 5. Batch → forward │────┼──▶ OpenLatch platform
226
- │ │ ◀── policy bundle │◀───┼── (the policy brain:
227
- │ └──────────────────────────────┘ │ zone, rules, analysis)
58
+ │ │ ◀── policy bundle │◀───┼── (policies, analysis,
59
+ │ └──────────────────────────────┘ │ dashboard)
228
60
  └─────────────────────────────────────────────────────────────────┘
229
61
  ```
230
62
 
231
- - **Hook-native, not a proxy** — the decision point runs inside the agent's own runtime, so it evaluates the action rather than the traffic. Model-call economics additionally use a loopback listener on `127.0.0.1`.
232
- - **Local-authoritative verdicts** — the daemon evaluates a resident policy bundle in-process; the verdict path never touches the network. The cloud serves rules, it does not decide.
233
- - **The daemon owns `ANTHROPIC_BASE_URL`** — written after its bind succeeds and a synthetic round trip proves the listener can reach the provider, removed on teardown. Nothing else writes it, so the agent config can never name a listener that does not exist.
234
- - **Fail-static, not fail-open** — a resident bundle keeps enforcing offline forever. Genuine fail-open is limited to "no bundle was ever fetched" and "the hook binary cannot reach the daemon".
235
- - **Privacy-first** — credentials are redacted locally before anything leaves the machine.
63
+ - **Inside the agent, not a proxy in front of it.** The decision point is the agent's own hook lifecycle, so it sees the *action* rather than the traffic. Model calls additionally pass through a loopback listener, so cost and token usage are measured on the same host.
64
+ - **Local-authoritative.** The resident policy bundle is the authority, not a cache of one. Evaluation reads an in-memory handle and returns.
65
+ - **Fail-static, not fail-open.** A resident bundle keeps enforcing offline, forever. A failed refresh keeps the last known good.
66
+ - **Privacy-first.** Credentials are redacted locally before anything leaves the machine.
236
67
 
237
- Two binaries ship: **`openlatch`** (<30 MB, the CLI and daemon) and **`openlatch-hook`** (<20 MB, spawned per hook event, fails open to `~/.openlatch/logs/fallback.jsonl`).
68
+ ## What a verdict does
238
69
 
239
- The product perimeter — what the client does, and what it deliberately does not — is **[AGENTS.md](AGENTS.md)**. Subsystem detail (envelope format, policy engine, subsystem supervision, the boundary's wiring invariants, releasing) lives in [`.claude/rules/`](.claude/rules/), one file per subsystem, scoped to the paths it governs.
70
+ The verdict vocabulary is **Allow, Ask, Block or Optimize**. What this client can express today is narrower than the vocabulary, and this is the honest map of it. A verdict is deterministic because an explicit policy produced it.
240
71
 
241
- ### Supported agents
72
+ | Verdict | On the wire / in the bundle | What this client does today |
73
+ | ------- | --------------------------- | ------------------------- |
74
+ | **Allow** | `allow`, `approve` | The action proceeds. `approve` is a user-confirmed allow |
75
+ | **Ask** | No wire variant — an `allow` / `approve` carrying `context` | It **allows and flags**; it does not hold the agent waiting on a human. Claude Code renders it as `permissionDecision: "ask"` with the alert as its reason; Codex CLI has no `ask` tier, so it degrades to a `systemMessage` carrying that same reason. It prevents recurrence, not the first occurrence |
76
+ | **Block** | `deny` — the only action a `kind=command` rule may take | Reaches the agent as a native deny at `pre_tool_use`, naming the rule that produced it |
77
+ | **Optimize** | `kind=request` rules: `prefix_reorder`, `history_trim`, `prompt_edit` | **Measurement only.** Out of the box the model relay observes, reports what a transform *would* have saved, and forwards the original bytes |
242
78
 
243
- Claude Code, on macOS, Windows and Linux, across 12 hook events. It is the reference implementation, and the only agent this node can currently make **Enforced**. Other coding agents are recognised as envelope `agent_type` values — `cursor`, `windsurf`, `github-copilot`, `codex-cli`, `gemini-cli`, `cline`, `openclaw` — so their events store and attribute correctly, but `init` cannot install their hooks yet.
79
+ Each rule runs in Monitor (record the match, allow the action) or Enforce (apply the verdict). Most restrictive wins across matching rules.
244
80
 
245
- Adding one means an `AgentBinding` in `src/hooks/bindings/` **and** a verdict translator in `src/hook_output/` — without the translator a `deny` is discarded before the developer ever sees it, which is worse than not enforcing. The translator comes first.
81
+ ## Supported agents
246
82
 
247
- ---
83
+ **Two agents are wired end-to-end: [Claude Code](https://claude.ai/code) and [OpenAI Codex CLI](https://developers.openai.com/codex/cli).** `init` detects every agent on the host and wires **all** of them — coverage is the default, and `--agent <type>` is how you opt one out. `doctor`, `status` and `uninstall` each report and tear down every agent they find.
248
84
 
249
- ## Configuration
85
+ Coverage is stated per agent **and per plane**. An unqualified "Enforced" would round an enforced command plane and an observe-only request plane back up to green, and that is the one arithmetic this table refuses.
250
86
 
251
- Precedence: CLI flags → environment (`OPENLATCH_*`) → `~/.openlatch/config.toml` → defaults.
252
-
253
- | Variable | Description | Default |
254
- | -------- | ----------- | ------- |
255
- | `OPENLATCH_DIR` | State directory | `~/.openlatch` |
256
- | `OPENLATCH_PORT` | Daemon port. `init` binds this exact port; unset, it probes 7443–7543. | `7443` |
257
- | `OPENLATCH_API_URL` | Cloud API base URL | `https://app.openlatch.ai` |
258
- | `OPENLATCH_API_KEY` | API key (credential chain: environment → keychain → encrypted file) | — |
259
- | `OPENLATCH_SKIP_KEYRING` | Treat the OS keychain as unavailable, so the env var wins | unset |
260
- | `OPENLATCH_LOG` | `error` / `warn` / `info` / `debug` / `trace` | `info` |
261
- | `OPENLATCH_BOUNDARY_ENABLED` | Model-boundary listener. While on, the daemon points the agent at it — but only once a synthetic request proves the listener can reach the provider. Being wired disables Claude Code Remote Control. | `true` |
262
- | `OPENLATCH_BOUNDARY_PORT` | Boundary port. A non-default port makes the instance isolated. | `7600` |
263
- | `OPENLATCH_BOUNDARY_OWN_WIRING` | Let an isolated instance write its own agent config | derived from the port |
264
- | `OPENLATCH_BOUNDARY_UPSTREAM` | Where the boundary forwards. Every model call and provider credential goes here — change it only for a local harness. | `https://api.anthropic.com` |
265
- | `OPENLATCH_BOUNDARY_TRANSFORMS_ACT` | Whether an acting `prefix_reorder` rule may rewrite the forwarded request body. Off, the boundary measures and forwards the original bytes. See [Optimize](#verdicts-and-which-ones-this-node-enforces-today) for what it does and does not gate. | `false` |
266
- | `OPENLATCH_POLICY_ENABLED` | Local policy evaluation. `false` is a complete off switch, not observe mode. | `true` |
267
- | `OPENLATCH_INVENTORY_ENABLED` | Configuration-plane monitoring | `true` |
268
- | `OPENLATCH_CLOUD_BATCH_MAX_EVENTS` | Events per ingest batch, clamped to `1..=100` | `50` |
269
- | `OPENLATCH_CLOUD_BATCH_MAX_WAIT_MS` | Flush deadline, anchored to the first buffered event | `5000` |
270
- | `OPENLATCH_CLOUD_OUTBOX_MAX_BYTES` | Outbox cap before drop-oldest (0 disables) | `104857600` |
271
- | `OPENLATCH_CLOUD_FALLBACK_MAX_BYTES` | Fallback-log cap before drop-oldest (0 disables) | `52428800` |
272
- | `OPENLATCH_AUTO_UPDATE` | Background auto-update worker | `true` |
273
- | `OPENLATCH_UPDATE_CHECK` | Startup version check | `true` |
274
- | `OPENLATCH_NPM_REGISTRY` | Registry origin for `openlatch update` | `https://registry.npmjs.org` |
275
- | `OPENLATCH_TELEMETRY_DISABLED` | `1` opts out of anonymous usage telemetry | unset |
276
-
277
- **Cloud forwarding is not optional.** `[cloud] enabled` and `OPENLATCH_CLOUD_ENABLED` are still parsed so existing configs keep loading, but they are ignored — a client that captures events and sends them nowhere is a log rotator. Point `[cloud] api_url` elsewhere to change *where* events go.
278
-
279
- Auto-update, its quiet-window deferral and its rollback sentinel are documented in the module rustdoc of [`src/core/update.rs`](src/core/update.rs); `openlatch update --check --json` is the manual probe.
87
+ | Agent | Delivery | Command plane | Request plane | Control level |
88
+ | ----- | -------- | ------------- | ------------- | ------------- |
89
+ | **Claude Code** | any | **Enforced** | Observed *(runtime-checked)* | **Enforced** *(command plane)* |
90
+ | **Codex CLI** | managed (MDM / system / cloud) | **Enforced**, and **not disableable by the developer** | Observed *(runtime-checked)* | **Enforced** *(command plane)* |
91
+ | **Codex CLI** | self-serve (`npx init`) | **Monitored** until `/hooks` trust; **Enforced** after | Observed *(runtime-checked)* | Monitored → Enforced |
92
+ | Cursor · Windsurf · GitHub Copilot · Gemini CLI · Cline · OpenClaw | — | Not wired | Not wired | Known |
280
93
 
281
- ---
94
+ **The vocabulary is closed.** *Enforced* — the verdict reaches the agent and is obeyed. *Monitored* — the integration is installed and events flow, but a verdict cannot yet be delivered, so nothing is prevented. *Observed* — capture and would-have measurement only, by design for this phase. *Known* — identified and classified, with the limits stated.
95
+
96
+ **Why Codex has two rows.** A user-level Codex hook is *marked for review and skipped until trusted*, so a fresh self-serve install is Monitored — not Enforced — until you run `/hooks` in Codex and trust the OpenLatch hook. Any re-install that changes the hook command re-arms that review. On the managed path the hook is trusted by policy and cannot be switched off by the developer, which is a stronger claim than we can make on Claude Code. `openlatch doctor` proves the hook by **invoking** it rather than by observing that a file exists, and reports the trust state per agent — an untrusted hook is never spawned, and that is the one failure that looks identical to working from the outside.
97
+
98
+ Making an agent **Enforced** is a hook binding plus a verdict translator. Both are contributions we welcome — see [Contributing](#contributing).
99
+
100
+ ## Behind a corporate proxy
101
+
102
+ `init` finds the route on its own: it probes what is already configured, then walks the OS's own proxy settings (Windows, macOS, GNOME), and only asks if none of them reach the platform. Kerberos/Negotiate uses the logged-on identity; a TLS-inspecting proxy needs only its root CA in `ca_bundle`. Proxy credentials go to the OS keychain, never to a file.
103
+
104
+ ```bash
105
+ openlatch init --proxy http://proxy.corp:8080 --ca-bundle /etc/ssl/corp-root.pem
106
+ openlatch system proxy test # walks the chain hop by hop and names the failing one
107
+ ```
108
+
109
+ The hosts to open, every `[proxy]` key and every `OL-122x` code: [docs/egress.md](docs/egress.md).
282
110
 
283
- ## Releases
111
+ ## Configuration
112
+
113
+ `openlatch init` writes `~/.openlatch/config.toml`, and every key has an `OPENLATCH_*` environment variable that overrides it. Precedence is CLI flags → environment → `config.toml` → defaults. The full list is in [docs/configuration.md](docs/configuration.md).
284
114
 
285
- Two artifacts on independent version lines, both cut by [release-please](https://github.com/googleapis/release-please) from Conventional Commits:
115
+ ## Documentation
286
116
 
287
- | Artifact | Tag | Where |
288
- | -------- | --- | ----- |
289
- | The client | `v1.2.3` | GitHub Releases, npm, crates.io |
290
- | The wire-format JSON Schemas | `schemas-v1.2.3` | npm, PyPI |
117
+ | Where | What |
118
+ | ----- | ---- |
119
+ | [openlatch.ai/docs](https://openlatch.ai/docs/) | Installation, getting started, how it works, FAQ, privacy |
120
+ | [docs/configuration.md](docs/configuration.md) | Environment variables, `config.toml`, what the daemon writes into the agent's config |
121
+ | [docs/egress.md](docs/egress.md) | Proxies, the hosts to open, Kerberos, troubleshooting codes |
122
+ | [docs/cli.md](docs/cli.md) | Command reference, health reports, exit codes |
123
+ | [docs/evaluate-protocol.md](docs/evaluate-protocol.md) | Evaluation process frames, caller-owned session state, errors and diagnostics |
124
+ | [CHANGELOG.md](CHANGELOG.md) | What changed in each release |
291
125
 
292
- The schema packages are versioned **only** by changes under `schemas/`, so a major bump means a breaking change to the events exchanged with the platform and nothing else. Pin them independently. Details in [`.claude/rules/release-lines.md`](.claude/rules/release-lines.md).
126
+ ## Contributing
293
127
 
294
- ## Why it is open source
128
+ ```bash
129
+ git clone https://github.com/OpenLatch/openlatch-client && cd openlatch-client
130
+ cargo build # Rust 1.88+, no other prerequisites
131
+ cargo test
132
+ ```
295
133
 
296
- The platform is closed; this node is Apache-2.0, for three enterprise reasons.
134
+ Never run a development build against your own install: `openlatch init` rewires every live agent session on the host. The [Contributing Guide](.github/CONTRIBUTING.md) covers the sandbox that prevents it, the checks CI runs, Conventional Commits and the PR process; [AGENTS.md](AGENTS.md) states what the client does and what it deliberately does not.
297
135
 
298
- | Reason | Why it matters |
299
- | ------ | -------------- |
300
- | **Transparency** | A node that sits in the execution path of every agent action cannot be a black box. Source access is a hard procurement gate at regulated enterprises. |
301
- | **Auditability** | Security reviews, internal AppSec and third-party testers all need to read the code that enforces policy on production agents. |
302
- | **Distribution** | The developer inside the account is who runs `npx @openlatch/client init` first. Open source removes the friction from that. |
136
+ Pick a [good first issue](https://github.com/OpenLatch/openlatch-client/labels/good%20first%20issue), or join us on [Slack](https://openlatch.slack.com).
303
137
 
304
138
  ## Security
305
139
 
@@ -307,15 +141,6 @@ The platform is closed; this node is Apache-2.0, for three enterprise reasons.
307
141
  - Releases are built with SLSA provenance via GitHub Actions
308
142
  - Full policy: [SECURITY.md](SECURITY.md)
309
143
 
310
- ## Contributing
311
-
312
- Read the [Contributing Guide](.github/CONTRIBUTING.md), pick a [good first issue](https://github.com/OpenLatch/openlatch-client/labels/good%20first%20issue), and join us on [Slack](https://openlatch.slack.com).
313
-
314
- Licensed under [Apache-2.0](LICENSE).
144
+ ## License
315
145
 
316
- | Resource | URL |
317
- | -------- | --- |
318
- | Website | [openlatch.ai](https://openlatch.ai) |
319
- | Documentation | [docs.openlatch.ai](https://docs.openlatch.ai) |
320
- | Slack | [openlatch.slack.com](https://openlatch.slack.com) |
321
- | Twitter / X | [@openlatch](https://x.com/openlatch) |
146
+ This client is licensed under [Apache-2.0](LICENSE). The OpenLatch platform — policy authoring, analysis and the dashboard — is a commercial product; see [openlatch.ai](https://openlatch.ai).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlatch/client",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "OpenLatch runtime enforcement node — the capture-and-enforce adapter that evaluates every covered action against a coding agent's Autonomy Zone before it runs",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -20,10 +20,10 @@
20
20
  "postinstall": "node lib/postinstall.js"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@openlatch/client-darwin-arm64": "0.2.2",
24
- "@openlatch/client-darwin-x64": "0.2.2",
25
- "@openlatch/client-linux-x64": "0.2.2",
26
- "@openlatch/client-linux-arm64": "0.2.2",
27
- "@openlatch/client-win32-x64": "0.2.2"
23
+ "@openlatch/client-darwin-arm64": "0.4.0",
24
+ "@openlatch/client-darwin-x64": "0.4.0",
25
+ "@openlatch/client-linux-x64": "0.4.0",
26
+ "@openlatch/client-linux-arm64": "0.4.0",
27
+ "@openlatch/client-win32-x64": "0.4.0"
28
28
  }
29
29
  }