@remits/remits-cli 0.1.86 → 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
@@ -62,11 +62,11 @@ remits-cli install --skills --overwrite true
62
62
  - `components clear` clears staged entries. Scope it with `--component-type` and/or `--component-id`. Component ids are type-local, so an id alone clears that one component when the id is staged in only one family; if the same id is staged across multiple families it returns an ambiguity error asking you to add `--component-type`. With no filter it clears every staged entry for the current branch; pass `--all` to force the full-branch wipe explicitly.
63
63
  - `components stage`, `components status`, and `components clear` print concise summaries by default. Add `--json` or `--verbose` to print the full server response.
64
64
  - `components sync` performs a server-side sync from the git remote into the Remits platform for the selected branch. It does not run local git commands. After a successful non-dry-run sync, the platform clears the branch/user staging scope so staged aliases cannot keep shadowing the newly synced DB rows.
65
- - On trunk, `components sync` performs the full repo-to-DB reconcile. On a non-trunk branch, it writes `ComponentVariant` overlays only. `--dry-run` is accepted only for non-trunk variant syncs and reports overrides/additions/tombstones without writing variants, caching the sync SHA, or clearing staging. `--force-tombstones` is accepted only for non-trunk variant syncs and should be used only when missing trunk component files are intentional tombstone overrides.
65
+ - On trunk, `components sync` performs the full repo-to-DB reconcile. On a non-trunk branch, it writes `ComponentVariant` overlays only and may refresh branch-local `account-info.json` for the subscribing account that initiated the sync. `--dry-run` is accepted only for non-trunk variant syncs and reports overrides/additions/tombstones without writing variants, caching the sync SHA, updating metadata, or clearing staging. `--force-tombstones` is accepted only for non-trunk variant syncs and should be used only when missing trunk component files are intentional tombstone overrides.
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.86",
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,118 +7,223 @@ description: Use remits-cli for fast branch-scoped component staging, test execu
7
7
 
8
8
  ## Table of Contents
9
9
 
10
- - Line 102: Account Targeting Model
11
- - Line 125: Component Integrity Rules: Repo ↔ Database Reconciliation (read before any sync/commit)
12
- - Line 131: How the platform reconciles the repo into the database (the mechanism you must understand)
13
- - Line 186: The surfaces and their intended behavior
14
- - Line 210: Intended workflows
15
- - Line 229: Pre-sync safety check (confirm ALL before `components sync` or `components commit`)
16
- - Line 242: If something looks wrong — stop, don't paper over
17
- - Line 266: Required Local Index Reads
18
- - Line 300: Big Picture: How remits-cli State Is Organized
19
- - Line 330: Support Ticket Mental Model
20
- - Line 366: Efficiency Rules
21
- - Line 378: Account Repository Index
22
- - Line 403: Two Workflows
23
- - Line 410: Test Mode vs Prod Mode
24
- - Line 442: Platform Mental Model: Front Stage vs Back Stage
25
- - Line 449: Documents vs Records
26
- - Line 459: HTTP Audits
27
- - Line 513: Record `content` / Context Mental Model
28
- - Line 533: Provenance Fields
29
- - Line 551: Why Persisted Context Looks Different From Runtime Context
30
- - Line 572: Investigation Rule for Record Context
31
- - Line 587: AI Request Response Records
32
- - Line 594: AI Session Groupings
33
- - Line 613: Correlation Keys
34
- - Line 619: Node Reference Table
35
- - Line 629: Repository vs External Context
36
- - Line 636: Getting Started
37
- - Line 638: Authentication
38
- - Line 651: Host vs Data Mode
39
- - Line 670: Tool Execution Lifecycle
40
- - Line 724: Data Mode
41
- - Line 734: Development Workflow
42
- - Line 736: The Golden Rule: Writing Code Is Not Finishing the Job
43
- - Line 748: Avoid Brittle Front-Stage Intelligence
44
- - Line 761: The Development Fast Loop
45
- - Line 928: User Confirmation Preferences
46
- - Line 938: Component Resolution: Staging Cache vs DB (which "version" actually runs)
47
- - Line 944: The three source layers + the compile cache
48
- - Line 967: Staging cache key format
49
- - Line 982: How the platform picks staged vs DB (the compile signature)
50
- - Line 1004: When staged overrides apply
51
- - Line 1028: Diagnosing which version is in play
52
- - Line 1049: Stage / commit / clear with the MCP tools
53
- - Line 1073: Stale after sync / commit (the in-memory compile cache)
54
- - Line 1083: Account Resolution: how a request travels the account graph
55
- - Line 1153: Branched Component Variants (per-account component overrides)
56
- - Line 1161: The model (three moving parts)
57
- - Line 1228: Which world does your working tree resolve? (read this before you run anything)
58
- - Line 1260: Two levers, two different questions
59
- - Line 1274: The SDLC is identical on a variant branch
60
- - Line 1298: Promotion: getting the branch back into trunk
61
- - Line 1340: Verifying as the subscriber
62
- - Line 1359: Agents (Utility) on a variant branch
63
- - Line 1371: Danger profile on a variant branch (different, not absent)
64
- - Line 1399: Inspecting branches and drift
65
- - Line 1431: Diagnosing a variant
66
- - Line 1438: Production Support Workflow
67
- - Line 1446: Investigation Strategy
68
- - Line 1476: Presenting Findings
69
- - Line 1484: Verifying a Production Issue Fix
70
- - Line 1497: Tool Reference
71
- - Line 1499: Execute a Tool
72
- - Line 1528: `mcp_account_view`
73
- - Line 1546: `mcp_firestore_search`
74
- - Line 1584: `mcp_object_activity`
75
- - Line 1593: `mcp_record_listing`
76
- - Line 1618: `mcp_record_view`
77
- - Line 1631: `mcp_ai_session_search`
78
- - Line 1667: `mcp_run_action`
79
- - Line 1711: `mcp_run_agent`
80
- - Line 1747: `mcp_system_logs`
81
- - Line 1770: `mcp_component_view`
82
- - Line 1793: `mcp_component_grep`
83
- - Line 1806: `mcp_support_ticket`
84
- - Line 1855: `mcp_run_test`
85
- - Line 1864: `mcp_component_edit`
86
- - Line 1879: `mcp_component_create`
87
- - Line 1893: `mcp_component_commit`
88
- - Line 1901: `mcp_cache`
89
- - Line 1913: Multi-Session Support
90
- - Line 1933: Persistent Service, Control Center, and Agent Dispatch
91
- - Line 1942: Starting the Service
92
- - Line 1968: Control Center
93
- - Line 1983: Agent Dispatch
94
- - Line 2004: Configuring the Preferred Agent
95
- - Line 2015: Local State Files
96
- - Line 2063: Command Reference
97
- - Line 2105: Troubleshooting
98
- - Line 2141: When Something Doesn't Work as Expected
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)
99
124
 
100
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.
101
126
 
102
127
  ## Account Targeting Model
103
128
 
104
- Before deciding which repo or account context to use, read the target account's `type` from `account-info.json` or `Account.getInformation` / `mcp_account_view`.
129
+ **Establish the account's shape before you touch anything.** Which repo you work in, which account you run
130
+ against, where a fix belongs, and why one account behaves unlike its siblings are all answered by the account
131
+ structure — never by the account's name. Read it from `account-info.json` (in the repo) or `mcp_account_view`
132
+ (remotely). Both return the same thing.
105
133
 
106
- - **`PLATFORM`** = a use-case/platform implementation account. This is often where the shared Remits components live.
107
- - **`PRODUCT`** = a product/use-case account under a platform. This can also hold shared implementation components.
108
- - **`CLIENT`** = an actual customer account. This is usually where production data lives and where an issue is observed, but not necessarily where the shared implementation is authored.
134
+ ### Account types
109
135
 
110
- Do not guess from the account name alone.
136
+ | Type | What it is | Components | Business data |
137
+ |---|---|---|---|
138
+ | `PLATFORM` | Top of a use-case tree. Owns the shared implementation and the git repository. | **Owned here** | Rarely — mostly configuration |
139
+ | `PRODUCT` | A product/use case under a platform. May own shared components too. | **Owned here or above** | Rarely |
140
+ | `CLIENT` | An actual customer. Where an issue is observed. | Usually **inherited**, not owned | **Here** — the customer's documents and lifecycle records |
141
+ | `PROVIDER` | A partner/vendor participant in a use case | Rarely | Sometimes |
142
+
143
+ - **Feature, enhancement, component change, shared behavior fix** → the implementation target is usually the
144
+ owning `PLATFORM` or `PRODUCT` account, **not** the `CLIENT` that reported it.
145
+ - **Production investigation or client-specific data issue** → start with the affected `CLIENT` account's
146
+ data and runtime history.
147
+ - **Both** → confirm symptoms on the `CLIENT`, then move to the owning `PLATFORM`/`PRODUCT` repo to change code.
148
+
149
+ ### How accounts connect (and why it changes what runs)
150
+
151
+ Components are **inherited downward** and de-duplicated **by component name, nearest owner wins** — so a
152
+ client can run an Action owned three levels up, and can override it just by owning one with the same name.
153
+ Business data does **not** inherit; it belongs to the account that wrote it, in that account's storage
154
+ namespace.
155
+
156
+ An account is linked upward in two ways, and they coexist:
111
157
 
112
- - If the work is a **feature, enhancement, component change, or shared behavior fix**, the implementation target is usually the relevant `PLATFORM` or `PRODUCT` account, not the `CLIENT` account that reported the issue.
113
- - If the work is a **production investigation or client-specific data issue**, start with the affected `CLIENT` account's data and runtime history.
114
- - If the request spans both, investigate in the `CLIENT` account first to confirm symptoms, then move to the owning `PLATFORM` or `PRODUCT` repo before making code changes.
158
+ - **The primary parent** — one per account. The overwhelming majority of accounts have only this.
159
+ - **Membership edges** — extra links letting the *same account* be reached through **more than one** parent
160
+ (a customer in two product lines; a branch deployment reaching the same owner).
115
161
 
116
- Apply these rules before making remote tool calls:
162
+ Any link can independently carry three things. They are **orthogonal** — never infer one from another:
117
163
 
118
- - **Inside the target implementation repo**: read `account-info.json` (the same data that `mcp_account_view` returns) and inspect `/components` directly.
119
- - **Inside one repo but supporting a different account**: switch to the correct repo for that account type if available; otherwise use `mcp_account_view` / `mcp_component_view` / `mcp_component_grep`.
164
+ | Edge property | Means |
165
+ |---|---|
166
+ | `branchName` | **Which code runs** — the component-variant branch this account subscribes to (see "Branched Component Variants") |
167
+ | `databaseName` | **Where data lives** — a storage-namespace override scoped to this link |
168
+ | `domainName` | **Which host reaches it** — a custom hostname that resolves this account *and* this link's parent as the path travelled |
169
+
170
+ Two consequences that generate most "this account is weird" tickets:
171
+
172
+ 1. **The same account can legitimately resolve differently depending on how the request reached it** — a
173
+ different component version, a different namespace, a different host. Establish which path a failing
174
+ request travelled before comparing behavior. (Full detail in "Account Resolution: how a request travels
175
+ the account graph".)
176
+ 2. **An account with no primary parent and several membership edges inherits nothing and runs trunk** until
177
+ a path is named — the platform refuses to guess between equally valid parents. That is by design.
178
+
179
+ ### Users are a separate model — don't reason about them as a tree
180
+
181
+ - A user is **global, keyed by email**. There is no per-account copy of a person.
182
+ - A user **belongs to many accounts** (a membership list, not a parent pointer).
183
+ - A user's **custom fields are per-account**: the same person can be `role: 'Admin'` on one account and
184
+ `role: 'Viewer'` on another. A field written while bound to the wrong account lands on the wrong account.
185
+ - **Access reach is a union over every link** — a user credentialed on a parent can act on an account below
186
+ it through any link, which is deliberately broader than the single-path component inheritance.
187
+
188
+ There is no dedicated user MCP tool. For access questions ("who can see this client account?", "why does
189
+ this user see the wrong data?") use `mcp_sql_query` against `user` / `user_account`, or `account.users([scope:
190
+ 'children'])` from inside a component. See `features/account-management.md` (`mcp_get_guide`).
191
+
192
+ ### Reading the shape
193
+
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:
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`.
202
+ - **`type`** — decide repo/ownership per the table above.
203
+ - **`resolvedDatabaseName`** vs **`databaseName`** — the namespace actually in effect vs the account's own
204
+ override. Check this first when documents are "missing".
205
+ - **`relationships`** — every link upward, primary first, each with its own `branchName` / `databaseName` /
206
+ `domainName`. **This is where you see that an account has two parents, and which link carries what.**
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.
210
+ - **`branchName`** — the account **repo's** trunk sync branch. Not a component-variant branch. Do not confuse
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.
215
+ - **`componentBranches`** (top level) — variant branches this account **owns**, with drift and subscriber
216
+ counts. Check it before editing a shared component.
217
+
218
+ ### Repo selection rules
219
+
220
+ - **Inside the target implementation repo**: read `account-info.json` and inspect `/components` directly.
221
+ - **Inside one repo but supporting a different account**: switch to the correct repo for that account if
222
+ available; otherwise use `mcp_account_view` / `mcp_component_view` / `mcp_component_grep`.
120
223
  - **Outside any repo**: rely on the tools for account structure and component source.
121
- - **Never create a new local repo/directory just because a ticket references an account name.** First resolve the account type and parent hierarchy. Only work from an existing indexed repo unless the user explicitly asks you to create or clone one.
224
+ - **Never create a new local repo/directory just because a ticket references an account name.** First resolve
225
+ the account type and parent hierarchy. Only work from an existing indexed repo unless the user explicitly
226
+ asks you to create or clone one.
122
227
 
123
228
  Use `remits-cli` for everything else: staging changes, running tests, generating embeddable tokens, committing work, and diagnosing production issues.
124
229
 
@@ -144,6 +249,11 @@ local working tree** — and:
144
249
  - **Match / update:** each component is matched to a DB row by the **numeric id prefix of its files**
145
250
  (`58_x.groovy` → component 58), not by name. Matching files overwrite that component's DB fields
146
251
  (source/schema/html/etc.).
252
+ - **Rename:** changing the component's `name:` in `.meta.yml` is supported as a normal update **as long as
253
+ the numeric id prefix stays the same**. On staging, the CLI updates the id/name cache aliases and prunes
254
+ stale old-name aliases for that id. On trunk sync, the platform canonicalizes the repo filenames to the
255
+ current component name (`58_OldName.groovy` with `name: New Name` becomes `58_NewName.groovy`, plus
256
+ sidecars) and reports those moves in `syncResults.renamed`.
147
257
  - **Create:** a file whose id prefix is **not** a live component on the account — including any `new_*` file —
148
258
  is created as a **brand-new DB row with a fresh server-assigned id**, and the platform renames the repo files
149
259
  to that id (the `Rename X→Y after component creation` / `Delete old file` commits).
@@ -175,13 +285,15 @@ local working tree** — and:
175
285
  > nor got renamed."* Check the sidecar's `auxiliary` flag first.
176
286
 
177
287
  **The single most important consequence:** the id in a component's **filename is load-bearing**. If a file's id
178
- no longer matches its DB row (a rename/renumber), the next sync will **create a duplicate at the new id and
179
- hard-delete the original at the old id**. If a component's files are missing from the repo at sync time, that
180
- component is **hard-deleted from the DB**. This is exactly how a prior session deleted live schemas and an
181
- embeddable.
288
+ no longer matches its DB row (a renumber or move across ids), the next sync will **create a duplicate at the
289
+ new id and hard-delete the original at the old id**. If a component's files are missing from the repo at sync
290
+ time, that component is **hard-deleted from the DB**. This is exactly how a prior session deleted live schemas
291
+ and an embeddable.
182
292
 
183
- **Therefore: never renumber, rename-across-ids, or remove component files as a side effect.** Before any sync,
184
- the repo must already mirror the live DB: every live component present at its real id, and nothing extra.
293
+ **Therefore: never renumber, rename-across-ids, or remove component files as a side effect.** Name-only
294
+ renames are fine when every file keeps the same numeric id; either rename the local filename stem yourself or
295
+ let trunk sync canonicalize it from `.meta.yml`. Before any sync, the repo must already mirror the live DB:
296
+ every live component present at its real id, and nothing extra.
185
297
 
186
298
  ### The surfaces and their intended behavior
187
299
 
@@ -191,7 +303,7 @@ the repo must already mirror the live DB: every live component present at its re
191
303
  | `mcp_component_edit` `mode:'stage'` | Redis staging cache for one component/field. | none |
192
304
  | `mcp_component_edit` `mode:'commit'` / `mcp_component_commit` `commit` | Writes the field(s) to the **live DB** for that exact existing component and clears its staging. Does not create/delete other components. | low (scoped to one known component) |
193
305
  | `remits-cli components sync` **on trunk** | **Server-side git→DB reconcile of the whole account** (create/update/**delete**/rename). Reads the pushed remote; ignores local files. | **high** |
194
- | `remits-cli components sync` **on a variant branch** | Writes `ComponentVariant` overlays for that branch only. Never touches trunk rows, `account-info.json`, or the account's trunk branch. `--dry-run` reports the plan without writes. | medium (a missing file becomes a **tombstone** that hides the component from subscribers) |
306
+ | `remits-cli components sync` **on a variant branch** | Writes `ComponentVariant` overlays for that branch only. Never touches trunk rows or the account's trunk branch. When the checkout identifies a subscribing account, the branch-local `account-info.json` is refreshed for that subscriber; `--dry-run` reports the plan without writes. | medium (a missing file becomes a **tombstone** that hides the component from subscribers) |
195
307
  | `remits-cli components commit` | **One shot:** `git add -A` + commit + `git push` + **`components sync`** + `git pull --ff-only`. Blindly stages the *entire* working tree (including any drift) and reconciles it into prod. Inherits the danger of whichever sync mode the branch selects. | **highest on trunk** |
196
308
  | `mcp_component_create` | Writes a **new** component row **directly to the DB** (immediate, new id). | medium (can create duplicates) |
197
309
 
@@ -211,7 +323,9 @@ Key implications:
211
323
 
212
324
  **Change existing components (normal path):**
213
325
  1. Edit files under `components/` **keeping each component's existing numeric id** (use `new_*` only for
214
- genuinely new components).
326
+ genuinely new components). To rename a component, update `name:` in its `.meta.yml`; keep the id prefix
327
+ fixed. Renaming the file stem is optional before trunk sync because the platform will canonicalize it, but
328
+ doing it locally keeps the working tree easier to read.
215
329
  2. `remits-cli components stage` → verify in test mode. Iterate (edit → stage → run).
216
330
  3. When ready to promote: pass the pre-sync safety check below, then
217
331
  `git add -A && git commit && git push`, `remits-cli components sync`, `git pull --ff-only`.
@@ -765,6 +879,12 @@ This is how every development task should flow:
765
879
  #### Step 1: Understand the Request
766
880
  Read the user's request. If you may need a repo other than the current one, read `~/.remits-cli/account-repos.json` first. Then review `account-info.json` and `README.md` to understand what components exist and how they relate. Read the source of any component you'll modify before changing it.
767
881
 
882
+ **Establish the account's shape too, not just its components.** Read the `resolution` block in
883
+ `account-info.json` (or `mcp_account_view`): the account `type` decides whether this repo is even the right
884
+ place to change code, `resolution.relationships` shows whether the account has more than one parent (and
885
+ which link carries a branch/namespace/host), and `resolvedDatabaseName` tells you where its data actually
886
+ lands. See "Account Targeting Model" and `features/account-management.md` (`mcp_get_guide`).
887
+
768
888
  **Also establish which world you are working in.** `remits-cli components status` reports whether the
769
889
  working tree is a **trunk** checkout or a **variant branch** checkout — which decides both what your test
770
890
  runs resolve and what a sync writes. If `account-info.json` carries a `componentBranches` section, branch
@@ -774,6 +894,41 @@ variants of these components exist: editing an origin component will drift them,
774
894
  #### Step 2: Make the Change
775
895
  Edit component files under `components/`. This is local file editing — the platform doesn't know about your changes yet.
776
896
 
897
+ **Creating a component that does not exist yet.** Files are named `<id>_<Name>.<ext>`, where the numeric
898
+ prefix is the platform's component id. A new component has no id, so name its files with the **`new_`
899
+ prefix** and let the sync assign one (it then renames the files to that id):
900
+
901
+ ```
902
+ components/embeddables/new_MerchantPortal.groovy # source
903
+ components/embeddables/new_MerchantPortal.html # markup
904
+ components/embeddables/new_MerchantPortal.js # client script
905
+ components/embeddables/new_MerchantPortal.meta.yml # metadata sidecar
906
+ ```
907
+
908
+ **Do NOT put an `id:` in a new component's sidecar.** `id` is what links a sidecar to an *existing*
909
+ component and is parsed as a number, so a placeholder (`id: new`, `id: TBD`) fails the **entire**
910
+ stage/sync request with a `NumberFormatException` — not just that one file, and the error does not name
911
+ the file. Omit the key; the platform fills it in on sync:
912
+
913
+ ```yaml
914
+ # components/embeddables/new_MerchantPortal.meta.yml — no `id:` yet
915
+ name: Merchant Portal
916
+ summary: One-line statement of what this component is for.
917
+ description: |
918
+ Longer technical description with line-number references to the key logic.
919
+ path: /page/merchant-portal # Readers and Embeddables only
920
+ category: default
921
+ auxiliary: false # `true` means the sync SKIPS the file entirely — see Auxiliary
922
+ mermaid: |
923
+ graph TD
924
+ A[Request] --> B[Load documents]
925
+ ```
926
+
927
+ > **Staging creates nothing in the database, so a `new_` component has no id yet — address it BY NAME.**
928
+ > `remits-cli test run --test "My Suite"`, not `--test <id>`. Component-to-component resolution and
929
+ > request-level addressing are name-based too; the component guides cover those. After a trunk sync the
930
+ > component has a real id and either form works.
931
+
777
932
  #### Step 3: Stage to Platform
778
933
 
779
934
  ```bash
@@ -806,7 +961,9 @@ Important test-runner constraints:
806
961
 
807
962
  If no relevant Test component exists yet, consider creating one. Test components live in `components/tests/` and follow the same component structure. They provide permanent regression protection — every test you write today saves debugging time tomorrow.
808
963
 
809
- New test files use the `new_` prefix (e.g., `new_MyTest.groovy`). New tests have no database ID, so you must run them **by name**: `remits-cli test run --test "My Test"`. After committing, the platform assigns an ID and renames the file (e.g., `4_MyTest.groovy`) — then you can run by either ID or name.
964
+ New test files use the `new_` prefix (e.g., `new_MyTest.groovy`) and no `id:` in the sidecar — see "Creating a component that does not exist yet" in Step 2. Run them **by name** (`remits-cli test run --test "My Test"`) until a sync assigns an id and renames the file.
965
+
966
+ **How to write the Test itself is not a CLI concern** — what a suite can assert, how mocks behave across HTTP/relay boundaries, driving an embeddable in-process, and the front-stage-only rule all live in `guides/components/test-components.md`. Read that before authoring a suite.
810
967
 
811
968
  **Option B — Visual verification with Playwright** (for UI changes or when the user wants to "see it"):
812
969
 
@@ -870,7 +1027,9 @@ Before committing, update metadata so the next session understands what changed:
870
1027
  2. **`README.md`** — If the change affects account-level capabilities or workflows.
871
1028
  3. **New components** — Always fill in `.meta.yml` immediately.
872
1029
 
873
- `account-info.json` is read-only — never edit it. It regenerates automatically after sync.
1030
+ `account-info.json` is read-only — never edit it. It regenerates automatically after sync. On a trunk sync it
1031
+ describes the owning repo account. On a subscriber-initiated variant sync it describes the subscribing
1032
+ account reached through the branch edge, even though the component files still belong to the owner's repo.
874
1033
 
875
1034
  #### Step 7: Commit and Durable Sync
876
1035
 
@@ -1108,8 +1267,8 @@ edge's *child* as the execution account **and** the edge's *parent* as the branc
1108
1267
  makes that edge's branch variants apply. An account-level host resolves the account with **no** anchor
1109
1268
  (today's behavior). Edge wins, then the account's own host, so removing an edge degrades cleanly instead
1110
1269
  of taking the hostname offline. Hosts are stored as bare lowercase hostnames; a full URL is normalized on
1111
- the way in. This is what lets a forked/branch deployment get its own domain without a separate account
1112
- 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
1113
1272
  with a branch.
1114
1273
 
1115
1274
  **Two traversals, deliberately different.** Confusing them is the usual source of wrong conclusions:
@@ -1139,17 +1298,40 @@ disambiguate it by branch name; from the CLI you supply it explicitly.
1139
1298
  legitimately resolve a different component variant *and* a different data segment. When you investigate
1140
1299
  such an account, always establish which anchor the failing request used before comparing behavior.
1141
1300
 
1301
+ **How to actually see an account's edges.** `mcp_account_view` (and the repo's `account-info.json`) returns
1302
+ `resolution.relationships` — one entry per structural link, primary first, each carrying its own
1303
+ `branchName` / `databaseName` / `domainName`. The hierarchy tree flattens every link into one shape, so this
1304
+ block is the only place that answers "how many parents does this account really have, and which link carries
1305
+ what?" Start here for any resolution question:
1306
+
1307
+ ```bash
1308
+ remits-cli tool --name mcp_account_view --input '{"accountId": 101}' --data-mode prod
1309
+ # then read: resolution.relationships, resolution.resolvedDatabaseName, resolution.componentBranch
1310
+ ```
1311
+
1142
1312
  **Practical checklist when a subscription "doesn't work":**
1143
1313
 
1144
- 1. Does the account have a `parentId`, or is it membership-only? (Membership-only + multiple edges ⇒
1314
+ 1. Does the account have a primary parent, or is it membership-only? Count the entries in
1315
+ `resolution.relationships` and check which one is `primary: true`. (Membership-only + multiple edges ⇒
1145
1316
  ambiguous ⇒ trunk.)
1146
- 2. Which **edge** carries the `branchName` — `remits-cli components branch <name> --subscribers` prints
1147
- `via primary|membership edge -> parent N`.
1317
+ 2. Which **edge** carries the `branchName` — it is on the edge in `resolution.relationships`, and
1318
+ `remits-cli components branch <name> --subscribers` prints `via primary|membership edge -> parent N`.
1148
1319
  3. Was the run anchored through *that* edge's parent? Re-run with `--as-account <subscriberId>` so the
1149
1320
  account's own edge selects the branch, exactly as production would.
1150
1321
  4. Check the resolved layer, not the source text: `testComponentSource` / the `variant:<id>:<hash>`
1151
1322
  compile signature (see "Diagnosing a variant").
1152
1323
 
1324
+ **The same block answers the non-branch resolution questions too:** "why are this account's documents not
1325
+ where I expect?" → compare `databaseName` vs `resolvedDatabaseName` and any edge `databaseName`. "Why does
1326
+ this hostname land on the wrong account?" → `domainName` vs `resolvedDomainName` and the edge `domainName`
1327
+ (an edge host wins over the account's own, and additionally supplies the path travelled).
1328
+
1329
+ **Users are not part of this graph.** A user is global, belongs to many accounts, and can reach an account
1330
+ below one they are credentialed on through **any** link — a deliberately broader rule than the single-path
1331
+ component inheritance above. Their custom fields (`role`, `team`, …) are stored **per account**, so the same
1332
+ person can differ per account. There is no user MCP tool: use `mcp_sql_query` against `user` /
1333
+ `user_account`, and read `features/account-management.md` (`mcp_get_guide`) for the model.
1334
+
1153
1335
  ## Branched Component Variants (per-account component overrides)
1154
1336
 
1155
1337
  Sometimes one account — often a customer nested several levels down a hierarchy — needs *slightly*
@@ -1162,14 +1344,14 @@ resolve.
1162
1344
 
1163
1345
  1. **The origin account owns the component and the branch.** Say platform account 1 owns
1164
1346
  `Extract Invoice` (Action 50). Its repo `remits-<name>` has trunk branch `main` and a second git branch
1165
- `feature_forked`.
1166
- 2. **A `ComponentVariant` row is the overlay.** Committing on `feature_forked` stores rows owned by
1167
- **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
1168
1350
  branch physically contains every file; only the *differing* ones become variants. That is computed at
1169
1351
  sync time — you never declare it.
1170
1352
  3. **A child account subscribes via its relationship edge.** Account 101's `AccountRelationship` edge
1171
- carries `branchName = 'feature_forked'`. Resolution then walks 101's inheritance chain and applies
1172
- 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.
1173
1355
 
1174
1356
  Consequences worth internalizing:
1175
1357
 
@@ -1187,8 +1369,14 @@ Consequences worth internalizing:
1187
1369
  only subscribe an account reachable from one you already have access to.
1188
1370
  - **`--subscribe` sets the branch on an edge that must already exist — it cannot create one.** If the
1189
1371
  account has no relationship edge to the owner you will get *"Account N has no relationship edge to
1190
- subscribe; add a membership edge first"*. Creating a membership edge is an **admin** operation (the
1191
- 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.
1192
1380
  - **When the account has several parents, say which edge you mean:**
1193
1381
  `--subscribe <accountId> --parent-account <ownerId>`. Without it the CLI picks the edge to the owner
1194
1382
  whose branch you are managing, then falls back to the account's primary edge — which may not be the
@@ -1233,7 +1421,7 @@ the loop. The rule turns entirely on **trunk vs non-trunk**:
1233
1421
  | Working tree | Staging scope | A run resolves | `components sync`/`commit` writes |
1234
1422
  |---|---|---|---|
1235
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** |
1236
- | **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 |
1237
1425
 
1238
1426
  **The precedence trap that costs the most time:** `variantBranch` OUTRANKS every account's subscription. So
1239
1427
  running a Test suite that asserts *production* semantics from a **variant checkout** pins every account in
@@ -1250,13 +1438,47 @@ remits-cli components status
1250
1438
  ```
1251
1439
 
1252
1440
  ```
1253
- Working tree: VARIANT BRANCH "feature_forked" (trunk is "main")
1254
- runs resolve: trunk + the 'feature_forked' variant overlays
1255
- 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)
1256
1444
  variants stored on this branch: 3
1257
1445
  subscribing accounts: 101 (Acme Child)
1258
1446
  ```
1259
1447
 
1448
+ **Branch-local `account-info.json` can describe a subscriber.** On a variant branch, the same git repository
1449
+ is still the OWNER's component repo: files under `components/` overlay that owner's trunk component ids, and
1450
+ `components sync` writes `ComponentVariant` rows owned by that parent account. But if the checkout was synced
1451
+ from a subscribing account reached through an `AccountRelationship` edge, the branch's `account-info.json`
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.
1476
+
1477
+ Consequence: if a variant checkout's `account-info.json` is stale and still names the owner, run the first
1478
+ repair sync with an explicit subscriber target, for example `remits-cli components sync --account-id 101`.
1479
+ After that sync and `git pull --ff-only`, normal commands from that checkout should resolve the subscriber
1480
+ from `account-info.json` and continue writing variants under the owner selected by the branch edge.
1481
+
1260
1482
  ### Two levers, two different questions
1261
1483
 
1262
1484
  - **`--as-account <id>`** changes **who** the run executes as, so that account's own edge picks the branch.
@@ -1276,13 +1498,13 @@ Both work on `remits-cli test run` and `remits-cli token`; `--variant-branch` al
1276
1498
  The loop does not change shape — `edit → stage → verify → commit`:
1277
1499
 
1278
1500
  ```bash
1279
- git checkout feature_forked # or: git checkout -b feature_forked
1501
+ git checkout feature_branch # or: git checkout -b feature_branch
1280
1502
  # edit components/actions/50_ExtractInvoice.groovy (KEEP the trunk id)
1281
1503
  remits-cli components stage # Redis, scoped to this branch — same as always
1282
- 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
1283
1505
  remits-cli test run --test "Invoice Tests" --as-account 101 # ...as the real subscriber
1284
1506
  # promote:
1285
- git add -A && git commit -m "..." && git push origin feature_forked
1507
+ git add -A && git commit -m "..." && git push origin feature_branch
1286
1508
  remits-cli components sync --dry-run # inspect overrides/additions/tombstones without writes
1287
1509
  remits-cli components sync # writes ComponentVariant overlays ONLY
1288
1510
  ```
@@ -1291,9 +1513,10 @@ Two things that differ from trunk:
1291
1513
 
1292
1514
  - **Keep the origin id in the filename.** `50_ExtractInvoice.groovy` on the branch overlays Action 50. That
1293
1515
  is what preserves component identity and lets drift be computed against the origin.
1294
- - **Nothing is renamed.** A variant sync never renames files, never regenerates `account-info.json`, and
1295
- never repoints the account's trunk branch. A `new_*` file stays `new_*` and becomes a branch-only
1296
- component keyed by name.
1516
+ - **Nothing is renamed.** A variant sync never renames files and never repoints the account's trunk branch.
1517
+ When launched from a subscribing account, it may refresh that branch's `account-info.json` so the checkout
1518
+ describes the account reached through the branch edge. A `new_*` file stays `new_*` and becomes a
1519
+ branch-only component keyed by name.
1297
1520
 
1298
1521
  ### Promotion: getting the branch back into trunk
1299
1522
 
@@ -1302,12 +1525,12 @@ by a **trunk** sync — the platform does not merge anything for you.
1302
1525
 
1303
1526
  ```bash
1304
1527
  # 1. merge the branch into trunk (review the diff FIRST - see the deletion hazard below)
1305
- git checkout main && git merge feature_forked && git push origin main
1528
+ git checkout main && git merge feature_branch && git push origin main
1306
1529
  # 2. trunk sync: creates real rows for new_* files, assigns ids, RENAMES those files on trunk
1307
1530
  remits-cli components sync
1308
1531
  git pull --ff-only origin main
1309
1532
  # 3. bring trunk back into the branch so the two stop diverging
1310
- 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
1311
1534
  remits-cli components sync # reconciles the branch's overlays
1312
1535
  ```
1313
1536
 
@@ -1400,9 +1623,9 @@ The analogous hazard is different and you must still respect it:
1400
1623
 
1401
1624
  ```bash
1402
1625
  remits-cli components branches # branches with variants, counts, drift
1403
- remits-cli components branch feature_forked # overridden / added / removed + subscribers
1404
- remits-cli components branch feature_forked --diff 50 --component-type action
1405
- 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
1406
1629
  ```
1407
1630
 
1408
1631
  **Drift is the number to watch.** Each variant records the trunk content hash at the moment it was cut
@@ -1531,18 +1754,118 @@ Returns complete account structure — schemas, components, relationships.
1531
1754
  Also returns two blocks that explain how the account RESOLVES, which is what you need before comparing
1532
1755
  its behavior against component source:
1533
1756
 
1534
- - `resolution` — `databaseName` (the account's own override, often null) vs `resolvedDatabaseName` (the
1535
- storage namespace actually in effect), `branchName` (the repo sync branch), `domainName` vs
1536
- `resolvedDomainName` (the custom host in effect, which differs when reached through an edge host),
1537
- `editMode`, and — when the account subscribes to a component branch — `componentBranch` plus
1538
- `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`.
1765
+ - `resolution.relationships` — **every structural link upward**, primary first: `parentAccountId` /
1766
+ `parentAccountName` / `parentAccountCode` / `parentAccountType`, `primary` (true for the one link that
1767
+ mirrors the account's primary parent), `active`, and the three independent link-scoped properties
1768
+ `branchName` (which component-variant code runs), `databaseName` (where data lives), `domainName` (which
1769
+ host reaches the account through this link). The hierarchy tree flattens all links into one shape, so this
1770
+ is the **only** place that answers "does this account have more than one parent, and which link carries the
1771
+ branch/namespace/host?" More than one entry ⇒ this account can resolve differently depending on the path a
1772
+ request travelled — establish which one a failing request used before comparing behavior.
1539
1773
  - `componentBranches` — the variant branches this account OWNS, with override/add/remove, subscriber, and
1540
1774
  drift counts. Same summary the owner's `account-info.json` carries.
1541
1775
 
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`.
1778
+
1542
1779
  | Parameter | Required | Description |
1543
1780
  |-----------|----------|-------------|
1544
1781
  | `accountId` | yes | Account ID |
1545
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
+
1546
1869
  ### `mcp_firestore_search`
1547
1870
  Query Firestore documents.
1548
1871
 
@@ -1898,6 +2221,25 @@ Inspect, flush, or clear the CLI staging cache for components.
1898
2221
  | `accountId` | yes | Account ID |
1899
2222
  | `action` | yes | `read` (list staged entries), `commit` (flush staged → DB), or `clear` (drop staged entries without touching the DB) |
1900
2223
 
2224
+ ### `mcp_component_branches`
2225
+ The MCP counterpart of `remits-cli components branches` / `components branch <name>` — use it when you are
2226
+ driving the platform **remotely** (no local repo/checkout) and need to know whether a component already has
2227
+ committed branch variants, who subscribes, and whether they have drifted.
2228
+
2229
+ | Parameter | Required | Description |
2230
+ |-----------|----------|-------------|
2231
+ | `action` | no | `list` (default) — every branch this owner has variants on, with drift + subscriber counts; `status` — one branch's overridden/added/removed; `diff` — one component's variant beside current trunk; `subscribers` — accounts resolving a branch; `subscribe`/`unsubscribe` — set/clear the branch on a subscriber's existing relationship edge; `retire` — delete a branch's overlays |
2232
+ | `ownerAccountId` | no | The account whose branches are inspected. **Outranks `accountId`**, because `accountId` also selects which account the tool is resolved on — so `accountId` alone cannot target another account's branches. |
2233
+ | `branchName` | conditional | Required for everything except `list`. Alias: `branch`. |
2234
+ | `componentId` / `componentName` / `componentType` | conditional | Address the component for `diff` |
2235
+ | `targetAccountId` | conditional | The account to subscribe/unsubscribe |
2236
+ | `parentAccountId` | no | Which relationship edge to set the branch on. Without it: the edge toward the branch owner, then the target's primary edge. |
2237
+ | `force` | no | `retire` only — proceed while subscribers remain |
2238
+
2239
+ Same rules as the CLI: `subscribe` only **sets the branch on an edge that already exists** (creating a
2240
+ membership edge is an admin operation), authorization is downward-only, and `retire` refuses while
2241
+ subscribers remain unless forced.
2242
+
1901
2243
  ### `mcp_cache`
1902
2244
  Bounded read-only investigation of the platform Redis keyspace — the way to see exactly what a staged
1903
2245
  entry holds (and its TTL) or any other cache key. Read-only: no delete (use `mcp_component_commit clear`
@@ -1910,6 +2252,143 @@ to remove staged entries).
1910
2252
  | `key` | no | Exact key for `action:'inspect'` |
1911
2253
  | `pageSize`/`sampleSize`/`previewChars` | no | Bounding controls |
1912
2254
 
2255
+ ### `mcp_sql_query`
2256
+ Read-only, bounded SQL against the platform database. This is the **catch-all investigation surface** for
2257
+ questions the purpose-built tools do not model — above all **users and account membership**, for which there
2258
+ is no dedicated tool.
2259
+
2260
+ | Parameter | Required | Description |
2261
+ |-----------|----------|-------------|
2262
+ | `query` | yes* | One read-only statement. Alias: `sql`. Must start with `SELECT`, `WITH`, `SHOW`, `DESCRIBE`/`DESC`, or `EXPLAIN`; mutation, DDL, locking, and filesystem constructs are rejected. |
2263
+ | `queries` | yes* | Batch of up to 10 read-only queries (strings, or `{query, params}` objects) |
2264
+ | `params` / `parameters` | no | Positional parameters — **use these instead of interpolating values** |
2265
+ | `maxRows` / `limit` | no | Rows per query. Default 100, max 500. |
2266
+ | `maxValueChars` | no | Truncation width per string value. Default 2000, max 20000. |
2267
+ | `redact` | no | Redact secret-like columns (`password`, `token`, `secret`, `authorization`, …). **Default true — leave it on.** |
2268
+
2269
+ *Provide `query`/`sql` or `queries`.
2270
+
2271
+ Useful shapes:
2272
+
2273
+ ```sql
2274
+ -- who has access to a client account (and through which membership rows)
2275
+ SELECT u.id, u.username, u.enabled FROM user u
2276
+ JOIN user_account ua ON ua.user_id = u.id WHERE ua.account_id = ?;
2277
+
2278
+ -- every account a user can reach directly
2279
+ SELECT a.id, a.name, a.type FROM account a
2280
+ JOIN user_account ua ON ua.account_id = a.id WHERE ua.user_id = ?;
2281
+
2282
+ -- the account's structural links, including membership edges (`primary` is column `is_primary`)
2283
+ SELECT parent_id, is_primary, branch_name, database_name, domain_name, active
2284
+ FROM account_relationship WHERE account_id = ?;
2285
+ ```
2286
+
2287
+ Prefer the purpose-built tools when one fits — they apply account scoping, data-mode segmentation, and
2288
+ resolution awareness that raw SQL does not. Reach for SQL when nothing else models the question.
2289
+
2290
+ ### `mcp_index_search`
2291
+ Query and **diagnose** the Vertex AI Search index through the platform's Vertex DSL. Use it to check what a
2292
+ RAG/search-backed component actually retrieves before blaming the component.
2293
+
2294
+ | Parameter | Required | Description |
2295
+ |-----------|----------|-------------|
2296
+ | `accountId` | yes | Tenant scoping |
2297
+ | `action` | no | `search` (default, `index_search()`), `facets` (`index_facets()` — taxonomy/distinct values), `diagnose` (explain why strict filtering dropped matches), `inspect` (what is actually indexed for given `sourceDocumentIds`) |
2298
+ | `query` | conditional | Required for `search`/`diagnose` |
2299
+ | `schema` / `projectionType(s)` / `projectionSource` | no | Scope to a schema's Vertex projections |
2300
+ | `filters` | no | Vertex-style structured filters on indexed metadata |
2301
+ | `pageSize` / `maxResults` / `pageToken` | no | Paging and local trimming |
2302
+ | `searchProfile` | no | `ai`/`agent`/`strict` (precision) vs `admin`/`default` (recall) |
2303
+ | `includeMatchDiagnostics` | no | Return the applied filter/query plus the pre-strict-filter candidate set |
2304
+ | `accountIds` | no | Explicit multi-account search |
2305
+ | `dataMode` | no | `test` (default) or `prod` |
2306
+
2307
+ When a component "can't find" an obviously-present document, run `action:'inspect'` on its source document id
2308
+ first — that shows what was indexed, which is usually the answer.
2309
+
2310
+ ### `mcp_get_guide`
2311
+ Load the packaged front-stage guides — the same `docs/guides/` set `remits-cli` syncs into a repo. Use it when
2312
+ you are working **outside a repo** (or the repo's `guides/` is stale) and need the authoritative guidance
2313
+ before writing a component.
2314
+
2315
+ | Parameter | Required | Description |
2316
+ |-----------|----------|-------------|
2317
+ | `guide` | conditional | Short name (`agent-components`), relative path (`features/account-management`), or full path |
2318
+ | `list` | no | List available guides instead of loading one |
2319
+ | `directory` | no | Scope a list to `components` or `features` |
2320
+ | `contains` | no | Substring filter when listing |
2321
+
2322
+ ### `mcp_test_fixture`
2323
+ Seed and remove schema-backed fixture documents in the **forced test** data segment. This is how you construct
2324
+ realistic conditions for verification without copying live customer data.
2325
+
2326
+ | Parameter | Required | Description |
2327
+ |-----------|----------|-------------|
2328
+ | `accountId` | yes | Account owning the target schema/collection |
2329
+ | `action` | no | `create` (fails on existing id), `upsert`, or `delete` |
2330
+ | `schemaName` / `collection` | conditional | Schema display name or collection name |
2331
+ | `documentId` / `documentIds` | no | Explicit Firestore ids for single/batch operations |
2332
+ | `data` / `documents` | conditional | Single payload, or a batch array |
2333
+ | `dataMode` | no | Must be `test` — **prod-mode writes are rejected** |
2334
+
2335
+ ### `mcp_embeddable_test_url`
2336
+ Mint an authenticated browser URL for an embeddable — the MCP counterpart of `remits-cli token --path
2337
+ embeddable/index/<id>`. Returns the URL plus branch/variant/data-mode hints so you know which world the page
2338
+ will render.
2339
+
2340
+ | Parameter | Required | Description |
2341
+ |-----------|----------|-------------|
2342
+ | `accountId` | yes | Account owning the embeddable |
2343
+ | `embeddableId` / `embeddableName` | conditional | Provide one |
2344
+ | `userId` | no | User to mint for. Defaults to the current user. |
2345
+ | `variantBranch` | no | Probe a committed component-variant branch. Usually inherited from the caller. |
2346
+
2347
+ ### `mcp_playwright_replay`
2348
+ Hosted browser automation (the `playwright-relay` service) for visual verification when local `playwright-cli`
2349
+ is unavailable — e.g. an agent running remotely. Returns an accessibility snapshot and interactive refs on
2350
+ every command, so you navigate iteratively.
2351
+
2352
+ | Parameter | Required | Description |
2353
+ |-----------|----------|-------------|
2354
+ | `command` | yes | `open`, `goto`, `snapshot`, `click`, `dblclick`, `hover`, `fill`, `select`, `check`, `uncheck`, `eval`, `run-code`, `screenshot`, `pdf`, `console`, `network`, `go-back`, `go-forward`, `reload`, `tab-*`, `close`, `close-all` |
2355
+ | `sessionId` | conditional | Reuse an existing session. `open`/`goto` without one starts a session. |
2356
+ | `url` / `target` / `value` / `expression` / `code` | conditional | Per-command inputs (`target` is an element ref or selector) |
2357
+ | `compact` | no | Default true — omits bulky raw relay payloads |
2358
+ | `includeSnapshot` / `includeAccessibility` / `includeRefs` / `includePage` / `includeResult` / `includeRaw` | no | Response shaping |
2359
+ | `pattern` / `level` / `limit` | no | Filters for `console` / `network` |
2360
+ | `ticketId` / `artifactType` / `artifactLabel` / `artifactNotes` | no | Attach a screenshot/pdf/trace/video to a support ticket |
2361
+
2362
+ ### `mcp_jvm_spike_triage`
2363
+ Production-aware triage bundle for a Cloud Run service showing a latency/memory spike. Safe by construction:
2364
+ optional class-histogram sampling, **no heap dump and no JFR**.
2365
+
2366
+ | Parameter | Required | Description |
2367
+ |-----------|----------|-------------|
2368
+ | `serviceName` | yes | e.g. `remits`, `remits-actions` |
2369
+ | `region` | yes | e.g. `us-east5`, `us-east1` |
2370
+ | `sampleHeap` | no | Default true — one class histogram + heap composition sample (brief stop-the-world) |
2371
+ | `top` | no | Top classes to return. Default 20, max 100. |
2372
+ | `includeThreadDump` / `threadLimit` | no | Fuller thread dump beyond the built-in top-thread preview |
2373
+ | `includeLogs` / `logLookbackMinutes` / `logLimit` | no | Recent WARNING+ log signals for the same service |
2374
+
2375
+ ### `mcp_support_ticket_queue`
2376
+ List and filter tickets **across an account and its descendants** so you can choose what to work on. Lifecycle
2377
+ actions stay on `mcp_support_ticket`.
2378
+
2379
+ | Parameter | Required | Description |
2380
+ |-----------|----------|-------------|
2381
+ | `action` | no | `list` (default) |
2382
+ | `accountId` / `accountIds` / `includeChildren` / `includeRoot` | no | Queue scope. Defaults to the current account **and its descendants**. |
2383
+ | `statuses` / `status` | no | Defaults to `open`, `accepted`, `in_progress`, `pending_review`. `['all']` disables filtering. |
2384
+ | `priorities` / `types` / `sources` / `tags` | no | Additional filters |
2385
+ | `assignedTo` / `unassigned` | no | Assignment filters |
2386
+ | `implementationAccountId` | no | Filter by owning `PLATFORM`/`PRODUCT` account |
2387
+ | `search` | no | Case-insensitive across subject, description, account, affected component, sender, tags |
2388
+ | `sortBy` / `sortDirection` | no | `triage` (default-style: critical/high unassigned first), `updated`, `priority`, `status`, `account` |
2389
+ | `limit` / `offset` / `scanLimitPerAccount` | no | Paging and scan bounds |
2390
+ | `dataMode` | no | Normal agent work uses the **prod** ticket queue |
2391
+
1913
2392
  ## Multi-Session Support
1914
2393
 
1915
2394
  The CLI supports multiple authenticated sessions simultaneously. Sessions are stored in `~/.remits-cli/sessions.json` as a map keyed by `accountId + dataMode + baseUrl`, so the same account can stay authenticated against both localhost and production without one session overwriting the other. When you run any command from an account repo, the CLI automatically resolves the best matching session based on the `account-info.json` in that directory and any `--base-url` or `--data-mode` flags provided. If the same account is authenticated against multiple hosts and you omit `--base-url`, the CLI may legitimately choose either localhost or a deployed host depending on the best session match, so agents should treat `--base-url` as mandatory whenever host matters.
@@ -2120,6 +2599,12 @@ For tests specifically:
2120
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. |
2121
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`. |
2122
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". |
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. |
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. |
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. |
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). |
2607
+ | Need users of an account, or accounts of a user | There is no user MCP tool. Use `mcp_sql_query` on `user` / `user_account` (or `account.users([scope:'children'])` inside a component). Remember user custom fields are stored **per bound account**, so the same person can differ per account. |
2123
2608
  | One account behaves differently from its siblings on the same component | It probably subscribes to a **branch variant**. Check `remits-cli components branches` and `remits-cli components branch <name> --subscribers`, and reproduce with `remits-cli test run --as-account <ID>`. Do NOT "fix" this by adding per-account logic to the origin component. |
2124
2609
  | Edits on a feature branch seem to run against trunk code | You are likely on the **trunk** branch, or passed `--variant-branch none`. Run `remits-cli components status` — it states which world the working tree resolves. |
2125
2610
  | A component vanished for one account after a variant-branch sync | Its file is missing from that branch, so the sync created a **tombstone** that hides it from subscribers. Restore the file on the branch and re-sync. Trunk is unaffected. |