@datarails-ai/dr-cli 0.0.1-locked → 1.6.71

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.
Files changed (58) hide show
  1. package/README.md +608 -0
  2. package/dist/chunk-DWMCBGQH.js +242 -0
  3. package/dist/cli.js +64468 -0
  4. package/dist/kb-6UWI7Q32.js +21 -0
  5. package/dist/scopes-map.json +4412 -0
  6. package/dist/skills/connector-sandbox/SKILL.md +95 -0
  7. package/dist/skills/datarails-connect-workato/SKILL.md +140 -0
  8. package/dist/skills/datarails-connectors-onboard-connector/SKILL.md +813 -0
  9. package/dist/skills/dr-cli/SKILL.md +659 -0
  10. package/dist/skills/dr-cli/reference/admin.md +796 -0
  11. package/dist/skills/dr-cli/reference/budget-builder.md +151 -0
  12. package/dist/skills/dr-cli/reference/calc-vals.md +73 -0
  13. package/dist/skills/dr-cli/reference/calcmodels.md +76 -0
  14. package/dist/skills/dr-cli/reference/cash.md +61 -0
  15. package/dist/skills/dr-cli/reference/dashboards-widgets.md +85 -0
  16. package/dist/skills/dr-cli/reference/datamappers.md +150 -0
  17. package/dist/skills/dr-cli/reference/desk.md +472 -0
  18. package/dist/skills/dr-cli/reference/filebox-documents.md +373 -0
  19. package/dist/skills/dr-cli/reference/forecast.md +51 -0
  20. package/dist/skills/dr-cli/reference/integrations.md +57 -0
  21. package/dist/skills/dr-cli/reference/lookups.md +168 -0
  22. package/dist/skills/dr-cli/reference/metrics.md +512 -0
  23. package/dist/skills/dr-cli/reference/multi-product.md +180 -0
  24. package/dist/skills/dr-cli/reference/reconciliation-mec.md +76 -0
  25. package/dist/skills/dr-cli/reference/rh-config.md +84 -0
  26. package/dist/skills/dr-cli/reference/safety.md +143 -0
  27. package/dist/skills/dr-cli/reference/spend-control.md +206 -0
  28. package/dist/skills/dr-cli/reference/templates.md +163 -0
  29. package/dist/skills/dr-cli/reference/workflows.md +137 -0
  30. package/dist/skills/dr-error-enrichment/SKILL.md +80 -0
  31. package/dist/skills/dr-error-enrichment/reference/core.md +257 -0
  32. package/dist/skills/dr-error-enrichment/reference/groundcover.md +84 -0
  33. package/dist/skills/dr-error-enrichment/reference/jira-bugs.md +219 -0
  34. package/dist/skills/dr-error-enrichment/reference/safety-backup.md +122 -0
  35. package/dist/skills/dr-error-enrichment-author/SKILL.md +219 -0
  36. package/dist/skills/dr-error-enrichment-improve/SKILL.md +218 -0
  37. package/dist/skills/dr-error-enrichment-maintain/SKILL.md +237 -0
  38. package/dist/skills/dr-error-enrichment-reconcile/SKILL.md +167 -0
  39. package/dist/skills/dr-filebox-api-setup/SKILL.md +170 -0
  40. package/dist/skills/dr-switch-user/SKILL.md +395 -0
  41. package/dist/skills/dr-validate/SKILL.md +392 -0
  42. package/dist/skills/dr-validate/report-template.html +950 -0
  43. package/dist/skills/fx-conversion-matrix/SKILL.md +763 -0
  44. package/dist/skills/fx-conversion-matrix/scripts/_args.mjs +52 -0
  45. package/dist/skills/fx-conversion-matrix/scripts/_xlsx.mjs +241 -0
  46. package/dist/skills/fx-conversion-matrix/scripts/build-matrix.mjs +366 -0
  47. package/dist/skills/fx-conversion-matrix/scripts/gen-mappers.mjs +171 -0
  48. package/dist/skills/fx-conversion-matrix/scripts/rates-to-xlsx.mjs +172 -0
  49. package/dist/skills/fx-onboard/SKILL.md +325 -0
  50. package/dist/skills/mec-table-validation/SKILL.md +383 -0
  51. package/dist/skills/plugins.json +24 -0
  52. package/dist/skills/validate-workato-migration/SKILL.md +167 -0
  53. package/dist/skills/validate-workato-migration/reference/gotchas.md +16 -0
  54. package/dist/skills/validate-workato-migration/reference/staging-orgs.md +26 -0
  55. package/dist/skills/validate-workato-migration/scripts/compare_files.py +255 -0
  56. package/dist/zendeskKb-JPSHVOPH.js +243 -0
  57. package/package.json +56 -9
  58. package/scripts/postinstall.mjs +91 -0
@@ -0,0 +1,180 @@
1
+ # `dr multi-product` — product-content catalog & per-org assignment
2
+
3
+ The `multi-product` microservice (`/api/multi-product/v1/...`) is the
4
+ source of truth for two things:
5
+
6
+ 1. **The catalog of available "product contents"** — every row Datarails
7
+ can possibly assign to an organization, tagged with a `type`
8
+ discriminator (`core_interface`, `dataset`, `product`, …).
9
+ 2. **The per-organization assignment** — which subset of that catalog a
10
+ given org is entitled to, bucketed by `type`.
11
+
12
+ Two read endpoints + one *replace-the-whole-list* write endpoint. The
13
+ write is destructive in spirit (the server overwrites the org's full
14
+ list with whatever body you send) so it's gated behind a two-step
15
+ confirm token — same flow as `dr entities delete`.
16
+
17
+ ## Subcommands
18
+
19
+ All take `--server <key>` (required) and `--account <email>` (when
20
+ multiple identities are stored). Reads accept `--json` for raw
21
+ pass-through; `set` accepts `--json` to emit the server's
22
+ `{"status":"ok"}` ack verbatim.
23
+
24
+ ### Catalog (global)
25
+
26
+ - `dr multi-product product-content list` — list every product-content
27
+ row the service knows about. Renders an `ID | NAME | TYPE` table; use
28
+ `--json` for parseable output. Empty → `(no product contents)`.
29
+ → `GET /api/multi-product/v1/product_content/list`
30
+
31
+ Use this to discover which `(id, name)` pairs are valid for the
32
+ `items` arrays inside the per-org body — names alone don't bind, the
33
+ server matches on the integer `id`.
34
+
35
+ ### Per-organization assignment
36
+
37
+ - `dr multi-product org-products list <org_id>` — show the products
38
+ assigned to one org, grouped by `type`. The default text form prints
39
+ each type bucket as a header with `<id>\t<name>` rows underneath;
40
+ `--json` returns the raw `[{type, items:[{id,name}]}]` shape.
41
+ → `GET /api/multi-product/v1/organizations/<org_id>/products`
42
+
43
+ - `dr multi-product org-products set <org_id> --file <path>
44
+ [--db-only] [--confirm-token <tok>]` — **replace** the org's full
45
+ product list with the JSON in `<path>`. Two-step confirm gated.
46
+ → `PUT /api/multi-product/v1/organizations/<org_id>/products[?db_only=true]`
47
+ → server replies `{"status":"ok"}` on success
48
+
49
+ **The body has replace semantics — anything not in the file is
50
+ removed.** Always read the current state first (`org-products list`)
51
+ and either edit that file or apply your delta on top of it. Sending a
52
+ partial body silently revokes everything you forgot.
53
+
54
+ **`--db-only` controls whether the data importer runs.** Omit it (the
55
+ default) when you want the user to actually have data for the new
56
+ product — the server inserts the catalog row AND kicks off the
57
+ data-import workflow. Pass `--db-only` when you only want the
58
+ product row to exist in the MP DB (e.g. provisioning placeholder /
59
+ fixing an out-of-sync catalog) — the server skips the importer
60
+ entirely. Always ask the user which mode they want before running.
61
+ The plan-phase output prints a `MODE:` line (`full` vs `db-only`) so
62
+ you can double-check before confirming.
63
+
64
+ ## `--file` body shape
65
+
66
+ `org-products set` takes a JSON array of type buckets — identical to the
67
+ GET response, so a round-trip "list → edit → set" works without
68
+ reshaping. Schema:
69
+
70
+ ```json
71
+ [
72
+ {
73
+ "type": "core_interface",
74
+ "items": [
75
+ { "id": 1, "name": "full_fpna" }
76
+ ]
77
+ },
78
+ {
79
+ "type": "dataset",
80
+ "items": [
81
+ { "id": 5, "name": "native_fpna" }
82
+ ]
83
+ },
84
+ {
85
+ "type": "product",
86
+ "items": [
87
+ { "id": 11, "name": "ai_agents" }
88
+ ]
89
+ }
90
+ ]
91
+ ```
92
+
93
+ - Root must be an array (not an object).
94
+ - Each entry needs a non-empty string `type` and an `items` array (may
95
+ be empty to clear that bucket).
96
+ - Each item needs an integer `id` and a string `name`. The server
97
+ matches on `id`; the `name` is for human readability.
98
+ - Parser errors are prefixed with the offending location, e.g.
99
+ `--file[0].items[0].id: expected an integer`.
100
+
101
+ ## Two-step confirm (the `set` gate)
102
+
103
+ `org-products set` mirrors the `delete`-style flow. The token is bound
104
+ to `(resource:'org-products', id:<org_id>, verb:<verb>)`. `<verb>` is
105
+ `replace` for the default full-import flow and `replace-db-only` when
106
+ `--db-only` is passed — a token issued for one mode cannot be reused
107
+ in the other, and a token issued for org 42 cannot be reused against
108
+ org 99.
109
+
110
+ 1. **Plan phase** (no `--confirm-token`): the CLI parses + validates
111
+ the `--file`, prints what it's *about to apply* (one line per type
112
+ bucket with count + `id:name` pairs), and emits the exact confirm
113
+ command with a fresh token. No HTTP call is made.
114
+ 2. **Apply phase**: re-run the command with `--confirm-token <tok>`.
115
+ The body is PUT and the server's `{"status":"ok"}` is shown
116
+ (or emitted as raw JSON under `--json`).
117
+
118
+ Token TTL is 10 minutes — past that, re-run step 1.
119
+
120
+ For prod (`US`/`US2`/`UK`/`CA`/`EU`/`DEMO`), get the user's in-chat "yes" before
121
+ re-invoking with the token; the binary's interactive gate then has the user
122
+ type a challenge word in a dialog, same as any other destructive write — see
123
+ [safety.md](safety.md).
124
+
125
+ ## Workflow recipe — "give this org access to product X"
126
+
127
+ ```
128
+ # 1. Pick the org id (organizations list → find it)
129
+ dr organizations list --server US --json | jq '.[] | {id,name}'
130
+
131
+ # 2. See what's available in the catalog
132
+ dr multi-product product-content list --server US
133
+
134
+ # 3. Read the org's current list as the baseline
135
+ dr multi-product org-products list 42 --server US --json > /tmp/org42.json
136
+
137
+ # 4. Edit /tmp/org42.json to add the new product
138
+ # (e.g. append { "id": 11, "name": "ai_agents" } to the "product" bucket)
139
+
140
+ # 5. Plan phase — review what's about to change
141
+ dr multi-product org-products set 42 --file /tmp/org42.json --server US
142
+
143
+ # 6. Apply with the token printed in step 5
144
+ dr multi-product org-products set 42 --file /tmp/org42.json --server US \
145
+ --confirm-token <tok>
146
+ ```
147
+
148
+ The "always read first" pattern matters here because the PUT replaces.
149
+ Hand-crafting the file without listing first risks dropping buckets you
150
+ didn't realise existed.
151
+
152
+ ## Foot-guns
153
+
154
+ - **Replace, not merge.** `set` overwrites the whole list. Read → edit
155
+ → write. If the user asks to "add product X" or "remove product Y",
156
+ the recipe still routes through a full-list PUT.
157
+ - **`id` is what binds**, not `name`. A typo in `name` is silently
158
+ accepted at parse time. Cross-check ids against `product-content list`.
159
+ - **`type` is free-form**, not a closed enum. The service may add new
160
+ bucket types over time (the catalog is the source of truth) — don't
161
+ hard-code the three documented buckets (`core_interface`, `dataset`,
162
+ `product`) in scripts; iterate whatever the server returns.
163
+ - **Empty body clears everything**. Sending `[]` is treated as a valid
164
+ replace and revokes all assignments. The plan-phase output flags this
165
+ with `new list: (empty — clears all assignments)`; double-check
166
+ before you confirm.
167
+ - **Token binds to org id.** Generated one for org 42, paste it against
168
+ org 99 — the CLI rejects it with `confirm token does not match this
169
+ resource / action`. Re-run step 1 for the correct id.
170
+ - **Token also binds to `--db-only`.** A plan-phase token issued
171
+ without `--db-only` can't be applied with `--db-only` (or vice
172
+ versa) — the CLI rejects it with the same `does not match this
173
+ resource / action` error. Re-run the plan phase with the mode you
174
+ actually want.
175
+ - **Choose the mode deliberately.** `--db-only` is a row-only
176
+ provisioning lever — the server will NOT start the data-import
177
+ workflow that normally fires when a product is added. If the user
178
+ expects their data to actually show up in the new product, you must
179
+ omit `--db-only` (the default). Confirm with the user which they
180
+ want before confirming the plan-phase token.
@@ -0,0 +1,76 @@
1
+ # Reconciliation + MEC close-dates
2
+
3
+ Alias `recon`. For workflow-engine commands (`mec workflow …`) see
4
+ [workflows.md](workflows.md).
5
+
6
+ ## Read
7
+
8
+ - `reconciliation accounts list | entities | entity-currencies | info | progress | settings`.
9
+ - `reconciliation processes dates | accounts`.
10
+ - `reconciliation evidences list | get | process | supporting | file`.
11
+ The v2 verbs (`process`/`supporting`/`file`/`create`) accept either
12
+ `--process <uuid>` **or** `--entity <name> --date <YYYY-MM-DD|YYYY-MM>` (which
13
+ resolves the UUID via the accounts endpoint). The v1 path (`list`, and `file
14
+ --account`) is deprecated and prints a stderr warning.
15
+ - `reconciliation filebox list | get | progress | unlinked`.
16
+ - `reconciliation audit status`.
17
+
18
+ ## Write
19
+
20
+ Account assignment / sign-off (all take the bank-account UUID via
21
+ `--account-uuid` — see the flag note below):
22
+
23
+ - `reconciliation accounts update-settings --file <p>` — admin-only PATCH.
24
+ Two-step confirm; the token binds to a hash of the file's rows, so editing
25
+ the file between plan and confirm invalidates it.
26
+ - `reconciliation accounts set-assignee <account_uuid> --date <YYYY-MM-DD>
27
+ --type Preparer|Reviewer --user-id <n> [--user-name <s> --user-email <s>]` —
28
+ resets any prior sign-off; name/email are auto-fetched if not supplied.
29
+ Two-step confirm: first run prints the current holder + a token; re-run
30
+ with `--confirm-token` to actually write.
31
+ - `reconciliation accounts set-assignee --file <csv> --date <YYYY-MM-DD>` —
32
+ the bulk form, for more than a handful of accounts. Header
33
+ `account_id,type,user_id[,user_name,user_email]`, one row per
34
+ (account, role); blank name/email cells are looked up once per user id.
35
+ One plan and one token cover the whole file (the token binds to a hash of
36
+ the rows and the date). The plan reports rows to change, rows skipped
37
+ because the slot already holds that user, and how many sign-offs the write
38
+ resets. Every account is checked before anything is written, and the
39
+ write goes out in PATCHes of 100 accounts. If one fails, the error says
40
+ how many accounts landed; re-run the same file without a token and the
41
+ new plan covers only the rest. Do not script a loop of single
42
+ `set-assignee` calls for this.
43
+ - `reconciliation accounts clear-assignee <account_uuid> --date <YYYY-MM-DD>
44
+ --type Preparer|Reviewer` — unassigns (preserves due_date, resets sign-off).
45
+ Two-step confirm.
46
+ - `reconciliation accounts set-due-date <account_uuid> --date <YYYY-MM-DD>
47
+ --type Preparer|Reviewer (--due-date <YYYY-MM-DD> | --epoch <n> | --clear)`.
48
+ Two-step confirm.
49
+ - `reconciliation accounts sign <account_uuid> --date <YYYY-MM-DD>
50
+ --type Preparer|Reviewer [--revoke]`. Two-step confirm; sign and revoke
51
+ tokens are not interchangeable.
52
+
53
+ Evidences / filebox:
54
+
55
+ - `reconciliation evidences create --file <path> --account-uuid <uuid>
56
+ --amount <n> [--note <s>] [--name <s>]` — multipart upload of a v2 supporting
57
+ item. `--account-uuid` / `--amount` / `--note` are repeatable and
58
+ index-aligned for attaching to multiple accounts.
59
+ - `reconciliation filebox create --file <p>` (`--effective-since` accepts
60
+ `YYYY-MM` or `YYYY-MM-DD`), `reconciliation filebox delete` (two-step confirm).
61
+
62
+ **Flag note:** the bank-account-scoped subcommands take `--account-uuid <uuid>`
63
+ for the bank-account UUID. (`--account` is reserved CLI-wide for the auth-identity
64
+ selector.)
65
+
66
+ ## MEC close-dates
67
+
68
+ - `mec close-dates get` — the org's close-date map (whole org, or `--year`).
69
+ - `mec close-dates set --file <p>` — admin-only PUT; replaces the org's
70
+ close-date map from a JSON file.
71
+
72
+ ## Customer-facing docs (KB)
73
+
74
+ Help Center → the **"Month End Close"** category. Find current articles with `dr kb search "month end close reconciliation"` (or
75
+ browse `dr kb categories` / `dr kb sections`). Cite the article; don't
76
+ paraphrase from memory.
@@ -0,0 +1,84 @@
1
+ # `dr rh_config` — legacy RH_CONFIG inspection (read-only)
2
+
3
+ RH_CONFIG is the **legacy** mechanism by which a filebox's "config workbook"
4
+ (the Excel attached to the bucket with `is_config=True`) defines its
5
+ TableTemplates. The Excel contains a sheet literally named `RH_Config` that
6
+ the monolith's parser reads via `LEGACY_get_document_data_from_workbook_rh_config`
7
+ (`HippiWeb/Documents/utils_cython.py:233`) to build the templates and their
8
+ LUTs. A template generated from that path carries `is_rh_config: true`
9
+ (true when `TableTemplate.config == ''` server-side).
10
+
11
+ The `rh_config` family is purely read-only — five GETs for inspecting
12
+ legacy state during audits or debugging. No writes; if you need to upload a
13
+ new config workbook or trigger a rescan, use the standard `filebox` /
14
+ `buckets` write surfaces (which the FE drives).
15
+
16
+ ## Subcommands
17
+
18
+ All take `--server <key>` (required) and `--account <email>` (when multiple
19
+ identities are stored). Every read accepts `--json` for raw pass-through.
20
+
21
+ - `dr rh_config config <bucket-id>` — show the config `DocumentVersion`
22
+ attached to a bucket (the workbook with the `RH_Config` sheet). Renders a
23
+ kv summary: version id, document id, name, version number, status,
24
+ created timestamp. `(no config version)` when the bucket has never had a
25
+ config workbook.
26
+ → `GET /api/buckets/<id>/config`
27
+
28
+ - `dr rh_config tables <bucket-id>` — show the config file URL plus the
29
+ table names defined by the workbook (the names of `ACTIVE`, non-archive
30
+ `TableTemplate` rows that belong to the bucket's data model). Useful
31
+ for "what does this filebox's config say it should create?"
32
+ → `GET /api/buckets/admin/<id>/config_update`
33
+
34
+ - `dr rh_config download <bucket-id> [--output <path>]` — download the raw
35
+ config `.xlsx`. Default destination is `bucket_<id>_config.xlsx` in the
36
+ current directory; `--output -` streams bytes to stdout (pipe-friendly).
37
+ → `GET /api/buckets/admin/<id>/file`
38
+ - **Broken — don't use.** The endpoint doesn't accept the CLI's JWT, so the
39
+ command writes the auth login HTML page to disk instead of the workbook
40
+ (exit 0, no error). **Workaround:** get the config version's `id` and
41
+ `document` from `dr rh_config config <bucket-id> --json`, then
42
+ `dr filebox download <document> --doc-version <id> --output <path>`.
43
+
44
+ - `dr rh_config doc-templates <document-id> [--legacy-only]` — list
45
+ templates associated with a document, with the `is_rh_config` flag
46
+ surfaced. `--legacy-only` filters to RH_CONFIG-derived rows (the usual
47
+ ask during a legacy audit). The document id is the `Document` id (not a
48
+ version id, not a bucket id).
49
+ → `GET /api/documents/<id>/template_configs`
50
+
51
+ - `dr rh_config version-templates <version-id> [--v2] [--legacy-only]` —
52
+ list templates referenced by a document version (functions + extables
53
+ combined). `--v2` switches to the v2 path that also reports
54
+ `split_obj_exists`, the indicator the FE uses to show "this version is
55
+ split". The version id is a `DocumentVersion` id (get it from
56
+ `filebox versions <doc_id>`).
57
+ → `GET /api/documents/versions/<id>/get_functions_templates`
58
+ → with `--v2`: `GET /api/documents/v2/versions/<id>/get_functions_templates`
59
+
60
+ ## When to reach for `rh_config` instead of `templates` / `filebox`
61
+
62
+ - "Is this template RH_CONFIG-derived?" → `dr rh_config doc-templates <doc>
63
+ --legacy-only` (the regular `templates list` doesn't render the flag).
64
+ - "What does the config workbook look like for this filebox?" → `dr
65
+ rh_config config <bucket> --json` for the version `id` + `document`, then
66
+ `dr filebox download <document> --doc-version <id>` to grab the .xlsx
67
+ (not `rh_config download` — it saves the login page, see above). Or `dr
68
+ rh_config tables <bucket>` for just the table names.
69
+ - "Did this version reference any legacy-config tables?" → `dr rh_config
70
+ version-templates <vid> --legacy-only`.
71
+
72
+ For non-legacy template operations (sample data, distinct, aggregate,
73
+ create, set field type, …) keep using `dr templates ...` — RH_CONFIG is
74
+ about the legacy plumbing only.
75
+
76
+ ## Why this family is read-only
77
+
78
+ RH_CONFIG is on the deprecation runway: the monolith's
79
+ `utils_cython.py:72` literally says `# !!! this one should be removed
80
+ after getting rid of RH_CONFIG !!`. Writes against the RH_CONFIG path
81
+ exist (uploading a new config workbook, triggering a rescan), but the
82
+ sanctioned way to drive them is the existing FE flow — exposing them in a
83
+ "legacy" CLI family would invite people to keep extending the surface
84
+ instead of migrating off it.
@@ -0,0 +1,143 @@
1
+ # Safety — confirm flow, prod gate, escalation
2
+
3
+ ## Two-step confirm (every `delete`, plus `templates set-field-type`)
4
+
5
+ Running a gated command without a token fetches the target, prints its name +
6
+ key attributes, and emits a short-lived confirmation token. Re-run with
7
+ `--confirm-token <tok>` to actually perform the write.
8
+
9
+ - The token is bound to `(resource, id, verb)`: a token for LUT 12 refuses
10
+ against function 12 — it catches ID typos, not just stray enter-hits.
11
+ - Tokens expire after 10 minutes; the signing secret is per-machine and never
12
+ leaves the local machine.
13
+ - Bulk operations bind the token to a hash of the change set (e.g.
14
+ `templates set-field-type --file`, `cash rules delete-all`), so editing the
15
+ file between plan and confirm invalidates the token.
16
+ - The printed confirm command echoes the plan invocation's `--account`, so on
17
+ a keychain holding several identities for the server it can be pasted
18
+ verbatim — no need to re-add the flag by hand (gap #41).
19
+
20
+ Gated commands include: `dashboards delete`, `datamappers delete`,
21
+ `dynamic-ranges delete`, `extables delete`, `functions delete`, `lut delete`,
22
+ `reports delete`, `storyboards delete`, `metrics delete`, `metrics categories
23
+ delete`, `metrics dimensions delete`, `calcmodels delete|set-flow|recalculate`,
24
+ `reconciliation filebox delete`, `integrations delete`, `integrations it
25
+ delete`, `devices command-delete`, `validate onboarding session delete`,
26
+ `widgets delete`, `cash rules delete|delete-all|reorder|update`,
27
+ `cash hidden-rules upsert|delete`, `forecast` lock/unlock/default/delete/clone
28
+ verbs, `workflow`/`mec workflow` create/update/activate/delete and friends,
29
+ `collection-processes` create/mutate verbs, and the non-`delete` mutations
30
+ `templates set-field-type`, `rescan table`, `features orgs add|remove`,
31
+ `dashboards push`, `filebox push`, and `reconciliation accounts
32
+ set-assignee|clear-assignee|set-due-date|sign|update-settings`. When
33
+ in doubt, run the command without a token and read the plan output.
34
+
35
+ ## Prod write gate (when Claude drives the CLI)
36
+
37
+ Reads never need confirmation. Gated **writes** fall into two tiers (full table:
38
+ `src/commands/_prodGateTiers.ts`):
39
+
40
+ - **Tier A — destructive / irreversible / org-wide.** On a prod tenant (`US`,
41
+ `US2`, `UK`, `CA`, `EU`, `DEMO` — DEMO is customer-facing) the binary requires a
42
+ live human to type a fresh challenge word in a desktop dialog / TTY (see
43
+ "Binary-enforced interactive gate" below). Relay the plan output (target name
44
+ + blast radius), get a clear in-chat "yes, do it", then re-invoke with
45
+ `--confirm-token <tok>`. That dialog IS the attentiveness check — do **not**
46
+ add your own word ritual in chat.
47
+ - **Tier B — reversible / additive / low-blast.** No challenge word on any
48
+ server: token-only, fully scriptable, completable by an agent end-to-end.
49
+ Still relay the plan and get the user's in-chat "yes" before the execute step,
50
+ but it will not pop a dialog.
51
+ - **Non-prod (`DEV`, `DEV-1`, `TEST`, `TEST-1`…`TEST-7`):** a plain `yes` is fine
52
+ for either tier — token only.
53
+
54
+ **Tier A is the smaller set:** every `delete` (across all resources), plus
55
+ `workflow`/`mec workflow` `archive` (and its `delete` alias), `process delete`,
56
+ `step delete`, `task delete`; `forecast scenarios bulk-edit`; `cash rules
57
+ delete-all`; `filebox archive` and `filebox data-query clear`;
58
+ `multi-product org-products set`;
59
+ `error-enrichments import` (replaces every rule on the server, zeroes all
60
+ hits/feedback counters, and reassigns every rule id); and
61
+ `dashboards push --override` / `filebox push --override`. `import` is **not** an
62
+ edit or reconcile tool: changing a fleet of rules — including making one server
63
+ match another — is a batch `create`/`update`, and `import` runs only when the
64
+ user names `import` and confirms the loss of hits/thumbs analytics and the id
65
+ reassignment. Never reach for it on your own initiative. `error-enrichments
66
+ delete` takes several ids at once and spends **one** word gate on the whole
67
+ batch, so the plan output — which lists every targeted rule with its hits and
68
+ feedback — is the blast-radius check; read it per-rule, not as a count. Batch
69
+ writes (`create`/`update`/`delete` with several targets) run sequentially and
70
+ keep going after a per-item failure, then exit non-zero: the per-item summary
71
+ table, not the exit code, is what says which ids actually landed. The two pushes
72
+ **without** `--override` are Tier B — rolling a template out to child orgs is
73
+ the workflow they exist for. One caveat on `filebox push`: create-new is the
74
+ usual outcome but not guaranteed — if a destination already holds a filebox
75
+ with the same alias and tags, the push adds a version to *that* filebox and it
76
+ becomes the one served. The CLI cannot tell in advance and no word gate will
77
+ stop it, so check the destination afterwards.
78
+ Everything else gated is Tier B (all `create`/`update`/`reorder`/`set-*`/`lock`/
79
+ `unlock` verbs, `templates set-field-type`, `rescan table` (a full historical
80
+ rescan — expensive/high-blast but reversible, so token-only; the plan step shows
81
+ the document + version counts), `metrics re-aggregate`, `metrics migrate` (the
82
+ org-wide V1→V2 backfill — deletes nothing, but **overwrites**
83
+ `category`/`time_aggregation` with the name-derived mapping, hand-set values
84
+ included; per-metric before→after is in the response `details[]`. A
85
+ request-level failure (500) rolls back everything; per-metric failures are
86
+ non-fatal — a 200 can carry `metrics.errors[]` with the rest of the org
87
+ committed, and under `--json` that warning is on **stderr**, not stdout.
88
+ Always run `--dry-run` first, and check `metrics.errors[]` after the live
89
+ run), `collection-processes`
90
+ verbs, `cash rules update|reorder`, `spend-control contracts bulk-create`,
91
+ `features orgs add|remove` (a delta over one `(org, flag)` boolean — each verb
92
+ sets it, neither destroys state — so it is token-only even on prod, unlike
93
+ `multi-product org-products set`, which replaces the whole entitlement set and
94
+ stays Tier A. Running the opposite verb is **not** an undo: it sets membership to
95
+ the opposite value, which restores the prior state only if that was the prior
96
+ state, and the CLI never reads current membership. Check with `features orgs list
97
+ <org_id>` before treating either verb as a revert), …).
98
+ When unsure, run the plan step — a Tier-A prod execute in a non-interactive
99
+ channel refuses and names the fix.
100
+
101
+ For destructive operations, surface the blast radius first — e.g. "this removes
102
+ the LUT that 4 functions depend on" — before running.
103
+
104
+ ### Binary-enforced interactive gate (Tier A only)
105
+
106
+ The human check is enforced **in the binary** — not by prose an agent could
107
+ skip or forget. When a valid `--confirm-token` is redeemed for a **Tier-A**
108
+ action against a prod tenant (`US`, `US2`, `UK`, `CA`, `EU`, `DEMO` — plus,
109
+ fail-closed, any server the CLI cannot positively classify as non-prod, and any
110
+ action not positively classified as Tier B), the binary requires a live human:
111
+
112
+ - **Interactive human** (desktop dialog on Windows/macOS/Linux, or a TTY
113
+ prompt): a fresh random word is shown *only in the dialog* and must be typed
114
+ back. Wrong word / cancel → the write does not happen.
115
+ - **No interactive channel** (agent shell, pipe, headless/SSH): the command
116
+ refuses — it **exits non-zero** with an error naming the exact line to run
117
+ in a real terminal, so a script can't mistake the refusal for success.
118
+
119
+ Practical consequence when you (Claude) drive the CLI: for a Tier-A prod write,
120
+ run the **plan** step, relay it, get the user's in-chat yes, then run the
121
+ **execute** step with the token yourself. On a desktop machine your subprocess
122
+ runs inside the user's login session, so the dialog pops on *their screen* and
123
+ they answer it there — the challenge word travels on a channel your toolchain
124
+ can't read. In a headless/SSH context the execute step refuses instead, exits
125
+ non-zero, and names the exact command for the user to run in a real terminal.
126
+ Tier-B and non-prod writes are unaffected — token-only, fully scriptable.
127
+
128
+ ## Escalate / stop
129
+
130
+ - A prod destructive without a clear in-chat "yes, do it" from the user.
131
+ - A write that affects more than one customer or a shared fixture (e.g. editing
132
+ a data model multiple tenants depend on) — file a ticket instead.
133
+ - **Exception: `dashboards push` / `filebox push`.** Writing into other
134
+ organizations is the whole point of those two, so they are sanctioned rather
135
+ than escalated. What makes them safe is bounded: destinations are refused
136
+ unless they appear in `organizations push-targets` (the caller's own
137
+ inherited orgs — never an arbitrary tenant), the batch is capped at 50, and
138
+ the plan step names every destination as `name (id)` before the token is
139
+ issued. Relay that destination list to the user and get an explicit "yes"
140
+ naming the orgs — the multi-customer blast radius is real even though the
141
+ command is allowed.
142
+ - The task needs a new subcommand / flag / API the CLI doesn't have — open a PR
143
+ against `Datarails/dr-cli`. Don't invent a command to fill the gap.