xmemcli 0.0.4__tar.gz → 0.0.7__tar.gz
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.
- {xmemcli-0.0.4 → xmemcli-0.0.7}/PKG-INFO +208 -12
- xmemcli-0.0.7/README.md +585 -0
- {xmemcli-0.0.4 → xmemcli-0.0.7}/pyproject.toml +1 -1
- {xmemcli-0.0.4 → xmemcli-0.0.7}/uv.lock +1 -1
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/__init__.py +1 -1
- xmemcli-0.0.7/xmemcli/_binding.py +1017 -0
- xmemcli-0.0.7/xmemcli/_binding_cmd.py +415 -0
- xmemcli-0.0.7/xmemcli/_context_cmd.py +785 -0
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_help.py +78 -14
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_instance_schema.py +561 -57
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_login.py +22 -11
- xmemcli-0.0.7/xmemcli/_mcp_bridge.py +698 -0
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_org_cluster.py +4 -4
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_output.py +29 -5
- xmemcli-0.0.7/xmemcli/_pretty.py +697 -0
- xmemcli-0.0.7/xmemcli/_text.py +132 -0
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_version.py +1 -1
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_xmem_bridge.py +24 -8
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/cli.py +915 -185
- xmemcli-0.0.4/README.md +0 -389
- xmemcli-0.0.4/xmemcli/_pretty.py +0 -373
- {xmemcli-0.0.4 → xmemcli-0.0.7}/.gitignore +0 -0
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_envelope.py +0 -0
- {xmemcli-0.0.4 → xmemcli-0.0.7}/xmemcli/_rc.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xmemcli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: Command-line client for the xmemory HTTP API: PKCE auth, instances, read/write, schema and XMD tools.
|
|
5
5
|
Keywords: api,cli,llm,memory,xmemory
|
|
6
6
|
Requires-Python: <4,>=3.12
|
|
@@ -22,12 +22,20 @@ xmemcli read <query>
|
|
|
22
22
|
xmemcli write <text>
|
|
23
23
|
xmemcli write-status <write_id> [<id> …]
|
|
24
24
|
xmemcli quota
|
|
25
|
+
xmemcli binding list [--autoload]
|
|
26
|
+
xmemcli binding add <instance_id> [--tier autoload|available|off] [--scope project|user]
|
|
27
|
+
xmemcli binding remove <instance_id> [--scope project|user]
|
|
28
|
+
xmemcli context [--text] [--max-tokens N] [--no-live-state]
|
|
25
29
|
```
|
|
26
30
|
|
|
27
|
-
Global flags / env: `--api-key` / `$XMEM_API_KEY`, `--instance-id` / `$XMEM_INSTANCE_ID`, `--api-url` / `$XMEM_API_URL`, `--rc-dir` / `$XMEM_RC_DIR`, `--json`, `--verbose`. See `xmemcli help options`.
|
|
31
|
+
Global flags / env: `--api-key` / `$XMEM_API_KEY`, `--instance-id` / `$XMEM_INSTANCE_ID`, `--api-url` / `$XMEM_API_URL`, `--rc-dir` / `$XMEM_RC_DIR`, `--binding-dir` / `$XMEM_BINDING_DIR`, `--json`, `--verbose`. See `xmemcli help options`.
|
|
28
32
|
|
|
29
33
|
Credential resolution: `--api-key` → `$XMEM_API_KEY` → nearest `.xmemrc.json` (walk up from `--rc-dir` toward `$HOME`). Origin: `--api-url` → `$XMEM_API_URL` → rc `api_url` → default.
|
|
30
34
|
|
|
35
|
+
`context` is the exception: it runs unattended from a session-start hook, with no person and no chosen directory behind it, so it resolves the credential from `$HOME` **only** — a project `.xmemrc.json` is used only when `--api-key` / `$XMEM_API_KEY` or `--rc-dir` / `$XMEM_RC_DIR` names it explicitly. That stops a cloned repository shipping the key and origin its own context is fetched with.
|
|
36
|
+
|
|
37
|
+
Two local files, same discovery rule, different jobs: `.xmemrc.json` holds the credential (`0600`, never committed, nearest wins); `.xmemory.json` holds the instance binding (`0644`, *meant* to be committed at project scope, every scope merged). `binding` commands are local-only — no network, no credential.
|
|
38
|
+
|
|
31
39
|
## Read / write modes
|
|
32
40
|
|
|
33
41
|
| CLI | API field |
|
|
@@ -43,7 +51,7 @@ Credential resolution: `--api-key` → `$XMEM_API_KEY` → nearest `.xmemrc.json
|
|
|
43
51
|
|
|
44
52
|
## Curated output
|
|
45
53
|
|
|
46
|
-
The CLI does not echo raw API payloads. Server internals (`sql`, `diff_plan`, extraction trees) are never emitted. `--verbose` adds `trace_id` and `console_url` when present.
|
|
54
|
+
The CLI does not echo raw API payloads. Server internals (`sql`, `diff_plan`, extraction trees) are never emitted. Read responses keep `pending_suggestions` (schema-evolution hint). `--verbose` adds `trace_id` and `console_url` when present.
|
|
47
55
|
|
|
48
56
|
## Output personality — JSON vs pretty
|
|
49
57
|
|
|
@@ -89,7 +97,7 @@ xmemcli version
|
|
|
89
97
|
xmemcli auth login
|
|
90
98
|
```
|
|
91
99
|
|
|
92
|
-
Version: **0.0.
|
|
100
|
+
Version: **0.0.7**.
|
|
93
101
|
|
|
94
102
|
|
|
95
103
|
---
|
|
@@ -133,7 +141,7 @@ AI-assisted IDE ── xmemcli read/write ──► CLI resolves key; never hand
|
|
|
133
141
|
|
|
134
142
|
Project-local **`.xmemrc.json`**: `{email, api_url, api_key}`. Found by walking up from `--rc-dir` / CWD, ceiling `$HOME`.
|
|
135
143
|
|
|
136
|
-
Resolution order: `--api-key` → `$XMEM_API_KEY` → `.xmemrc.json`. Origin: `--api-url` → `$XMEM_API_URL` → rc `api_url` → default
|
|
144
|
+
Resolution order: `--api-key` → `$XMEM_API_KEY` → `.xmemrc.json`. Origin: `--api-url` → `$XMEM_API_URL` → rc `api_url` → default — **except** when the key is explicit (`--api-key` / `$XMEM_API_KEY`): the rc's `api_url` is skipped and the origin falls back to the built-in default unless you also set `--api-url` / `$XMEM_API_URL`. The localhost-key-at-prod guard applies when the key comes from the rc and an explicit `--api-url` / `$XMEM_API_URL` mismatches that rc origin.
|
|
137
145
|
|
|
138
146
|
## Identity — `/whoami`
|
|
139
147
|
|
|
@@ -159,7 +167,7 @@ Fixed port **9636** ("xmem" on phone keypad) allows SSH/devcontainer forwarding;
|
|
|
159
167
|
|
|
160
168
|
# `xmemcli` — capabilities reference
|
|
161
169
|
|
|
162
|
-
**Version:** `0.0.
|
|
170
|
+
**Version:** `0.0.7` (see `xmemcli version`)
|
|
163
171
|
|
|
164
172
|
`xmemcli` is the command-line client for the **xmemory HTTP API**. It is **human-governed for key acquisition**; an AI-assisted IDE may run reads, writes, and inventory once credentials exist. Humans acquire API keys and change quota limits in the **Console UI**.
|
|
165
173
|
|
|
@@ -203,6 +211,7 @@ Permission-filtered view of what this API key can see.
|
|
|
203
211
|
|---------|-------------|
|
|
204
212
|
| **`instance get`** `<instance_id>` | Fetch one instance |
|
|
205
213
|
| **`instance create`** | Create from XMD/JSON schema. Required `--name`; schema via `--schema-file` or `--schema-stdin`. |
|
|
214
|
+
| **`instance setup`** `[instance_id]` `[--format agent\|project]` | How to connect this instance to an agent, ordered for where it is likely to be used. Prints the same steps the `get_setup_instructions` MCP tool gives an agent, so a person and the agent beside them read the same thing. `--format project` additionally prints the shared setup files to commit; each teammate still approves the install and signs in once. Carries no credential. |
|
|
206
215
|
|
|
207
216
|
---
|
|
208
217
|
|
|
@@ -219,6 +228,9 @@ XMD (xmemory Data) is the typed schema format for instances. These commands mirr
|
|
|
219
228
|
| Preview migration | **`schema dry-run`** `[instance_id]` | Same flags as `schema update`; returns planned DDL without applying. |
|
|
220
229
|
| List migrations | **`schema migrations list`** `[instance_id]` | Newest first. `--limit`, `--before-id`, `--include-yaml`. |
|
|
221
230
|
| Fetch one migration | **`schema migrations get`** `[instance_id]` `<migration_id>` | Optional positional instance id; else `--instance-id` / `$XMEM_INSTANCE_ID`. `--include-yaml`. |
|
|
231
|
+
| Review suggestions | **`schema suggestions review`** `[instance_id]` | Suggestion engine: consolidated proposal from read-traffic gaps. |
|
|
232
|
+
| Decide suggestions | **`schema suggestions decide`** `[instance_id]` | `--proposal-version` (required) + `--accept`/`--reject`/`--defer`/`--file`. |
|
|
233
|
+
| Apply suggestions | **`schema suggestions apply`** `[instance_id]` | `--proposal-version` plus mandatory `--confirm-destructive`; preview removals in Console first. |
|
|
222
234
|
| Enhance bound schema | **`xmd enhance --from-instance`** `<description>` | Uses live schema; requires instance id. |
|
|
223
235
|
| Synthesize schema | **`xmd generate`** `<description>` | Cluster-scoped LLM synthesis. `-o` writes YAML. |
|
|
224
236
|
| Enhance from file | **`xmd enhance`** `[schema_file]` `<description>` | From a file, or `--from-instance` for bound enhance. `-o`, `--plan-output`. |
|
|
@@ -226,7 +238,7 @@ XMD (xmemory Data) is the typed schema format for instances. These commands mirr
|
|
|
226
238
|
| Validate schema | **`xmd validate`** / **`validate-yaml`** / **`validate-json`** | Cluster-scoped server validation. |
|
|
227
239
|
| Convert JSON Schema | **`xmd convert`** | JSON Schema → XMD YAML via the API (`validate_json_schema`). |
|
|
228
240
|
|
|
229
|
-
**Not exposed in CLI** (Console
|
|
241
|
+
**Not exposed in CLI** (Console-only today): the suggestions before/after YAML **preview**.
|
|
230
242
|
|
|
231
243
|
#### Typical workflow
|
|
232
244
|
|
|
@@ -246,6 +258,11 @@ xmemcli schema update INST_ID --schema-file next.yml --migration-plan plan.json
|
|
|
246
258
|
# 4. Inspect history
|
|
247
259
|
xmemcli schema migrations list INST_ID
|
|
248
260
|
xmemcli schema migrations get INST_ID MIGRATION_UUID
|
|
261
|
+
|
|
262
|
+
# 5. Suggestion engine (from real read traffic) — confirm with the user before decide/apply
|
|
263
|
+
xmemcli schema suggestions review INST_ID
|
|
264
|
+
xmemcli schema suggestions decide INST_ID --proposal-version PV --accept FP1 --accept FP2
|
|
265
|
+
xmemcli schema suggestions apply INST_ID --proposal-version NEXT_PV --confirm-destructive
|
|
249
266
|
```
|
|
250
267
|
|
|
251
268
|
#### Commands
|
|
@@ -257,6 +274,9 @@ xmemcli schema migrations get INST_ID MIGRATION_UUID
|
|
|
257
274
|
| **`schema dry-run`** `[instance_id]` | Preview migration (same schema/plan flags as update). |
|
|
258
275
|
| **`schema migrations list`** `[instance_id]` | Applied migrations, newest first. `--limit` (default 50), `--before-id`, `--include-yaml`. |
|
|
259
276
|
| **`schema migrations get`** `[instance_id]` `<migration_id>` | One record. Optional positional instance id; else global instance flags. `--include-yaml`. |
|
|
277
|
+
| **`schema suggestions review`** `[instance_id]` | Consolidated proposal from read-traffic gaps. Returns `proposal_version` + items. |
|
|
278
|
+
| **`schema suggestions decide`** `[instance_id]` | Record accept/reject/defer. Requires `--proposal-version` plus fingerprints or `--file`. |
|
|
279
|
+
| **`schema suggestions apply`** `[instance_id]` | Apply accepted items as one migration. Requires `--proposal-version` and `--confirm-destructive`. |
|
|
260
280
|
| **`xmd generate`** `<description>` | LLM-synthesize XMD. Optional `-o`. Requires cluster resolution. |
|
|
261
281
|
| **`xmd enhance`** `[schema_file]` `<description>` | LLM-augment schema from file, or **`--from-instance`** for live schema. `-o`, `--plan-output`. |
|
|
262
282
|
| **`xmd validate`** `<schema_file>` | Validate; YAML vs JSON inferred from `.json` extension. |
|
|
@@ -268,6 +288,99 @@ Instance id for `schema *` commands: positional `[instance_id]`, else **`--insta
|
|
|
268
288
|
|
|
269
289
|
---
|
|
270
290
|
|
|
291
|
+
### Binding (local only — no network, no credential)
|
|
292
|
+
|
|
293
|
+
Which instances an agent working in **this directory** should know about, and how eagerly to
|
|
294
|
+
engage each one. Stored in `.xmemory.json`, discovered by walking **up** from `--binding-dir` /
|
|
295
|
+
`$XMEM_BINDING_DIR` (or the cwd), ceilinged at `$HOME` — the same rule `.xmemrc.json` has always
|
|
296
|
+
used, and **no git anywhere**. From a start outside `$HOME` the walk checks that directory and
|
|
297
|
+
stops, rather than climbing into a shared parent like `/work` or `/tmp` where another user's file
|
|
298
|
+
could be planted. A session-start hook passes the project root explicitly, so it never depends on
|
|
299
|
+
the walk at all.
|
|
300
|
+
`~/.xmemory.json` is consulted as the outermost scope whenever `$HOME` is the user's own rather than part of the tree being read. Where the session root *is* the home directory — a dotfiles repository, a devcontainer or an archive unpacked as `$HOME` — that file is treated as project scope like any other file inside the tree.
|
|
301
|
+
|
|
302
|
+
Unlike the rc — where the nearest file simply wins — every scope is **merged**, git-config style:
|
|
303
|
+
`~/.xmemory.json` supplies personal instances, a repository's committed `.xmemory.json` adds the
|
|
304
|
+
team's, and the nearer file wins **field by field** on any instance both mention.
|
|
305
|
+
|
|
306
|
+
| Command | Description |
|
|
307
|
+
|---------|-------------|
|
|
308
|
+
| **`binding list`** | Merged view for this directory. `--autoload` lists only what a session-start hook would pull. |
|
|
309
|
+
| **`binding add <id>`** | Bind an instance, or update the binding it already has. `--name`, `--purpose`, `--tier`, `--engage` (repeatable), `--scope`. |
|
|
310
|
+
| **`binding remove <id>`** | Unbind from **one** scope. To silence an instance inherited from a wider scope, bind it here with `--tier off` instead. |
|
|
311
|
+
| **`context`** | Session-start pack for the `autoload`-tiered bindings here. `--text` prints the pack alone, `--max-tokens`, `--no-live-state`, `--timeout`. The only one of these that needs a credential. |
|
|
312
|
+
|
|
313
|
+
**Tiers:** `autoload` (pull its context every session) · `available` (default; engage on demand) ·
|
|
314
|
+
`off` (bound but dormant).
|
|
315
|
+
|
|
316
|
+
**Scopes:** `--scope project` (default) writes the committable file — at an existing nearer
|
|
317
|
+
binding, else the git work-tree root **when git can say and the reader would actually look
|
|
318
|
+
there**, else the cwd. git only ever suggests: no git, or a directory that is not a checkout, is
|
|
319
|
+
an ordinary state and never blocks a write. The one refusal left is when the target would resolve
|
|
320
|
+
onto the home directory, which would write the user-scope file while calling it a project one.
|
|
321
|
+
`--scope user` always writes `~/.xmemory.json`.
|
|
322
|
+
|
|
323
|
+
`context` makes no request when nothing is tiered `autoload`, and resolves no credential
|
|
324
|
+
either — a hook running on every session start must not error in a project that was never
|
|
325
|
+
going to fetch anything. A server without the endpoint is treated as nothing to inject, so a
|
|
326
|
+
client ahead of its deployment degrades quietly instead of failing every session, as does a
|
|
327
|
+
binding this build cannot parse.
|
|
328
|
+
|
|
329
|
+
**`--timeout` bounds the whole command.** Not the request — *everything*: binding discovery,
|
|
330
|
+
the credential preflight, the git provenance lookup, name resolution, TLS, response headers and
|
|
331
|
+
body. It is a wall-clock limit, because it is the only bound a session-start hook has (POSIX
|
|
332
|
+
`sh` has no portable `timeout`) and a bound with an exception in it is not one. Expiry degrades
|
|
333
|
+
like every other failure: exit **0**, empty pack, one `warning:` line naming the budget.
|
|
334
|
+
|
|
335
|
+
`--text` prints the pack and nothing else, for a caller that will **wrap** it. Do not point a
|
|
336
|
+
hook at it directly: a hook's stdout is parsed as its control document on some events, so a
|
|
337
|
+
pack that happened to be valid JSON would be read as control fields rather than injected. A
|
|
338
|
+
companion editor-integration plugin wraps this output in the documented hook envelope its own
|
|
339
|
+
client expects; it ships from a separate repository and is not part of this one.
|
|
340
|
+
|
|
341
|
+
**No secrets.** An instance id is not a credential, so a *project* `.xmemory.json` is written
|
|
342
|
+
`0644` and is *meant* to be committed — the opposite of `.xmemrc.json` (`0600`, never
|
|
343
|
+
committed). `~/.xmemory.json` is written `0600`: it stays on one machine, and on a shared host
|
|
344
|
+
its instance names and purposes are nobody else's business.
|
|
345
|
+
|
|
346
|
+
**Scope precedence has one exception: your own entries are a ceiling.** A nearer scope normally
|
|
347
|
+
wins field by field, but a project file arrives by `git clone` and is the less trusted of the
|
|
348
|
+
two. So for any instance `~/.xmemory.json` lists, a committed file may make it **less** eager,
|
|
349
|
+
never more:
|
|
350
|
+
|
|
351
|
+
- **Tier.** Ranked `autoload` > `available` > `off`. A project may take your `autoload` down to
|
|
352
|
+
`available` or `off`; it can never raise `off` to `available`, or `available` to `autoload`.
|
|
353
|
+
**An omitted `tier` in your file means `available` and binds as one** — so `binding add --scope
|
|
354
|
+
user <id>` with no `--tier` caps that instance at `available` everywhere. If you want a
|
|
355
|
+
project's `autoload` to stand, say `--tier autoload` in your own file: your entry states the
|
|
356
|
+
most eager you are willing to be, not merely that you know the id.
|
|
357
|
+
- **`engage`.** Replaced by a nearer scope for every other instance, but not for one of yours —
|
|
358
|
+
otherwise a committed file could rewrite the cues attached to your own instance, which is a
|
|
359
|
+
quieter version of raising its tier.
|
|
360
|
+
|
|
361
|
+
Everything else (`name`, `purpose`) still merges nearest-wins, and a project may always add
|
|
362
|
+
detail to an instance you listed.
|
|
363
|
+
|
|
364
|
+
**File format** (v1). `id` is required; everything else is optional. Unknown keys are rejected,
|
|
365
|
+
so a typo fails loudly rather than being ignored.
|
|
366
|
+
|
|
367
|
+
```json
|
|
368
|
+
{
|
|
369
|
+
"version": 1,
|
|
370
|
+
"instances": [
|
|
371
|
+
{
|
|
372
|
+
"id": "9c421cd4-77ab-4a51-a7e3-b8fd5d09d394",
|
|
373
|
+
"name": "Team Knowledge",
|
|
374
|
+
"purpose": "shared dev conventions",
|
|
375
|
+
"tier": "autoload",
|
|
376
|
+
"engage": ["a convention is learned or corrected"]
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
271
384
|
### Auth & meta
|
|
272
385
|
|
|
273
386
|
| Command | Description |
|
|
@@ -275,9 +388,30 @@ Instance id for `schema *` commands: positional `[instance_id]`, else **`--insta
|
|
|
275
388
|
| **`auth login`** | PKCE via Console `/xmemcli/<challenge>` → `.xmemrc.json`. `--no-browser`, `--timeout`, `--console-url`. |
|
|
276
389
|
| **`auth logout`** | Remove active `.xmemrc.json` |
|
|
277
390
|
| **`auth status`** | Call `/whoami`. No key → exit 0; bad key → auth error; good key → email + prefix. |
|
|
391
|
+
| **`mcp <instance-id>`** | Serve one instance to an MCP client over stdio, using this CLI's credential. Not for humans — see below. |
|
|
278
392
|
| **`version`** | CLI release version (no network) |
|
|
279
393
|
| **`status`** | Local health: version + whether `.xmemrc.json` exists (no network) |
|
|
280
394
|
|
|
395
|
+
**`mcp` is a transport, not a command you run.** An MCP client starts it and speaks
|
|
396
|
+
JSON-RPC to it over stdio; it forwards each frame to `<mcp-url>/instance/<id>` with this
|
|
397
|
+
CLI's credential attached, and writes the answer back. Register it with
|
|
398
|
+
`claude mcp add <name> -- xmemcli mcp <instance-id>` (or the equivalent for another
|
|
399
|
+
client).
|
|
400
|
+
|
|
401
|
+
It exists because an MCP client can reference an environment variable in an
|
|
402
|
+
`Authorization` header but cannot read `.xmemrc.json`. Reading the credential per
|
|
403
|
+
connection means nothing is captured when the server is registered, so a configuration
|
|
404
|
+
written today still works in a session opened next week with an empty environment.
|
|
405
|
+
|
|
406
|
+
Two consequences worth knowing:
|
|
407
|
+
|
|
408
|
+
- **stdout is the protocol.** Alone among these commands it emits no JSON document and
|
|
409
|
+
honours neither `--json` nor the exit-code table above; its exit code is a process
|
|
410
|
+
status. Diagnostics go to stderr.
|
|
411
|
+
- **Signed out is reported, not fatal.** Every request is answered with a JSON-RPC error
|
|
412
|
+
naming `auth login`, because a client that is told only "the server failed to start"
|
|
413
|
+
gives the reader nothing to act on. Exit code and stage do not apply.
|
|
414
|
+
|
|
281
415
|
**Console `/xmemcli` routing:**
|
|
282
416
|
|
|
283
417
|
- **Onboarding** → silent onboarding-key handoff to the CLI (no overlay, no button click).
|
|
@@ -302,13 +436,60 @@ Quota **increases** are Console-only — see [What `xmemcli` does not do](#what-
|
|
|
302
436
|
|------|---------|
|
|
303
437
|
| **0** | Success |
|
|
304
438
|
| **2** | Usage error (bad flags, unknown `help` topic, missing required args) |
|
|
305
|
-
| **3** | HTTP / request failure (includes unwritable `-o` paths) |
|
|
306
|
-
| **4** | Auth error
|
|
439
|
+
| **3** | HTTP / request failure — see [HTTP status mapping](#http-status--exit-code-and-json-stage) (includes permission denied, other API errors, and unwritable `-o` paths) |
|
|
440
|
+
| **4** | Auth error — invalid or missing API key (`401`; `stage: "auth"`) |
|
|
307
441
|
| **5** | Timeout |
|
|
308
|
-
| **6** | Quota exhausted (API quota-exceeded response) |
|
|
442
|
+
| **6** | Quota exhausted (API quota-exceeded response; `stage: "quota"`) |
|
|
309
443
|
| **7** | Quota headroom below `--fail-if-under` |
|
|
310
444
|
| **130** | Interrupted (Ctrl+C) |
|
|
311
445
|
|
|
446
|
+
### HTTP status → exit code and JSON `stage`
|
|
447
|
+
|
|
448
|
+
`xmemcli` mirrors the API's **401 vs 403** distinction on the process exit code and on the machine-readable `stage` field. This is the single contract for **every** command that performs an HTTP call (read/write, `org list *`, schema/XMD, quota, `auth status`, …) — with one deliberate exception, below.
|
|
449
|
+
|
|
450
|
+
**`context` is exempt, by design** — from the release that introduces `context`, which is the
|
|
451
|
+
first one where this carve-out means anything. It is the one command nobody invokes: a
|
|
452
|
+
session-start hook runs it unattended, and a non-zero exit there costs the user their session
|
|
453
|
+
rather than their context. So **every** HTTP outcome — 401 and 403 included — exits **0** with an
|
|
454
|
+
empty context and an explanatory `warnings[]` entry. Use `auth status` to tell a credential
|
|
455
|
+
problem apart from an empty binding; `context` will not.
|
|
456
|
+
|
|
457
|
+
The exemption goes further than HTTP status. Any runtime failure inside `context` — a malformed
|
|
458
|
+
binding, an unreadable response shape, a timeout, a bug nobody anticipated — exits **0** with an
|
|
459
|
+
empty pack and a `warning:` line naming the cause. This is enforced in code rather than by
|
|
460
|
+
enumerating failure modes, so an unforeseen one degrades like the rest.
|
|
461
|
+
|
|
462
|
+
**And it is exempt from the one-JSON-document rule on stdout.** Every other command emits a JSON
|
|
463
|
+
error document in machine mode, including on usage errors. A piped, non-`--json` `context` whose
|
|
464
|
+
arguments fail to parse writes **zero bytes to stdout** and puts its reason on stderr instead,
|
|
465
|
+
because a hook discards stdout at exit **2** — so a JSON error document there is a session start
|
|
466
|
+
failing with no stated cause anywhere the user can see it. Usage and parse errors are the only
|
|
467
|
+
paths that still exit **2**; they are a mistake in the hook's own configuration, not a runtime
|
|
468
|
+
condition, and the hook author is the one reading stderr.
|
|
469
|
+
|
|
470
|
+
#### Quick reference
|
|
471
|
+
|
|
472
|
+
| API HTTP status | Shell exit code | JSON `stage` | Meaning |
|
|
473
|
+
|-----------------|-----------------|--------------|---------|
|
|
474
|
+
| **401** | **4** | `auth` | **Bad credential** — missing, invalid, expired, or inactive API key |
|
|
475
|
+
| **403** | **3** | `permission` | **Bad authorization** — key is valid but this key/role cannot perform the operation |
|
|
476
|
+
| **Other 4xx/5xx** | **3** | `request` | Request failed for another reason (404, 422, 5xx, …) |
|
|
477
|
+
| **402** (quota exhausted) | **6** | `quota` | Quota window exhausted — human must extend quota in Console |
|
|
478
|
+
|
|
479
|
+
#### How to interpret failures
|
|
480
|
+
|
|
481
|
+
1. **Exit 4 / `stage: "auth"` / HTTP 401** → fix the key: login again, rotate the key, check `$XMEM_API_KEY` / `.xmemrc.json`, confirm `--api-url` points at the environment that issued the key.
|
|
482
|
+
2. **Exit 3 / `stage: "permission"` / HTTP 403** → the key works, but the operation needs a broader API role (for example `data.write`, `instance.generate_schema`, `cluster.get_own`). Do **not** treat this as a wrong password.
|
|
483
|
+
3. **Exit 3 / `stage: "request"`** → other HTTP failure (instance not found, validation error, server error). Read the error message and HTTP status in the JSON body.
|
|
484
|
+
|
|
485
|
+
Some commands attach a more specific `stage` (`validate`, `usage`, `limit`, …) while still using exit **3** unless the row above applies. The `schema suggestions` commands add their own stages: `stale_proposal` (re-run review for a fresh `proposal_version`), `invalid_decision`, `dependency` (accept the dangling dependencies first), `not_initialised` (submit a write first), and `apply`; `review` reports an `evolution_in_progress` condition as a successful status with exit 0.
|
|
486
|
+
|
|
487
|
+
**Envelope errors** (HTTP **200** with non-empty `errors[]`) are not HTTP 401/403; they typically exit **3** with `stage: "request"`.
|
|
488
|
+
|
|
489
|
+
**Breaking change in 0.0.5:** HTTP **403** previously exited **4** (`auth`); it now exits **3** (`permission`). Scripts that treated exit **4** as “any auth-layer failure” must check `stage` or handle exit **3** for permission denials.
|
|
490
|
+
|
|
491
|
+
See also [`ACCOUNTS_AUTH.md`](../ACCOUNTS_AUTH.md) for the server-side 401/403/404 rules.
|
|
492
|
+
|
|
312
493
|
---
|
|
313
494
|
|
|
314
495
|
## Help
|
|
@@ -341,6 +522,10 @@ xmemcli help schema dry-run
|
|
|
341
522
|
xmemcli help schema migrations
|
|
342
523
|
xmemcli help schema migrations list
|
|
343
524
|
xmemcli help schema migrations get
|
|
525
|
+
xmemcli help schema suggestions
|
|
526
|
+
xmemcli help schema suggestions review
|
|
527
|
+
xmemcli help schema suggestions decide
|
|
528
|
+
xmemcli help schema suggestions apply
|
|
344
529
|
xmemcli help xmd
|
|
345
530
|
xmemcli help xmd generate
|
|
346
531
|
xmemcli help xmd enhance
|
|
@@ -363,7 +548,7 @@ Nested topics work at any level that exists in the parser (`help org`, `help org
|
|
|
363
548
|
|------|-------------------------|
|
|
364
549
|
| **Quota increases** | No `quota request-increase`. Observe with `xmemcli quota`; **raise limits in Billing / Quotas UX**. |
|
|
365
550
|
| **Routine API key creation** | Post-onboarding: API Keys UI (CLI opens that flow via `/xmemcli`). |
|
|
366
|
-
| **Billing
|
|
551
|
+
| **Billing & plans** | Console only |
|
|
367
552
|
| **Users, roles, org admin** | Console only |
|
|
368
553
|
| **Instance chat / trace inspection** | Console only |
|
|
369
554
|
| **Cluster create/delete** | CLI lists clusters; provisioning in Console |
|
|
@@ -385,12 +570,23 @@ These apply **before** any subcommand (`xmemcli help options`).
|
|
|
385
570
|
| `--api-key` | `XMEM_API_KEY` | Bearer API key |
|
|
386
571
|
| `--instance-id` | `XMEM_INSTANCE_ID` | Default instance for read/write and cluster derivation |
|
|
387
572
|
| `--rc-dir` | `XMEM_RC_DIR` | Where `auth login` writes `.xmemrc.json`; reads walk **up** toward `$HOME` |
|
|
573
|
+
| `--binding-dir` | `XMEM_BINDING_DIR` | Where `binding` commands look for `.xmemory.json`; reads walk **up** toward `$HOME` and **merge** every scope |
|
|
388
574
|
| `--json` | — | Force one JSON document on stdout |
|
|
389
575
|
| `--verbose` | — | Add `trace_id` / `console_url` when present (never SQL, diff plans, or internals) |
|
|
390
576
|
|
|
391
577
|
**Credential resolution:** `--api-key` → `$XMEM_API_KEY` → nearest `.xmemrc.json` → *Not logged in — run `xmemcli auth login` first.*
|
|
392
578
|
|
|
393
|
-
|
|
579
|
+
**`context` is the one exception, and it is a security boundary.** Every other command walks up
|
|
580
|
+
from the current directory for the nearest `.xmemrc.json`, which is deliberate: a person chose
|
|
581
|
+
that directory and ran the command in it. `context` has neither — a session-start hook runs it
|
|
582
|
+
unattended, in whatever tree the editor happened to open — so it resolves the credential from
|
|
583
|
+
**`$HOME` only**, and consults a project `.xmemrc.json` only when the caller named that source
|
|
584
|
+
explicitly with `--api-key` / `$XMEM_API_KEY` or `--rc-dir` / `$XMEM_RC_DIR`. Without the pin, a
|
|
585
|
+
cloned repository could ship a key *and* an origin and have both used automatically. This is a
|
|
586
|
+
rule rather than a detector: earlier versions tried to *detect* a checkout-supplied credential
|
|
587
|
+
and each delivery mechanism turned out to be a fresh bypass.
|
|
588
|
+
|
|
589
|
+
**Origin resolution:** `--api-url` → `$XMEM_API_URL` → rc `api_url` → default — **with one escape hatch**: when the key comes from `--api-key` / `$XMEM_API_KEY` (not from the rc), the rc's `api_url` is **not** consulted and the origin falls back to the built-in default (`https://api.xmemory.ai`) unless you also set `--api-url` / `$XMEM_API_URL`. That keeps an explicitly supplied key from being silently paired with an unrelated origin in a project `.xmemrc.json`. If `$XMEM_API_KEY` is set without `$XMEM_API_URL`, the CLI warns once per invocation.
|
|
394
590
|
|
|
395
591
|
**Instance resolution (read/write):** `--instance-id` → `$XMEM_INSTANCE_ID` → if exactly **one** instance is visible, auto-select with a **stderr warning** → else error.
|
|
396
592
|
|