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