@remits/remits-cli 0.1.87 → 0.1.89

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
@@ -29,10 +29,10 @@ git add -A
29
29
  git commit -m "sync passing changes"
30
30
  git push
31
31
  remits-cli components sync
32
- remits-cli components sync --branch feature_forked --dry-run
33
- remits-cli components sync --branch feature_forked --force-tombstones
32
+ remits-cli components sync --branch feature_branch --dry-run
33
+ remits-cli components sync --branch feature_branch --force-tombstones
34
34
  remits-cli token --path page/my-embeddable
35
- remits-cli token --path page/my-embeddable --variant-branch feature_forked
35
+ remits-cli token --path page/my-embeddable --variant-branch feature_branch
36
36
  remits-cli data-mode
37
37
  remits-cli data-mode set prod
38
38
  remits-cli sessions list
@@ -66,7 +66,7 @@ remits-cli install --skills --overwrite true
66
66
  - `components commit` is a convenience wrapper that performs local git commit/push, then `components sync`, then local `git fetch`/`git pull --ff-only`.
67
67
  - `components sync` returns the post-sync branch SHA produced by the platform. `components commit` verifies that `origin/<branch>` and local `HEAD` both match that exact SHA after the final pull.
68
68
  - `components push` is deprecated and currently behaves the same as `components stage`.
69
- - `accountId` resolution for CLI commands: explicit `--account-id` flag wins, then the current repo's `account-info.json`, then the active session. For `remits-cli tool` calls the server applies a further precedence — explicit `--account-id` > `input.accountId` > session/repo default — so a tool can execute against a different account than the surrounding repo.
69
+ - `accountId` resolution for CLI commands: explicit `--account-id` flag wins, then the current repo's `account-info.json` (`resolution.accountId`, then the short-lived `repoContext.accountInfoAccountId`, then the legacy top-level id — legacy files are rooted at the hierarchy ROOT, so their top-level `id` may be an ancestor), then the active session. For `remits-cli tool` calls the server applies a further precedence — explicit `--account-id` > `input.accountId` > session/repo default — so a tool can execute against a different account than the surrounding repo.
70
70
  - Auth sessions are stored per `accountId + dataMode + baseUrl`, so the same account can stay authenticated against both localhost and production without overwriting the other session.
71
71
  - `--base-url` and `--data-mode` are independent. `--base-url` chooses the Remits host (`http://localhost:8080` vs deployed prod), while `--data-mode` chooses the data segment on that host (`test` vs `prod`). Do not assume `--data-mode prod` means the deployed prod host, or that `--data-mode test` means localhost.
72
72
  - `remits-cli start` scans the machine for `account-info.json` files and rebuilds `~/.remits-cli/account-repos.json` before bringing up the background service.
package/index.js CHANGED
@@ -477,7 +477,21 @@ function loadAccountId(cwd) {
477
477
  throw new Error('account-info.json not found in current directory');
478
478
  }
479
479
  const data = JSON.parse(fs.readFileSync(file, 'utf8'));
480
- return Number(data.id || data.accountId || (data.account && data.account.id));
480
+ return Number(accountIdFromAccountInfo(data));
481
+ }
482
+
483
+ // `resolution.accountId` is the account the export DESCRIBES, and the only key that is unambiguous in
484
+ // every shape: a legacy account-info.json is rooted at the hierarchy ROOT, so its top-level `id` is an
485
+ // ancestor, not this repo's account. `repoContext` is a short-lived earlier name for the same fact and is
486
+ // still read so checkouts written during that window keep resolving.
487
+ function accountIdFromAccountInfo(info) {
488
+ return (info && (
489
+ (info.resolution && info.resolution.accountId) ||
490
+ (info.repoContext && info.repoContext.accountInfoAccountId) ||
491
+ info.id ||
492
+ info.accountId ||
493
+ (info.account && info.account.id)
494
+ )) || null;
481
495
  }
482
496
 
483
497
  function loadAccountInfo(cwd) {
@@ -512,14 +526,23 @@ function buildAccountRepoEntryFromInfo(info, directory, source = 'discovered') {
512
526
  if (!info || typeof info !== 'object') {
513
527
  return null;
514
528
  }
515
- const accountId = Number(info.id || info.accountId || (info.account && info.account.id));
529
+ const accountId = Number(accountIdFromAccountInfo(info));
516
530
  if (!Number.isFinite(accountId) || accountId <= 0) {
517
531
  return null;
518
532
  }
519
533
  return {
520
534
  accountId,
521
- name: info.name || info.accountName || (info.account && info.account.name) || '',
522
- type: info.type || info.accountType || (info.account && info.account.type) || null,
535
+ name: (info.resolution && info.resolution.accountName) ||
536
+ (info.repoContext && info.repoContext.accountInfoAccountName) ||
537
+ info.name ||
538
+ info.accountName ||
539
+ (info.account && info.account.name) ||
540
+ '',
541
+ type: (info.resolution && info.resolution.type) ||
542
+ info.type ||
543
+ info.accountType ||
544
+ (info.account && info.account.type) ||
545
+ null,
523
546
  platformAccountId: info.platformAccountId || (info.platform && info.platform.id) || null,
524
547
  directory: path.resolve(directory),
525
548
  accountInfoPath: path.join(path.resolve(directory), 'account-info.json'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remits/remits-cli",
3
- "version": "0.1.87",
3
+ "version": "0.1.89",
4
4
  "description": "Local CLI for auth, component sync, and live test execution against Remits",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -7,119 +7,120 @@ description: Use remits-cli for fast branch-scoped component staging, test execu
7
7
 
8
8
  ## Table of Contents
9
9
 
10
- - Line 126: Account Targeting Model
11
- - Line 133: Account types
12
- - Line 148: How accounts connect (and why it changes what runs)
13
- - Line 178: Users are a separate model — don't reason about them as a tree
14
- - Line 191: Reading the shape
15
- - Line 207: Repo selection rules
16
- - Line 219: Component Integrity Rules: Repo ↔ Database Reconciliation (read before any sync/commit)
17
- - Line 225: How the platform reconciles the repo into the database (the mechanism you must understand)
18
- - Line 280: The surfaces and their intended behavior
19
- - Line 304: Intended workflows
20
- - Line 323: Pre-sync safety check (confirm ALL before `components sync` or `components commit`)
21
- - Line 336: If something looks wrong — stop, don't paper over
22
- - Line 360: Required Local Index Reads
23
- - Line 394: Big Picture: How remits-cli State Is Organized
24
- - Line 424: Support Ticket Mental Model
25
- - Line 460: Efficiency Rules
26
- - Line 472: Account Repository Index
27
- - Line 497: Two Workflows
28
- - Line 504: Test Mode vs Prod Mode
29
- - Line 536: Platform Mental Model: Front Stage vs Back Stage
30
- - Line 543: Documents vs Records
31
- - Line 553: HTTP Audits
32
- - Line 607: Record `content` / Context Mental Model
33
- - Line 627: Provenance Fields
34
- - Line 645: Why Persisted Context Looks Different From Runtime Context
35
- - Line 666: Investigation Rule for Record Context
36
- - Line 681: AI Request Response Records
37
- - Line 688: AI Session Groupings
38
- - Line 707: Correlation Keys
39
- - Line 713: Node Reference Table
40
- - Line 723: Repository vs External Context
41
- - Line 730: Getting Started
42
- - Line 732: Authentication
43
- - Line 745: Host vs Data Mode
44
- - Line 764: Tool Execution Lifecycle
45
- - Line 818: Data Mode
46
- - Line 828: Development Workflow
47
- - Line 830: The Golden Rule: Writing Code Is Not Finishing the Job
48
- - Line 842: Avoid Brittle Front-Stage Intelligence
49
- - Line 855: The Development Fast Loop
50
- - Line 859: Step 1: Understand the Request
51
- - Line 874: Step 2: Make the Change
52
- - Line 877: Step 3: Stage to Platform
53
- - Line 892: Step 4: Verify the Change
54
- - Line 955: Step 5: Iterate If Needed
55
- - Line 965: Step 6: Update Documentation
56
- - Line 975: Step 7: Commit and Durable Sync
57
- - Line 1013: Step 8: Close the Ticket
58
- - Line 1028: User Confirmation Preferences
59
- - Line 1038: Component Resolution: Staging Cache vs DB (which "version" actually runs)
60
- - Line 1044: The three source layers + the compile cache
61
- - Line 1067: Staging cache key format
62
- - Line 1082: How the platform picks staged vs DB (the compile signature)
63
- - Line 1104: When staged overrides apply
64
- - Line 1128: Diagnosing which version is in play
65
- - Line 1149: Stage / commit / clear with the MCP tools
66
- - Line 1173: Stale after sync / commit (the in-memory compile cache)
67
- - Line 1183: Account Resolution: how a request travels the account graph
68
- - Line 1276: Branched Component Variants (per-account component overrides)
69
- - Line 1284: The model (three moving parts)
70
- - Line 1351: Which world does your working tree resolve? (read this before you run anything)
71
- - Line 1383: Two levers, two different questions
72
- - Line 1397: The SDLC is identical on a variant branch
73
- - Line 1421: Promotion: getting the branch back into trunk
74
- - Line 1463: Verifying as the subscriber
75
- - Line 1482: Agents (Utility) on a variant branch
76
- - Line 1494: Danger profile on a variant branch (different, not absent)
77
- - Line 1522: Inspecting branches and drift
78
- - Line 1554: Diagnosing a variant
79
- - Line 1561: Production Support Workflow
80
- - Line 1569: Investigation Strategy
81
- - Line 1599: Presenting Findings
82
- - Line 1607: Verifying a Production Issue Fix
83
- - Line 1620: Tool Reference
84
- - Line 1622: Execute a Tool
85
- - Line 1651: `mcp_account_view`
86
- - Line 1680: `mcp_firestore_search`
87
- - Line 1718: `mcp_object_activity`
88
- - Line 1727: `mcp_record_listing`
89
- - Line 1752: `mcp_record_view`
90
- - Line 1765: `mcp_ai_session_search`
91
- - Line 1801: `mcp_run_action`
92
- - Line 1845: `mcp_run_agent`
93
- - Line 1881: `mcp_system_logs`
94
- - Line 1904: `mcp_component_view`
95
- - Line 1927: `mcp_component_grep`
96
- - Line 1940: `mcp_support_ticket`
97
- - Line 1989: `mcp_run_test`
98
- - Line 1998: `mcp_component_edit`
99
- - Line 2013: `mcp_component_create`
100
- - Line 2027: `mcp_component_commit`
101
- - Line 2035: `mcp_component_branches`
102
- - Line 2054: `mcp_cache`
103
- - Line 2066: `mcp_sql_query`
104
- - Line 2101: `mcp_index_search`
105
- - Line 2121: `mcp_get_guide`
106
- - Line 2133: `mcp_test_fixture`
107
- - Line 2146: `mcp_embeddable_test_url`
108
- - Line 2158: `mcp_playwright_replay`
109
- - Line 2173: `mcp_jvm_spike_triage`
110
- - Line 2186: `mcp_support_ticket_queue`
111
- - Line 2203: Multi-Session Support
112
- - Line 2223: Persistent Service, Control Center, and Agent Dispatch
113
- - Line 2232: Starting the Service
114
- - Line 2258: Control Center
115
- - Line 2273: Agent Dispatch
116
- - Line 2294: Configuring the Preferred Agent
117
- - Line 2305: Local State Files
118
- - Line 2353: Command Reference
119
- - Line 2395: Troubleshooting
120
- - Line 2436: When Something Doesn't Work as Expected
121
- - Line 2447: Back-Stage Escalation Workflow (platform defect/limitation)
122
- - Line 2456: Escalation Bundle (tooling/operational issue)
10
+ - Line 127: Account Targeting Model
11
+ - Line 134: Account types
12
+ - Line 149: How accounts connect (and why it changes what runs)
13
+ - Line 179: Users are a separate model — don't reason about them as a tree
14
+ - Line 192: Reading the shape
15
+ - Line 218: Repo selection rules
16
+ - Line 230: Component Integrity Rules: Repo ↔ Database Reconciliation (read before any sync/commit)
17
+ - Line 236: How the platform reconciles the repo into the database (the mechanism you must understand)
18
+ - Line 298: The surfaces and their intended behavior
19
+ - Line 322: Intended workflows
20
+ - Line 343: Pre-sync safety check (confirm ALL before `components sync` or `components commit`)
21
+ - Line 356: If something looks wrong — stop, don't paper over
22
+ - Line 380: Required Local Index Reads
23
+ - Line 414: Big Picture: How remits-cli State Is Organized
24
+ - Line 444: Support Ticket Mental Model
25
+ - Line 480: Efficiency Rules
26
+ - Line 492: Account Repository Index
27
+ - Line 517: Two Workflows
28
+ - Line 524: Test Mode vs Prod Mode
29
+ - Line 556: Platform Mental Model: Front Stage vs Back Stage
30
+ - Line 563: Documents vs Records
31
+ - Line 573: HTTP Audits
32
+ - Line 627: Record `content` / Context Mental Model
33
+ - Line 647: Provenance Fields
34
+ - Line 665: Why Persisted Context Looks Different From Runtime Context
35
+ - Line 686: Investigation Rule for Record Context
36
+ - Line 701: AI Request Response Records
37
+ - Line 708: AI Session Groupings
38
+ - Line 727: Correlation Keys
39
+ - Line 733: Node Reference Table
40
+ - Line 743: Repository vs External Context
41
+ - Line 750: Getting Started
42
+ - Line 752: Authentication
43
+ - Line 765: Host vs Data Mode
44
+ - Line 784: Tool Execution Lifecycle
45
+ - Line 838: Data Mode
46
+ - Line 848: Development Workflow
47
+ - Line 850: The Golden Rule: Writing Code Is Not Finishing the Job
48
+ - Line 862: Avoid Brittle Front-Stage Intelligence
49
+ - Line 875: The Development Fast Loop
50
+ - Line 879: Step 1: Understand the Request
51
+ - Line 894: Step 2: Make the Change
52
+ - Line 932: Step 3: Stage to Platform
53
+ - Line 947: Step 4: Verify the Change
54
+ - Line 1012: Step 5: Iterate If Needed
55
+ - Line 1022: Step 6: Update Documentation
56
+ - Line 1034: Step 7: Commit and Durable Sync
57
+ - Line 1072: Step 8: Close the Ticket
58
+ - Line 1087: User Confirmation Preferences
59
+ - Line 1097: Component Resolution: Staging Cache vs DB (which "version" actually runs)
60
+ - Line 1103: The three source layers + the compile cache
61
+ - Line 1126: Staging cache key format
62
+ - Line 1141: How the platform picks staged vs DB (the compile signature)
63
+ - Line 1163: When staged overrides apply
64
+ - Line 1187: Diagnosing which version is in play
65
+ - Line 1208: Stage / commit / clear with the MCP tools
66
+ - Line 1232: Stale after sync / commit (the in-memory compile cache)
67
+ - Line 1242: Account Resolution: how a request travels the account graph
68
+ - Line 1335: Branched Component Variants (per-account component overrides)
69
+ - Line 1343: The model (three moving parts)
70
+ - Line 1410: Which world does your working tree resolve? (read this before you run anything)
71
+ - Line 1476: Two levers, two different questions
72
+ - Line 1490: The SDLC is identical on a variant branch
73
+ - Line 1515: Promotion: getting the branch back into trunk
74
+ - Line 1557: Verifying as the subscriber
75
+ - Line 1576: Agents (Utility) on a variant branch
76
+ - Line 1588: Danger profile on a variant branch (different, not absent)
77
+ - Line 1616: Inspecting branches and drift
78
+ - Line 1648: Diagnosing a variant
79
+ - Line 1655: Production Support Workflow
80
+ - Line 1663: Investigation Strategy
81
+ - Line 1693: Presenting Findings
82
+ - Line 1701: Verifying a Production Issue Fix
83
+ - Line 1714: Tool Reference
84
+ - Line 1716: Execute a Tool
85
+ - Line 1745: `mcp_account_view`
86
+ - Line 1777: `mcp_account_user_admin`
87
+ - Line 1812: `mcp_firestore_search`
88
+ - Line 1850: `mcp_object_activity`
89
+ - Line 1859: `mcp_record_listing`
90
+ - Line 1884: `mcp_record_view`
91
+ - Line 1897: `mcp_ai_session_search`
92
+ - Line 1933: `mcp_run_action`
93
+ - Line 1977: `mcp_run_agent`
94
+ - Line 2013: `mcp_system_logs`
95
+ - Line 2036: `mcp_component_view`
96
+ - Line 2059: `mcp_component_grep`
97
+ - Line 2072: `mcp_support_ticket`
98
+ - Line 2121: `mcp_run_test`
99
+ - Line 2130: `mcp_component_edit`
100
+ - Line 2145: `mcp_component_create`
101
+ - Line 2159: `mcp_component_commit`
102
+ - Line 2167: `mcp_component_branches`
103
+ - Line 2186: `mcp_cache`
104
+ - Line 2198: `mcp_sql_query`
105
+ - Line 2233: `mcp_index_search`
106
+ - Line 2253: `mcp_get_guide`
107
+ - Line 2265: `mcp_test_fixture`
108
+ - Line 2278: `mcp_embeddable_test_url`
109
+ - Line 2290: `mcp_playwright_replay`
110
+ - Line 2305: `mcp_jvm_spike_triage`
111
+ - Line 2318: `mcp_support_ticket_queue`
112
+ - Line 2335: Multi-Session Support
113
+ - Line 2355: Persistent Service, Control Center, and Agent Dispatch
114
+ - Line 2364: Starting the Service
115
+ - Line 2390: Control Center
116
+ - Line 2405: Agent Dispatch
117
+ - Line 2426: Configuring the Preferred Agent
118
+ - Line 2437: Local State Files
119
+ - Line 2485: Command Reference
120
+ - Line 2527: Troubleshooting
121
+ - Line 2569: When Something Doesn't Work as Expected
122
+ - Line 2580: Back-Stage Escalation Workflow (platform defect/limitation)
123
+ - Line 2589: Escalation Bundle (tooling/operational issue)
123
124
 
124
125
  `remits-cli` is the brainstem for both **development** and **production support**. You might run it inside an account repository (where `account-info.json` and `/components` already exist) or from outside any repo when a user needs help on another account. Your users are business professionals — they think in terms of what they can see in a browser.
125
126
 
@@ -156,7 +157,7 @@ An account is linked upward in two ways, and they coexist:
156
157
 
157
158
  - **The primary parent** — one per account. The overwhelming majority of accounts have only this.
158
159
  - **Membership edges** — extra links letting the *same account* be reached through **more than one** parent
159
- (a customer in two product lines; a forked deployment reaching the same owner).
160
+ (a customer in two product lines; a branch deployment reaching the same owner).
160
161
 
161
162
  Any link can independently carry three things. They are **orthogonal** — never infer one from another:
162
163
 
@@ -190,17 +191,27 @@ this user see the wrong data?") use `mcp_sql_query` against `user` / `user_accou
190
191
 
191
192
  ### Reading the shape
192
193
 
193
- `account-info.json` / `mcp_account_view` carry a `resolution` block. Read it in this order:
194
+ `account-info.json` / `mcp_account_view` carry a `resolution` block — the ONE place these facts appear
195
+ (nothing in it is repeated elsewhere in the file). Read it in this order:
194
196
 
197
+ - **`role`** + **`summary`** — `OWNER` (resolves its own component trunk: the files here ARE its components)
198
+ or `SUBSCRIBER` (resolves ANOTHER account's components with a variant branch applied). `summary` says it
199
+ in one sentence, naming the owner. Read this before you touch anything.
200
+ - **`accountId`** — the account described. In a repo export the top-level `id` is the same account; in a
201
+ legacy export it is the hierarchy ROOT, so prefer `resolution.accountId`.
195
202
  - **`type`** — decide repo/ownership per the table above.
196
203
  - **`resolvedDatabaseName`** vs **`databaseName`** — the namespace actually in effect vs the account's own
197
204
  override. Check this first when documents are "missing".
198
205
  - **`relationships`** — every link upward, primary first, each with its own `branchName` / `databaseName` /
199
206
  `domainName`. **This is where you see that an account has two parents, and which link carries what.**
200
- - **`componentBranch`** (+ `componentBranchOwnerAccountId`) — the component-variant branch this account
201
- subscribes to, if any. Present only when subscribed.
207
+ - **`componentBranch`** (+ `componentOwnerAccountId` / `componentOwnerAccountName`) — the component-variant
208
+ branch in effect for this resolution and who owns it. A `SUBSCRIBER` with no `componentBranch` subscribes
209
+ through an edge that nothing anchored this resolution to (multi-parent, no path named) — `summary` says so.
202
210
  - **`branchName`** — the account **repo's** trunk sync branch. Not a component-variant branch. Do not confuse
203
211
  these two.
212
+ - **`parents`** / **`children`** — the anchored ancestor chain and a DIRECT-child summary with counts (repo
213
+ exports only; the default `mcp_account_view` shape carries the full tree instead). The deep tree is a
214
+ lookup — `mcp_account_user_admin` with `action:'hierarchy'` and a `depth` — never a committed artifact.
204
215
  - **`componentBranches`** (top level) — variant branches this account **owns**, with drift and subscriber
205
216
  counts. Check it before editing a shared component.
206
217
 
@@ -1256,8 +1267,8 @@ edge's *child* as the execution account **and** the edge's *parent* as the branc
1256
1267
  makes that edge's branch variants apply. An account-level host resolves the account with **no** anchor
1257
1268
  (today's behavior). Edge wins, then the account's own host, so removing an edge degrades cleanly instead
1258
1269
  of taking the hostname offline. Hosts are stored as bare lowercase hostnames; a full URL is normalized on
1259
- the way in. This is what lets a forked/branch deployment get its own domain without a separate account
1260
- tree — `forked.example.com` and `app.example.com` can serve the same owner's components, one overlaid
1270
+ the way in. This is what lets a branch deployment get its own domain without a separate account
1271
+ tree — `branch.example.com` and `app.example.com` can serve the same owner's components, one overlaid
1261
1272
  with a branch.
1262
1273
 
1263
1274
  **Two traversals, deliberately different.** Confusing them is the usual source of wrong conclusions:
@@ -1333,14 +1344,14 @@ resolve.
1333
1344
 
1334
1345
  1. **The origin account owns the component and the branch.** Say platform account 1 owns
1335
1346
  `Extract Invoice` (Action 50). Its repo `remits-<name>` has trunk branch `main` and a second git branch
1336
- `feature_forked`.
1337
- 2. **A `ComponentVariant` row is the overlay.** Committing on `feature_forked` stores rows owned by
1338
- **account 1**, on branch `feature_forked`, for the components whose content **differs from trunk**. A git
1347
+ `feature_branch`.
1348
+ 2. **A `ComponentVariant` row is the overlay.** Committing on `feature_branch` stores rows owned by
1349
+ **account 1**, on branch `feature_branch`, for the components whose content **differs from trunk**. A git
1339
1350
  branch physically contains every file; only the *differing* ones become variants. That is computed at
1340
1351
  sync time — you never declare it.
1341
1352
  3. **A child account subscribes via its relationship edge.** Account 101's `AccountRelationship` edge
1342
- carries `branchName = 'feature_forked'`. Resolution then walks 101's inheritance chain and applies
1343
- account 1's `feature_forked` overlays.
1353
+ carries `branchName = 'feature_branch'`. Resolution then walks 101's inheritance chain and applies
1354
+ account 1's `feature_branch` overlays.
1344
1355
 
1345
1356
  Consequences worth internalizing:
1346
1357
 
@@ -1358,8 +1369,14 @@ Consequences worth internalizing:
1358
1369
  only subscribe an account reachable from one you already have access to.
1359
1370
  - **`--subscribe` sets the branch on an edge that must already exist — it cannot create one.** If the
1360
1371
  account has no relationship edge to the owner you will get *"Account N has no relationship edge to
1361
- subscribe; add a membership edge first"*. Creating a membership edge is an **admin** operation (the
1362
- account page), not a CLI one.
1372
+ subscribe; add a membership edge first"*. Create it with
1373
+ `mcp_account_user_admin` `action:'edge_add'` (`targetAccountId` = the child, `parentAccountId` = the
1374
+ owner), which also accepts `branchName` so you can create and subscribe in one call. The admin account
1375
+ page does the same thing.
1376
+ - **Many older accounts have no relationship row at all.** The edge table was introduced after the fact
1377
+ and never backfilled, so an account whose parent link is only `Account.parentId` resolves fine but has
1378
+ nothing for `--subscribe` to attach to. `mcp_account_user_admin` `action:'reparent'` with the account's
1379
+ *current* parent is the one-call repair: it creates the missing primary edge and changes nothing else.
1363
1380
  - **When the account has several parents, say which edge you mean:**
1364
1381
  `--subscribe <accountId> --parent-account <ownerId>`. Without it the CLI picks the edge to the owner
1365
1382
  whose branch you are managing, then falls back to the account's primary edge — which may not be the
@@ -1404,7 +1421,7 @@ the loop. The rule turns entirely on **trunk vs non-trunk**:
1404
1421
  | Working tree | Staging scope | A run resolves | `components sync`/`commit` writes |
1405
1422
  |---|---|---|---|
1406
1423
  | **trunk** (`main`, or whatever `account-info.json` says) | that branch | trunk + **each account's subscribed** variant branch (production semantics) | the **live component rows** — full reconcile, creates/updates/**deletes** |
1407
- | **any other branch** (`feature_forked`) | that branch | trunk + **`feature_forked`** overlays | **`ComponentVariant` overlays on that branch only** — never touches trunk rows |
1424
+ | **any other branch** (`feature_branch`) | that branch | trunk + **`feature_branch`** overlays | **`ComponentVariant` overlays on that branch only** — never touches trunk rows |
1408
1425
 
1409
1426
  **The precedence trap that costs the most time:** `variantBranch` OUTRANKS every account's subscription. So
1410
1427
  running a Test suite that asserts *production* semantics from a **variant checkout** pins every account in
@@ -1421,9 +1438,9 @@ remits-cli components status
1421
1438
  ```
1422
1439
 
1423
1440
  ```
1424
- Working tree: VARIANT BRANCH "feature_forked" (trunk is "main")
1425
- runs resolve: trunk + the 'feature_forked' variant overlays
1426
- commit writes: ComponentVariant overlays on 'feature_forked' (never touches trunk rows)
1441
+ Working tree: VARIANT BRANCH "feature_branch" (trunk is "main")
1442
+ runs resolve: trunk + the 'feature_branch' variant overlays
1443
+ commit writes: ComponentVariant overlays on 'feature_branch' (never touches trunk rows)
1427
1444
  variants stored on this branch: 3
1428
1445
  subscribing accounts: 101 (Acme Child)
1429
1446
  ```
@@ -1432,8 +1449,30 @@ Working tree: VARIANT BRANCH "feature_forked" (trunk is "main")
1432
1449
  is still the OWNER's component repo: files under `components/` overlay that owner's trunk component ids, and
1433
1450
  `components sync` writes `ComponentVariant` rows owned by that parent account. But if the checkout was synced
1434
1451
  from a subscribing account reached through an `AccountRelationship` edge, the branch's `account-info.json`
1435
- is intentionally refreshed from the subscriber's resolved account information. That is what lets a forked
1436
- checkout answer "who am I acting as?" while preserving "who owns these component variants?"
1452
+ is intentionally rooted at that subscriber and refreshed from the subscriber's resolved account information.
1453
+ That is what lets a branch checkout answer "who am I acting as?" while preserving "who owns these component
1454
+ variants?"
1455
+
1456
+ Read the `resolution` block before acting from any checkout — it is the ONE place account-info states this
1457
+ (nothing in it is repeated elsewhere in the file):
1458
+
1459
+ - `resolution.role` — `OWNER` for a trunk/owner export, `SUBSCRIBER` for an account reached through an
1460
+ `AccountRelationship` branch edge. `resolution.summary` says the same thing in one sentence.
1461
+ - `resolution.accountId` — the account the local checkout should be treated as. **This, not the top-level
1462
+ `id`, is the key to read**: an `account-info.json` predating this shape is rooted at the hierarchy root.
1463
+ - `resolution.componentOwnerAccountId` — the account whose trunk component ids the files overlay and whose
1464
+ `ComponentVariant` rows sync writes. Equals `resolution.accountId` for an `OWNER`.
1465
+ - `resolution.componentBranch` / `resolution.scopeAccountId` — the branch and the path anchor that made this
1466
+ subscriber resolution possible.
1467
+ - `resolution.parents` / `resolution.children` / `resolution.relationships` — the account graph, stated once
1468
+ and compactly. The full descendant tree is a lookup (`mcp_account_user_admin`, `mcp_account_view`), not a
1469
+ committed artifact.
1470
+
1471
+ **One branch, one `account-info.json`.** There is exactly one git branch, so when a branch has MORE THAN ONE
1472
+ subscriber the refresh is skipped (the sync result says so under `accountInfo.skipped`/`reason`) and the file
1473
+ keeps describing the owner — which is at least true for all of them. Otherwise each subscriber's sync would
1474
+ rewrite the file as its own and hand the other subscriber's agent a file naming the wrong account. Overlay
1475
+ ownership is unaffected either way: variants always belong to the owner account.
1437
1476
 
1438
1477
  Consequence: if a variant checkout's `account-info.json` is stale and still names the owner, run the first
1439
1478
  repair sync with an explicit subscriber target, for example `remits-cli components sync --account-id 101`.
@@ -1459,13 +1498,13 @@ Both work on `remits-cli test run` and `remits-cli token`; `--variant-branch` al
1459
1498
  The loop does not change shape — `edit → stage → verify → commit`:
1460
1499
 
1461
1500
  ```bash
1462
- git checkout feature_forked # or: git checkout -b feature_forked
1501
+ git checkout feature_branch # or: git checkout -b feature_branch
1463
1502
  # edit components/actions/50_ExtractInvoice.groovy (KEEP the trunk id)
1464
1503
  remits-cli components stage # Redis, scoped to this branch — same as always
1465
- remits-cli test run --test "Invoice Tests" # resolves the feature_forked world
1504
+ remits-cli test run --test "Invoice Tests" # resolves the feature_branch world
1466
1505
  remits-cli test run --test "Invoice Tests" --as-account 101 # ...as the real subscriber
1467
1506
  # promote:
1468
- git add -A && git commit -m "..." && git push origin feature_forked
1507
+ git add -A && git commit -m "..." && git push origin feature_branch
1469
1508
  remits-cli components sync --dry-run # inspect overrides/additions/tombstones without writes
1470
1509
  remits-cli components sync # writes ComponentVariant overlays ONLY
1471
1510
  ```
@@ -1486,12 +1525,12 @@ by a **trunk** sync — the platform does not merge anything for you.
1486
1525
 
1487
1526
  ```bash
1488
1527
  # 1. merge the branch into trunk (review the diff FIRST - see the deletion hazard below)
1489
- git checkout main && git merge feature_forked && git push origin main
1528
+ git checkout main && git merge feature_branch && git push origin main
1490
1529
  # 2. trunk sync: creates real rows for new_* files, assigns ids, RENAMES those files on trunk
1491
1530
  remits-cli components sync
1492
1531
  git pull --ff-only origin main
1493
1532
  # 3. bring trunk back into the branch so the two stop diverging
1494
- git checkout feature_forked && git merge origin/main && git push origin feature_forked
1533
+ git checkout feature_branch && git merge origin/main && git push origin feature_branch
1495
1534
  remits-cli components sync # reconciles the branch's overlays
1496
1535
  ```
1497
1536
 
@@ -1584,9 +1623,9 @@ The analogous hazard is different and you must still respect it:
1584
1623
 
1585
1624
  ```bash
1586
1625
  remits-cli components branches # branches with variants, counts, drift
1587
- remits-cli components branch feature_forked # overridden / added / removed + subscribers
1588
- remits-cli components branch feature_forked --diff 50 --component-type action
1589
- remits-cli components branch feature_forked --subscribers
1626
+ remits-cli components branch feature_branch # overridden / added / removed + subscribers
1627
+ remits-cli components branch feature_branch --diff 50 --component-type action
1628
+ remits-cli components branch feature_branch --subscribers
1590
1629
  ```
1591
1630
 
1592
1631
  **Drift is the number to watch.** Each variant records the trunk content hash at the moment it was cut
@@ -1715,11 +1754,14 @@ Returns complete account structure — schemas, components, relationships.
1715
1754
  Also returns two blocks that explain how the account RESOLVES, which is what you need before comparing
1716
1755
  its behavior against component source:
1717
1756
 
1718
- - `resolution` — `databaseName` (the account's own override, often null) vs `resolvedDatabaseName` (the
1719
- storage namespace actually in effect), `branchName` (the repo sync branch), `domainName` vs
1720
- `resolvedDomainName` (the custom host in effect, which differs when reached through an edge host),
1721
- `editMode`, and — when the account subscribes to a component branch — `componentBranch` plus
1722
- `componentBranchOwnerAccountId`.
1757
+ - `resolution` — `role` (`OWNER` = resolves its own component trunk, `SUBSCRIBER` = resolves another
1758
+ account's components through a branch edge) and a one-sentence `summary`; `accountId` (the account
1759
+ described — the top level of this shape is the hierarchy ROOT, so do not read identity from there);
1760
+ `databaseName` (the account's own override, often null) vs `resolvedDatabaseName` (the storage namespace
1761
+ actually in effect); `branchName` (the repo sync branch) and `lastRepoSync`; `domainName` vs
1762
+ `resolvedDomainName` (the custom host in effect, which differs when reached through an edge host);
1763
+ `editMode`; and — when a component branch is in effect — `componentBranch` plus `componentOwnerAccountId`
1764
+ / `componentOwnerAccountName`.
1723
1765
  - `resolution.relationships` — **every structural link upward**, primary first: `parentAccountId` /
1724
1766
  `parentAccountName` / `parentAccountCode` / `parentAccountType`, `primary` (true for the one link that
1725
1767
  mirrors the account's primary parent), `active`, and the three independent link-scoped properties
@@ -1731,13 +1773,99 @@ its behavior against component source:
1731
1773
  - `componentBranches` — the variant branches this account OWNS, with override/add/remove, subscriber, and
1732
1774
  drift counts. Same summary the owner's `account-info.json` carries.
1733
1775
 
1734
- Note: this tool does **not** return users. For user/access questions use `mcp_sql_query` (`user`,
1735
- `user_account`).
1776
+ Note: this tool does **not** return users, and it returns EVERYTHING about one account. For users, for the
1777
+ deep account tree, or for small account/user updates, use `mcp_account_user_admin`.
1736
1778
 
1737
1779
  | Parameter | Required | Description |
1738
1780
  |-----------|----------|-------------|
1739
1781
  | `accountId` | yes | Account ID |
1740
1782
 
1783
+ ### `mcp_account_user_admin`
1784
+ The account-graph and user surface: the middle ground between `account-info.json` (which states structure
1785
+ compactly, because it is read into your context every session) and `mcp_account_view` (everything about one
1786
+ account).
1787
+
1788
+ - `action: 'hierarchy'` (default) — the descendant tree trimmed to `depth` (1-10, default 2; nodes cut off
1789
+ are marked `truncated` and still report their child count) and/or the anchored ancestor chain plus every
1790
+ edge (`direction: 'down'|'up'|'both'`). **This is how you get the deep tree account-info.json omits.**
1791
+ - `action: 'account'` — one account's `resolution` block plus masked configuration fields, without paying
1792
+ for the component inventory.
1793
+ - `action: 'users'` — an account's users at a hierarchy `scope` (`self`/`children`/`parents`/`hierarchy`),
1794
+ optional `email` substring filter. Extension fields are omitted here on purpose: they are stored **per
1795
+ account** and these users are bound to their own.
1796
+ - `action: 'user'` — one user (`userId` or `email`) with roles, account memberships, and extension fields
1797
+ **correctly scoped to the requested account**. It never grants membership as a side effect of a read, and
1798
+ tells you when the fields shown belong to a different account.
1799
+ - `action: 'account_update'` — write Account-schema configuration `fields`, and/or `name`/`status`
1800
+ (`ACTIVE`/`ON_HOLD`/`PENDING`).
1801
+ - `action: 'user_update'` — write User-schema `fields` under the named account (refused unless the user is a
1802
+ member or you pass `addAccount: true`, because the write would otherwise land on another account), plus
1803
+ `name`/`enabled` and membership add/remove.
1804
+
1805
+ **Building an account hierarchy** (the structural writes — this is how a coding agent provisions accounts
1806
+ without a browser):
1807
+
1808
+ - `action: 'account_create'` — create a child under `parentAccountId`, with its **primary relationship edge**,
1809
+ applying `type` / `databaseName` / `domainName` / `code` / `repositoryNameOverride` / `branchName` /
1810
+ `editMode` / … **at birth**. That ordering matters: the storage namespace is resolved from those properties,
1811
+ and the parent's cascaded schema fields are written into it during creation. Idempotent — an existing
1812
+ same-name account under that parent comes back with `reusedExisting: true`, unchanged.
1813
+ - `action: 'account_structure'` — change those properties on an existing account.
1814
+ - `action: 'edge_add'` / `'edge_update'` / `'edge_remove'` — manage a membership `AccountRelationship` edge to
1815
+ `parentAccountId`, including the three independent edge properties `branchName` (which component code runs),
1816
+ `databaseName` (branch-scoped namespace — stored, but inert until segment inheritance is enabled) and
1817
+ `domainName` (which host reaches the account through that edge). Cycles, self-edges, and removing the primary
1818
+ edge are all refused.
1819
+ - `action: 'reparent'` — move the account's **primary** edge (and `Account.parentId`) to `parentAccountId`.
1820
+
1821
+ > **The namespace guard.** An account's storage namespace resolves as
1822
+ > `databaseName ?: platform.code ?: code`, and `Account.setName` **regenerates `code`** — so renaming an
1823
+ > account whose namespace falls through to its own code silently repoints its storage. Any write that would
1824
+ > move the resolved namespace is **refused** unless you pass `confirmSegmentChange: true`, and the refusal
1825
+ > names both namespaces. To rename without moving storage, pin `code` to the old value in the same call.
1826
+ >
1827
+ > The namespace follows the **path**: the nearest `databaseName` walking up from the account — its own
1828
+ > first, then the edge it was reached through, then the same two questions at each account above — falling
1829
+ > back to the nearest `PLATFORM` ancestor's `code`. So a namespace set anywhere above is inherited by
1830
+ > everything below it until a nearer account or edge overrides it, and an edge answer is path-specific (the
1831
+ > same account reached through a different parent can resolve a different namespace).
1832
+
1833
+ Every write supports `dryRun: true`, which reports each `from -> to` without writing. Not here by design:
1834
+ component-branch subscription reporting and drift (`mcp_component_branches` — though `edge_add`/`edge_update`
1835
+ set the branch directly), and account/user **deletion** (admin only, so the destructive-teardown contract
1836
+ applies).
1837
+
1838
+ **Provisioning recipe** — a new product account under a platform, running its own component branch, with
1839
+ client accounts beneath it:
1840
+
1841
+ ```
1842
+ 1. mcp_account_user_admin action:'account_create' parentAccountId:<platform> name:'Adyen'
1843
+ type:'PLATFORM'|'PRODUCT' [databaseName:'...']
1844
+ 2. git branch + push in the OWNER's repo, then `remits-cli components sync` from that checkout
1845
+ (non-trunk => writes ComponentVariant overlays only)
1846
+ 3. mcp_account_user_admin action:'edge_update' targetAccountId:<new> parentAccountId:<platform>
1847
+ branchName:'<branch>' # or mcp_component_branches action:'subscribe'
1848
+ 4. mcp_account_user_admin action:'account_create' parentAccountId:<new> name:'<business unit>'
1849
+ type:'CLIENT' # inherits the branch automatically
1850
+ ```
1851
+
1852
+ > **Put the branch on the account's PRIMARY edge.** Component inheritance follows the *anchored* path, which
1853
+ > for an account with a `parentId` is its primary chain. An account that has both a primary edge and a
1854
+ > *membership* edge carrying the branch resolves **trunk** by default — the membership edge is never
1855
+ > anchored unless a request names it (`--as-account`, `--variant-branch`, or the edge's own host). Descendants
1856
+ > then inherit the branch down that primary chain automatically, which is what makes step 4 free.
1857
+
1858
+ | Parameter | Required | Description |
1859
+ |-----------|----------|-------------|
1860
+ | `action` | no | `hierarchy` (default), `account`, `users`, `user`, `account_update`, `user_update` |
1861
+ | `accountId` / `targetAccountId` | no | Account to act on; `targetAccountId` targets another account without moving tool resolution |
1862
+ | `depth` / `direction` | no | `hierarchy` only |
1863
+ | `scope` | no | `users` only |
1864
+ | `userId` / `email` | no | Identify the user (`user`, `user_update`); `email` is a filter for `users` |
1865
+ | `fields` / `name` / `status` / `enabled` | no | The update payload |
1866
+ | `addAccount` / `removeAccount` | no | Membership changes for `user_update` |
1867
+ | `dryRun` | no | Report the change without writing |
1868
+
1741
1869
  ### `mcp_firestore_search`
1742
1870
  Query Firestore documents.
1743
1871
 
@@ -2471,7 +2599,8 @@ For tests specifically:
2471
2599
  | Long-running tool times out | For `mcp_run_action`/`mcp_run_agent`, use the tool's own `executionMode:"async"` and poll with a `controlAction:"status"` call (see "Tool Execution Lifecycle"). For other long tools without their own async, use `remits-cli tool --async true` and poll `remits-cli tool status --call-id <callId>`. `--timeout-ms` only adjusts the per-request HTTP timeout; it is not a substitute for async. |
2472
2600
  | Need to continue tracking a long Action or Agent after terminal disconnect | Read `./.remits-cli/tool-responses/<callId>.json` for the returned `actionRunId`/`agentRunId`/`sessionId`/`threadGroupingId`. Re-poll the run with a `controlAction:"status"` call carrying that `actionRunId`/`agentRunId`, or inspect the agent session via `mcp_ai_session_search` with the `sessionId`. |
2473
2601
  | Staged change has no effect in a live (non-CLI) run | Staged overrides resolve only under a CLI TestMode (`branchName`+`cliUserId`). Live webhooks and other non-CLI runtime paths still use the DB (trunk, or the account's subscribed variant). `commit` to make it durable. See "Component Resolution". |
2474
- | Need to know an account's shape (type, parents, namespace, branch) | `mcp_account_view` → read `resolution` (`type`, `resolvedDatabaseName`, `relationships`, `componentBranch`) and top-level `componentBranches`. Never infer structure from the account's name. |
2602
+ | Need to know an account's shape (role, type, parents, namespace, branch) | Read `resolution` — from the repo's `account-info.json`, or `mcp_account_user_admin` `action:'account'` (cheap), or `mcp_account_view` (full inventory): `role`/`summary`, `type`, `resolvedDatabaseName`, `relationships`, `componentBranch`, plus top-level `componentBranches`. Never infer structure from the account's name. |
2603
+ | Need the account tree below an account, or its users | `mcp_account_user_admin` (`action:'hierarchy'` with a `depth`, or `action:'users'`). `account-info.json` deliberately carries only direct children plus counts. |
2475
2604
  | An account has two parents and you don't know which one a run used | `resolution.relationships` lists every link with its own `branchName`/`databaseName`/`domainName`. A membership-only account with several edges resolves **trunk and inherits nothing** until a path is named (`--as-account`, `--variant-branch`, or an edge host) — that is by design, not a bug. |
2476
2605
  | Documents missing / written to the wrong place | Compare `resolution.databaseName` (the account's own override) with `resolution.resolvedDatabaseName` (what is actually in effect), and check for a `databaseName` on one of the `relationships` edges. Data does not inherit; components do. |
2477
2606
  | A custom hostname resolves to an unexpected account | Compare `resolution.domainName` with `resolvedDomainName` and the edge `domainName`s. An **edge** host wins over the account's own host and additionally supplies the path travelled (which is what makes that edge's branch variants apply). |