xmemcli 0.0.8__tar.gz → 0.0.9__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: xmemcli
3
- Version: 0.0.8
3
+ Version: 0.0.9
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
@@ -15,7 +15,7 @@ Full command reference is included below.
15
15
  ## Usage
16
16
 
17
17
  ```text
18
- xmemcli auth login [--no-browser] [--timeout S] [--console-url URL]
18
+ xmemcli auth login [--no-browser] [--timeout S] [--console-url URL] [--email ADDR [--org-name NAME]]
19
19
  xmemcli auth logout
20
20
  xmemcli auth status
21
21
  xmemcli read <query>
@@ -97,25 +97,29 @@ xmemcli version
97
97
  xmemcli auth login
98
98
  ```
99
99
 
100
- Version: **0.0.8**.
100
+ Version: **0.0.9**.
101
101
 
102
102
 
103
103
  ---
104
104
 
105
- # `xmemcli` auth flow — PKCE handoff and credentials
105
+ # `xmemcli` auth flow — PKCE handoff, email sign-in, and credentials
106
106
 
107
- The CLI is **human-governed for key acquisition**: an AI-assisted IDE may run reads, writes, and inventory, but **acquiring an API key** stays under human control in the browser. A key must **never enter the AI transcript** — it is handed to the CLI out-of-band via `xmemcli auth login` or environment / `.xmemrc.json`.
107
+ The CLI is **human-approved for key acquisition**: an AI-assisted IDE may run reads, writes, and inventory, and may even *initiate* key acquisition, but a key is only ever issued after **one explicit human approval** — a click in the browser (PKCE handoff) or an approval of a sign-in email (`--email`). A key must **never enter the AI transcript** — it is handed to the CLI out-of-band via `xmemcli auth login` or environment / `.xmemrc.json`, and the CLI prints only its prefix.
108
108
 
109
- **Model:** the CLI sends the human to **`/xmemcli/<challenge>`** on the Console, listens on **`127.0.0.1:9636/callback`**, and the Console redirects a signed short-lived **code** (not the key) to that callback.
109
+ Two acquisition paths share `xmemcli auth login`:
110
110
 
111
- > **Scope.** Shipped in this package: `.xmemrc.json` discovery, PKCE `auth login` / `logout` / `status`, `/whoami` consumption, and `quota`. Server endpoints: `POST /cli/handoff`, `POST /cli/token`.
111
+ - **Browser PKCE handoff** (default): the CLI sends the human to **`/xmemcli/<challenge>`** on the Console, listens on **`127.0.0.1:9636/callback`**, and the Console redirects a signed short-lived **code** (not the key) to that callback.
112
+ - **Headless email sign-in** (`--email <addr>`): the CLI plays the waiting-browser role of the Console's cross-device email sign-in and then mints its own key — no browser on this machine. See [Email sign-in](#email-sign-in----email) below.
113
+
114
+ > **Scope.** Shipped in this package: `.xmemrc.json` discovery, PKCE `auth login` / `logout` / `status`, email `auth login --email`, `/whoami` consumption, and `quota`. Server endpoints: `POST /cli/handoff`, `POST /cli/token`, and — for the email path — the Console sign-in and accounts routes listed below (all pre-existing Console surfaces; the email path added no server endpoint).
112
115
 
113
116
  ## Acquiring a key
114
117
 
115
118
  The human either:
116
119
 
117
120
  - **Provides a key they already hold** (`$XMEM_API_KEY`, `.xmemrc.json`, or paste at login), or
118
- - **Creates a key** in the Console and clicks **"Use this key in the CLI"** (when the page was opened via `/xmemcli/<challenge>`).
121
+ - **Creates a key** in the Console and clicks **"Use this key in the CLI"** (when the page was opened via `/xmemcli/<challenge>`), or
122
+ - **Approves a sign-in email** for an `auth login --email` run, after which the CLI mints its own key.
119
123
 
120
124
  During **onboarding**, the Console may auto-handoff an onboarding key while a short-lived cookie bridge is active.
121
125
 
@@ -137,6 +141,22 @@ CLI ◄── localhost redirect ── redeems code + verifier → writes .xmem
137
141
  AI-assisted IDE ── xmemcli read/write ──► CLI resolves key; never handles plaintext key
138
142
  ```
139
143
 
144
+ ## Email sign-in — `--email`
145
+
146
+ `xmemcli auth login --email <addr> [--org-name <name>]` acquires the key with **one human action and no browser on this machine** — the flow an agent-driven IDE uses. The CLI takes the waiting-device role of the Console's cross-device email sign-in; every endpoint below already served the Console before this flag existed. **The fully headless path requires the server to have cross-device hand-off enabled**; a server without it only offers the typed six-digit code, so a run with no interactive terminal is refused there (after cancelling the attempt it had to start to find out).
147
+
148
+ 1. `POST /api/kingdom-signin-request` — the server emails a six-digit code + one-click link; the CLI holds the signed pending cookie **in memory**. The reply's **matching code** is consumed only as the hand-off signal and is not printed (the compare UI is retired across all sign-in surfaces for now).
149
+ 2. The human opens the email on any device and Approves. *This is the single human action.*
150
+ 3. The CLI claim-polls `POST /api/kingdom-signin-claim` on the Console's own waiting-tab cadence (a short grace, ten fast polls, then a slow poll; transient network failures count as missed polls, not aborts) and exchanges the proof via `POST /api/kingdom-signin-mint` for the browser-session cookie — held **in memory only, never written to disk**.
151
+ 4. With the session, the CLI runs the Console onboarding's core sequence: `GET /api/check-user`; when the address has no account, `GET /api/suggest-slug` (server-derived org name, `--org-name` overrides; ignored for an existing account) and `POST /api/public-signup` — **note that creating a new organisation requires the deployment to allow public registration, which the hosted service currently does not**: an existing account gets a key, a new address gets the server's "organisation creation is not available" refusal (the Console's admin-fallback signup arm is not implemented here); then `GET /api/accounts/users/by-email`, `GET /api/accounts/api-roles` (the seeded default role, or the org's only role — an ambiguous set is refused, never guessed), and `POST /api/accounts/api-keys` with **no cluster list** — the key attaches to every cluster the org has at mint time. Clusters created later are attached by a server-side backfill that repairs only keys already linked to every other cluster in the org; an org with no clusters at mint time gets a key attached to nothing. The key is named **`CLI email login (<hostname>, <timestamp>)`** so every mint stays individually identifiable and revocable on the Console's API Keys page.
152
+ 5. The key is written to `.xmemrc.json` (0600), stdout carries the prefix only, and the session cookie dies with the process.
153
+
154
+ The wait is bounded by `--timeout` — 600 seconds for this path by default, which is also a **ceiling**: nothing stays claimable past the server's pending window, so larger values are clamped. The emailed one-click link and six-digit code themselves expire at about five minutes; the wait continues past that because an approval given in time stays claimable, and the terminal says when the emailed artifacts have lapsed. The Console origin must be `https` (or a loopback host, for local development). The Console must also match the API origin the key will be used against: with a non-default `--api-url` the CLI refuses to guess the Console (pass `--console-url` or set `$XMEM_CONSOLE_URL`), and an explicitly named Console that provably mismatches the API origin (mixed loopback-ness, or a default-production half paired with a non-default one) is refused rather than trusted.
155
+
156
+ When the server offers no matching code on the request reply (cross-device hand-off disabled, no public Console origin configured, or a transient degradation), there is nothing for a headless starter to claim — the emailed link then signs in the *approving* browser — so the CLI falls back to the emailed **six-digit code typed into the terminal** (`POST /api/kingdom-signin-verify`), still a single human action. That fallback needs an interactive stdin; a non-interactive run cancels the attempt it just started (the mode is only known from the server's reply, after the email is on its way) and refuses with instructions — the typed code dies with that cancel, but on such a server the one-click link has nothing durable to revoke and stays redeemable in a browser until it expires (about five minutes), which the terminal states plainly.
157
+
158
+ A credential that already resolves (via `/whoami`) to the requested address at the requested origin — checked across `--api-key`, `$XMEM_API_KEY`, and the rc, in that order — short-circuits without sending any email, so re-running the command is free (a matching `$XMEM_API_KEY` is copied into `.xmemrc.json` so the project gains a durable credential; an explicit `--api-key` is never persisted); when the check itself cannot be made (the API is unreachable) the CLI refuses to mint rather than stranding a duplicate key. Every abort of a started attempt — Ctrl+C, timeout, or an error mid-wait — best-effort-cancels it (`POST /api/kingdom-signin-cancel`, retried briefly) and reports what the cancel actually achieved: a **confirmed** cancel of a cross-device attempt makes the emailed link unapprovable; an unconfirmed one is reported as such; and on a hand-off-disabled server the link has nothing durable to revoke — it stays redeemable (in the browser that opens it) until it expires on its own, and the terminal says so.
159
+
140
160
  ## Credential store (`.xmemrc.json`)
141
161
 
142
162
  Project-local **`.xmemrc.json`**: `{email, api_url, api_key}`. Found by walking up from `--rc-dir` / CWD, ceiling `$HOME`.
@@ -151,11 +171,15 @@ Resolution order: `--api-key` → `$XMEM_API_KEY` → `.xmemrc.json`. Origin: `-
151
171
 
152
172
  | Threat | Mitigation |
153
173
  | --- | --- |
154
- | Key in AI transcript | localhost callback → `0600` store; login stdout shows `key_prefix` only |
174
+ | Key in AI transcript | localhost callback / in-process mint → `0600` store; login stdout shows `key_prefix` only |
155
175
  | Key in URL | URL carries code only; key over TLS on handoff/token |
156
176
  | Captured code replay | PKCE verifier never leaves CLI; code is TTL-bounded |
157
177
  | CSRF on callback | state = PKCE challenge; redeem requires verifier |
158
178
  | Wrong Console page | CLI button only on `/xmemcli/<challenge>` |
179
+ | Session token outliving the login | the email-path session cookie is held in process memory only — never printed, never on disk — and is discarded when the process exits; the token itself stays server-valid until its ~2-day expiry, so the containment is the CLI never letting it out of memory, not revocation |
180
+ | Session cookie over cleartext | the email path refuses non-`https` Console origins (loopback excepted), refuses every redirect on its cookie-carrying requests, and fails fast when a tunnelled Console marks its cookie `Secure` for an `http://` origin |
181
+ | Unsolicited sign-in email initiation | server-side send limits per mailbox (enforced per server node, so the fleet-wide budget scales with node count); the email itself grants nothing without the inbox owner's Approve, and the CLI best-effort-cancels attempts it cannot complete |
182
+ | Approving someone else's email sign-in | **user-mediated** — the confirmation page leads with "only if this is your address" and states that approving lets the requesting device act on the account, including creating API keys; the stake is higher here than in the browser flow, because approving a CLI-started attempt ends in a durable API key, not a two-day browser session. The matching-code comparison that once narrowed this further is retired for now (the code still travels on the wire but no surface displays it). Approve only sign-ins you started. |
159
183
 
160
184
  Fixed port **9636** ("xmem" on phone keypad) allows SSH/devcontainer forwarding; security rests on PKCE, not port secrecy.
161
185
 
@@ -167,9 +191,9 @@ Fixed port **9636** ("xmem" on phone keypad) allows SSH/devcontainer forwarding;
167
191
 
168
192
  # `xmemcli` — capabilities reference
169
193
 
170
- **Version:** `0.0.8` (see `xmemcli version`)
194
+ **Version:** `0.0.9` (see `xmemcli version`)
171
195
 
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**.
196
+ `xmemcli` is the command-line client for the **xmemory HTTP API**. It is **human-approved for key acquisition**: an AI-assisted IDE may run reads, writes, and inventory, and may initiate `auth login`, but a key is only issued after one explicit human approval — a click in the Console UI (PKCE handoff) or an approval of a sign-in email (`--email`). Quota limits change only in the **Console UI**. The full acquisition contract is in the auth-flow reference bundled with this package.
173
197
 
174
198
  ```bash
175
199
  xmemcli … # installed CLI
@@ -185,7 +209,7 @@ Every command below has dedicated help — see [Help](#help).
185
209
 
186
210
  | Command | Description |
187
211
  |---------|-------------|
188
- | **`write`** `<text>` | Sync write (`POST …/write`). `--extraction fast\|deep` (default `fast`). `--no-wait` queues async write, returns `write_id`. |
212
+ | **`write`** `<text>` | Sync write (`POST …/write`). `--extraction fast\|deep` (default `fast`). `--no-wait` queues async write, returns `write_id`. `--scope TYPE:ID` (repeatable) anchors the write to existing objects: only they may be modified/deleted, new objects and links to them are allowed, anything else fails; fast extraction only. |
189
213
  | **`write-status`** `<write_id>` … | Poll async writes until terminal or `--timeout` (default 60s). Accepts multiple ids. |
190
214
  | **`read`** `<query>` | Read from active instance. `--read-mode single\|raw\|xresponse`, `--scope TYPE:ID` (repeatable), `--scope-relations`. |
191
215
 
@@ -386,7 +410,7 @@ so a typo fails loudly rather than being ignored.
386
410
 
387
411
  | Command | Description |
388
412
  |---------|-------------|
389
- | **`auth login`** | PKCE via Console `/xmemcli/<challenge>` → `.xmemrc.json`. `--no-browser`, `--timeout`, `--console-url`. |
413
+ | **`auth login`** | PKCE via Console `/xmemcli/<challenge>` → `.xmemrc.json`. `--no-browser`, `--timeout`, `--console-url`. With `--email ADDR` (+ optional `--org-name`, used only when a new account is created; requires `--email`): headless email sign-in — one emailed approval, then the CLI mints its own org-wide key named `CLI email login (<hostname>, <timestamp>)`; details in the auth-flow reference. New-organisation creation additionally requires the deployment to allow public registration. Payload shapes: a fresh email mint carries `method: email`, `key_name`, `api_role`, and `org_created`; the browser path carries `method: pkce` (no role/org fields); a matching `--api-key` or rc credential short-circuits to `status: already_authorized` with `source`: flag / rc (`persisted: false` on the flag arm, which saves nothing); a matching `$XMEM_API_KEY` is copied into the rc and reports `status: authorized`, `source: environment`. Exit codes follow the standard HTTP contract (401 → 4 with stage `auth`, 403 → 3 with stage `permission`, other HTTP/network/server-state failures → 3). |
390
414
  | **`auth logout`** | Remove active `.xmemrc.json` |
391
415
  | **`auth status`** | Call `/whoami`. No key → exit 0; bad key → auth error; good key → email + prefix. |
392
416
  | **`mcp <instance-id>`** | Serve one instance to an MCP client over stdio, using this CLI's credential. Not for humans — see below. |
@@ -7,7 +7,7 @@ Full command reference is included below.
7
7
  ## Usage
8
8
 
9
9
  ```text
10
- xmemcli auth login [--no-browser] [--timeout S] [--console-url URL]
10
+ xmemcli auth login [--no-browser] [--timeout S] [--console-url URL] [--email ADDR [--org-name NAME]]
11
11
  xmemcli auth logout
12
12
  xmemcli auth status
13
13
  xmemcli read <query>
@@ -89,25 +89,29 @@ xmemcli version
89
89
  xmemcli auth login
90
90
  ```
91
91
 
92
- Version: **0.0.8**.
92
+ Version: **0.0.9**.
93
93
 
94
94
 
95
95
  ---
96
96
 
97
- # `xmemcli` auth flow — PKCE handoff and credentials
97
+ # `xmemcli` auth flow — PKCE handoff, email sign-in, and credentials
98
98
 
99
- The CLI is **human-governed for key acquisition**: an AI-assisted IDE may run reads, writes, and inventory, but **acquiring an API key** stays under human control in the browser. A key must **never enter the AI transcript** — it is handed to the CLI out-of-band via `xmemcli auth login` or environment / `.xmemrc.json`.
99
+ The CLI is **human-approved for key acquisition**: an AI-assisted IDE may run reads, writes, and inventory, and may even *initiate* key acquisition, but a key is only ever issued after **one explicit human approval** — a click in the browser (PKCE handoff) or an approval of a sign-in email (`--email`). A key must **never enter the AI transcript** — it is handed to the CLI out-of-band via `xmemcli auth login` or environment / `.xmemrc.json`, and the CLI prints only its prefix.
100
100
 
101
- **Model:** the CLI sends the human to **`/xmemcli/<challenge>`** on the Console, listens on **`127.0.0.1:9636/callback`**, and the Console redirects a signed short-lived **code** (not the key) to that callback.
101
+ Two acquisition paths share `xmemcli auth login`:
102
102
 
103
- > **Scope.** Shipped in this package: `.xmemrc.json` discovery, PKCE `auth login` / `logout` / `status`, `/whoami` consumption, and `quota`. Server endpoints: `POST /cli/handoff`, `POST /cli/token`.
103
+ - **Browser PKCE handoff** (default): the CLI sends the human to **`/xmemcli/<challenge>`** on the Console, listens on **`127.0.0.1:9636/callback`**, and the Console redirects a signed short-lived **code** (not the key) to that callback.
104
+ - **Headless email sign-in** (`--email <addr>`): the CLI plays the waiting-browser role of the Console's cross-device email sign-in and then mints its own key — no browser on this machine. See [Email sign-in](#email-sign-in----email) below.
105
+
106
+ > **Scope.** Shipped in this package: `.xmemrc.json` discovery, PKCE `auth login` / `logout` / `status`, email `auth login --email`, `/whoami` consumption, and `quota`. Server endpoints: `POST /cli/handoff`, `POST /cli/token`, and — for the email path — the Console sign-in and accounts routes listed below (all pre-existing Console surfaces; the email path added no server endpoint).
104
107
 
105
108
  ## Acquiring a key
106
109
 
107
110
  The human either:
108
111
 
109
112
  - **Provides a key they already hold** (`$XMEM_API_KEY`, `.xmemrc.json`, or paste at login), or
110
- - **Creates a key** in the Console and clicks **"Use this key in the CLI"** (when the page was opened via `/xmemcli/<challenge>`).
113
+ - **Creates a key** in the Console and clicks **"Use this key in the CLI"** (when the page was opened via `/xmemcli/<challenge>`), or
114
+ - **Approves a sign-in email** for an `auth login --email` run, after which the CLI mints its own key.
111
115
 
112
116
  During **onboarding**, the Console may auto-handoff an onboarding key while a short-lived cookie bridge is active.
113
117
 
@@ -129,6 +133,22 @@ CLI ◄── localhost redirect ── redeems code + verifier → writes .xmem
129
133
  AI-assisted IDE ── xmemcli read/write ──► CLI resolves key; never handles plaintext key
130
134
  ```
131
135
 
136
+ ## Email sign-in — `--email`
137
+
138
+ `xmemcli auth login --email <addr> [--org-name <name>]` acquires the key with **one human action and no browser on this machine** — the flow an agent-driven IDE uses. The CLI takes the waiting-device role of the Console's cross-device email sign-in; every endpoint below already served the Console before this flag existed. **The fully headless path requires the server to have cross-device hand-off enabled**; a server without it only offers the typed six-digit code, so a run with no interactive terminal is refused there (after cancelling the attempt it had to start to find out).
139
+
140
+ 1. `POST /api/kingdom-signin-request` — the server emails a six-digit code + one-click link; the CLI holds the signed pending cookie **in memory**. The reply's **matching code** is consumed only as the hand-off signal and is not printed (the compare UI is retired across all sign-in surfaces for now).
141
+ 2. The human opens the email on any device and Approves. *This is the single human action.*
142
+ 3. The CLI claim-polls `POST /api/kingdom-signin-claim` on the Console's own waiting-tab cadence (a short grace, ten fast polls, then a slow poll; transient network failures count as missed polls, not aborts) and exchanges the proof via `POST /api/kingdom-signin-mint` for the browser-session cookie — held **in memory only, never written to disk**.
143
+ 4. With the session, the CLI runs the Console onboarding's core sequence: `GET /api/check-user`; when the address has no account, `GET /api/suggest-slug` (server-derived org name, `--org-name` overrides; ignored for an existing account) and `POST /api/public-signup` — **note that creating a new organisation requires the deployment to allow public registration, which the hosted service currently does not**: an existing account gets a key, a new address gets the server's "organisation creation is not available" refusal (the Console's admin-fallback signup arm is not implemented here); then `GET /api/accounts/users/by-email`, `GET /api/accounts/api-roles` (the seeded default role, or the org's only role — an ambiguous set is refused, never guessed), and `POST /api/accounts/api-keys` with **no cluster list** — the key attaches to every cluster the org has at mint time. Clusters created later are attached by a server-side backfill that repairs only keys already linked to every other cluster in the org; an org with no clusters at mint time gets a key attached to nothing. The key is named **`CLI email login (<hostname>, <timestamp>)`** so every mint stays individually identifiable and revocable on the Console's API Keys page.
144
+ 5. The key is written to `.xmemrc.json` (0600), stdout carries the prefix only, and the session cookie dies with the process.
145
+
146
+ The wait is bounded by `--timeout` — 600 seconds for this path by default, which is also a **ceiling**: nothing stays claimable past the server's pending window, so larger values are clamped. The emailed one-click link and six-digit code themselves expire at about five minutes; the wait continues past that because an approval given in time stays claimable, and the terminal says when the emailed artifacts have lapsed. The Console origin must be `https` (or a loopback host, for local development). The Console must also match the API origin the key will be used against: with a non-default `--api-url` the CLI refuses to guess the Console (pass `--console-url` or set `$XMEM_CONSOLE_URL`), and an explicitly named Console that provably mismatches the API origin (mixed loopback-ness, or a default-production half paired with a non-default one) is refused rather than trusted.
147
+
148
+ When the server offers no matching code on the request reply (cross-device hand-off disabled, no public Console origin configured, or a transient degradation), there is nothing for a headless starter to claim — the emailed link then signs in the *approving* browser — so the CLI falls back to the emailed **six-digit code typed into the terminal** (`POST /api/kingdom-signin-verify`), still a single human action. That fallback needs an interactive stdin; a non-interactive run cancels the attempt it just started (the mode is only known from the server's reply, after the email is on its way) and refuses with instructions — the typed code dies with that cancel, but on such a server the one-click link has nothing durable to revoke and stays redeemable in a browser until it expires (about five minutes), which the terminal states plainly.
149
+
150
+ A credential that already resolves (via `/whoami`) to the requested address at the requested origin — checked across `--api-key`, `$XMEM_API_KEY`, and the rc, in that order — short-circuits without sending any email, so re-running the command is free (a matching `$XMEM_API_KEY` is copied into `.xmemrc.json` so the project gains a durable credential; an explicit `--api-key` is never persisted); when the check itself cannot be made (the API is unreachable) the CLI refuses to mint rather than stranding a duplicate key. Every abort of a started attempt — Ctrl+C, timeout, or an error mid-wait — best-effort-cancels it (`POST /api/kingdom-signin-cancel`, retried briefly) and reports what the cancel actually achieved: a **confirmed** cancel of a cross-device attempt makes the emailed link unapprovable; an unconfirmed one is reported as such; and on a hand-off-disabled server the link has nothing durable to revoke — it stays redeemable (in the browser that opens it) until it expires on its own, and the terminal says so.
151
+
132
152
  ## Credential store (`.xmemrc.json`)
133
153
 
134
154
  Project-local **`.xmemrc.json`**: `{email, api_url, api_key}`. Found by walking up from `--rc-dir` / CWD, ceiling `$HOME`.
@@ -143,11 +163,15 @@ Resolution order: `--api-key` → `$XMEM_API_KEY` → `.xmemrc.json`. Origin: `-
143
163
 
144
164
  | Threat | Mitigation |
145
165
  | --- | --- |
146
- | Key in AI transcript | localhost callback → `0600` store; login stdout shows `key_prefix` only |
166
+ | Key in AI transcript | localhost callback / in-process mint → `0600` store; login stdout shows `key_prefix` only |
147
167
  | Key in URL | URL carries code only; key over TLS on handoff/token |
148
168
  | Captured code replay | PKCE verifier never leaves CLI; code is TTL-bounded |
149
169
  | CSRF on callback | state = PKCE challenge; redeem requires verifier |
150
170
  | Wrong Console page | CLI button only on `/xmemcli/<challenge>` |
171
+ | Session token outliving the login | the email-path session cookie is held in process memory only — never printed, never on disk — and is discarded when the process exits; the token itself stays server-valid until its ~2-day expiry, so the containment is the CLI never letting it out of memory, not revocation |
172
+ | Session cookie over cleartext | the email path refuses non-`https` Console origins (loopback excepted), refuses every redirect on its cookie-carrying requests, and fails fast when a tunnelled Console marks its cookie `Secure` for an `http://` origin |
173
+ | Unsolicited sign-in email initiation | server-side send limits per mailbox (enforced per server node, so the fleet-wide budget scales with node count); the email itself grants nothing without the inbox owner's Approve, and the CLI best-effort-cancels attempts it cannot complete |
174
+ | Approving someone else's email sign-in | **user-mediated** — the confirmation page leads with "only if this is your address" and states that approving lets the requesting device act on the account, including creating API keys; the stake is higher here than in the browser flow, because approving a CLI-started attempt ends in a durable API key, not a two-day browser session. The matching-code comparison that once narrowed this further is retired for now (the code still travels on the wire but no surface displays it). Approve only sign-ins you started. |
151
175
 
152
176
  Fixed port **9636** ("xmem" on phone keypad) allows SSH/devcontainer forwarding; security rests on PKCE, not port secrecy.
153
177
 
@@ -159,9 +183,9 @@ Fixed port **9636** ("xmem" on phone keypad) allows SSH/devcontainer forwarding;
159
183
 
160
184
  # `xmemcli` — capabilities reference
161
185
 
162
- **Version:** `0.0.8` (see `xmemcli version`)
186
+ **Version:** `0.0.9` (see `xmemcli version`)
163
187
 
164
- `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**.
188
+ `xmemcli` is the command-line client for the **xmemory HTTP API**. It is **human-approved for key acquisition**: an AI-assisted IDE may run reads, writes, and inventory, and may initiate `auth login`, but a key is only issued after one explicit human approval — a click in the Console UI (PKCE handoff) or an approval of a sign-in email (`--email`). Quota limits change only in the **Console UI**. The full acquisition contract is in the auth-flow reference bundled with this package.
165
189
 
166
190
  ```bash
167
191
  xmemcli … # installed CLI
@@ -177,7 +201,7 @@ Every command below has dedicated help — see [Help](#help).
177
201
 
178
202
  | Command | Description |
179
203
  |---------|-------------|
180
- | **`write`** `<text>` | Sync write (`POST …/write`). `--extraction fast\|deep` (default `fast`). `--no-wait` queues async write, returns `write_id`. |
204
+ | **`write`** `<text>` | Sync write (`POST …/write`). `--extraction fast\|deep` (default `fast`). `--no-wait` queues async write, returns `write_id`. `--scope TYPE:ID` (repeatable) anchors the write to existing objects: only they may be modified/deleted, new objects and links to them are allowed, anything else fails; fast extraction only. |
181
205
  | **`write-status`** `<write_id>` … | Poll async writes until terminal or `--timeout` (default 60s). Accepts multiple ids. |
182
206
  | **`read`** `<query>` | Read from active instance. `--read-mode single\|raw\|xresponse`, `--scope TYPE:ID` (repeatable), `--scope-relations`. |
183
207
 
@@ -378,7 +402,7 @@ so a typo fails loudly rather than being ignored.
378
402
 
379
403
  | Command | Description |
380
404
  |---------|-------------|
381
- | **`auth login`** | PKCE via Console `/xmemcli/<challenge>` → `.xmemrc.json`. `--no-browser`, `--timeout`, `--console-url`. |
405
+ | **`auth login`** | PKCE via Console `/xmemcli/<challenge>` → `.xmemrc.json`. `--no-browser`, `--timeout`, `--console-url`. With `--email ADDR` (+ optional `--org-name`, used only when a new account is created; requires `--email`): headless email sign-in — one emailed approval, then the CLI mints its own org-wide key named `CLI email login (<hostname>, <timestamp>)`; details in the auth-flow reference. New-organisation creation additionally requires the deployment to allow public registration. Payload shapes: a fresh email mint carries `method: email`, `key_name`, `api_role`, and `org_created`; the browser path carries `method: pkce` (no role/org fields); a matching `--api-key` or rc credential short-circuits to `status: already_authorized` with `source`: flag / rc (`persisted: false` on the flag arm, which saves nothing); a matching `$XMEM_API_KEY` is copied into the rc and reports `status: authorized`, `source: environment`. Exit codes follow the standard HTTP contract (401 → 4 with stage `auth`, 403 → 3 with stage `permission`, other HTTP/network/server-state failures → 3). |
382
406
  | **`auth logout`** | Remove active `.xmemrc.json` |
383
407
  | **`auth status`** | Call `/whoami`. No key → exit 0; bad key → auth error; good key → email + prefix. |
384
408
  | **`mcp <instance-id>`** | Serve one instance to an MCP client over stdio, using this CLI's credential. Not for humans — see below. |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xmemcli"
3
- version = "0.0.8"
3
+ version = "0.0.9"
4
4
  description = "Command-line client for the xmemory HTTP API: PKCE auth, instances, read/write, schema and XMD tools."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12,<4"
@@ -4,5 +4,5 @@ requires-python = ">=3.12, <4"
4
4
 
5
5
  [[package]]
6
6
  name = "xmemcli"
7
- version = "0.0.8"
7
+ version = "0.0.9"
8
8
  source = { editable = "." }
@@ -1,3 +1,3 @@
1
1
  """Standalone xmemcli package (``xmemcli`` console script)."""
2
2
 
3
- __version__ = "0.0.8"
3
+ __version__ = "0.0.9"