@vectros-ai/cli 0.19.0 → 0.20.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/AUTHORING.md CHANGED
@@ -69,6 +69,16 @@ A name must be 2–50 chars: a lowercase letter, then lowercase letters / digits
69
69
  `dataScope: {}` when a shared/tenant-wide resource is what you intend
70
70
  (warnings — they print but don't fail).
71
71
 
72
+ A schema may also declare `expectedScopeDims` — the ownership dimensions
73
+ its records are typically scoped by, e.g. `expectedScopeDims: [org,
74
+ client]`. Purely advisory (never sent to the platform, never runtime-
75
+ enforced): it lets the lint warn when a role/`accessProfile` clause grants
76
+ `r`/`u`/`d` on that typeName (via a type-qualified action like
77
+ `records:r:case`) but its `dataScope` names only SOME of the declared
78
+ dims — reads never require full-dimension coverage the way creates do, so
79
+ a clause naming one of two declared dims silently leaves the other
80
+ unconstrained. Omit the field entirely and this lint never fires.
81
+
72
82
  `validate` accepts a file path **or** a bundled blueprint name.
73
83
 
74
84
  ### 3. `plan` — preview before you mint
@@ -196,8 +206,9 @@ accessProfile:
196
206
  # capabilities: [member-lifecycle]
197
207
  # A SEPARATE gated dimension from allowedActions — named platform effects a
198
208
  # resource:ops verb can't express (e.g. creating/removing an identity in
199
- # your tenant). Only 'member-lifecycle' is admitted today; every other name
200
- # is hard-rejected, same posture as the scope gate. See "Capabilities" below.
209
+ # your tenant). 'member-lifecycle' and 'delegate-principal-stamp' are
210
+ # admitted today; every other name is hard-rejected, same posture as the
211
+ # scope gate. See "Capabilities" below.
201
212
  #
202
213
  # Instead of allowedActions (+ optional dataScope/capabilities), accessProfile
203
214
  # may declare `roleIds: [<roleId>, ...]` — one or more roles declared below,
@@ -456,10 +467,10 @@ boundary, not the file.
456
467
  An `accessProfile` or role clause may also declare `capabilities: [...]` —
457
468
  named platform effects (like creating or removing an identity in your tenant)
458
469
  that a `resource:ops` scope token can't express. This rides its own field,
459
- separate from `allowedActions`, and has its own allowlist: **only
460
- `member-lifecycle` is admitted today.** Every other capability name —
461
- including ones the platform's own registry recognizes — is refused, the same
462
- fail-closed, deliberately-narrow posture as the scope gate above. `validate`,
470
+ separate from `allowedActions`, and has its own allowlist: **`member-lifecycle`
471
+ and `delegate-principal-stamp` are admitted today.** Every other capability
472
+ name — including ones the platform's own registry recognizes — is refused,
473
+ the same fail-closed, deliberately-narrow posture as the scope gate above. `validate`,
463
474
  `plan`, `blueprint-test` and `bootstrap` all report a rejected capability the
464
475
  same way they report a rejected scope: nothing mints, and the CLI exits
465
476
  non-zero.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,147 @@
3
3
  All notable changes to `@vectros-ai/cli` are documented here.
4
4
  This project adheres to [Semantic Versioning](https://semver.org).
5
5
 
6
+ ## 0.20.0 — 2026-08-27
7
+
8
+ ### Added
9
+
10
+ - **The capability gate now admits `delegate-principal-stamp`**, alongside the
11
+ existing `member-lifecycle`. Grantable on an `accessProfile` or role clause's
12
+ `capabilities: [...]`, same as before — a blueprint can now let an admin
13
+ role create a membership-shaped record on behalf of a known third-party
14
+ user, once the clause authorizing the write also explicitly names `userId`
15
+ in its own `dataScope` (the capability itself may be granted on a
16
+ different clause of the same role, e.g. via a separately-composed
17
+ `roleIds` entry — only the write's own verb + `userId` admission must be
18
+ co-located). Bounded by the SAME app context and record type the clause's
19
+ `dataScope` already confines the write to — unlike `delegate-mint`/
20
+ `forensic-read`/`context-directory-read`, this is not tenant-wide, and
21
+ (like `member-lifecycle`) it is self-signup-eligible.
22
+ - **`vectros identity list-all`** — lists every user in the tenant, for the one
23
+ recovery case `identity list` can't reach: a user created but never granted
24
+ access anywhere (the gap between creating a principal and binding it to a
25
+ context). `identity list` is scoped to the caller's own context by design —
26
+ a user with no access grant at all is invisible there no matter how many
27
+ times a create is retried, since a retry with the same `--external-id` just
28
+ collides with the same invisible row. `list-all` authenticates with your own
29
+ login session (an account owner) instead of a context-scoped credential, so
30
+ it can see every user regardless of context. Supports `--external-id`,
31
+ `--tenant`, `--limit`, and `--json`, matching `identity list`'s conventions.
32
+ - **`vectros blueprint validate`/`plan`: new advisory lint —
33
+ `partial-datascope-dimension-coverage`** (needs `@vectros-ai/blueprints` ≥
34
+ 0.17.0). Warns when a role/`accessProfile` clause grants `r`/`u`/`d` on a
35
+ typeName (e.g. `records:r:case`) whose schema declares
36
+ `expectedScopeDims`, but the clause's `dataScope` names only SOME of those
37
+ dims — the missing dimension(s) are silently unconstrained for that grant,
38
+ since reads (unlike creates) never require full-dimension `dataScope`
39
+ coverage. Opt-in: a schema with no `expectedScopeDims` declared never
40
+ trips it, and it never fires on an untyped (bare `records:r`) grant.
41
+ Never runtime-enforced — pure authoring-time visibility into a choice
42
+ that's easy to make by omission rather than intent.
43
+ - **`bootstrap`/`blueprint-test` now catch a FRESH (first-apply) seed index
44
+ failure, not just a re-apply's.** A seed create's response always carries
45
+ `PENDING_INDEX` on a first apply (indexing runs async, after the
46
+ response), so the existing `seedIndexFailures` summary previously only
47
+ ever saw a terminal `FAILED` on a later idempotent re-apply — a
48
+ newly-bootstrapped demo whose seeds failed to index looked silently empty
49
+ in search/RAG until the operator happened to re-run bootstrap. Every seed
50
+ still `PENDING_INDEX` after seeding is now re-checked with a bounded,
51
+ concurrent, best-effort poll (default: 3 attempts, 500ms apart, ≤ ~1.5s
52
+ added to the happy path) and folded into the same run-summary warning if
53
+ it settles to `FAILED` within the bound. Deliberately NOT a guarantee — a
54
+ seed still `PENDING_INDEX` when the bound is exhausted stays silent, so a
55
+ genuinely slow index (reconcile/quarantine can stall for minutes) never
56
+ turns a one-shot provisioning command into an unbounded wait.
57
+ - **`vectros issuers` gains `register`/`update`/`delete`** — previously
58
+ read-only (`list`/`get`). Closes the gap where adding a second IdP, or
59
+ editing one issuer's `selfSignupPolicies` after initial setup, required
60
+ hand-authoring a blueprint `issuers:` block and re-running a full apply.
61
+ `register` is idempotent by issuer id (a repeat returns the existing
62
+ registration unchanged, not an error); `update` only ever sends the safe,
63
+ mutable fields (`subClaim`/`emailClaim`/`userinfoUri`/`status`/
64
+ `selfSignupPolicies`) — trust-anchor fields stay immutable via this route,
65
+ matching the platform; `delete` uses the same re-type-the-id confirmation
66
+ as `context destroy` (`--force` for non-interactive use), and is refused
67
+ server-side while any user is bound through the issuer. All three accept
68
+ `--tenant test|live` (like their `list`/`get` siblings) so a context
69
+ living in the `test` tenant is reachable, not just `live`.
70
+ - **New `vectros namespace` command group: `register`/`list`/`get`.**
71
+ Registering a brand-new scope namespace (e.g. a `practice`/`team` entity
72
+ dimension) was blueprint-apply-only before this; there was also no way to
73
+ discover which namespaces already exist without already knowing their
74
+ names. `register --entity-backed` is what makes a namespace a real
75
+ identity-entity dimension that `identity create --type <name>` can create
76
+ entities in. No `update`/`delete` verbs — both are gated to a genuine root
77
+ API key on the platform side with no provisioning-capability door, so
78
+ neither could ever succeed for any credential the CLI holds (documented in
79
+ the command's own module header).
80
+ - **`role create` gains `--assumable <json>`** — a role-level `vectros
81
+ assume` entitlement grant (JSON map of `scope:<namespace>` → allowed
82
+ values), previously blueprint-`roleAssumable:`-only. Independent of
83
+ `--data-scope`: holding broad data-scope reach in a namespace does not by
84
+ itself grant assuming any value in it.
85
+ - **New `vectros assume --context <c> --scope <ns:value>...`** — re-mints
86
+ the caller's own verb token with one or more `identity.<namespace>` values
87
+ switched (`POST /v1/auth/token/assume`), for a caller whose role
88
+ explicitly grants assuming those values. The CLI's first standalone
89
+ command reaching this endpoint; entitlement is checked live against the
90
+ caller's current roles, never a copy frozen into a token at mint time. No
91
+ `--to-keyring` — the response is an ephemeral bearer token with the same
92
+ remaining lifetime as the verb token this command itself mints to make the
93
+ call, not a durable secret.
94
+
95
+ ### Changed
96
+
97
+ - **`runLoader`'s `provisioned` is now REQUIRED — the self-provisioning
98
+ fallback is gone.** Internal hardening only, no CLI-facing behavior
99
+ change: every real caller (`vectros bootstrap`, `blueprint-test`) already
100
+ always ran `provisionContext` first and passed the result in, so the
101
+ fallback branch was dead in production. Removing it makes the
102
+ `provisionContext` → (apply-time identity resolution) → `runLoader`
103
+ ordering structurally required instead of convention-enforced — a future
104
+ caller can no longer reproduce the ordering bug the original fix
105
+ closed by skipping the split. `allowTenantWideNamespaces` and
106
+ `confirmExistingPrincipal` moved with it: both now live only on
107
+ `provisionContext`'s own input, where their actual checks have run since
108
+ that original fix — `runLoader`'s own copies of both parameters were already dead
109
+ plumbing before this change.
110
+ - **Apply-time identity resolution now REQUIRES `provisionContext`'s result.**
111
+ Internal hardening only, no CLI-facing behavior change. Closes the other
112
+ half of the ordering gap above: `runLoader` already required
113
+ `provisionContext`'s output, but the step between them — resolving a
114
+ blueprint's declared `identities:` — took a bare client with nothing tying
115
+ it to `provisionContext` having run first, so a caller could still
116
+ reproduce the original ordering bug (a non-`user` identity in a namespace
117
+ the same blueprint also registers racing that registration) with no
118
+ compiler signal. It now derives which client to use internally instead of
119
+ each caller doing so independently.
120
+
121
+ ### Fixed
122
+
123
+ - **`bootstrap`'s post-merge hint is now blueprint-specific, and `--client
124
+ code` always shows the `claude mcp add` command.** The restart hint used to
125
+ read "list my tasks" / "add a task to …" for EVERY blueprint (a leftover
126
+ from when only `task-management` existed) — it now names the actual
127
+ blueprint applied. The `claude mcp add` line (the idiomatic Claude Code
128
+ install path) used to print only on `--no-merge` / a declined / a failed
129
+ merge — a successful auto-merge silently hid it; it's now shown there too.
130
+ - Scrubbed internal issue/MR references, review-process citations, and
131
+ backend class names out of `packages/cli`'s comments — visible in the
132
+ published npm package's sourcemaps to anyone who reads mapped source.
133
+ Comment-only; no behavior change.
134
+ - **Keyring secret-store hardening.** A 0-byte salt file removed by
135
+ something else mid-poll (a concurrent cleanup, a manual delete of the
136
+ crash remnant) used to throw a raw `ENOENT` out of `setSecret`; it now
137
+ restarts salt creation instead, since nothing was ever encrypted under an
138
+ empty salt in the first place. Also fixed an order-dependent assumption
139
+ in two `keyring prune` tests (they now pin the processing order they
140
+ depend on, so a future ordering change fails with a diagnosable message
141
+ instead of a confusing downstream one).
142
+
143
+ ### Changed
144
+
145
+ - Bundled `@vectros-ai/sdk` refreshed to the current release's staging build.
146
+
6
147
  ## 0.19.0 — 2026-08-27
7
148
 
8
149
  ### Added
package/README.md CHANGED
@@ -9,9 +9,11 @@ The Vectros provisioning CLI — the `vectros` binary:
9
9
  - **`vectros blueprint`** — author + inspect blueprints (`init` / `validate` / `plan` / `list`), creds-free.
10
10
  - **`vectros blueprint-test`** — apply a blueprint to a live env, assert it provisioned a working credential, then tear it down.
11
11
  - **`vectros context`** — create, list, and destroy app contexts.
12
- - **`vectros issuers`** — inspect registered third-party IdP issuers (token-exchange trust anchors) for a context.
12
+ - **`vectros issuers`** — register, update, delete, and inspect third-party IdP issuers (token-exchange trust anchors) for a context.
13
+ - **`vectros namespace`** — register a new scope namespace, and list/get existing ones.
13
14
  - **`vectros identity`** — manage tenant-wide principals (users, orgs, clients, and namespaces you register).
14
15
  - **`vectros role`** — define reusable, context-scoped access rules.
16
+ - **`vectros assume`** — switch identity namespace values on your own token, per a role's `assumable` grant.
15
17
  - **`vectros access`** — bind principals to contexts, and inspect what a binding grants.
16
18
  - **`vectros key`** — issue, list, revoke, and rotate scoped API keys (`ssk_*`).
17
19
  - **`vectros keyring`** — hold several identities on one machine, pick which is active, and let other tools resolve keys from one place.
@@ -148,23 +150,60 @@ flags (`--base-url`, `--token`).
148
150
 
149
151
  ## `vectros issuers` — registered third-party IdP issuers
150
152
 
151
- Read the third-party identity-provider registrations a context trusts for
153
+ Manage the third-party identity-provider registrations a context trusts for
152
154
  [RFC 8693 token exchange](https://www.rfc-editor.org/rfc/rfc8693) — the
153
155
  `issuer`/`jwksUri`/`audience` a blueprint's `issuers[]` entries register, plus
154
- any self-signup policy attached to one. Read-only: registering an issuer is
155
- done through a blueprint (`bootstrap`/`blueprint-test`), not this command.
156
+ any self-signup policy attached to one. Everything a blueprint's `issuers:`
157
+ block can do is available standalone here too — adding a second IdP, or
158
+ editing one issuer's `selfSignupPolicies` after initial setup, no longer
159
+ requires hand-authoring a blueprint and re-running a full apply.
156
160
 
157
161
  ```bash
162
+ vectros issuers register --context my-app --issuer-id auth0-prod \
163
+ --issuer https://your-tenant.us.auth0.com/ \
164
+ --jwks-uri https://your-tenant.us.auth0.com/.well-known/jwks.json \
165
+ --audience https://api.your-app.example.com
158
166
  vectros issuers list --context my-app
159
167
  vectros issuers get primary --context my-app
168
+ vectros issuers update primary --context my-app --status suspended
169
+ vectros issuers delete primary --context my-app # re-types the id to confirm
160
170
  ```
161
171
 
162
172
  | Subcommand | Flags | Notes |
163
173
  |---|---|---|
174
+ | `register` | `--context`, `--issuer-id`, `--issuer`, `--jwks-uri`, `--audience` (all required); `--sub-claim`, `--email-claim`, `--userinfo-uri`, `--self-signup-policy <type:roleId>` (repeatable), `--tenant test\|live` | Idempotent by `--issuer-id` within the tenant — a repeat returns the existing registration unchanged, not an error. |
175
+ | `update <issuerId>` | `--context <contextId>` (required); `--sub-claim`, `--email-claim`, `--userinfo-uri`, `--status active\|suspended`, `--self-signup-policy <type:roleId>` (repeatable), `--clear-self-signup-policies`, `--tenant test\|live` | Only ever sends the SAFE, mutable fields — `issuer`/`jwks-uri`/`audience`/`contextId` are trust-anchor fields, immutable via this route on the platform side; rotating one is `delete` + `register`. |
176
+ | `delete <issuerId>` | `--context <contextId>` (required), `--force`, `--tenant test\|live` | Re-types the issuer id to confirm (mirrors `context destroy`); `--force` skips the prompt and is required when stdin isn't a TTY. Refused server-side while any user was ever created or matched through this issuer. |
164
177
  | `list` | `--context <contextId>` (required), `--tenant test\|live` | Every issuer registered in that context. `--context` has no default — an issuer read is confined to the context you name; there's no tenant-wide "every issuer in every context" view. |
165
178
  | `get <issuerId>` | `--context <contextId>` (required), `--tenant test\|live` | One issuer's full registration, including its self-signup policies. |
166
179
 
167
- Both accept `--json`, plus the common auth flags (`--base-url`, `--token`).
180
+ All five accept `--json`, plus the common auth flags (`--base-url`, `--token`).
181
+
182
+ ## `vectros namespace` — scope-namespace registrations
183
+
184
+ Register and inspect the namespaces a `scope:<namespace>` value can belong
185
+ to — whether values in that namespace must resolve to a real identity entity
186
+ (`entityBacked`, the same field `identity create --type <namespace>`
187
+ relies on) or are free-form strings. Registering a brand-new namespace (e.g.
188
+ a `practice`/`team` entity dimension) was blueprint-apply-only before this
189
+ command existed.
190
+
191
+ ```bash
192
+ vectros namespace register practice --context my-app --specificity-rank 1500 --entity-backed
193
+ vectros namespace list # tenant-wide registrations
194
+ vectros namespace list --context my-app # just my-app's own
195
+ vectros namespace get practice --context my-app
196
+ ```
197
+
198
+ | Subcommand | Flags | Notes |
199
+ |---|---|---|
200
+ | `register <name>` | `--context`, `--specificity-rank <n>` (both required); `--entity-backed`, `--default-schema-id <id>` | NOT idempotent — a repeat name 400s (unlike `issuers register`). `--context` has no tenant-wide option here — a confined credential may only register against its own bound context. |
201
+ | `list` | `--context <contextId>` (optional) | Omit for every tenant-wide registration; supply for one context's own. |
202
+ | `get <name>` | `--context <contextId>` (optional) | Same two-mode read as `list`. |
203
+
204
+ No `update`/`delete` — both routes require a genuine root API key on the
205
+ platform side, which this CLI never holds, so neither could ever succeed
206
+ here. All three subcommands accept `--json`.
168
207
 
169
208
  ## `vectros identity` — tenant-wide principals
170
209
 
@@ -190,12 +229,13 @@ vectros identity invite --context my-app --role editor --email bob@example.com \
190
229
  | | `--type user` only: `--email <email>`, `--service` (mint a SERVICE principal; default HUMAN) | `--name`/`--scope` are rejected for `--type user`. |
191
230
  | | entity namespaces only: `--name <name>`, `--scope <ns:value>` (repeatable, up to 2 parent ownership edges) | `--email`/`--service` are rejected for an entity namespace. |
192
231
  | | both: `--metadata <json>` | Free-form JSON object. |
193
- | `list` | `--type <user\|namespace>` (required), `--external-id <id>` (filter), `--limit <n>` | Omit `--limit` and the CLI drains every page for the complete set; pass `--limit` (1–100) and it returns exactly one page of that size instead. |
232
+ | `list` | `--type <user\|namespace>` (required), `--external-id <id>` (filter), `--limit <n>` | Scoped to your own context — see `list-all` below for a user created but never granted access anywhere. Omit `--limit` and the CLI drains every page for the complete set; pass `--limit` (1–100) and it returns exactly one page of that size instead. |
233
+ | `list-all` | `--external-id <id>` (filter), `--tenant test\|live`, `--limit <n>` | **Users only, and requires an account owner login.** Lists every user in the tenant, regardless of app-context access — for recovering a user `identity list` can never show you: one created but not (yet) granted access anywhere, so no context-scoped view can ever reach it, and a `create` retry with the same `--external-id` just collides with the same invisible row. Find it here by `--external-id`, then grant it access or `identity delete` it with an ordinary credential. |
194
234
  | `get` | `--type <user\|namespace>` (required), `--id <vectrosId>` (required) | `--id` is the Vectros-assigned id from `create`/`list`, not the `--external-id`. |
195
235
  | `delete` | `--type <user\|namespace>` (required), `--id <vectrosId>` (required) | |
196
236
  | `invite` | `--context <c>`, `--role <roleId>`, `--email <e>` (all required); `--first-name <n>`, `--accept-url <url>`, `--no-send-email` | Onboards a person into a context by email (`POST /v1/users/invite`) — no root key required, your `vectros login` session already carries enough scope. `--role` is an existing Role's own id (no separate lookup). `--accept-url` is required unless `--no-send-email` is given, in which case the response carries the raw `inviteToken`/`acceptLink` for you to deliver yourself. |
197
237
 
198
- `create`/`list`/`get`/`invite` accept `--json`; `delete` does not.
238
+ `create`/`list`/`list-all`/`get`/`invite` accept `--json`; `delete` does not.
199
239
 
200
240
  ## `vectros role` — reusable, context-scoped access rules
201
241
 
@@ -210,6 +250,8 @@ vectros role create --context my-app --role-id editor --name Editor \
210
250
  --actions records:cru,search:r
211
251
  vectros role create --context my-app --role-id own-org --name "Own org" \
212
252
  --actions records:r --data-scope '{"scope:org":["<orgId>", null]}'
253
+ vectros role create --context my-app --role-id hr-admin --name "HR Admin" \
254
+ --actions records:cru --assumable '{"scope:org":["org_engineering", "org_sales"]}'
213
255
  vectros role list --context my-app
214
256
  vectros role get --context my-app --role-id editor
215
257
  vectros role delete --context my-app --role-id editor
@@ -217,13 +259,35 @@ vectros role delete --context my-app --role-id editor
217
259
 
218
260
  | Subcommand | Flags | Notes |
219
261
  |---|---|---|
220
- | `create` | `--context <c>`, `--role-id <id>`, `--name <n>`, `--actions <csv>` (all required); `--data-scope <json>`, `--description <text>` | Idempotent by `roleId`. `--data-scope` confines the clause to owned data — a JSON map of ownership dimension → allowed values, ANDed across keys (e.g. `{"userId":["${{ self.userId }}"]}`, or `{"scope:org":["<orgId>", null]}` — the `null` entry additionally admits scope-less/tenant-shared records). Keys must be `userId` or `scope:<namespace>` (the legacy flat `orgId`/`clientId` keys are rejected server-side). |
262
+ | `create` | `--context <c>`, `--role-id <id>`, `--name <n>`, `--actions <csv>` (all required); `--data-scope <json>`, `--assumable <json>`, `--description <text>` | Idempotent by `roleId`. `--data-scope` confines the clause to owned data — a JSON map of ownership dimension → allowed values, ANDed across keys (e.g. `{"userId":["${{ self.userId }}"]}`, or `{"scope:org":["<orgId>", null]}` — the `null` entry additionally admits scope-less/tenant-shared records). Keys must be `userId` or `scope:<namespace>` (the legacy flat `orgId`/`clientId` keys are rejected server-side). `--assumable` is a SEPARATE, role-level grant — a JSON map of `scope:<namespace>` → allowed values naming which values a holder of this role may switch into via `vectros assume`; holding broad `--data-scope` reach in a namespace does not by itself grant assuming any value in it. |
221
263
  | `list` | `--context <c>` (required) | |
222
- | `get` | `--context <c>`, `--role-id <id>` (both required) | Also shows the role's `assumable` grant (which values, per namespace, a holder of this role may become via `POST /v1/auth/token/assume`), if any is set. `role create` has no `--assumable` flag today — author it via a blueprint's `roleAssumable:` block or a direct API call. |
264
+ | `get` | `--context <c>`, `--role-id <id>` (both required) | Also shows the role's `assumable` grant, if any is set. |
223
265
  | `delete` | `--context <c>`, `--role-id <id>` (both required) | No cascade — any access profile still referencing the role fails to mint (not silently downgraded) until reassigned. |
224
266
 
225
267
  `create`/`list`/`get` accept `--json`; `delete` does not.
226
268
 
269
+ ## `vectros assume` — switch identity namespace values on your own token
270
+
271
+ Re-mints your own verb token with one or more `identity.<namespace>` values
272
+ switched — the "org switcher" flow, named (like the platform endpoint it
273
+ calls) after AWS STS `AssumeRole`. Only works if a role you currently hold
274
+ explicitly grants assuming the requested value(s) via that role's own
275
+ `--assumable` grant (checked live against your CURRENT roles, never a value
276
+ frozen into your token at mint time).
277
+
278
+ ```bash
279
+ vectros assume --context my-app --scope org:org_sales
280
+ ```
281
+
282
+ | Flags | Notes |
283
+ |---|---|
284
+ | `--context <c>` (required), `--scope <ns:value>` (repeatable, at least one required) | Each `--scope` becomes one `scope:<namespace>` entry in the request. No artificial cap on how many namespaces you name — the platform requires a SINGLE role to jointly grant the whole combination and rejects an unsatisfiable one itself. |
285
+
286
+ Prints the re-minted `access_token`/`expires_in` (accepts `--json`) — there
287
+ is no `--to-keyring` here, since the result is an ephemeral bearer token
288
+ with the same remaining lifetime as the verb token this command itself
289
+ mints to make the call, not a durable secret the keyring is built to hold.
290
+
227
291
  ## `vectros access` — bind principals to contexts
228
292
 
229
293
  The binding layer between an identity and a context: `access grant` joins a
@@ -437,10 +501,10 @@ A blueprint's `accessProfile` and role clauses may also declare
437
501
  `capabilities: [...]` — named platform effects (like creating or removing an
438
502
  identity in your tenant) that reach across a partition boundary in a way no
439
503
  `resource:ops` verb can express. This rides a field entirely separate from
440
- `allowedActions`, and it has its own allowlist: **only `member-lifecycle` is
441
- admitted today.** Every other capability name — including ones the platform's
442
- own registry recognizes — is refused, the same fail-closed, deliberately-widen
443
- posture as the scope gate above. `vectros blueprint validate`/`plan` and
504
+ `allowedActions`, and it has its own allowlist: **`member-lifecycle` and
505
+ `delegate-principal-stamp` are admitted today.** Every other capability name —
506
+ including ones the platform's own registry recognizes — is refused, the same
507
+ fail-closed, deliberately-widen posture as the scope gate above. `vectros blueprint validate`/`plan` and
444
508
  `bootstrap` all report a rejected capability the same way they report a
445
509
  rejected scope: nothing mints, and the CLI exits non-zero.
446
510