@remits/remits-cli 0.1.112 → 0.1.114

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.
@@ -0,0 +1,268 @@
1
+ # Getting Started and Command Reference
2
+
3
+ > A `remits-cli` skill reference. **Load this when** you need the exact command surface: authentication, host versus data mode, the tool execution lifecycle, hierarchy-scoped reads, and every flag.
4
+ >
5
+ > The table of contents below carries **real line numbers** (`- L84 Some Heading`), resolved when
6
+ > this file is installed, so they are never stale. Read the head, pick your sections, and offset-read
7
+ > only those. The entry text is the heading verbatim, so it also greps.
8
+
9
+ ## Table of Contents
10
+
11
+ - [Getting Started](#getting-started)
12
+ - [Authentication](#authentication)
13
+ - [Host vs Data Mode](#host-vs-data-mode)
14
+ - [Tool Execution Lifecycle](#tool-execution-lifecycle)
15
+ - [Hierarchy-scoped tool reads](#hierarchy-scoped-tool-reads)
16
+ - [Data Mode](#data-mode)
17
+ - [Command Reference](#command-reference)
18
+ - [Prod banners and retryable failures](#prod-banners-and-retryable-failures)
19
+
20
+ ## Getting Started
21
+
22
+ ### Authentication
23
+
24
+ Authenticate once per session. Opens the user's browser for OAuth login:
25
+
26
+ ```bash
27
+ remits-cli auth --account-id <ACCOUNT_ID>
28
+ remits-cli auth --account-id <ACCOUNT_ID> --base-url http://localhost:8080
29
+ ```
30
+
31
+ - `--account-id` is auto-resolved from `account-info.json` when you're inside an account repo, so you can usually just run `remits-cli auth`. Pass `--account-id <ID>` explicitly to target a different account (e.g., authenticating into a child account from a parent-account repo) — the explicit flag always wins over the repo's `account-info.json` and any prior session.
32
+ - `--base-url` targets a specific platform instance (e.g., localhost for development). Sessions are stored per account + base URL + data mode, so authenticating against localhost does not overwrite a production session for the same account.
33
+ - If any command returns a 401 error, re-run `remits-cli auth` (with the same `--base-url` if you were targeting a non-default instance).
34
+
35
+ ### Host vs Data Mode
36
+
37
+ Treat host selection and data mode as two separate decisions:
38
+
39
+ - `--base-url` chooses the Remits host: localhost vs a deployed environment.
40
+ - `--data-mode` chooses the data segment on that host: `test` vs `prod`.
41
+
42
+ Examples:
43
+
44
+ ```bash
45
+ # Deployed prod host, but test data segment
46
+ remits-cli tools --base-url https://your-prod-host --data-mode test
47
+
48
+ # Localhost host, but prod data segment on that localhost instance
49
+ remits-cli tool --base-url http://localhost:8080 --name mcp_account_view --data-mode prod
50
+ ```
51
+
52
+ Do not assume `--data-mode prod` implies the deployed prod host, or that `--data-mode test` implies localhost. If host matters, read `~/.remits-cli/sessions.json` first and pass `--base-url` explicitly.
53
+
54
+ ### Tool Execution Lifecycle
55
+
56
+ `remits-cli tool` supports both synchronous and asynchronous execution. Use normal synchronous execution
57
+ for quick investigation tools:
58
+
59
+ ```bash
60
+ remits-cli tool --name "mcp_account_view" --input '{"accountId": 37}' --data-mode prod
61
+ ```
62
+
63
+ **There are two independent async mechanisms — do not confuse or stack them:**
64
+
65
+ 1. **The tool's own async mode** (`mcp_run_action` / `mcp_run_agent`, via `executionMode:"async"` in the
66
+ tool input). The tool spawns the long work server-side and **returns immediately in the same HTTP
67
+ response** with its own run identifiers — `actionRunId` (or `agentRunId`) and, for agents, a stable
68
+ `sessionId`. You poll it with the tool's **own** status protocol (`controlAction:"status"`). This is the
69
+ preferred path for long Actions/Agents, because the run ids come back on the very first call.
70
+
71
+ 2. **The CLI transport async** (`--async true`). This wraps *any* tool call in a background server task and
72
+ returns a CLI-level `callId` immediately, which you poll with `remits-cli tool status --call-id`. Use it
73
+ for long tools that do **not** have their own async mode. Its start response carries `callId`,
74
+ `status:"running"`, `threadGroupingId`, `accountId`, `branchName`, and `dataMode` — but **not** any
75
+ tool-specific ids, because the tool has not run yet; those arrive inside the `result` of the polled
76
+ completed status.
77
+
78
+ For `mcp_run_action` / `mcp_run_agent`, prefer mechanism (1) alone — it already makes the call non-blocking
79
+ **and** returns the run ids up front. Pass your own `actionRunId`/`agentRunId` so you can poll it
80
+ deterministically:
81
+
82
+ ```bash
83
+ remits-cli tool --name "mcp_run_action" --input '{"accountId":49,"actionId":200,"executionMode":"async","actionRunId":"my-stable-run-id","actionInput":{"sourceDocumentId":"..."}}' --data-mode prod
84
+ ```
85
+
86
+ Every tool response is saved to `./.remits-cli/tool-responses/<callId>.json`.
87
+
88
+ ### Hierarchy-scoped tool reads
89
+
90
+ For read/discovery tools, the account resolved from the checkout/session is the **scope root**, not proof
91
+ that the business record is owned by that account. This closes the common support loop where you know a
92
+ precise document, object, event, or indexed source id but do not yet know which child account owns it.
93
+
94
+ Use the tool flags rather than editing JSON by hand:
95
+
96
+ ```bash
97
+ remits-cli tool --name mcp_firestore_search \
98
+ --input '{"collection":"statements","documentId":"1234"}' \
99
+ --scope children --data-mode prod
100
+ ```
101
+
102
+ Available flags:
103
+
104
+ | Flag | Meaning |
105
+ |---|---|
106
+ | `--scope self|children|hierarchy` | Expand from the repo/session account for read/discovery. Exact-id lookups usually default to `children`; broad searches default to `self` unless widened. |
107
+ | `--target-account-id ID` | Exact owner/execution account when already known. Required by mutating tools. |
108
+ | `--account-ids 1,2,3` | Explicit bounded owner list. The platform verifies every id against the scope root. |
109
+ | `--anchor-account-id ID` | Path-disambiguation anchor for multi-parent account relationships. |
110
+
111
+ The CLI merges these into `--input`; a value already present in `--input` wins. Tool responses echo
112
+ `scopeRootAccountId`, `scope`, `accountIds`, and, when an exact owner is discovered,
113
+ `resolvedTargetAccountId`. Feed that returned owner to `mcp_firestore_patch`, action/test runs, and browser
114
+ tokens. Mutating tools do not infer or fan out writes.
115
+
116
+ The implicit account ceiling is intentionally different by shape: broad searches stay capped at 100 accounts
117
+ unless the tool says otherwise, while exact-id discovery may span up to 1000 accounts by default. If a broad
118
+ tool returns `scopeTooBroad`, narrow with `--target-account-id`, `--account-ids`, or a smaller `--scope`.
119
+
120
+ `mcp_firestore_search` handles exact Firestore document ids. `mcp_index_search` handles fuzzy/semantic
121
+ lookup through Vertex. `mcp_bigquery_query` handles warehouse lookup/query with server-resolved
122
+ `{table_current}`/`{table}` placeholders and the scoped `{account_filter}` predicate. BigQuery is a prod
123
+ analytics surface, so use `--data-mode prod` when you intend to query it.
124
+
125
+ Poll a CLI-transport async call (mechanism 2) by call id:
126
+
127
+ ```bash
128
+ remits-cli tool status --call-id <callId> --data-mode prod
129
+ ```
130
+
131
+ Pass `--wait true` to have the CLI process poll locally until the transport call completes (short polling
132
+ requests instead of one long HTTP connection):
133
+
134
+ ```bash
135
+ remits-cli tool --name "some_long_tool_without_its_own_async" --async true --wait true --input '{...}' --data-mode prod
136
+ ```
137
+
138
+ Stacking both (`--async true` **and** `executionMode:"async"`) works but is redundant: the tool's
139
+ `actionRunId`/`agentRunId`/`sessionId` then appear only in the polled completed `result`, not in the CLI
140
+ start response — which is why the start response looks "incomplete." Pick one mechanism.
141
+
142
+ `--timeout-ms <ms>` controls the per-request HTTP timeout. Prefer async execution over a large timeout for
143
+ multi-minute work so the server task is not tied to one HTTP connection.
144
+
145
+ ### Data Mode
146
+
147
+ Controls whether you work with test data or production data. **Default is `test`.**
148
+
149
+ ```bash
150
+ remits-cli data-mode # Show current mode
151
+ remits-cli data-mode set prod # Switch to prod for investigations
152
+ remits-cli data-mode set test # Switch back to test for development
153
+ ```
154
+
155
+ ## Command Reference
156
+
157
+ ```
158
+ remits-cli auth [--base-url URL] [--account-id ID] [--data-mode test|prod]
159
+ remits-cli sessions [list|remove] [--account-id ID]
160
+ remits-cli config [set] [--agent claude|codex|gemini]
161
+ remits-cli agent serve [--worker-agent claude|codex|gemini] [--max-concurrent N] [--mode edit|investigate] [--label NAME] [--data-mode test|prod]
162
+ remits-cli agent workers [--json]
163
+ remits-cli agent register [--label NAME] [--data-mode test|prod] [--account-id ID] [--max-concurrent N]
164
+ remits-cli agent work [--wait SECONDS] [--json]
165
+ remits-cli agent status [--state idle|working|paused] [--ticket ID] [--activity "..."] [--step "..."]
166
+ remits-cli agent list [--account-id ID] [--json]
167
+ remits-cli agent map [--account-ids 1,4] [--json] # who is EDITING which repository, from which checkout/branch/staging lane
168
+ remits-cli agent release
169
+ remits-cli ticket read|accept|status|progress|complete|release|reopen|assign|planning --ticket ID [--status S] [--resolution "..."] [--summary "..."] [--category C] [--assignee EMAIL] [--workstream VALUE] [--planned-in VALUE] [--board-stage VALUE] [--rank N] [--size VALUE] [--blocked-by VALUE] [--notes "..."]
170
+ remits-cli ticket lease|unlease|force-unlease --ticket ID [--reason "..."] # force-unlease breaks SOMEBODY ELSE'S lease; operator only
171
+ remits-cli ticket where --ticket ID # WHERE this work is: repo account, checkout, branch, staging lane, live lease + holder's location, claim, your phase
172
+ remits-cli ticket ask --ticket ID --question "..." [--context "..."] [--to WHO] # park on a human decision
173
+ remits-cli ticket answer --ticket ID --message "..." [--route false] # answer it (alias: reply); re-routes by default
174
+ remits-cli ticket message --ticket ID --message "..." [--to a@x,b@y] [--subject "..."] [--channel email] # PUBLIC — the requester reads it
175
+ remits-cli ticket note --ticket ID --message "..." # INTERNAL — the next worker and a reviewer read it
176
+ remits-cli ticket deliver --ticket ID --channel email --to a@x [--template T] [--subject "..."] [--idempotency-key K] # ask for it to be SENT
177
+ remits-cli ticket deliveries --ticket ID [--channel email] # what is queued to go out, and what already went
178
+ remits-cli ticket delivered --ticket ID --delivery-id ID | ticket delivery-failed --ticket ID --delivery-id ID --reason "..."
179
+ remits-cli ticket tag --ticket ID --tags a,b # make a cluster of near-identical tickets visible as one
180
+ remits-cli ticket artifact --ticket ID --type TYPE --label "..." [--url U | --content "..."]
181
+ remits-cli ticket participant --ticket ID --email E [--role watcher|requester|agent]
182
+ remits-cli ticket field --ticket ID --key K --value V # the ORGANIZATION's own field, outside the planning slots
183
+ remits-cli ticket reclaim [--ticket ID | --account-id ID] [--stale-hours 24] [--apply] # OPERATOR: take back an agent's abandoned ticket
184
+ remits-cli ticket queue --account-id ID [--status ...] [--unrouted] [--unassigned] [--awaiting-response] [--workstream W] [--board-stage S] [--planned-in P] [--search "..."] [--sort-by ...] [--json]
185
+ remits-cli ticket create --account-id ID --subject "..." --type defect|question|task|incident|enhancement [--priority P] [--description "..."] [--tags a,b] [--workstream W] [--affected-component C] [--implementation-account-id ID] [--reference-id KEY]
186
+ remits-cli start [--foreground true] [--port 8787]
187
+ remits-cli stop
188
+ remits-cli status [--base-url URL] [--account-id ID] [--data-mode test|prod] [--json]
189
+ remits-cli whoami [--base-url URL] [--account-id ID] [--data-mode test|prod] [--json]
190
+ remits-cli listen [stop|status] [--foreground true] # compatibility alias
191
+ remits-cli data-mode [set test|prod]
192
+ remits-cli components stage [--branch <name>] [--workspace <name>] [--changed-only] [--data-mode test|prod] [--json|--verbose]
193
+ remits-cli workspace [show | use <name> | use --auto | clear]
194
+ remits-cli components status [--branch <name>] [--component-type <type>] [--component-id <id>] [--json|--verbose]
195
+ remits-cli components clear [--branch <name>] [--component-type <type>] [--component-id <id>] [--all] [--json|--verbose] # id alone scopes to one component when unambiguous (ids are type-local; add --component-type if the same id is staged in multiple families); no filter clears the whole branch scope; --all forces the full wipe
196
+ remits-cli components sync [--branch <name>] [--data-mode test|prod] [--force-tombstones] [--dry-run] [--summary] [--changed-only [--changed-since <ref>]] # gated; on trunk = full repo->DB reconcile, on a variant branch = ComponentVariant overlays only
197
+ remits-cli components commit [--message "msg"] [--data-mode test|prod] [--force-tombstones]
198
+ remits-cli components branches [--json] # branches carrying committed variants, with counts + drift
199
+ remits-cli components branch <name> [--json] # one branch: overridden / added / removed, drift flags, subscribers
200
+ remits-cli components branch <name> --diff <componentId> --component-type <kind> [--json]
201
+ remits-cli components branch <name> --subscribers [--json]
202
+ remits-cli components branch <name> --subscribe <accountId> [--parent-account <id>] [--domain <host>] [--dry-run] [--confirm-primary-edge] # make an account resolve this branch
203
+ remits-cli components branch <name> --unsubscribe <accountId> # return that account to trunk
204
+ remits-cli components branch <name> --retire [--force] # delete the branch's overlays
205
+ remits-cli test run --test <id|name> [--branch <stagingScope>] [--names "a|b"] [--watch true|false] [--data-mode test|prod] [--as-account <ID>] [--variant-branch <name|none>]
206
+ remits-cli token [--path <embeddablePathOrId>] [--data-mode test|prod] [--as-account <ID>] [--variant-branch <name|none>]
207
+ remits-cli token inspect --token <token|tokenKey|URL> # inspect token metadata, safety/dataMode evidence, and full context
208
+ remits-cli tools [--branch <name>] [--data-mode test|prod] [--variant-branch <name|none>]
209
+ remits-cli tool --name <toolName> [--branch <name>] [--input "{...}"] [--data-mode test|prod] [--variant-branch <name|none>] [--timeout-ms 60000] [--async true --wait true]
210
+ remits-cli tool status --call-id <callId> [--data-mode test|prod]
211
+ ```
212
+
213
+ For tests specifically:
214
+ - If `--data-mode` is omitted, `remits-cli test run` uses `test`.
215
+ - `--names` is `|`-delimited (a comma still splits a single value) and may be repeated; an unmatched
216
+ selector fails the run instead of reporting zero cases as success.
217
+ - `--as-account <ID>` runs AS a descendant subscriber so its edge selects the component branch
218
+ (*"what does customer X get?"*); `--variant-branch <name>` probes a branch from any checkout
219
+ (*"what does branch Y look like?"*), and `--variant-branch none` forces production/subscription semantics.
220
+ Omit both and the working tree decides — see `branch-variants.md`.
221
+ - `--branch <stagingScope>` on `test run` selects the Redis staging namespace only. It is useful with
222
+ `--variant-branch none` when an existing staged cache on the real git branch would shadow committed trunk
223
+ or variant rows. On `components sync` / `commit`, `--branch` is different: it names the GitHub branch to
224
+ reconcile.
225
+ - `--force-tombstones` is only for non-trunk variant syncs, when missing trunk component files are known,
226
+ intentional tombstone overrides. It is rejected on trunk.
227
+ - `--dry-run` is only for `components sync` on non-trunk variant branches. It reports the variant write
228
+ plan without writing rows, caching the sync SHA, or clearing staging.
229
+ - `--summary` on `components sync --dry-run` prints compact counts, removals/tombstones, skipped items, errors,
230
+ and warnings instead of the full override/add/remove payload.
231
+ - **Fail-closed sync gates.** On non-trunk variant branches these flags now force a server dry-run first,
232
+ evaluate that plan before any overlay row is written, and only then run the mutating sync when the plan
233
+ passes. On trunk, there is no safe dry-run plan, so do not treat these as scoped commit controls:
234
+ - `--changed-only` — fail unless every planned write is a component **this checkout actually changed**.
235
+ This is the strongest guard against a sync that quietly rewrites components you never touched. It
236
+ also fails when the checkout is not a git working tree, because "git could not answer" must never
237
+ be read as "nothing changed".
238
+ > **Pair it with `--changed-since <ref>` after you have committed.** On its own `--changed-only`
239
+ > reads UNCOMMITTED edits, and the documented flow commits and pushes *before* syncing (sync reads
240
+ > the pushed remote, so it cannot see uncommitted work at all) — so the changed set is empty at
241
+ > exactly the moment the gate runs, and it refuses the whole plan. `--changed-since origin/main`
242
+ > (or the commit you branched from) makes the changed set the components your commits touched.
243
+ > The refusal message says this when it detects the empty-set case.
244
+ - `--fail-on-removed` — fail if the plan removes or tombstones anything.
245
+ - `--expected-removed <type:id>` — whitelist the removals you intend (repeatable, or comma-delimited,
246
+ e.g. `--expected-removed action:5,reader:9`). It **implies** `--fail-on-removed`, so any removal you
247
+ did not name fails the sync.
248
+ - `--fail-on-errors` — fail if the server reported any per-component sync error.
249
+ - `--names-only` — dry-run and print only `BUCKET type:id name` lines for the planned writes, then stop
250
+ without writing overlays.
251
+
252
+ A good default for an unattended promotion is:
253
+ `remits-cli components sync --summary --changed-only --fail-on-errors`
254
+
255
+ ### Prod banners and retryable failures
256
+
257
+ - Every command that can touch production (`tool`, `test run`, `components sync`) prints a `PROD DATA`
258
+ banner naming the operation, the resolved account, and the host — and distinguishes a live **WRITE**
259
+ from a live **READ** and from a **DRY RUN**. `remits-cli tool` also prints an explicit **TEST DATA WRITE**
260
+ banner for mutating tool calls in the test lane, including multi-action tools such as
261
+ `mcp_account_user_admin` where the write is signaled by `input.action` (`account_create`, `user_update`,
262
+ `edge_update`, etc.). If you see a WRITE banner you did not intend, stop.
263
+ - A tool call that fails **in the platform runtime** rather than in the tool (Groovy reflective dispatch
264
+ of a runtime-compiled component, an empty connection pool, a Redis reconnect, a lock-wait timeout)
265
+ now comes back as HTTP `503` with `failureClass: "transient_infrastructure"` and `retryable: true`,
266
+ and the CLI prints `TRANSIENT INFRASTRUCTURE FAILURE (retryable)`. Retry that **once**; prefer an
267
+ idempotent input if the tool has side effects. A genuine tool error stays HTTP `500` with
268
+ `failureClass: "tool_error"` — do **not** retry it, fix the input or the component.
@@ -0,0 +1,175 @@
1
+ # Component Integrity: Repo to Database Reconciliation
2
+
3
+ > A `remits-cli` skill reference. **Load this when** you are about to run `components sync` or `components commit`, or a sync reported something you did not expect. This is the highest-impact failure mode in remits-cli.
4
+ >
5
+ > The table of contents below carries **real line numbers** (`- L84 Some Heading`), resolved when
6
+ > this file is installed, so they are never stale. Read the head, pick your sections, and offset-read
7
+ > only those. The entry text is the heading verbatim, so it also greps.
8
+
9
+ ## Table of Contents
10
+
11
+ - [Component Integrity Rules: Repo ↔ Database Reconciliation (read before any sync/commit)](#component-integrity-rules-repo--database-reconciliation-read-before-any-synccommit)
12
+ - [How the platform reconciles the repo into the database (the mechanism you must understand)](#how-the-platform-reconciles-the-repo-into-the-database-the-mechanism-you-must-understand)
13
+ - [The surfaces and their intended behavior](#the-surfaces-and-their-intended-behavior)
14
+ - [Intended workflows](#intended-workflows)
15
+ - [Pre-sync safety check (confirm ALL before `components sync` or `components commit`)](#pre-sync-safety-check-confirm-all-before-components-sync-or-components-commit)
16
+ - [If something looks wrong — stop, don't paper over](#if-something-looks-wrong--stop-dont-paper-over)
17
+
18
+ ## Component Integrity Rules: Repo ↔ Database Reconciliation (read before any sync/commit)
19
+
20
+ Component source-of-truth mistakes are the highest-impact failure in remits-cli. A repo/DB mismatch can
21
+ hard-delete live components, spawn duplicates, renumber files, or leave the database and repo describing
22
+ different implementations. These rules override the normal fast loop whenever they conflict.
23
+
24
+ ### How the platform reconciles the repo into the database (the mechanism you must understand)
25
+
26
+ > **First, check which branch you are on.** Everything in this section describes a **TRUNK** sync. Syncing
27
+ > from a **non-trunk branch** is a different, much safer operation — it writes `ComponentVariant` overlays
28
+ > only and can never create, delete, rename, or overwrite a live component row. Run
29
+ > `remits-cli components status` to see which mode your working tree is in, and read
30
+ > `branch-variants.md` for the variant-branch rules (which have their own hazard: tombstones).
31
+
32
+ `remits-cli components sync` (and the sync phase of `components commit`) calls
33
+ `GitHubClient.syncFromRepository`. On the account's **trunk branch** it is a **full two-way reconcile in
34
+ which the GitHub remote is authoritative over the database.** It reads the **remote repo ZIP — not your
35
+ local working tree** — and:
36
+
37
+ - **Match / update:** each component is matched to a DB row by the **numeric id prefix of its files**
38
+ (`58_x.groovy` → component 58), not by name. Matching files overwrite that component's DB fields
39
+ (source/schema/html/etc.).
40
+ - **Rename:** changing the component's `name:` in `.meta.yml` is supported as a normal update **as long as
41
+ the numeric id prefix stays the same**. On staging, the CLI updates the id/name cache aliases and prunes
42
+ stale old-name aliases for that id. On trunk sync, the platform canonicalizes the repo filenames to the
43
+ current component name (`58_OldName.groovy` with `name: New Name` becomes `58_NewName.groovy`, plus
44
+ sidecars) and reports those moves in `syncResults.renamed`.
45
+ - **Create:** a file whose id prefix is **not** a live component on the account — including any `new_*` file —
46
+ is created as a **brand-new DB row with a fresh server-assigned id**, and the platform renames the repo files
47
+ to that id (the `Rename X→Y after component creation` / `Delete old file` commits).
48
+ - **Delete:** after the create/update pass, **any live DB component whose id has no matching repo file is
49
+ hard-deleted** (`deleteMissingComponentsFor`), in reverse-dependency order. This runs only when the ZIP
50
+ "looks healthy" (contains `account-info.json` or `README.md`). Exempt from deletion: `auxiliary` components,
51
+ README-purpose prompts, and AGENT-purpose prompts.
52
+
53
+ > ### `auxiliary: true` opts a component OUT of the repo entirely — in BOTH directions
54
+ >
55
+ > This is a silent trap, so know it before you author a sidecar. `auxiliary: true` does not merely
56
+ > "de-emphasize" a component:
57
+ >
58
+ > - **Repo → platform:** the sync **skips the file outright**. A `new_*` component whose `.meta.yml` says
59
+ > `auxiliary: true` is never created, so it **never gets a real id** and the file is never renamed. It
60
+ > looks like the sync silently ignored your work — because it did.
61
+ > - **Platform → repo:** the component's save hooks skip pushing source to GitHub, and repo initialization
62
+ > omits it.
63
+ > - It is also excluded from `getInformation()` (so AI agents do not discover it) and exempt from the
64
+ > deletion pass above.
65
+ >
66
+ > **Use `auxiliary: true` only for genuinely throwaway components** — ad-hoc reports, experiments, and the
67
+ > ephemeral fixtures a Test creates and deletes at runtime (those are created in Groovy with
68
+ > `auxiliary: true` and must never touch the repo).
69
+ >
70
+ > **Use `auxiliary: false` for anything durable** — above all a Test suite that is a regression guard. If you
71
+ > want it versioned in git, addressable by a stable id, or discoverable by another agent, it is not
72
+ > auxiliary. Symptom to recognize: *"I added `new_Foo.groovy`, synced, and it neither appeared on the account
73
+ > nor got renamed."* Check the sidecar's `auxiliary` flag first.
74
+
75
+ **The single most important consequence:** the id in a component's **filename is load-bearing**. If a file's id
76
+ no longer matches its DB row (a renumber or move across ids), the next sync will **create a duplicate at the
77
+ new id and hard-delete the original at the old id**. If a component's files are missing from the repo at sync
78
+ time, that component is **hard-deleted from the DB**. This is exactly how a prior session deleted live schemas
79
+ and an embeddable.
80
+
81
+ **Therefore: never renumber, rename-across-ids, or remove component files as a side effect.** Name-only
82
+ renames are fine when every file keeps the same numeric id; either rename the local filename stem yourself or
83
+ let trunk sync canonicalize it from `.meta.yml`. Before any sync, the repo must already mirror the live DB:
84
+ every live component present at its real id, and nothing extra.
85
+
86
+ ### The surfaces and their intended behavior
87
+
88
+ | Command | What it touches | Danger |
89
+ |---|---|---|
90
+ | `remits-cli components stage` (alias: deprecated `push`) | **Redis staging cache only.** Never mutates the DB or git. The safe iteration surface. | none |
91
+ | `remits-cli components status` | Reads this lane's staging scope (account/user/branch/workspace) and branch resolution, and lists every other lane on the branch. | none |
92
+ | `remits-cli components clear` | Clears THIS lane's staging cache without changing DB or git. Never touches another workspace lane. | none |
93
+ | `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** |
94
+ | `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) |
95
+ | `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** |
96
+
97
+ Key implications:
98
+ - **`stage` is always safe** — stage and test as much as you want; it never reconciles or deletes.
99
+ - **`components commit` is the most dangerous command**, not a mere convenience wrapper: it `git add -A`
100
+ commits and pushes whatever is in the working tree, then immediately syncs. Never run it while the tree
101
+ contains drift or unexplained changes. Prefer the explicit, observable
102
+ `git commit → git push → components sync → git pull` sequence so each phase can be inspected.
103
+ - **`components sync` acts on the pushed remote**, so local edits are invisible to it until committed **and
104
+ pushed**, and a drifted **remote** is dangerous even when your local tree looks fine.
105
+ - After a successful non-dry-run `components sync` / `components commit`, the server clears the full
106
+ staging scope for that lane (account/user/branch/workspace). This is the expected clean state: old Redis aliases should not keep shadowing
107
+ the newly synced DB rows. `components sync --dry-run` intentionally leaves staging untouched.
108
+
109
+ ### Intended workflows
110
+
111
+ **Change existing components (normal path):**
112
+ 1. Edit files under `components/` **keeping each component's existing numeric id** (use `new_*` only for
113
+ genuinely new components). To rename a component, update `name:` in its `.meta.yml`; keep the id prefix
114
+ fixed. Renaming the file stem is optional before trunk sync because the platform will canonicalize it, but
115
+ doing it locally keeps the working tree easier to read.
116
+ 2. `remits-cli components stage` → verify in test mode. Iterate (edit → stage → run).
117
+ 3. When ready to promote: pass the pre-sync safety check below, then
118
+ `git add -A && git commit && git push`, `remits-cli components sync`, `git pull --ff-only`.
119
+
120
+ **Create a new component:** add `new_Name.groovy` (+ `.json` / `.meta.yml` as applicable). Sync assigns the
121
+ durable id and renames the files. Standalone Prompts live in `components/prompts/new_Name.md`, and their
122
+ sidecar must include `name`, `summary`, `description`, and `purpose` (usually `CUSTOM`). AGENT prompts do
123
+ not live there; they are the `.md` sidecar beside the Utility in `components/agents/`. Do not create a
124
+ direct database row to work around an id/name mismatch, and never create a replacement for a component
125
+ that was unexpectedly deleted or renumbered.
126
+
127
+ **Delete a component (deliberate only):** remove **all** of that component's files from the repo, confirm via
128
+ `git status` that only those files are gone, then sync — the delete phase removes exactly that DB row. Deletion
129
+ is a real, supported outcome of a missing file, which is precisely why an *accidentally* missing or renamed
130
+ file is catastrophic.
131
+
132
+ ### Pre-sync safety check (confirm ALL before `components sync` or `components commit`)
133
+
134
+ - **You know which sync mode this branch selects.** `remits-cli components status` states it outright. On a
135
+ variant branch the id/delete/renumber checks below apply to the **overlay set** instead: confirm every
136
+ component absent from the branch is *meant* to be tombstoned for subscribers.
137
+ - The user intends durable platform promotion now — not just local edits, staging, or verification.
138
+ - `git status --short` shows only intended changes; every rename/delete is explained. **No component file has
139
+ been renumbered to a different id.**
140
+ - Local branch is committed and pushed; sync will read the intended remote commit.
141
+ - Local filenames and live inventory (`mcp_account_view`) **agree on id and name for every component**: no live
142
+ component appears locally under a different id, and no expected component is missing a repo file.
143
+ > **Do not run this comparison against `account-info.json` alone — it will report false orphans.** That
144
+ > file omits `auxiliary: true` components by design, so every auxiliary component looks like a repo file
145
+ > with no DB row, i.e. exactly the "a trunk sync will CREATE a duplicate" signal this check exists to
146
+ > catch. It also omits README- and AGENT-purpose Prompts, which live at the repo root and as `.md`
147
+ > sidecars in `components/agents/` rather than in `components/prompts/`, so they look like DB rows with
148
+ > no repo file — the "will be DELETED" signal. Both are benign. Before treating a flagged component as
149
+ > drift, confirm against the live row: `mcp_component_view`, or
150
+ > `mcp_run_action controlAction:"describe"` for an Action. A component that answers is not an orphan.
151
+ - You can state the expected create/update/delete set. **If any delete or renumber is unexpected, stop.**
152
+
153
+ ### If something looks wrong — stop, don't paper over
154
+
155
+ If sync reports unexpected `deleted` / `created` / `renamed`, uniqueness errors, or missing components — or you
156
+ discover id drift — **stop. Do not re-run sync, do not `components commit`, and do not create replacement
157
+ components to "make ids line up" or replace a deleted component.** Those actions compound the corruption.
158
+ Preserve the repo-local session log and tool responses, and reconcile source-of-truth first.
159
+
160
+ **Safe recovery pattern (repo ↔ DB drift):**
161
+ 1. Establish DB truth: `mcp_account_view` for the full live inventory; `mcp_component_view` to confirm and read
162
+ exact sources.
163
+ 2. Fix the **local tree to mirror the live DB** — rename component files back to their real DB ids, reassemble
164
+ any split components, remove orphan/duplicate files, and **refresh any local source that differs from the
165
+ live DB** (the DB is the running truth; a stale local file would overwrite good DB source on sync).
166
+ 3. Keep files for any components that were wrongly deleted so sync **re-creates** them (new ids are fine —
167
+ schemas are keyed by title, agents link tools by name).
168
+ 4. Make the remote authoritative **non-destructively**: commit the corrected tree, then
169
+ `git merge -s ours origin/<branch>` (keeps your tree, supersedes drifted remote history) and a fast-forward
170
+ `git push` — no force-push.
171
+ 5. Run **one** `components sync`: it updates everything to identical, creates the missing components, and
172
+ deletes nothing. Verify with `mcp_account_view`.
173
+
174
+ If the mismatch is a genuine platform/tooling defect (not agent drift), follow the Back-Stage Escalation
175
+ Workflow in `troubleshooting.md` instead of improvising.