metergraph-cli 0.2.0-preview.3 → 0.2.0-preview.5

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.
package/README.md CHANGED
@@ -1,603 +1,148 @@
1
1
  # metergraph-cli
2
2
 
3
- The Metergraph command line tool. Version `0.2.0-preview.3` is published on the
4
- `next` npm tag. The `latest` tag remains on `0.1.0`.
5
-
6
- Install the released preview channel with npm or run it directly:
3
+ [![npm](https://img.shields.io/npm/v/metergraph-cli/next?label=npm%40next)](https://www.npmjs.com/package/metergraph-cli)
4
+ [![CI](https://github.com/metergraph/cli/actions/workflows/ci.yml/badge.svg)](https://github.com/metergraph/cli/actions/workflows/ci.yml)
5
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/metergraph/cli/blob/main/LICENSE)
6
+
7
+ Connect a project to [Metergraph](https://www.metergraph.dev/) from the terminal or from
8
+ your coding agent. Metergraph learns from your application's LLM traces, benchmarks
9
+ models against your real usage and routes each task to the model that clears your
10
+ quality bar. This CLI signs a project in, writes its ingest key, installs the Metergraph
11
+ skill for Codex, Claude Code or Cursor, proves that a trace arrived, and reads cost,
12
+ token and route metadata back. Every command has stable `--json` output and exit codes,
13
+ so agents can run it as well as people.
7
14
 
8
15
  ```sh
9
16
  npx --yes metergraph-cli@next --help
10
- npx --yes metergraph-cli@next doctor --json
11
- npm install -g metergraph-cli@next
12
17
  ```
13
18
 
14
- The installed command is `metergraph`. Pin `metergraph-cli@0.2.0-preview.3`
15
- when you need this exact preview rather than whichever version `next` names later.
16
-
17
- **Availability:**
18
-
19
- - `metergraph-cli@0.1.0` contains only `doctor` and `skill install` /
20
- `skill update`. It has no sign in commands.
21
- - `metergraph-cli@0.2.0-preview.0` adds `login`, `logout`, `setup`, `verify`,
22
- `status`, `context`, `capabilities`, `usage`, `routes` and `traces`.
23
- - `metergraph-cli@0.2.0-preview.1` makes `setup` write the SDK service root as
24
- `METERGRAPH_INGEST_URL` and repairs the full ingest endpoint that
25
- `0.2.0-preview.0` wrote, after checking the saved key. It also keeps validated,
26
- workspace-bound trace links in Metadata reads.
27
- - `metergraph-cli@0.2.0-preview.2` makes `verify` exit 11 `verification_failed`
28
- when its deadline expires after the service reported the trace as pending, lets
29
- `login` and `setup` reruns that need no approval succeed with `--json
30
- --no-browser`, and reports why `verify --open` did not launch a browser.
31
- - `metergraph-cli@0.2.0-preview.3` makes a `verify` deadline that expires after
32
- the service reported the trace as pending return `trace_not_found_within_bounds`,
33
- the same result as running out of attempts, instead of `verification_timeout`.
34
- `setup --json --no-browser` now returns a `run_in_terminal` next action when
35
- approval is needed.
36
- `login` and `setup` use a pre-registered CLI client when the service names one
37
- in `metergraph_cli_client_id`, instead of registering a new client, and still
38
- register one on services that do not.
39
- - Sign in needs a Metergraph service that offers Metadata-only CLI grants and grant
40
- revocation. A service without them is reported as unsupported, and the CLI never
41
- falls back to broader access.
42
- - The read commands need a project signed in with `login`. `setup` also needs the
43
- deployment's ingest bootstrap API and browser approval by a workspace member.
44
- `verify` checks one exact trace identity in an explicit invocation window using
45
- Metadata access. It never sends application data.
46
-
47
- The preview includes:
48
-
49
- - `doctor` checks whether a Metergraph service is reachable, healthy and supported.
50
- - `skill install` and `skill update` copy the Metergraph agent skill bundled with the
51
- CLI into one coding agent's project skill directory.
52
- - `login` and `logout` sign a project in to one workspace through your
53
- browser with a delegated, Metadata-only grant, and sign it out again.
54
- - The read commands use that grant to read bounded workspace Metadata:
55
- connection status, workspace context, capabilities, daily usage, routes and one page
56
- of trace metadata.
57
- - `setup` guides browser sign in and workspace choice, asks for
58
- ingest-only approval, writes a private project env file, confirms delivery, and
59
- installs the selected client skill.
60
- - `verify` polls for one exact processed trace in a bounded window.
61
- It does not infer application provenance from a Metadata match.
62
-
63
- It does not read retained content, replay traces, call model providers or send
64
- application data. Setup does not prove that the application sent a trace.
65
-
66
- ## Requirements
19
+ This is a preview, published on the `next` npm tag. `latest` is still `0.1.0`, which has
20
+ only `doctor` and `skill`. See the [changelog](https://github.com/metergraph/cli/blob/main/CHANGELOG.md).
67
21
 
68
- | | Supported |
69
- | --- | --- |
70
- | Node.js | 22 and 24 |
71
- | Operating systems | Linux, macOS and Windows (each in the CI matrix) |
72
- | Runtime dependencies | None |
22
+ ## Quickstart
73
23
 
74
- ## Commands
24
+ **1. Set up the project.** Run this in your project directory. It opens your browser to
25
+ sign in and choose a workspace, asks a workspace member to approve an ingest-only key,
26
+ writes `METERGRAPH_APP_TOKEN` and `METERGRAPH_INGEST_URL` to a private `.env`, and
27
+ installs the skill for your coding agent.
75
28
 
76
29
  ```sh
77
- metergraph --help [--json]
78
- metergraph help doctor [--json]
79
- metergraph --version [--json]
80
- metergraph doctor [--url ORIGIN] [--timeout-ms N] [--json]
81
- metergraph help skill [--json]
82
- metergraph skill install --client CLIENT --runtime RUNTIME [--project DIR] [--json]
83
- metergraph skill update --client CLIENT --runtime RUNTIME [--project DIR] [--json]
84
- metergraph help login [--json]
85
- metergraph login --runtime local [--url ORIGIN] [--workspace UUID] [--project DIR] [--config-dir DIR] [--timeout-ms N] [--signup] [--no-browser] [--reconnect] [--json]
86
- metergraph logout [--project DIR] [--config-dir DIR] [--json]
87
- metergraph setup --runtime local (--client codex|claude|cursor | --skip-skill) [--deployment managed|customer-local|byoc|oss] [--url ORIGIN] [--workspace UUID] [--confirm-prerequisites] [--agent-token-file FILE] [--project DIR] [--config-dir DIR] [--env-file .env] [--timeout-ms N] [--signup] [--reconnect] [--no-browser] [--repair] [--json]
88
- metergraph status [--project DIR] [--config-dir DIR] [--timeout-ms N] [--json]
89
- metergraph context [--project DIR] [--config-dir DIR] [--timeout-ms N] [--json]
90
- metergraph capabilities [--project DIR] [--config-dir DIR] [--timeout-ms N] [--json]
91
- metergraph usage [--days N] [--limit N] [--project DIR] [--config-dir DIR] [--timeout-ms N] [--json]
92
- metergraph routes [--limit N] [--project DIR] [--config-dir DIR] [--timeout-ms N] [--json]
93
- metergraph traces [--days N] [--limit N] [--route NAME] [--status success|error] [--cursor CURSOR] [--project DIR] [--config-dir DIR] [--timeout-ms N] [--json]
94
- metergraph verify (--trace-id ID | --request-id ID) --since TIME --until TIME [--source application|synthetic|demo|import|unspecified] [--days N] [--timeout-ms N] [--poll-ms N] [--max-attempts N] [--open] [--no-browser] [--project DIR] [--config-dir DIR] [--json]
30
+ npx --yes metergraph-cli@next setup --runtime local --client claude
95
31
  ```
96
32
 
97
- `--help`, `--version` and the `skill` commands work offline and make no network
98
- requests. `login`, `logout`, `setup`, `verify` and the read commands are not in the published `0.1.0`
99
- package.
100
-
101
- ### Exact trace verification
102
-
103
- After an application invocation, pass its exact trace ID or request ID and the
104
- invocation start and end timestamps to `verify`. The optional `--source` label is a
105
- caller assertion. A matching Metadata row proves a processed trace is visible in the
106
- bound workspace, but does not independently prove that it came from your application.
107
- The result therefore keeps `application_traffic_verified: false` until a separate
108
- application instrumentation check supplies that evidence. A missing, ambiguous, stale
109
- or wrong-workspace result fails closed. The command neither creates an ingest key nor
110
- sends a test event.
111
-
112
- `--open` launches only a server-provided link carrying the exact trace and the
113
- verified workspace ID. The dashboard must check that ID against its signed-in
114
- workspace before displaying traces. Older links without a workspace remain a
115
- manual handoff; a conflicting workspace or unsafe link is refused. The result's
116
- `browser` field is `launcher_started`, `launcher_unavailable`, `not_requested`
117
- (no `--open`), or `suppressed_by_json` / `suppressed_by_no_browser` when `--open`
118
- was given but that flag returned the link instead of launching it.
119
-
120
- If `--timeout-ms` expires after the service has answered at least once with a
121
- pending result, `verify` exits 11 `verification_failed` with reason
122
- `trace_not_found_within_bounds`, the same result as running out of
123
- `--max-attempts`: the origin is reachable and the trace is not visible yet. Exit 4
124
- `connection_failed` is kept for transport failures. Its reason is
125
- `verification_timeout` when no valid answer arrived before the deadline. A deadline
126
- while `--open` launches a trace that was already found exits 11 with
127
- `verification_timeout`.
128
-
129
- ### doctor
130
-
131
- `doctor` sends three unauthenticated, read-only `GET` requests to one origin, in order,
132
- and stops at the first problem:
133
-
134
- 1. `/healthz` must answer `200` with the JSON body `{"ok": true}`.
135
- 2. `/v1/deployment` must answer `200` with a JSON `deployment_profile` this CLI supports.
136
- 3. `/v1/agent/capabilities` must answer `401` with a `WWW-Authenticate: Bearer` challenge.
137
-
138
- Options:
139
-
140
- | Option | Default | Notes |
141
- | --- | --- | --- |
142
- | `--url ORIGIN` | `https://app.metergraph.dev` | Bare origin only, see [Safe origins](#safe-origins). |
143
- | `--timeout-ms N` | `5000` | Whole number from 100 to 30000. Covers the whole probe, not each request. |
144
- | `--json` | off | Print exactly one JSON line on stdout and nothing on stderr. |
145
-
146
- A healthy, supported service exits with code **3, `authentication_required`**. That is
147
- the best result this preview can report: the service is reachable, but this CLI holds
148
- no credentials, so `authenticated` is always `false` and `workspace` is always `null`.
149
- A reachable service is not a working workspace connection. To connect an application,
150
- follow the [connection guide](https://www.metergraph.dev/docs/guides/agent-access/).
151
-
152
- `doctor` never opens a browser, never prompts and never reads stdin, so it is safe in
153
- scripts and CI.
154
-
155
- ### skill install and skill update
156
-
157
- `skill install` copies the Metergraph skill bundled with this CLI into one client's
158
- native project skill directory. Both `--client` and `--runtime` are required, so the
159
- command never guesses where the skill will be used.
160
-
161
- | `--client` | Client | Skill file written | Client documentation |
162
- | --- | --- | --- | --- |
163
- | `codex` | Codex | `.agents/skills/metergraph/SKILL.md` | [Build skills](https://learn.chatgpt.com/docs/build-skills) |
164
- | `claude` | Claude Code | `.claude/skills/metergraph/SKILL.md` | [Skills](https://code.claude.com/docs/en/skills) |
165
- | `cursor` | Cursor | `.cursor/skills/metergraph/SKILL.md` | [Skills](https://cursor.com/docs/skills) |
33
+ Use `--client codex` or `--client cursor` for the other agents.
166
34
 
167
- Each client has its own directory, so installing for several clients never makes one
168
- overwrite another.
35
+ **2. Run your application once**, instrumented with a Metergraph SDK (see the
36
+ [first trace guide](https://www.metergraph.dev/docs/start/first-trace/)). Note the trace
37
+ ID or request ID and when the call started and ended.
169
38
 
170
- | Option | Default | Notes |
171
- | --- | --- | --- |
172
- | `--client CLIENT` | required | `codex`, `claude` or `cursor`. |
173
- | `--runtime RUNTIME` | required | `local` when the client runs on this machine, `cloud` when it runs in a cloud environment with a shell and a checkout of the project. Recorded, not detected. |
174
- | `--project DIR` | current directory | Must be an existing directory. Symbolic links in this path are resolved once; nothing below it is followed. |
175
- | `--json` | off | Print exactly one JSON line on stdout and nothing on stderr. |
176
-
177
- What it writes, and nothing else:
178
-
179
- 1. The skill file in the table above, plus any of its missing parent directories.
180
- 2. `.metergraph/skill-installations.json`, a small ownership receipt. For each client it
181
- records the relative skill path, the skill name, the source revision and SHA-256,
182
- and the runtimes requested. It contains no credentials, user names or absolute
183
- paths, so it is safe to commit.
184
-
185
- Ownership rules:
186
-
187
- - `install` never replaces a skill it did not install, even one with identical bytes.
188
- - Running `install` again on an unchanged skill it installed changes nothing.
189
- - A skill it installed that was edited since is never overwritten, by `install` or by
190
- `update`. Restore or remove the file first.
191
- - `update` is the only way to replace an older revision this CLI installed. There is no
192
- force option.
193
- - A skill file this CLI installed that has gone missing is written again.
194
- - Symbolic links and other non-regular entries on the skill or receipt path are
195
- refused.
196
- - Files are written to an exclusive temporary file and renamed into place, under a lock
197
- file, `.metergraph/skill-installations.lock`. The receipt is written only after the
198
- skill file, and a failed receipt write puts the skill file back as it was. If the
199
- process is killed between the two writes, the skill is left without a receipt entry,
200
- so later runs refuse to touch it, and the lock stays until you delete it.
201
- - It never changes client settings, MCP configuration, `AGENTS.md`, `CLAUDE.md` or any
202
- other file, and keeps the permissions of a file it replaces.
203
-
204
- `--runtime cloud` writes the same project file. A cloud client sees it only through
205
- its own checkout of the project, so commit the file if you installed it elsewhere.
206
- Writing a skill file in a cloud checkout does not connect MCP, sign in or copy anything
207
- from your own machine. Local skills do not sync to desktop or cloud apps on their own.
208
-
209
- Clients and runtimes that cannot load project skill files get a pointer to the
210
- [connection guide](https://www.metergraph.dev/docs/guides/agent-access/) with exit code
211
- 6, and nothing is written: `--client claude-desktop`, `--client chatgpt` and
212
- `--runtime cloud-no-shell` (a cloud runtime without a shell or project checkout).
213
-
214
- A successful run exits `0` with `discovery: "pending"` and `authenticated: false`.
215
- Writing the file does not prove that a client has loaded it. Start or reload the client
216
- in the project and check that it lists the `metergraph` skill. The skill itself is
217
- instructions for the agent; it holds no credentials and does not connect a workspace.
218
-
219
- #### Bundled skill source
220
-
221
- `assets/skill/SKILL.md` is a byte-for-byte copy of the public skill at
222
- <https://www.metergraph.dev/SKILL.md>. The source has no version number of its own, so
223
- `assets/skill/manifest.json` records its source URL, size and SHA-256, and a revision
224
- derived from that hash (`sha256-` followed by the first 12 hex digits). The package
225
- version is not the skill version. At runtime the CLI checks the bundled file against a
226
- hash pinned in its code and in the manifest, and refuses to write anything if either
227
- does not match. It never downloads the skill or runs a remote script. A new skill
228
- revision ships only in a new CLI release; `skill update` then upgrades projects that
229
- hold an unchanged earlier revision.
230
-
231
- ### login and logout
232
-
233
- `login` binds a project directory to one Metergraph workspace. Your browser does the
234
- sign in, sign up, invitation and workspace consent on the service's own pages and
235
- keeps its own session. The CLI receives only a delegated OAuth grant limited to the
236
- Metadata scope, `agent:metadata`, checks it with the service and saves it privately.
39
+ **3. Prove the trace arrived.** Setup only proves the key works; `verify` checks that this
40
+ exact trace is visible in your workspace.
237
41
 
238
42
  ```sh
239
- metergraph login --runtime local --url https://metergraph.example.com
240
- metergraph logout
43
+ npx --yes metergraph-cli@next verify --trace-id TRACE_ID \
44
+ --since 2026-01-08T12:00:00Z --until 2026-01-08T12:00:05Z
241
45
  ```
242
46
 
243
- | Option | Default | Notes |
244
- | --- | --- | --- |
245
- | `--runtime RUNTIME` | required | `local`: the browser runs on this machine. `cloud` and `cloud-no-shell` get a handoff to the [connection guide](https://www.metergraph.dev/docs/guides/agent-access/) with exit code 6. |
246
- | `--url ORIGIN` | `https://app.metergraph.dev` | Bare origin only, see [Safe origins](#safe-origins). |
247
- | `--workspace UUID` | none | The workspace you expect. Sign in fails unless the browser grants exactly this one. Without it, the workspace you choose in the browser is used after the service confirms it. |
248
- | `--project DIR` | current directory | Existing project directory to bind. |
249
- | `--config-dir DIR` | see below | Private per-user directory for the saved grant. |
250
- | `--timeout-ms N` | `300000` | How long to wait for the browser, 1000 to 900000. |
251
- | `--signup` | off | Start at the hosted sign up page, which returns to the same authorization request. Managed service only; other profiles exit 6. |
252
- | `--no-browser` | off | Print the authorization URL on stderr for you to open on this machine, then wait. With `--json`, a rerun that needs no approval succeeds; one that needs approval exits 6 `no_browser_requires_terminal` with a `run_in_terminal` next action. |
253
- | `--reconnect` | off | Allow replacing a binding to a different origin or workspace. |
254
- | `--json` | off | Print exactly one JSON line on stdout and nothing on stderr. |
255
-
256
- What `login` does, in order:
257
-
258
- 1. Refuses cloud runtimes, SSH sessions, cloud development environments and CI (by the
259
- presence of variables such as `SSH_CONNECTION`, `CODESPACES` or `CI`; values are
260
- never read into output) before any request, listener or file write.
261
- 2. Reads the project binding. A project bound to another origin or workspace is refused
262
- with exit code 8 unless you pass `--reconnect`. A project that is already signed in
263
- and still verified is left as it is, with no browser and no new client.
264
- 3. Runs the same checks as `doctor`, then reads the service's OAuth metadata from the
265
- same origin. Every endpoint must be a fixed path on that origin, and the service must
266
- offer `agent:metadata`, PKCE with `S256`, public clients and revocation.
267
- 4. Chooses the OAuth client for a loopback redirect, `http://127.0.0.1:PORT/callback`
268
- on an ephemeral port. When the service's OAuth metadata names a pre-registered
269
- Metergraph CLI client in `metergraph_cli_client_id`, the CLI uses that client and
270
- registers nothing; the service accepts the loopback redirect on any port (RFC 8252
271
- section 7.3). Otherwise it registers a new public client named `Metergraph CLI` for
272
- that one redirect, as servers without the field expect. A malformed value stops
273
- sign in. The CLI then creates a random state and PKCE verifier, and arms the callback
274
- listener and its timeout before the browser opens.
275
- 5. Opens the authorization URL with the operating system's launcher (no shell). The
276
- listener accepts one `GET` with the exact host, path and state. Other requests get a
277
- fixed page and do not end the wait.
278
- 6. Exchanges the code and accepts only a Bearer grant for exactly `agent:metadata` whose
279
- claims name this issuer, resource, client and one workspace. The claims are a sanity
280
- check; the CLI does not verify token signatures.
281
- 7. Asks the service, with the new token, for `/v1/agent/workspace` and
282
- `/v1/agent/capabilities`. The workspace ID, its provenance and the token must agree,
283
- the deployment profile must match step 3, the access scopes must be exactly
284
- `agent:metadata`, and content, evidence and replay capabilities must be unavailable.
285
- Nothing else is read.
286
- 8. Saves the grant in the config directory and writes `.metergraph/project.json`. The
287
- saved grant keeps the client ID it was issued to, so a grant from a registered client
288
- still refreshes and revokes after the service starts offering a pre-registered one.
289
-
290
- Once the token response has been validated and holds a usable refresh token, a grant
291
- the CLI decides not to keep (a workspace other than the one expected or bound, failed
292
- verification, cancellation) is sent to the revocation endpoint before the command
293
- exits. If the grant cannot be saved or the binding cannot be written, the saved grant
294
- is removed, revocation is requested the same way, and the command exits 9. This is best
295
- effort: the service may not answer or may not confirm, and the CLI does not retry. A
296
- token response that fails validation is dropped without a revocation request, because
297
- the CLI cannot safely use anything in it; a server-side grant may remain active until it
298
- expires or is revoked from the service.
299
-
300
- The config directory is `--config-dir`, else `METERGRAPH_CONFIG_DIR` (an absolute
301
- path), else `~/.config/metergraph` on Linux and macOS or `AppData\Roaming\Metergraph` in
302
- your Windows profile. It holds `credentials/SLOT.json`:
303
-
304
- - On Linux and macOS the directories must be `0700` and the file `0600`, all owned by
305
- you. Existing paths with other permissions, other owners or symbolic links are
306
- refused and never changed.
307
- - On Windows the grant is encrypted with DPAPI for the current user before it is
308
- written. File permissions alone are not relied on there.
309
-
310
- `.metergraph/project.json` holds the origin, workspace ID, deployment profile and the
311
- name of the credential slot. It holds no token, user name or absolute path, so it is
312
- safe to commit. Other files in `.metergraph`, such as the skill receipt, are kept.
313
-
314
- Access tokens near expiry are refreshed once, under a lock, and the new refresh token
315
- is saved before it is used. If a refresh request may have reached the service but its
316
- result was not saved (a timeout after sending, a dropped connection, a server error or
317
- an unusable answer), the old refresh token is never sent again: the next use asks you
318
- to run `login` again. A revoked grant or lost workspace access fails closed with exit
319
- code 12.
320
-
321
- `logout` asks the service to revoke the project's grant through its revocation
322
- endpoint, then removes the saved grant and `.metergraph/project.json`. Other credential
323
- slots and project files are kept. A `200` from the service means it accepted the
324
- revocation request. If it does not answer `200`, local sign out still happens and the
325
- command exits 13 with `revocation: "unconfirmed"`. A project that is not signed in
326
- exits 0 without any request.
327
-
328
- ### setup
329
-
330
- Run setup once from a project directory, choosing the coding client that will use
331
- the skill:
47
+ Then read what Metergraph has recorded:
332
48
 
333
49
  ```sh
334
- metergraph setup --runtime local --client codex --project /path/to/project
50
+ npx --yes metergraph-cli@next usage --days 7 # calls, errors, cost and tokens per route per day
51
+ npx --yes metergraph-cli@next traces --limit 20 # one page of trace metadata
335
52
  ```
336
53
 
337
- For a customer-local bundle, point setup at its installed origin and exact
338
- workspace:
54
+ To install it globally instead, run `npm install -g metergraph-cli@next`. The command is
55
+ `metergraph`. Pin an exact version, such as `metergraph-cli@0.2.0-preview.5`, when a
56
+ script must not change with the `next` tag.
339
57
 
340
- ```sh
341
- metergraph setup --runtime local --deployment customer-local --url http://localhost:8080 --workspace 11111111-1111-4111-8111-111111111111 --confirm-prerequisites --client codex
342
- ```
58
+ ## Requirements
343
59
 
344
- `--confirm-prerequisites` records the operator's attestation that the released
345
- signed bundle, registry invitation, local admin, and separate Metadata access
346
- prerequisites are ready. It is not proof of bundle publication or registry
347
- access. Setup checks the live deployment profile before login. BYOC uses
348
- `--deployment byoc` and an explicit HTTPS private origin; its provisioning,
349
- network, and identity prerequisites remain the operator's work. An optional
350
- `--agent-token-file` can verify a separate Metadata credential for either
351
- route. OSS uses separate `MG_TOKENS` ingestion and `MG_AGENT_TOKENS` read
352
- credentials; `--deployment oss` verifies its Metadata route with a private
353
- agent token file and hands ingest configuration to the operator. It does not
354
- try hosted login or ingest bootstrap against OSS. Remote runtimes are handed
355
- off to a local machine, with no implicit tunnel or credential forwarding.
356
-
357
- If the project has no usable Metadata sign in, `setup` opens the deployment's
358
- browser sign in and workspace choice. `--signup` starts at hosted sign up;
359
- `--workspace UUID` requires that exact workspace. An existing binding to a
360
- different origin or workspace requires explicit `--reconnect`. The selected
361
- deployment must advertise `metergraph.cli-setup/v1` on its own origin. Its setup
362
- metadata may name a pre-registered CLI client in `metergraph_cli_client_id`, which
363
- setup then uses for ingest approval instead of registering a new client. Setup
364
- refuses reconnecting an existing ingest family to another workspace; its
365
- original workspace must be restored before that family can be reused. Setup
366
- checks the env file and Git state, then opens the deployment's consent page. An
367
- owner or member of the verified workspace approves an ingest-only key. The CLI
368
- redeems the single-use receipt, writes `METERGRAPH_APP_TOKEN` and
369
- `METERGRAPH_INGEST_URL` into `.env`, checks the new key with the service, and
370
- acknowledges delivery. It then installs the bundled skill for `codex`, `claude`
371
- or `cursor`. Use `--skip-skill` only if you intentionally want to install it
372
- later. Neither sign in nor setup requests Debug or Replay access. The browser
373
- page shows the workspace and the consequence of approval. A signed-in browser
374
- on another workspace must switch in Metergraph and rerun; the CLI does not
375
- switch it automatically.
376
-
377
- `METERGRAPH_INGEST_URL` is the deployment's service root. The Python SDK
378
- appends `/v1/ingest` itself. A setup rerun with a verified
379
- key repairs the endpoint value written by the first preview without minting a
380
- new key.
381
-
382
- The env file must be a project-relative `.env`, `.env.<name>` or `<name>.env`
383
- (`--env-file` selects another). The writer refuses tracked files, links,
384
- ambiguous dotenv syntax and unsafe paths. It adds a project `.gitignore` rule
385
- when needed and makes the env file private; Windows uses a user-only ACL.
386
- The env token is never printed, read from argv or stdin, or copied to the
387
- project's setup state file. An already working key is checked and reused without
388
- another browser approval.
389
-
390
- `.metergraph/setup.json` holds a family UUID, its current key ID and fixed state,
391
- but no credential. It is written before approval. If the redemption response is
392
- lost, a rerun asks for a new browser approval for that same family. The server
393
- resolves the request to creation if no key was issued or replacement of that
394
- family's pending key if one exists; the old receipt is not retried. If an
395
- acknowledged key no longer verifies or its env file was lost, use `--repair`
396
- to explicitly approve replacement of that exact key.
397
- An unsafe or changed state file is refused. If the earlier approval never
398
- reached redemption, rerun the command; the `create` intent is still safe.
399
-
400
- The JSON result includes a secret-free `receipt` with the origin, workspace ID,
401
- deployment profile, selected client, and completed and pending steps. A skill
402
- conflict leaves the delivered key in place and reports `credential_ready_skill_pending`;
403
- resolve the skill file conflict and rerun setup without another approval.
404
- With `--no-browser`, setup prints the approval URL on stderr instead of opening a
405
- browser. Under `--json` it cannot show that URL, so a rerun that needs no approval
406
- (a working saved key) still succeeds, and one that needs approval exits 6
407
- `no_browser_requires_terminal` before any approval request or env write, with
408
- `data.next_action` set to `{"kind": "run_in_terminal", "message": "..."}`. The
409
- message is fixed text and holds no URL or credential. Non-hosted operator
410
- handoffs carry their own deployment `next_action`; every other setup result has
411
- `next_action: null`.
412
- Success means the key was delivered and the project is ready to instrument.
413
- It does **not** mean application traffic has arrived. Run your application and
414
- verify one exact trace afterward. The hosted service advertises the setup
415
- contract, but each non-hosted deployment must be checked at its own origin.
416
- Local protocol tests do not prove browser approval or real application traffic.
417
-
418
- #### Repository identity
419
-
420
- After the key is ready, setup records which repository the project belongs to,
421
- so traces from several repositories in one workspace stay apart. The SDKs read
422
- `METERGRAPH_REPOSITORY`, then the nearest `.metergraph/config.json`:
423
-
424
- ```json
425
- {
426
- "version": 2,
427
- "repository": "example-org/example-app"
428
- }
60
+ | | Supported |
61
+ | --- | --- |
62
+ | Node.js | 22 and 24 |
63
+ | Operating systems | Linux, macOS and Windows, each tested in CI |
64
+ | Runtime dependencies | None |
65
+ | Service | Hosted Metergraph, or a self-hosted deployment (see [Deployments](#deployments)) |
66
+
67
+ Sign in needs a service that offers Metadata-only CLI grants and grant revocation; a
68
+ service without them is reported as unsupported, and the CLI never falls back to
69
+ broader access. `setup` also needs the deployment's ingest bootstrap API and approval by
70
+ a workspace member. Sign in needs a browser on the same machine. From SSH sessions,
71
+ cloud development environments and CI, `login` and `setup` hand off to a local machine
72
+ instead (exit 6).
73
+
74
+ ## Using it with a coding agent
75
+
76
+ The CLI is built to be run by Codex, Claude Code and Cursor as well as by people:
77
+
78
+ - **Skill.** `setup` installs the Metergraph skill, which tells the agent how to set up
79
+ and query Metergraph. To install or update only the skill, with no sign in and no
80
+ network access:
81
+
82
+ ```sh
83
+ npx --yes metergraph-cli@next skill install --client codex --runtime local
84
+ ```
85
+
86
+ Python users can run `pip install metergraph-skills` and
87
+ `metergraph-skills install --client codex --runtime local` instead
88
+ ([details](https://github.com/metergraph/cli/blob/main/python/metergraph-skills/README.md)).
89
+ Both write the same files and recognise each other's installs.
90
+ - **Model-swap skills.** `skills install` adds the workflow skills from
91
+ [metergraph/skills](https://github.com/metergraph/skills): choose a workload, choose
92
+ traces and models, define the eval, run the analysis, read the report and rerun,
93
+ all from the agent. Start with `metergraph-model-swap`. In Claude Desktop, add
94
+ the `metergraph/skills` plugin marketplace instead.
95
+
96
+ ```sh
97
+ npx --yes metergraph-cli@next skills install --client claude --runtime local
98
+ ```
99
+
100
+ - **Machine output.** Every command takes `--json` and then prints exactly one JSON
101
+ line on stdout and nothing on stderr. All results share one envelope:
102
+ `schema_version`, `command`, `ok`, `outcome`, `exit_code`, `data` and `error`.
103
+ Failures carry a fixed `error.reason` and, where useful, a `data.next_action` that
104
+ tells the agent what to do next.
105
+ - **No hidden prompts.** No command reads stdin or asks a question. `--no-browser`
106
+ prints the sign in URL for a person to open instead of launching a browser; with
107
+ `--json`, a step that needs approval exits 6 with a `run_in_terminal` next action.
108
+ - **MCP.** Workspace tools for agents are served by the hosted MCP endpoint, not by this
109
+ CLI. See the [MCP server guide](https://www.metergraph.dev/docs/guides/mcp-server/)
110
+ and the [agent access guide](https://www.metergraph.dev/docs/guides/agent-access/).
111
+
112
+ Suggested `AGENTS.md` or `CLAUDE.md` lines for a project that uses Metergraph:
113
+
114
+ ```md
115
+ - Metergraph CLI: `npx --yes metergraph-cli@next <command> --json`. Check exit codes;
116
+ follow `data.next_action` on failure.
117
+ - After changing instrumented code, run the app once and confirm the trace with
118
+ `metergraph verify` before reporting that tracing works.
429
119
  ```
430
120
 
431
- Setup takes `owner/name` from `--repository`, or else from the git `origin`
432
- remote (or the only remote). It writes `.metergraph/config.json` in the project
433
- directory only when no identity exists yet. The file holds no secret; review
434
- and commit it. An identity already set in `METERGRAPH_REPOSITORY` in the env
435
- file, or in a `.metergraph/config.json` in the project or a parent directory, is
436
- kept. If it differs from the remote or `--repository`, setup reports a mismatch
437
- and changes nothing. Setup never rewrites a config file the SDKs cannot use.
438
- Remotes with nested groups are not guessed; pass `--repository OWNER/NAME`.
439
- `--no-repository` records nothing.
440
-
441
- The JSON result reports the outcome in `data.repository`: `status` is
442
- `written`, `existing`, `mismatch`, `invalid_config`, `not_inferred`,
443
- `write_failed` or `skipped`, with the `repository`, its `source`
444
- (`git_remote`, `flag`, `config` or `env_file`), the config `path`, and, for a
445
- mismatch, the `expected` value. Only `owner/name` is reported, never a remote
446
- URL. Recording an identity never fails setup.
447
-
448
- With an identity configured, the SDKs exchange the ingest key for a
449
- repository-scoped session before sending traces. Without one they keep the
450
- older ingestion path and log that the identity is not configured; capture
451
- continues either way.
452
-
453
- Several repositories can send to one workspace. Run `setup` once in each
454
- repository, so each has its own project binding and private `.env`; pass the
455
- same `--workspace UUID` each time to pin the workspace; and give each
456
- repository its own identity.
457
-
458
- ### Read commands
459
-
460
- The read commands use the grant `login` saved for this project. They never open a
461
- browser, never sign in on their own and never request another scope. Each one:
462
-
463
- - reads `.metergraph/project.json` and the saved grant, and refreshes the grant at most
464
- once, under the same lock and rules as `login` (an interrupted refresh is never
465
- retried with a possibly used token);
466
- - asks the service for `/v1/agent/workspace` and `/v1/agent/capabilities` and checks,
467
- as `login` does, that the workspace, deployment profile and `agent:metadata` scope
468
- still match the binding and that content, evidence and replay are unavailable;
469
- - sends only `GET` requests to fixed paths on the bound origin, follows no redirects and
470
- reads at most 1 MiB of a response;
471
- - runs every request, including a refresh and any wait for another command that is
472
- refreshing the same grant, within one total `--timeout-ms` deadline (1000 to 60000,
473
- default 15000), which is never reset per request or page. A deadline exits 4
474
- (`timeout`) and Ctrl+C exits 17, also while waiting for that lock; a lock held by
475
- another process is never removed or taken over;
476
- - prints only fields it validated. Unknown response fields are ignored and never named.
477
- A metadata row that holds a field such as `prompt`, `messages`, `tool_calls` or
478
- `access_token` is refused as a whole (exit 11). Names that contain control or
479
- formatting characters are shown as `null`. Service warning and error text is not
480
- printed. If any printed value, such as a workspace name, route name, cursor or
481
- provenance source, contains a token the CLI holds for this project, nothing is
482
- printed and the command exits 11 with `credential_in_metadata_response`.
483
-
484
- Read commands do not change workspace configuration or telemetry, send no ingest data
485
- and call no model provider. They are not side-effect free on the service: a command may
486
- refresh its own saved grant, and the service may update its audit records and last used
487
- times for the grant.
488
-
489
- | Command | Request | What it prints |
490
- | --- | --- | --- |
491
- | `status` | `GET /healthz` and `GET /v1/deployment` (no credentials, checked as `doctor` does), then the two checks above | `configured`, `reachable`, `healthy`, `authenticated`, the bound (`intended`) and verified (`actual`) workspace, the bound deployment profile and `deployment_profile_verified`, scopes and capability flags. A `/v1/deployment` profile that differs from the binding exits 11 with `profile_mismatch` before the grant is used. `application_traffic_verified` is always `false`: a signed in project, existing data or a configured SDK does not prove that your application sends traffic. |
492
- | `context` | the two checks above | Workspace ID, slug, name and creation time, Metadata retention days, whether the workspace captures content (never included here) and the access scope. |
493
- | `capabilities` | the two checks above | Each known agent capability with `available`, `privacy_class`, `required_scope` and flags, and the service's bounds. Privacy class descriptions are not printed. |
494
- | `usage` | `GET /v1/agent/usage?days=N&limit=N` | Daily rows per route: calls, errors, cost, tokens and latency (latency may be `null`), the window, evidence completeness, warning codes and totals of the returned rows. |
495
- | `routes` | `GET /v1/agent/routes` | Route name, calls, replay eligible calls, evaluation contract version and hash, and whether a description or contract exists. |
496
- | `traces` | `GET /v1/agent/traces?days=N&limit=N[&route=&status=&cursor=]` | One page of trace metadata: IDs, name, status, times, span count, tokens, cost (may be `null`), routes, providers and models, plus `next_cursor`. |
497
-
498
- Bounds and honesty rules:
499
-
500
- - `--days` is 1 to 90 (default 7) and `--limit` 1 to 200 (default 50, or 20 for
501
- `traces`). Values outside these ranges exit 2. A value above the service's own
502
- advertised `max_days` or `max_rows` exits 6 with `exceeds_service_bounds`; it is never
503
- reduced silently.
504
- - `usage` and `traces` report `truncated` and `complete`. Totals are sums of the
505
- returned rows only; when `complete` is `false` they are not workspace totals. An
506
- empty window is a successful result with `empty: true`.
507
- - `GET /v1/agent/routes` takes no limit or window. The CLI validates every returned row,
508
- keeps the first `--limit`, and reports `server_rows`, `truncated` and
509
- `truncation: "local"`. Route descriptions, constraints and evaluation contract bodies
510
- are never printed; `omitted_fields` lists them.
511
- - `traces` fetches exactly one page. When more exist it returns `next_cursor`; pass it
512
- back with `--cursor` to read the next page. The cursor is opaque and at most 512
513
- printable characters. A page whose `limit` differs from the request, or rows that do
514
- not match `--status` or `--route`, exit 11. Free-text filter values are not printed
515
- back.
516
- - The `traces` listing prints no trace links; each row has `link: null` and the
517
- page reports `link_status: "server_link_unavailable"`. Exact-trace
518
- `verify --open` uses a server link only when it includes the verified
519
- workspace binding.
520
- - `--environment`, `--workload`, `--since`, `--until`, `--sql`, `--query`, `--content`,
521
- `--include-content`, `--debug` and `--replay` are recognized and refused with exit 6
522
- before any request. The agent access contract has no environment selector or
523
- absolute time range, and these commands never read content or replay. `--workload`
524
- is refused by this CLI version because the returned trace rows do not show which
525
- workload they belong to, so a filtered page could not be verified.
526
- - A capability the service does not offer to this grant exits 14 without a read. A
527
- refused read exits 15 (`insufficient_scope` or `forbidden`), rate limiting exits 16
528
- with `retry_after_seconds` when the service sends a whole number of seconds, and a
529
- token refused during the read exits 12. Nothing is retried. Ctrl+C exits 17.
530
-
531
- A successful `usage`, shortened:
532
-
533
- ```json
534
- {
535
- "schema_version": 1,
536
- "command": "usage",
537
- "ok": true,
538
- "outcome": "ok",
539
- "exit_code": 0,
540
- "data": {
541
- "origin": "https://metergraph.example.com",
542
- "workspace": { "id": "0b5c7c1e-1a2b-4c3d-8e4f-5a6b7c8d9e01" },
543
- "deployment_profile": "managed",
544
- "authenticated": true,
545
- "scopes": ["agent:metadata"],
546
- "result": {
547
- "provenance": {
548
- "deployment_profile": "managed",
549
- "workspace_id": "0b5c7c1e-1a2b-4c3d-8e4f-5a6b7c8d9e01",
550
- "generated_at": "2026-01-08T12:00:00Z",
551
- "source": "example-source"
552
- },
553
- "window": { "days": 7, "since": "2026-01-01T12:00:00Z", "until": "2026-01-08T12:00:00Z" },
554
- "evidence": { "sources": ["telemetry"], "rows": 1, "complete": true },
555
- "warnings": [],
556
- "content_included": false,
557
- "truncated": false,
558
- "complete": true,
559
- "empty": false,
560
- "rows": 1,
561
- "items": [
562
- {
563
- "date": "2026-01-02",
564
- "route": "checkout-summary",
565
- "calls": 40,
566
- "error_calls": 2,
567
- "cost_usd": 0.0125,
568
- "input_tokens": 12000,
569
- "output_tokens": 3400,
570
- "avg_latency_ms": 820,
571
- "p95_latency_ms": null
572
- }
573
- ],
574
- "totals": {
575
- "scope": "returned_rows",
576
- "complete": true,
577
- "calls": 40,
578
- "error_calls": 2,
579
- "cost_usd": 0.0125,
580
- "input_tokens": 12000,
581
- "output_tokens": 3400
582
- }
583
- },
584
- "retry_after_seconds": null,
585
- "notices": [],
586
- "next_action": null
587
- },
588
- "error": null
589
- }
590
- ```
121
+ ## Commands
591
122
 
592
- On failure `result` is `null`, `authenticated` says whether the grant was verified
593
- before the failure, and `notices` lists fixed tokens such as `rows_truncated`,
594
- `evidence_incomplete`, `routes_truncated_locally`, `unsafe_text_omitted` or
595
- `trace_links_unavailable`.
123
+ | Command | What it does | Network |
124
+ | --- | --- | --- |
125
+ | `setup` | Sign in, choose a workspace, write the ingest key to `.env`, record the repository, install the skill | Yes |
126
+ | `verify` | Confirm that one exact trace, by trace ID or request ID, reached the workspace | Yes |
127
+ | `usage` | Daily calls, errors, cost, tokens and latency per route | Yes |
128
+ | `traces` | One page of trace metadata, with a cursor for the next page | Yes |
129
+ | `routes` | Routes with call counts and evaluation contract status | Yes |
130
+ | `status` | Whether the project is signed in, and to which workspace | Yes |
131
+ | `context` | Workspace details and retention | Yes |
132
+ | `capabilities` | What the workspace makes available to this project | Yes |
133
+ | `login`, `logout` | Sign a project in or out without the rest of `setup` | Yes |
134
+ | `doctor` | Check that a service is reachable, healthy and supported, without credentials | Yes |
135
+ | `skill install`, `skill update` | Install or update the Metergraph skill for one agent | No |
136
+ | `skills install`, `skills update`, `skills list` | Install, update or list the workflow skills, such as the model-swap loop | No |
137
+
138
+ `metergraph help COMMAND` lists a command's options. The
139
+ [CLI reference](https://github.com/metergraph/cli/blob/main/docs/reference.md) covers every option, what each command reads and
140
+ writes, and full JSON examples.
596
141
 
597
142
  ## Exit codes
598
143
 
599
- Exit codes are stable. Changing one is a breaking change. Codes 10 to 17 were
600
- added in `0.2.0-preview.0` and are unavailable in `0.1.0`.
144
+ Exit codes are stable. Changing one is a breaking change. Codes 10 to 17 are not in
145
+ `0.1.0`.
601
146
 
602
147
  | Code | Outcome | Meaning |
603
148
  | --- | --- | --- |
@@ -620,339 +165,47 @@ added in `0.2.0-preview.0` and are unavailable in `0.1.0`.
620
165
  | 16 | `rate_limited` | The service asked the CLI to slow down. Nothing was retried. Try again later. |
621
166
  | 17 | `cancelled` | A read command was interrupted before it finished. Read commands never change workspace configuration or telemetry. |
622
167
 
623
- ## JSON output
624
-
625
- With `--json`, every command prints one line with the same top-level keys:
626
-
627
- ```json
628
- {
629
- "schema_version": 1,
630
- "command": "doctor",
631
- "ok": false,
632
- "outcome": "authentication_required",
633
- "exit_code": 3,
634
- "data": {
635
- "origin": "https://app.metergraph.dev",
636
- "reachable": true,
637
- "healthy": true,
638
- "deployment_profile": "managed",
639
- "profile_status": "supported",
640
- "authentication_required": true,
641
- "authenticated": false,
642
- "workspace": null,
643
- "checks": [
644
- { "name": "health", "path": "/healthz", "result": "pass", "http_status": 200, "reason": null },
645
- { "name": "deployment", "path": "/v1/deployment", "result": "pass", "http_status": 200, "reason": null },
646
- { "name": "capabilities", "path": "/v1/agent/capabilities", "result": "pass", "http_status": 401, "reason": "bearer_token_required" }
647
- ],
648
- "next_action": { "kind": "connection_guide", "url": "https://www.metergraph.dev/docs/guides/agent-access/" }
649
- },
650
- "error": {
651
- "code": "authentication_required",
652
- "reason": "bearer_token_required",
653
- "message": "The service is reachable and supported, and it requires authentication. No workspace is connected."
654
- }
655
- }
656
- ```
657
-
658
- (Shown formatted here. The CLI prints it on a single line.)
659
-
660
- - `ok` is `true` only when `outcome` is `ok`. When `ok` is `false`, `error.code` equals
661
- `outcome` and `error.reason` is a fixed token such as `timeout`, `invalid_url`,
662
- `unrecognized_profile` or `response_too_large`.
663
- - `profile_status` is `supported`, `unrecognized`, `unavailable` (the server has no
664
- `/v1/deployment` endpoint) or `unknown` (not checked).
665
- - Checks that did not run have `result: "skipped"`.
666
- - `--help --json` includes the command list and the exit code table.
667
-
668
- A successful `skill install`:
669
-
670
- ```json
671
- {
672
- "schema_version": 1,
673
- "command": "skill install",
674
- "ok": true,
675
- "outcome": "ok",
676
- "exit_code": 0,
677
- "data": {
678
- "client": "claude",
679
- "runtime": "local",
680
- "path": ".claude/skills/metergraph/SKILL.md",
681
- "status": "installed",
682
- "source": {
683
- "name": "metergraph",
684
- "revision": "sha256-57b920677adf",
685
- "sha256": "57b920677adf62759c7221629327192a2d16b7e6034f7948ffd96cee402d4891"
686
- },
687
- "discovery": "pending",
688
- "authenticated": false,
689
- "next_action": {
690
- "kind": "reload_client",
691
- "message": "Start or restart Claude Code in this project, then confirm that it lists the metergraph skill."
692
- }
693
- },
694
- "error": null
695
- }
696
- ```
697
-
698
- - `status` is `installed`, `updated` or `reused` (already in place, nothing rewritten).
699
- - `path` is always relative to the project. Absolute paths are never printed.
700
- - On failure `status` and `discovery` are `null`, and `error.reason` is a fixed token
701
- such as `not_owned`, `modified`, `update_required`, `not_installed`, `unsafe_path`,
702
- `receipt_invalid`, `locked`, `invalid_project`, `client_not_supported`,
703
- `write_failed` or `bundled_skill_invalid`.
704
-
705
- A successful `login`:
706
-
707
- ```json
708
- {
709
- "schema_version": 1,
710
- "command": "login",
711
- "ok": true,
712
- "outcome": "ok",
713
- "exit_code": 0,
714
- "data": {
715
- "origin": "https://metergraph.example.com",
716
- "runtime": "local",
717
- "deployment_profile": "managed",
718
- "workspace": { "id": "0b5c7c1e-1a2b-4c3d-8e4f-5a6b7c8d9e01" },
719
- "scopes": ["agent:metadata"],
720
- "authenticated": true,
721
- "configured": true,
722
- "status": "signed_in",
723
- "binding": ".metergraph/project.json",
724
- "credential_protection": "owner_only_file",
725
- "previous_grant_revocation": null,
726
- "next_action": {
727
- "kind": "connected",
728
- "message": "This project is signed in with Metadata access. Run \"metergraph logout\" to sign out."
729
- }
730
- },
731
- "error": null
732
- }
733
- ```
734
-
735
- - `status` is `signed_in`, `reused` (already signed in and verified, nothing changed)
736
- or `reconnected` (a new grant replaced the previous one; `previous_grant_revocation`
737
- is then `accepted`, `unconfirmed` or `not_attempted`).
738
- - `credential_protection` is `owner_only_file` or `dpapi`.
739
- - On failure `authenticated` and `configured` are `false`, `scopes` is empty, and
740
- `next_action` is `null` or a handoff such as `connection_guide`, `reconnect`,
741
- `run_in_terminal` or `no_browser`.
742
- - The schema version `1` is the version of this CLI's own JSON output. It is unrelated
743
- to the service's agent access contract version, `metergraph.agent-access/v1`.
744
- - `login` and `logout` never print tokens, the authorization code, the PKCE verifier,
745
- user names, email addresses, workspace names, absolute paths or server text. The
746
- read commands never print tokens, email addresses, absolute paths or server error
747
- text either; `context` prints the workspace slug and name, and the read commands
748
- print validated route, trace, provider and model names, as described above.
749
-
750
- `logout` prints `local_credentials` (`removed` or `none`), `binding` (`removed`,
751
- `kept` or `none`) and `revocation` (`accepted`, `unconfirmed` or `not_attempted`).
752
-
753
- Without `--json`, results are printed as text on stdout and usage errors go to stderr.
754
- `login` prints progress lines, and with `--no-browser` the authorization URL, on
755
- stderr.
756
-
757
- ## Safe origins
758
-
759
- `--url` accepts only a bare origin, with an optional trailing slash:
760
-
761
- - `https://` origins on any host, for example `https://metergraph.example.com`.
762
- - `http://` only for `localhost`, `127.0.0.1` and `[::1]`, with an optional port.
763
-
764
- Usernames, passwords, paths, queries and fragments are rejected before any request is
765
- made. Invalid values and unknown arguments are not printed back, because a mistyped
766
- argument can contain a credential. An accepted origin is printed in the output and sent
767
- to the network, so do not put secrets in a hostname. See [Security](#security).
768
-
769
- ## Deployment profiles
770
-
771
- The CLI recognizes these `deployment_profile` values: `local`, `managed` and
772
- `byoc-core`. Managed staging uses the `managed` profile. Any other value is reported as `unsupported` and is not echoed. A server
773
- without `/v1/deployment`, such as a self-hosted open source server, is reported as
774
- `unsupported` with `profile_status: "unavailable"` until a dedicated adapter ships. The
775
- CLI never assumes such a server is hosted.
776
-
777
- ## What doctor does not do
778
-
779
- - It reads no credentials from environment variables, files, arguments or cookies, and
780
- sends no `Authorization` or `Cookie` header.
781
- - It follows no redirects.
782
- - It reads at most 32 KiB of any response body and stops at the `--timeout-ms` limit.
783
- - It never prints response bodies, response headers, authentication challenges,
784
- server-supplied URLs or error text from the network stack.
785
- - It makes no model provider calls, sends no usage data and reads no stored traces.
786
-
787
- ## What skill install does not do
788
-
789
- - It makes no network requests and no model provider calls. The skill comes from this
790
- package, not from a download.
791
- - It does not sign in, store credentials, configure MCP or edit client settings.
792
- - It does not claim a client has loaded the skill. `discovery` stays `pending`.
793
- - It never prints file contents, absolute paths or raw error text.
794
-
795
- ## What login does not do
796
-
797
- - It never asks for Debug (`agent:read`) or Replay (`agent:replay`) access, and never
798
- falls back to them when the service does not offer `agent:metadata`.
799
- - It never copies browser cookies or the browser's sign in.
800
- - It does not create an application ingest key, and no manual API key is required. The
801
- service records the grant as an OAuth connection on its own side; that connection
802
- can only use `agent:metadata`, is separate from any API or ingest key you manage, and
803
- is what `logout` asks the service to revoke.
804
- - It reads no telemetry, retained content or traces, and makes no model provider calls.
805
- - It sends the grant only to the origin it came from, follows no redirects and reads
806
- bounded responses within fixed time limits.
807
- - It accepts no credential on the command line, in the environment or on stdin.
808
-
809
- ## What the read commands do not do
810
-
811
- - They never sign in, open a browser, create a grant or change the project binding.
812
- The only file they may write is the saved grant, when a refresh rotates it.
813
- - They never request `agent:read` or `agent:replay`, never read retained content,
814
- evidence or replays, and never call a model provider.
815
- - They make only `GET` requests to the read endpoints (a grant refresh, when needed, is
816
- the only `POST`). They send no ingest data and change no evaluations, provider
817
- settings, workspace configuration or telemetry. The service may still record the
818
- access, for example audit entries and the grant's last used time.
819
- - They never print a token the CLI holds, even inside an otherwise valid name.
820
- - They never follow a cursor or page on their own, and never widen a request: an
821
- unsupported option, an out of range value or a capability the grant lacks fails
822
- instead.
823
- - They accept no credential on the command line, in the environment or on stdin.
824
-
825
- ## Development
826
-
827
- ```sh
828
- npm test # unit tests and CLI subprocess tests against loopback servers
829
- npm run test:package # npm pack into a temporary directory, clean install, run the installed bin
830
- node bin/metergraph.js --help
831
- node bin/metergraph.js doctor --url http://127.0.0.1:8080 --json
832
- node bin/metergraph.js skill install --client claude --runtime local --project /path/to/project --json
833
- node bin/metergraph.js login --runtime local --url http://127.0.0.1:8080 --project /path/to/project
834
- ```
835
-
836
- The sign in and read command tests run against a synthetic loopback service and a
837
- test-only browser stand-in loaded with `--import`. They prove the protocol, file
838
- handling and output rules, not the real service, a real browser, real workspace
839
- consent or real workspace data. The Windows DPAPI round trip
840
- runs only on the Windows CI runner.
841
-
842
- To try a packed artifact without publishing:
843
-
844
- ```sh
845
- npm pack --pack-destination "$(mktemp -d)"
846
- npx --yes --package=/path/to/metergraph-cli-0.2.0-preview.3.tgz -- metergraph --version
847
- ```
848
-
849
- Do not commit tarballs or other generated files.
850
-
851
- ## Releasing
852
-
853
- The source of truth is the public repository
854
- [github.com/metergraph/cli](https://github.com/metergraph/cli), licensed Apache-2.0.
855
- `0.2.0-preview.3` is published on the `next` npm tag; `latest` remains on
856
- `0.1.0`. The hosted service supports sign in, Metadata reads and ingest bootstrap.
857
- Subsequent releases must pass the checks below before publication.
858
-
859
- Releases are manual. The `Release CLI` workflow (`.github/workflows/release.yml`) runs
860
- only when a maintainer starts it from `main`. It does not run on tags, pushes or a
861
- schedule. It:
862
-
863
- 1. checks that `commit_sha` equals the commit the run started from (see
864
- [Exact revision rule](#exact-revision-rule)), that it is on `main`, and that
865
- `version` equals `package.json`;
866
- 2. asks the npm registry for that exact version and continues only on a `404`. An
867
- existing version, any other status or a network failure stops the run;
868
- 3. runs `npm test` and `npm run test:package` at that commit;
869
- 4. packs the tarball and records its SHA-256;
870
- 5. only if `publish` is true, waits for approval on the `npm-release` environment,
871
- checks out the same commit again, verifies the checksum and runs
872
- `npm publish --provenance` for that exact tarball.
873
-
874
- Leave `publish` false for a dry run that validates and packs without publishing.
875
-
876
- ### Exact revision rule
877
-
878
- npm provenance records the commit that triggered the workflow (`GITHUB_SHA`) as the
879
- source of the package. To keep that statement true, the workflow only releases that
880
- commit:
881
-
882
- - `commit_sha` must be the full 40 character SHA of the current head of `main`, and it
883
- must equal `GITHUB_SHA` for the run. Older commits on `main` are rejected even though
884
- they are ancestors of `main`.
885
- - Both the validate job and the publish job check out that commit and confirm it.
886
- - If `main` moves after you copy the SHA, the run fails. Start a new run with the new
887
- head. To release an older state, land it on `main` first.
888
-
889
- ### First package bootstrap (completed for 0.1.0)
890
-
891
- npm trusted publishing is configured on a package that already exists, so the very
892
- first version could not come from this workflow. The steps below describe the
893
- completed bootstrap of `0.1.0`; they are not part of subsequent releases. No npm
894
- token or secret is stored here.
895
-
896
- 1. Confirm the intended npm maintainer accounts and that `metergraph-cli` is
897
- available. The first approved publish establishes package ownership.
898
- 2. Run the `Release CLI` workflow with `publish` false. Download the
899
- `metergraph-cli-release` artifact and check its SHA-256 against the run summary.
900
- 3. From a maintainer machine with npm two-factor authentication, publish that exact
901
- tarball manually using `npm publish /path/to/metergraph-cli-0.1.0.tgz --access public
902
- --tag next --provenance=false --ignore-scripts`. This bootstrap version has no
903
- provenance attestation. Use a new version for the first trusted release.
904
- 4. Configure trusted publishing as described below.
905
-
906
- ### Trusted publishing
907
-
908
- After the package exists, follow the official npm guide,
909
- [Trusted publishing for npm packages](https://docs.npmjs.com/trusted-publishers/), and
910
- add a GitHub Actions trusted publisher with exactly these values:
911
-
912
- | Field | Value |
913
- | --- | --- |
914
- | Organization or user | `metergraph` |
915
- | Repository | `cli` |
916
- | Workflow filename | `release.yml` |
917
- | Environment name | `npm-release` |
918
-
919
- Trusted publishing requires npm 11.5.1 or newer. The publish job checks this before it
920
- publishes. After the trusted publisher works, consider restricting the package to
921
- trusted publishing so that long lived tokens cannot publish it.
922
-
923
- ### Release configuration
924
-
925
- Before an automated publish, confirm the following settings are still in place:
926
-
927
- - the [trusted publisher](#trusted-publishing) matches this repository and workflow;
928
- - the `npm-release` environment has required reviewers;
929
- - the repository variable `METERGRAPH_CLI_PUBLISH_ENABLED` is `true`.
930
-
931
- Until all of these are done, leave `publish` false.
932
-
933
- ### After a release
934
-
935
- After each release, confirm from a clean machine, replacing `VERSION`:
936
-
937
- ```sh
938
- npx --yes metergraph-cli@VERSION --version --json
939
- npx --yes metergraph-cli@VERSION doctor --json
940
- npm view metergraph-cli@VERSION dist.attestations
941
- ```
942
-
943
- Releases from the workflow should show a provenance attestation that names
944
- `metergraph/cli` and the released commit. The bootstrap version will not.
945
-
946
- ## Security
947
-
948
- Report security issues privately through
949
- [GitHub private vulnerability reporting](https://github.com/metergraph/cli/security/advisories/new)
950
- for `metergraph/cli`. Do not open a public issue, and do not include real credentials,
951
- tokens or customer data in a report. The security policy and the CLI's security
952
- properties are in `SECURITY.md` in the
953
- [source repository](https://github.com/metergraph/cli); it is not shipped in the npm
954
- package.
168
+ ## Security and privacy
169
+
170
+ - **No usage telemetry.** The CLI collects no analytics about how you use it. It talks
171
+ only to the Metergraph origin you point it at.
172
+ - **Least access.** Sign in grants only the Metadata scope, `agent:metadata`. The CLI
173
+ never requests Debug or Replay access, never falls back to broader access, and never
174
+ reads retained prompts, responses or other content. It calls no model provider.
175
+ - **Credentials.** The sign in grant is stored per user in `~/.config/metergraph`
176
+ (`AppData\Roaming\Metergraph` on Windows), as owner-only files on Linux and macOS and
177
+ encrypted with DPAPI on Windows. The ingest key goes only into the project's private
178
+ `.env`, which `setup` adds to `.gitignore`. No command accepts a credential on the
179
+ command line, in the environment or on stdin, or prints one.
180
+ - **Files it writes in your project:** `.env` (from `setup`), the skill file, and
181
+ secret-free state under `.metergraph/` that is safe to commit. The skill installer
182
+ never replaces a file it did not write and has no force option.
183
+ - **Network.** Only `GET` requests to fixed paths for reads, no redirects followed,
184
+ bounded response sizes and fixed timeouts. Mistyped arguments are never echoed, since
185
+ they may hold a secret. `--help`, `--version` and `skill` make no network requests.
186
+
187
+ The [CLI reference](https://github.com/metergraph/cli/blob/main/docs/reference.md) states what each command does and does not do.
188
+ Report vulnerabilities privately through
189
+ [GitHub private vulnerability reporting](https://github.com/metergraph/cli/security/advisories/new),
190
+ not in a public issue, and leave real credentials, tokens and customer data out of the
191
+ report. See [SECURITY.md](https://github.com/metergraph/cli/blob/main/SECURITY.md).
192
+
193
+ ## Deployments
194
+
195
+ `--url ORIGIN` selects the service; the default is `https://app.metergraph.dev`. It
196
+ accepts a bare `https://` origin, or `http://` on `localhost`, `127.0.0.1` or `[::1]`.
197
+ `setup --deployment` supports the hosted service (`managed`), the commercial
198
+ `customer-local` bundle, customer-owned cloud (`byoc`) and the open source server
199
+ (`oss`). See [self-hosting](https://www.metergraph.dev/docs/self-host/local/) and the
200
+ [setup reference](https://github.com/metergraph/cli/blob/main/docs/reference.md#setup).
201
+
202
+ ## Links
203
+
204
+ - [Documentation](https://www.metergraph.dev/docs/)
205
+ - [CLI reference](https://github.com/metergraph/cli/blob/main/docs/reference.md) and [changelog](https://github.com/metergraph/cli/blob/main/CHANGELOG.md)
206
+ - [Issues](https://github.com/metergraph/cli/issues)
207
+ - [Contributing](https://github.com/metergraph/cli/blob/main/CONTRIBUTING.md) and [releasing](https://github.com/metergraph/cli/blob/main/RELEASING.md)
955
208
 
956
209
  ## License
957
210
 
958
- Apache-2.0. See [LICENSE](LICENSE).
211
+ Apache-2.0. See [LICENSE](https://github.com/metergraph/cli/blob/main/LICENSE).