@remits/remits-cli 0.1.113 → 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,165 @@
1
+ # Account Targeting and Resolution
2
+
3
+ > A `remits-cli` skill reference. **Load this when** you need to know which account and which repo a piece of work belongs to, why a request resolved the way it did, or whether a record is test or production data.
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
+ - [Account Targeting Model](#account-targeting-model)
12
+ - [Read the shape first](#read-the-shape-first)
13
+ - [Which repo does the work belong in](#which-repo-does-the-work-belong-in)
14
+ - [Repo selection rules](#repo-selection-rules)
15
+ - [Account Resolution: how a request travels the account graph](#account-resolution-how-a-request-travels-the-account-graph)
16
+ - [Seeing an account's edges](#seeing-an-accounts-edges)
17
+ - [When a subscription "doesn't work"](#when-a-subscription-doesnt-work)
18
+ - [The same block answers the non-branch questions](#the-same-block-answers-the-non-branch-questions)
19
+
20
+ ## Account Targeting Model
21
+
22
+ **Establish the account's shape before you touch anything.** Which repo you work in, which account you run
23
+ against, and where a fix belongs are answered by the account's structure — never by its name.
24
+
25
+ The account model itself — types, component inheritance, primary vs membership edges, the three independent
26
+ edge properties, the user model — is in the always-loaded `platform-overview.md` and in depth in
27
+ `features/account-management.md` (`mcp_get_guide`). What follows is only what changes **what you type**.
28
+
29
+ ### Read the shape first
30
+
31
+ `account-info.json` (in a repo) and `mcp_account_view` (remotely) both carry a `resolution` block — the one
32
+ place these facts appear. Field-by-field detail is under **`mcp_account_view`** in `tool-reference.md`. The
33
+ four that decide a CLI action:
34
+
35
+ | Read | To decide |
36
+ |---|---|
37
+ | `role` + `summary` | `OWNER` (the files here **are** its components) vs `SUBSCRIBER` (it resolves another account's components under a variant branch). Read this before you touch anything. |
38
+ | `type` | whether this repo is where the change belongs — see below |
39
+ | `resolvedDatabaseName` | where its data actually lands. **Check this first when documents are "missing".** |
40
+ | `relationships` | every link upward, primary first, each with its own `branchName` / `databaseName` / `domainName`. **More than one entry means the account can legitimately resolve differently depending on the path a request travelled** — establish which one a failing request used before comparing behavior. |
41
+
42
+ Two more, easily confused: top-level **`componentBranches`** lists the variant branches this account
43
+ **owns**, with drift and subscriber counts — check it before editing a shared component. And
44
+ `resolution.branchName` is the **repo's trunk sync branch**, *not* a component-variant branch.
45
+
46
+ ### Which repo does the work belong in
47
+
48
+ | Situation | Target |
49
+ |---|---|
50
+ | Feature, enhancement, shared behavior fix | usually the owning `PLATFORM` / `PRODUCT` account — **not** the `CLIENT` that reported it |
51
+ | Production investigation, client-specific data issue | the affected `CLIENT` account's data and runtime history |
52
+ | Both | confirm the symptom on the `CLIENT`, then move to the owning repo to change code |
53
+
54
+ ### Repo selection rules
55
+
56
+ - **Inside the target implementation repo**: read `account-info.json` and inspect `components/` directly.
57
+ - **Inside one repo but supporting a different account**: switch to that account's repo if it exists;
58
+ otherwise use `mcp_account_view` / `mcp_component_view` / `mcp_component_grep`.
59
+ - **Outside any repo**: rely on the tools, and `mcp_get_guide` for the front-stage guides.
60
+ - **Never create a new local repo/directory just because a ticket references an account name.** Resolve the
61
+ account type and parent hierarchy first, and work only from an existing indexed repo unless the user
62
+ explicitly asks you to clone one.
63
+
64
+ For access questions — "who can see this client account?", "why does this user see the wrong data?" — use
65
+ `mcp_account_user_admin` first (`action:'users'`, `action:'user'`, or `action:'user_update'`). Use
66
+ `mcp_sql_query` only when you need raw join-table investigation. Remember a user's custom fields are stored
67
+ **per bound account**, so the same person can differ per account.
68
+
69
+ **Test-data flags are first-class safety evidence.** `Account.testAccount` and `User.testUser` are set by
70
+ the `account(...)` / `user(...)` factories when the execution data lane is `test` (which is how
71
+ `mcp_account_user_admin` creates); direct inserts such as `new Account(...).save()` are also flagged by the
72
+ domain `beforeInsert` hook in the test lane. Prod-data creates leave them false. Updating an existing real
73
+ account/user in test mode does not convert it into test data, though its Firestore extension-field writes
74
+ still go to the test lane. `Object.testMode` /
75
+ `Event.testMode` / `Alert.testMode` (and `testMode` inside test-lane Audit documents) identify lifecycle
76
+ rows in the test data lane. Agent-facing surfaces expose these fields:
77
+
78
+ - `account-info.json`, `account-hierarchy.json`, and `mcp_account_view`: `resolution.testAccount` for the
79
+ described account, and `testAccount` on returned hierarchy nodes.
80
+ - `mcp_account_user_admin`: `testAccount` on `hierarchy`, `account`, and `account_create` results;
81
+ `testUser` on `users` / `user` results.
82
+ - `mcp_record_listing`: top-level `dataMode` (the lane it searched — listings are **filtered** by lane,
83
+ so `totalItems:0` in the wrong lane reads exactly like "no such record"), plus `testMode` per record.
84
+ - `mcp_record_view`: `record.dataMode` (the lane read in) next to `record.testMode` (the lane the row
85
+ belongs to). This one loads **by id and does not filter**, so those two can legitimately disagree —
86
+ and when they do, that is the finding.
87
+ - `mcp_object_activity`: top-level `dataMode`, `object.testMode`, and `testMode` on Event/Alert
88
+ timeline entries.
89
+ - `mcp_event_diagnostics`: top-level `dataMode` and `result.event.testMode`.
90
+ - `remits-cli token inspect`: owner `account.testAccount` and `user.testUser`, plus a `safety` block
91
+ carrying `dataMode`, `dataModeDeclared`, and an explicit warning when the token does not declare one.
92
+ - `remits-cli whoami`: the resolved account / user / branch / lane / host tuple for the **next tool
93
+ call**. It does not describe `remits-cli test run`, which ignores the stored session lane — see below.
94
+
95
+ Two surfaces deliberately have **no** lane flags, and both mislead if you forget it:
96
+
97
+ - **`mcp_sql_query` reads MySQL directly and is lane-blind.** `object` / `event` / `alert` come back with
98
+ **both lanes mixed**, and `user` / `account` with test fixtures mixed into real records. Filter
99
+ explicitly — `test_mode = 0`, `test_user = 0`, `test_account = 0` — or use the purpose-built tool.
100
+ - **Persisted AI session rows** store no durable per-grouping `testMode` / `dataMode`. Use
101
+ `mcp_ai_session_search.dataMode` as the current execution lane only, never as proof of the historical
102
+ grouping's lane.
103
+
104
+ If any of those fields contradict the lane you intended, stop and rerun the command with an explicit
105
+ `--data-mode test` or `--data-mode prod`. Never infer prod/test from an account name, URL, branch name, or
106
+ the mere existence of a created account.
107
+
108
+ **A tool's `dataMode` input never widens the lane.** Tools that accept a `dataMode` argument clamp it
109
+ against the lane the *command* was launched with: it may narrow `prod` -> `test`, never escalate
110
+ `test` -> `prod`. So `--data-mode test --input '{"dataMode":"prod"}'` stays in **test**, and the response's
111
+ `dataMode` — not your input — is the truth. To reach prod data, pass `--data-mode prod` on the command
112
+ line. (Under MCP, the launch lane is the caller's own `dataMode` argument, which defaults to `prod`.)
113
+
114
+ ## Account Resolution: how a request travels the account graph
115
+
116
+ Component inheritance, branch variants, and where data physically lives are all decided by **how the
117
+ current request reached the executing account**. Read this before debugging *"my subscriber isn't picking
118
+ up the branch"* or *"why is this account reading the wrong collection"* — those are almost always
119
+ resolution questions, not component bugs.
120
+
121
+ > The model behind it — the linear inheritance walk, the ambiguity rule, the three orthogonal edge
122
+ > properties, and path-scoped storage namespaces — is in **`platform-overview.md` → *Account Structure***,
123
+ > which is already loaded. What follows is how to *observe* it from the CLI.
124
+
125
+ **The anchor is the branch of the graph you travelled.** At runtime it is `scope_account_id`, stamped onto
126
+ the `Object` / `Event` / `Alert` / `ObjectLog` records a run creates, so async workers re-resolve on the
127
+ same branch. A **null** anchor means "walk the structural chain". Entry points that already know the
128
+ branch supply an anchor; from the CLI you supply it explicitly with `--as-account`, `--variant-branch`, or
129
+ by using the edge's own host.
130
+
131
+ ### Seeing an account's edges
132
+
133
+ ```bash
134
+ remits-cli tool --name mcp_account_view --input '{"accountId": 101}' --data-mode prod
135
+ # then read: resolution.relationships, resolution.resolvedDatabaseName, resolution.componentBranch
136
+ ```
137
+
138
+ `resolution.relationships` returns one entry per structural link, primary first, each carrying its own
139
+ `branchName` / `databaseName` / `domainName`. The hierarchy tree flattens every link into one shape, so
140
+ this block is the **only** place that answers "how many parents does this account really have, and which
141
+ link carries what?"
142
+
143
+ ### When a subscription "doesn't work"
144
+
145
+ 1. Does the account have a primary parent, or is it membership-only? Count `resolution.relationships` and
146
+ see which is `primary: true`. (Membership-only **and** several edges ⇒ ambiguous ⇒ trunk, by design.)
147
+ 2. Which **edge** carries the `branchName`? `remits-cli components branch <name> --subscribers` prints
148
+ `via primary|membership edge -> parent N`.
149
+ 3. Was the run anchored through *that* edge's parent? Re-run with `--as-account <subscriberId>` so the
150
+ account's own edge selects the branch, exactly as production would.
151
+ 4. Check the resolved layer, not the source text: `testComponentSource`, or the `variant:<id>:<hash>`
152
+ compile signature (`branch-variants.md` → *Diagnosing a variant*).
153
+
154
+ ### The same block answers the non-branch questions
155
+
156
+ - *"Why are this account's documents not where I expect?"* → compare `databaseName` vs
157
+ `resolvedDatabaseName`, and check for a `databaseName` on one of the `relationships` edges — it applies
158
+ to everything below that edge.
159
+ - *"Why does this hostname land on the wrong account?"* → compare `domainName` vs `resolvedDomainName` and
160
+ the edge `domainName`. An **edge** host wins over the account's own, and additionally supplies the path
161
+ travelled — which is what makes that edge's branch variants apply.
162
+
163
+ **Users are not part of this graph** (see `platform-overview.md`). Use `mcp_account_user_admin`
164
+ (`action:'users'`, `action:'user'`, or `action:'user_update'`) for user membership and account-scoped user
165
+ fields. Drop to `mcp_sql_query` against `user` / `user_account` only for raw join-table evidence.
@@ -0,0 +1,218 @@
1
+ # Agent Sessions, Service, and Control Center
2
+
3
+ > A `remits-cli` skill reference. **Load this when** you are registering this session as an agent, diagnosing why a routed ticket never started, or a question involves the background service, the control center, or multiple authenticated sessions.
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
+ - [Registering This Session As An Agent](#registering-this-session-as-an-agent)
12
+ - [What registration actually does](#what-registration-actually-does)
13
+ - [What `serve` adds](#what-serve-adds)
14
+ - [Resolving which agent a command means](#resolving-which-agent-a-command-means)
15
+ - [Which agent gets a ticket](#which-agent-gets-a-ticket)
16
+ - [Why a routed ticket might not have started](#why-a-routed-ticket-might-not-have-started)
17
+ - [Background Service and Control Center](#background-service-and-control-center)
18
+ - [Control Center](#control-center)
19
+ - [Configuring the Preferred Agent](#configuring-the-preferred-agent)
20
+ - [Multi-Session Support](#multi-session-support)
21
+
22
+ ## Registering This Session As An Agent
23
+
24
+ `remits-cli agent` is how a terminal session makes itself available to work support tickets. It is
25
+ independent of everything else — no background service is required, and every tab is its own agent.
26
+
27
+ ```bash
28
+ remits-cli agent serve # routable AND autonomously working tickets — the usual choice
29
+ remits-cli agent workers # what this session is running right now
30
+ remits-cli agent list # who else is available across the accounts you cover
31
+ remits-cli agent release # stop serving and stop receiving tickets right now
32
+
33
+ remits-cli agent register # presence ONLY — nothing starts on its own
34
+ remits-cli agent work --wait 300 # ask for tickets routed here (manual loop)
35
+ remits-cli agent status --state working --ticket 22454 --activity "reproducing"
36
+ ```
37
+
38
+ `serve` is `register` plus a supervisor. Everything below about registration applies to both.
39
+
40
+ **Defaults exist so the user does not have to type them.** With no flags, `register` targets the
41
+ production platform (`REMITS_BASE_URL` when set) and the **prod** lane, and claims every account repo
42
+ indexed on this machine. That is a deliberate exception to the CLI's test-first default: registering
43
+ presence mutates no business data, and a test-lane agent is silently useless for support — it appears
44
+ online and can never be routed a production ticket. Every command after `register` reuses the
45
+ platform, lane and identity it registered with.
46
+
47
+ ### What registration actually does
48
+
49
+ - Mints an `agentId` for this session and tells the platform which account repos this machine has
50
+ checked out — read from the machine-wide index (`~/.remits-cli/account-repos.json`), which is why
51
+ the working directory does not matter. The platform **verifies** those claims against what your user
52
+ can access and returns the ones it refused, so "I registered but never get tickets for account 52"
53
+ is answerable from the registration output alone.
54
+ - Starts a small detached heartbeat process **anchored to the agent process that owns this terminal**
55
+ (it walks up the process tree to find `claude`/`codex`/`gemini`, then an interactive shell). When
56
+ that process ends, the heartbeat ends and the session stops being routable within a couple of
57
+ minutes. Closing the tab is a valid way to go offline; `agent release` just makes it immediate.
58
+ - Registers in the session's **data lane**. A `test`-lane run only ever reaches a `test`-lane agent,
59
+ which is what keeps fixture traffic away from a production terminal.
60
+ - Declares **capacity** — how many tickets this session can genuinely run at once (`--max-concurrent`,
61
+ default 1). The router will not exceed it.
62
+
63
+ ### What `serve` adds
64
+
65
+ The same detached process that maintains presence also polls for work. On each poll it publishes the
66
+ tickets it currently has running, renews their claims, and takes at most enough new ones to fill its
67
+ capacity. For each new ticket it launches a headless worker:
68
+
69
+ | | headless invocation | edit mode | investigate mode |
70
+ |---|---|---|---|
71
+ | `codex` | `codex exec --cd <repo>` | `--sandbox workspace-write` | `--sandbox read-only` |
72
+ | `claude` | `claude -p --add-dir <repo>` | `--permission-mode acceptEdits` | `--permission-mode plan` |
73
+ | `gemini` | `gemini -p` in `<repo>` | `--approval-mode auto_edit` | `--approval-mode plan` |
74
+
75
+ **Which of the three it launches:** `--worker-agent` if you pass it, otherwise **whatever agent this
76
+ session is** (detected from the process the agent anchored to — which finds nothing in a plain tab),
77
+ otherwise `~/.remits-cli/config.json`'s `agent` (set it with `remits-cli config set --agent NAME`),
78
+ otherwise `claude`. **It prints which it chose and why on startup**, because in the intended
79
+ plain-tab setup the choice comes from a config file you may have set months ago. So running `agent serve` inside a Codex tab gives you Codex workers
80
+ without a flag, and the label the operator sees (`codex@repo`) is resolved the same way — the label
81
+ and the worker are one answer, not two.
82
+
83
+ The brief always arrives on **stdin**, never in argv — it is a page of prose and argv has a hard
84
+ length limit, so an argv brief would fail on exactly the detailed tickets that most need the detail.
85
+ The brief itself is generated by the platform, so all three worker types are told the same thing.
86
+
87
+ **Following a run.** `remits-cli start`'s control center lists every worker; **Follow live** streams
88
+ that run's transcript into the page, rendering commands with their exit codes, file edits, and the
89
+ agent's own messages as distinct things. It keeps working after the worker exits — a finished run is
90
+ usually the one worth reading. For a terminal instead, each worker prints a `tail -f` for its log in
91
+ `~/.remits-cli/workers/`.
92
+
93
+ **There is no terminal to attach to, by design.** A worker is spawned with pipes and runs
94
+ non-interactively (`codex exec`, `claude -p`), so there is no tty and no prompt to type at — the
95
+ whole point is that it needs no supervision. Following the transcript is the way to watch, and it is
96
+ strictly better than a terminal would be: the output is structured, so it can be read as events
97
+ rather than scraped back out of ANSI text.
98
+
99
+ **No worker ever commits.** The brief forbids `git commit`/`git push` and nothing in the supervisor
100
+ runs git — a worker leaves its changes in the working tree and says so on the ticket, for a human to
101
+ review.
102
+
103
+ ### Resolving which agent a command means
104
+
105
+ Order: `--agent-id`, then `REMITS_AGENT_ID`, then the single agent registered for this working
106
+ directory. With several registered and no way to tell them apart, the command **fails and lists the
107
+ candidates** rather than guessing — routing work to the wrong tab is silent, and a message is not.
108
+
109
+ ### Which agent gets a ticket
110
+
111
+ The platform walks a ladder — the ticket's implementation account first (a defect seen on a client is
112
+ usually fixed in the platform repo above it), then the ticket's own account, then its
113
+ `PLATFORM`/`PRODUCT` ancestors — and takes the first account with an available agent. Among those it
114
+ prefers an **idle** agent, then the one that has waited longest, so work spreads across your tabs
115
+ instead of piling onto whichever one most recently ran a command. A `paused` agent stays visible and
116
+ is never routed to, and so is one **at capacity** — those are different facts and stay separate:
117
+ `paused` means a human stopped this session, at-capacity means its workers are all busy.
118
+
119
+ ### Why a routed ticket might not have started
120
+
121
+ In order of likelihood:
122
+
123
+ 1. **The session registered but never served.** `agent register` starts nothing. `agent workers`
124
+ showing none while a ticket is routed here is this.
125
+ 2. **At capacity.** Check `agent workers`; the ticket starts when one finishes.
126
+ 3. **Another session is running it.** A claim held by a different agent blocks it until that claim is
127
+ dropped or expires.
128
+ 4. **No local checkout.** The worker still starts, and its brief tells it to locate the repo rather
129
+ than guess — but if the account genuinely is not on this machine it will say so and stop.
130
+ 5. **It failed twice already** and was released back to the queue. The transcripts in
131
+ `~/.remits-cli/workers/` say why.
132
+
133
+ ## Background Service and Control Center
134
+
135
+ `remits-cli start` runs an optional background service for the **human** watching:
136
+
137
+ - Maintains persistent WebSocket connections to the Remits platform
138
+ - Hosts a localhost browser **control center** (typically `http://127.0.0.1:8787/`)
139
+
140
+ ```bash
141
+ remits-cli start
142
+ remits-cli start --foreground true
143
+ remits-cli status
144
+ remits-cli whoami
145
+ remits-cli stop
146
+ ```
147
+
148
+ Compatibility aliases still exist:
149
+
150
+ ```bash
151
+ remits-cli listen
152
+ remits-cli listen status
153
+ remits-cli listen stop
154
+ ```
155
+
156
+ **The service is not part of ticket delivery.** Agents register and collect work on their own, so the
157
+ dashboard being down never stops a ticket reaching an agent. What the service adds is visibility: it
158
+ scans for `account-info.json` files to rebuild the repo index, keeps one WebSocket per platform URL,
159
+ and holds a PID lock (`~/.remits-cli/listener.pid`) so only one runs per machine.
160
+
161
+ ### Control Center
162
+
163
+ The control center shows, in one browser view:
164
+ - which agent sessions are registered, what each is doing right now, and its recent activity
165
+ - the open support-ticket queue, and which agent each ticket is routed to
166
+ - a control to route a ticket at a specific available agent
167
+ - websocket connection and topic health
168
+ - the discovered account repo index and the important global/per-repo files
169
+
170
+ **What it shows is what the agents see.** The ticket queue comes from the platform's own generic
171
+ endpoint, not from any product's tool, so the control center reads the same on every Remits platform
172
+ and never implies a workflow that a particular product does not have. Product-specific views belong
173
+ in that product's Embeddables.
174
+
175
+ When a user asks a broad or vague question about remits-cli behavior, prefer reasoning from the
176
+ control center state before spelunking individual files.
177
+
178
+ ### Configuring the Preferred Agent
179
+
180
+ ```bash
181
+ remits-cli config # Show current config
182
+ remits-cli config set --agent claude # Use Claude Code (default)
183
+ remits-cli config set --agent codex # Use OpenAI Codex CLI
184
+ remits-cli config set --agent gemini # Use Gemini CLI
185
+ ```
186
+
187
+ The agent preference is stored in `~/.remits-cli/config.json` and applies globally.
188
+
189
+ ## Multi-Session Support
190
+
191
+ 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.
192
+
193
+ ```bash
194
+ # Authenticate for an account (run from its repo, or pass --account-id)
195
+ remits-cli auth
196
+ remits-cli auth --account-id 42
197
+ remits-cli auth --account-id 42 --base-url http://localhost:8080
198
+
199
+ # List all active sessions
200
+ remits-cli sessions list
201
+
202
+ # Remove a session (removes all sessions for the account, or narrow with --base-url / --data-mode)
203
+ remits-cli sessions remove --account-id 42
204
+ remits-cli sessions remove --account-id 42 --base-url http://localhost:8080
205
+ ```
206
+
207
+ You can work in multiple account repos simultaneously across different terminal windows — each uses its own session. You can also be authenticated against different base URLs (e.g., localhost for development and production) for the same account at the same time.
208
+
209
+ Use `remits-cli whoami` when you need a compact proof of the active target before a sensitive operation.
210
+ It prints the resolved Account ID, User ID, current git branch, data mode, and base URL. `remits-cli status`
211
+ prints the same session tuple after the service/dashboard status. Pass `--base-url`, `--account-id`, and
212
+ `--data-mode` when host or lane matters; do not infer those values from the repo directory or account name.
213
+
214
+ **The reported data mode describes the next `tool` / `tools` / `token` call, not `test run`.** It falls back
215
+ to the stored session lane, whereas `remits-cli test run` deliberately ignores that and defaults to `test`
216
+ unless you pass `--data-mode prod` explicitly. So `whoami` can read `prod` while a test run goes to the test
217
+ lane — which is the safe direction, but not the one you would predict from the output alone. `whoami` says
218
+ so in its own output; when a test run genuinely needs prod data, pass the flag.