@rosthq/cli 0.7.140 → 0.7.142

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -119,11 +119,16 @@ rost onboard source-ingest \
119
119
  The JSON output contains the opaque `source_upload_id` and the exact
120
120
  `source_ref` object to place in the setup plan's `sources[]`.
121
121
 
122
- Transport note: the command body is capped server-side at 1 MiB, and base64
123
- expands content by 4/3 so the largest source file reachable through this
124
- command today is about 780 KB, not the protocol's documented 5,000,000-byte
125
- bound. The CLI checks this before sending and names the exact fitting size;
126
- split or trim a larger export.
122
+ Transport note: two ceilings apply, and the smaller one wins. The application
123
+ caps the command body at 1 MiB for most commands, but `onboarding.source_ingest`
124
+ gets a selectively raised cap (≈ 6.7 MB) sized for its base64 expansion (×4/3).
125
+ The hosting platform enforces a lower request-body ceiling in front of that —
126
+ measured at **at least 4 MiB**, the largest body proven to reach the function —
127
+ and rejects a larger body at the edge before the application sees it. Base64
128
+ expansion therefore puts the largest source file this command can carry at
129
+ roughly **3.1 MB**, not the protocol's documented 5,000,000-byte bound. The CLI
130
+ derives its pre-check from the platform ceiling and names the exact fitting size
131
+ before sending; split or trim a larger export.
127
132
 
128
133
  Stage the one-approval composite setup with the complete declarative plan
129
134
  (`--input '<json>'` inline, or `--input-file <path>` for a large plan):
@@ -7,6 +7,26 @@ export type OnboardingDeps = {
7
7
  makeClient(): Promise<CommandClient>;
8
8
  readFile?: (path: string) => Promise<Buffer>;
9
9
  };
10
+ /**
11
+ * The largest source file this invocation can actually send: the smallest of the
12
+ * three real limits, derived ONCE so the byte count the CLI PRINTS is the byte
13
+ * count it ENFORCES.
14
+ *
15
+ * Exported and parameterised on `bodyCapBytes` for one reason: the
16
+ * `ONBOARDING_SOURCE_MAX_BYTES` clamp is **not the binding term today** — the
17
+ * platform ceiling puts the transport-derived term at ~3.14 MB, well under the
18
+ * 5,000,000-byte protocol bound — so no fixture built from the shipped constants
19
+ * can exercise it, and an untestable clamp is indistinguishable from a clamp that
20
+ * does not work. It becomes binding the moment the effective body cap rises above
21
+ * `ceil(ONBOARDING_SOURCE_MAX_BYTES / 3) * 4 + margins`, which is exactly what
22
+ * happens when the platform ceiling is raised (DER-2927). Passing the cap in lets
23
+ * a test pin that future without waiting for it.
24
+ *
25
+ * `overheadBytes` is the invocation's own serialized size measured with an EMPTY
26
+ * `content_base64`; base64 is ASCII, so its character length equals its UTF-8 byte
27
+ * length and the remaining budget converts at 4 base64 chars per 3 source bytes.
28
+ */
29
+ export declare function maxSendableSourceFileBytes(overheadBytes: number, bodyCapBytes?: number): number;
10
30
  export type OnboardingInvocation = {
11
31
  commandId: "onboarding.status" | "onboarding.resume" | "onboarding.rehearse" | "onboarding.activate" | "onboarding.source_ingest" | "onboarding.setup";
12
32
  body: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/commands/onboarding.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAsB,MAAM,sBAAsB,CAAC;AAMzE,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAI3B,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAGrC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C,CAAC;AAmDF,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EACL,mBAAmB,GACnB,mBAAmB,GACnB,qBAAqB,GACrB,qBAAqB,GACrB,0BAA0B,GAC1B,kBAAkB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,eAAe,GAAG,OAAO,GAAG,cAAc,CAAC;IAInG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAepG;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,oBAAoB,EAChC,EAAE,EAAE,KAAK,EACT,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,CAAC,CAAC;AACnB,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,oBAAoB,EAChC,EAAE,EAAE,KAAK,EACT,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE;IAAE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,GAAG,OAAO,CAAA;CAAE,GAC5D,OAAO,CAAC,MAAM,GAAG,cAAc,CAAC,CAAC;AAoCpC;;;;;GAKG;AACH,wBAAsB,gCAAgC,CACpD,UAAU,EAAE,oBAAoB,EAChC,YAAY,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAY,GACzD,OAAO,CAAC,IAAI,CAAC,CA8Cf;AAgDD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,oBAAoB,CA+G9E;AA2FD,wBAAgB,eAAe,IAAI,MAAM,CAUxC;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EACtC,MAAM,EAAE,OAAO,GACd,MAAM,CAoBR"}
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/commands/onboarding.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAsB,MAAM,sBAAsB,CAAC;AAMzE,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAI3B,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAGrC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C,CAAC;AAkDF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,YAAY,GAAE,MAAsC,GACnD,MAAM,CAMR;AAqBD,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EACL,mBAAmB,GACnB,mBAAmB,GACnB,qBAAqB,GACrB,qBAAqB,GACrB,0BAA0B,GAC1B,kBAAkB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,eAAe,GAAG,OAAO,GAAG,cAAc,CAAC;IAInG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAepG;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,oBAAoB,EAChC,EAAE,EAAE,KAAK,EACT,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,CAAC,CAAC;AACnB,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,oBAAoB,EAChC,EAAE,EAAE,KAAK,EACT,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE;IAAE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,GAAG,OAAO,CAAA;CAAE,GAC5D,OAAO,CAAC,MAAM,GAAG,cAAc,CAAC,CAAC;AAoCpC;;;;;GAKG;AACH,wBAAsB,gCAAgC,CACpD,UAAU,EAAE,oBAAoB,EAChC,YAAY,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAY,GACzD,OAAO,CAAC,IAAI,CAAC,CAqEf;AAgDD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,oBAAoB,CA+G9E;AA2FD,wBAAgB,eAAe,IAAI,MAAM,CAUxC;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EACtC,MAAM,EAAE,OAAO,GACd,MAAM,CAoBR"}
package/dist/index.js CHANGED
@@ -31855,7 +31855,25 @@ var commandViolationSchema = external_exports.object({
31855
31855
  /** Advisory human text. Do not parse. */
31856
31856
  message: external_exports.string().min(1),
31857
31857
  /** The violated bound, when the issue carries one (`max`/`min` on arrays, strings, numbers). */
31858
- limit: external_exports.number().optional()
31858
+ limit: external_exports.number().optional(),
31859
+ /**
31860
+ * Schema vocabulary describing what was expected — a type name, a declared enum
31861
+ * value set, a format identifier, or a bound direction, FOR EVERY IN-REPO
31862
+ * SCHEMA. It is not structurally guaranteed to stay that way: a `superRefine`
31863
+ * can forge `issue.expected` / `issue.format` from caller data, so the value is
31864
+ * sanitized, capped, and secret-gated (`gateExpected`) before it can reach here
31865
+ * rather than trusted outright. It is never the caller's own parsed VALUE,
31866
+ * which is what `received` describes.
31867
+ */
31868
+ expected: external_exports.string().optional(),
31869
+ /**
31870
+ * A type descriptor of the caller's own submitted value at the resolved path:
31871
+ * `missing`/`null`/`string`/`number`/`boolean`/`array`/`object`, with counts for
31872
+ * size violations — or, for `unrecognized_keys`, the caller's own unexpected key
31873
+ * NAMES (proven against the payload, secret-gated, capped). NEVER the value
31874
+ * itself (invariant #5).
31875
+ */
31876
+ received: external_exports.string().optional()
31859
31877
  }).strict();
31860
31878
 
31861
31879
  // ../../packages/protocol/src/command-introspection.ts
@@ -36074,6 +36092,9 @@ var canonicalReadingDecimalSchema = external_exports.string().trim().min(1).max(
36074
36092
  var managedInferenceHardCapSchema = external_exports.string().trim().max(11).regex(/^(?:0|[1-9]\d{0,7})\.\d{2}$/);
36075
36093
  var ONBOARDING_SETUP_PLAN_MAX_BYTES = 1048576;
36076
36094
  var ONBOARDING_SOURCE_MAX_BYTES = 5e6;
36095
+ var ONBOARDING_SOURCE_INGEST_BODY_MARGIN_BYTES = 8192;
36096
+ var ONBOARDING_SOURCE_INGEST_BODY_CAP_BYTES = Math.ceil(ONBOARDING_SOURCE_MAX_BYTES / 3) * 4 + ONBOARDING_SOURCE_INGEST_BODY_MARGIN_BYTES;
36097
+ var COMMAND_TRANSPORT_PLATFORM_BODY_CEILING_BYTES = 4194304;
36077
36098
  var onboardingSourceKindSchema = external_exports.enum([
36078
36099
  "org_chart",
36079
36100
  "signal_export",
@@ -53023,7 +53044,7 @@ When operating through CLI or MCP, create fewer seats first and ask for confirma
53023
53044
  order: 30,
53024
53045
  title: "Charter design playbook",
53025
53046
  summary: "How to draft strong Charters that work for human, agent, and hybrid seats.",
53026
- version: "2026-07-29.1",
53047
+ version: "2026-07-31.2",
53027
53048
  public: true,
53028
53049
  audiences: ["human", "cli", "mcp", "in_app_agent"],
53029
53050
  stages: ["charter_design", "staffing"],
@@ -53078,7 +53099,7 @@ List and read first, then draft, then leave activation to a human.
53078
53099
 
53079
53100
  - List: \`{{cli}} command charter.list --json '{}'\` or \`rost_list_charters\` (scope: tenant). Read one with \`charter.get\` / \`rost_get_charter\`.
53080
53101
  - Draft one: \`{{cli}} command charter.draft --json '{"seat_id":"<seat-id>"}'\` (scope: seat or tenant-admin); draft every eligible seat with \`charter.draft_all\` / \`rost_draft_all_charters\`. Draft commands are not gated \u2014 they produce a draft \`charter_version_id\`. \`charter.draft_all\` drafts every **active or vacant** non-reserved seat \u2014 a vacant seat can receive a conservative draft Charter before it is staffed, since Charters attach to seats, not people, and drafting is not activation: **Charter activation stays a separate, human-gated step** (\`charter.approve\`) whether or not the seat is staffed. Reserved system paths (e.g. \`system.ops\`, Forge role seats) are excluded entirely, before both drafting and skip accounting \u2014 they never appear in \`drafted\`, \`skipped\`, or \`skipped_seats\`. It returns the real result: \`{ drafted, skipped, draft_ids, skipped_seats: [{ seat_id, reason }], effect }\` where \`reason\` is \`seat_not_active\` (the seat is still a graph-authoring draft, not yet active or vacant) or \`charter_exists\` (it already has a draft/active Charter). Read \`skipped_seats\` to see why a freshly-built graph drafted fewer Charters than it has seats \u2014 among non-reserved seats.
53081
- - **Never read a governed command's success as "it changed something."** Every converted mutating command carries an \`effect\` block \u2014 \`{ attempted, applied, skipped, outcome, skips: [{ target_kind, target_id, reason }], skips_omitted }\`, where \`outcome\` is \`applied\`, \`partial\`, or \`none\`, and \`skips.length + skips_omitted\` always equals \`skipped\` (\`skips\` is capped at 50 entries, so a very large sweep itemises the first 50 and counts the rest \u2014 the arithmetic still adds up) \u2014 so you can branch on it without knowing any one command's field names. **Read it where your surface actually delivers it:** \`response.output.effect\` over HTTP, and \`effect\` on the unwrapped command output in CLI and MCP. (The executor also carries a copy on its internal result envelope, but the HTTP adapter does not re-emit it, so \`response.effect\` is \`undefined\` \u2014 do not read it there.) \`outcome: "none"\` means the call succeeded and changed nothing; \`skips\` tells you why, per target, as stable codes you can branch on rather than prose. Check it and self-correct in the same run instead of reporting a build that did nothing: a second \`charter.draft_all\` over a graph whose seats already have a draft or active Charter returns \`outcome: "none"\` with one \`charter_exists\` skip per seat, and a graph whose seats are still graph-authoring \`draft\` seats returns \`outcome: "none"\` with one \`seat_not_active\` skip per seat. (A freshly built graph of **vacant** seats is not one of these cases \u2014 vacant seats are eligible and do get drafted, per the bullet above.) A **converted** command that skipped work without naming a reason fails its own output validation, so a silent zero-effect success is not a shape *those* commands can return. **This is not yet an API-wide guarantee** \u2014 most mutating commands are not converted yet, and an unconverted bulk or sweep command still returns a bare success that changed nothing: \`confirmation.dismiss_stale\` with no expired confirmations returns \`{ dismissed_count: 0, dismissed_ids: [] }\` with no \`effect\` at all. Treat a missing \`effect\` as "this command cannot tell you", never as "it worked" \u2014 for those, verify against live state before reporting the step done. Input that violates a schema is reported the same way rather than swallowed, naming the offending field path, the stable issue \`code\`, and the violated \`limit\` \u2014 e.g. a 6-principle Compass against \`max(5)\` gives \`{ path: "doc.principles", code: "too_big", limit: 5 }\`. **The field sits at a different place on each surface:** CLI and HTTP callers read it at \`error.details.violations\` (alongside the legacy \`fieldErrors\`), while MCP tool callers read \`violations\` at the **top level** of the error result, next to \`code\` and \`help\` \u2014 MCP results have no \`details\` envelope, so \`details.violations\` is \`undefined\` there. A path segment shown as \`*\` is one the server would not prove safe to echo \u2014 most often a caller-supplied key (e.g. inside a \`capabilities\` or \`headers\` map), but also any segment whose structure it could not establish: tuple and intersection members, **every** array position (a genuine positional index and caller text smuggled in by a refinement are indistinguishable once the issue is built, so no array position is echoed \u2014 \`xs[3].on\` reports as \`xs.*.on\`), and every segment when the schema is unavailable. So read \`*\` as **"withheld, unproven"**, not as "this was your key" \u2014 the declared field names around it are still exact, and the \`code\` still tells you which constraint failed. \`limit\` is likewise only present when the schema itself declares that bound, so its absence means "not proven", not "no bound".
53102
+ - **Never read a governed command's success as "it changed something."** Every converted mutating command carries an \`effect\` block \u2014 \`{ attempted, applied, skipped, outcome, skips: [{ target_kind, target_id, reason }], skips_omitted }\`, where \`outcome\` is \`applied\`, \`partial\`, or \`none\`, and \`skips.length + skips_omitted\` always equals \`skipped\` (\`skips\` is capped at 50 entries, so a very large sweep itemises the first 50 and counts the rest \u2014 the arithmetic still adds up) \u2014 so you can branch on it without knowing any one command's field names. **Read it where your surface actually delivers it:** \`response.output.effect\` over HTTP, and \`effect\` on the unwrapped command output in CLI and MCP. (The executor also carries a copy on its internal result envelope, but the HTTP adapter does not re-emit it, so \`response.effect\` is \`undefined\` \u2014 do not read it there.) \`outcome: "none"\` means the call succeeded and changed nothing; \`skips\` tells you why, per target, as stable codes you can branch on rather than prose. Check it and self-correct in the same run instead of reporting a build that did nothing: a second \`charter.draft_all\` over a graph whose seats already have a draft or active Charter returns \`outcome: "none"\` with one \`charter_exists\` skip per seat, and a graph whose seats are still graph-authoring \`draft\` seats returns \`outcome: "none"\` with one \`seat_not_active\` skip per seat. (A freshly built graph of **vacant** seats is not one of these cases \u2014 vacant seats are eligible and do get drafted, per the bullet above.) A **converted** command that skipped work without naming a reason fails its own output validation, so a silent zero-effect success is not a shape *those* commands can return. **This is not yet an API-wide guarantee** \u2014 most mutating commands are not converted yet, and an unconverted bulk or sweep command still returns a bare success that changed nothing: \`confirmation.dismiss_stale\` with no expired confirmations returns \`{ dismissed_count: 0, dismissed_ids: [] }\` with no \`effect\` at all. Treat a missing \`effect\` as "this command cannot tell you", never as "it worked" \u2014 for those, verify against live state before reporting the step done. Input that violates a schema is reported the same way rather than swallowed, naming the offending field path, the stable issue \`code\`, and the violated \`limit\` \u2014 e.g. a 6-principle Compass against \`max(5)\` gives \`{ path: "doc.principles", code: "too_big", limit: 5, expected: "<= 5", received: "array (6 items)" }\`. Each violation also carries \`expected\` (what the schema declares at that spot \u2014 a type, format, allowed values, or bound; for a cross-field or business-rule check it is the fixed marker \`a value satisfying the schema's custom check (see message)\`, telling you to read \`message\` for the authored specifics) and \`received\` (the KIND of value you sent \u2014 \`string\`, \`number\`, \`array (6 items)\`, \`missing\` \u2014 or, for undeclared extra keys, their proven, secret-gated names \u2014 never the value itself). **The field sits at a different place on each surface:** CLI and HTTP callers read it at \`error.details.violations\` (alongside the legacy \`fieldErrors\`), while MCP tool callers read \`violations\` at the **top level** of the error result, next to \`code\` and \`help\` \u2014 MCP results have no \`details\` envelope, so \`details.violations\` is \`undefined\` there. Paths are real JSON paths into YOUR OWN submitted payload: a caller-supplied key (e.g. inside a \`capabilities\` or \`headers\` map) is echoed exactly, and an array position reports as \`xs[3].on\`, because a path into input you supplied tells you nothing you do not already hold. A segment shows as \`*\` only when the server could not prove it walks your payload \u2014 a segment no schema declares and your payload does not contain (a refinement can report a path that was never in your input) \u2014 or when the segment name is itself credential-shaped and withheld as secret material. So read \`*\` as **"withheld, unproven"**, not as "this was your key" \u2014 the field names around it are still exact, and the \`code\` still tells you which constraint failed. \`limit\` is likewise only present when the schema itself declares that bound, so its absence means "not proven", not "no bound". The error envelope's \`help\` names the exact next step \u2014 \`rost command schema <id>\` prints the full input contract, and when the payload came from \`--input-file\`, fix the file and re-run it.
53082
53103
  - Edit a draft: \`charter.update_draft\` / \`rost_update_charter_draft\` with the \`charter_version_id\` and the new \`doc\`.
53083
53104
 
53084
53105
  In the app, \`/charters\` is both a drafting queue and a governance library. It shows active Charters, draft amendments, seats missing Charters, unsigned manifests, and steward-review gaps. \`/charters/builder\` is the seat picker for Charter Builder: start there when you need to draft a missing Charter, continue an amendment, or review which seats are still missing operating contracts. Opening a live Charter is a review mode: read the active version, inspect its governance state, and open an amendment draft when the job needs to change. Active Charter content is never silently edited in place. Both \`charter.draft_all\` triggers on this page \u2014 the "Draft missing Charters" empty-queue card and the "Draft gaps" header CTA \u2014 render the run's \`effect\` distinctly rather than a bare success: a full run (\`outcome: "applied"\`) shows an ordinary "Done" state, a run that skipped some seats (\`"partial"\`) shows "Partial effect" plus how many seats were skipped and why (the app aggregates them into product copy \u2014 "17 skipped: seat not active" \u2014 while CLI and MCP callers still get the per-target \`target_id\`/\`reason\` values from the contract), and a run that drafted nothing (\`"none"\`) shows "No effect" the same way \u2014 so a human running this from the UI gets the same self-correction signal the effect contract gives a CLI/MCP/HTTP caller, above.
@@ -53708,7 +53729,7 @@ External connectors are being rolled out provider by provider, conservatively (r
53708
53729
  order: 48,
53709
53730
  title: "CLI and MCP installation guide",
53710
53731
  summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
53711
- version: "2026-07-31.1",
53732
+ version: "2026-07-31.2",
53712
53733
  public: true,
53713
53734
  audiences: ["human", "cli", "mcp", "in_app_agent"],
53714
53735
  stages: ["company_setup", "staffing"],
@@ -54242,7 +54263,7 @@ These are the security posture rules for operating after install \u2014 a checkl
54242
54263
  {{cli}} onboard rehearse|activate --setup-application-id <uuid> ... [--json]
54243
54264
  \`\`\`
54244
54265
 
54245
- Every tenant-scoped \`onboard\` verb (\`status\`, \`resume\`, \`source-ingest\`, \`setup\`, \`setup-status\`, \`rehearse\`, \`activate\` \u2014 \`onboard run\` is an offline public print) authenticates with an existing implementation-bootstrap credential first and falls back to the user session, so the agent-led composite flow works without a personal login. \`onboard source-ingest\` reads one local business file client-side, base64-encodes it, and calls \`onboarding.source_ingest\`; the server computes the digest and family manifest and returns the opaque \`source_ref\` to reference from the setup plan's \`sources[]\` (paths and client digests are rejected). The server's 1 MiB command-body cap is authoritative, and base64 expands content by 4/3, so the largest file reachable through this command today is about 780 KB \u2014 the CLI pre-checks and names the exact fitting size; split a larger export. \`onboard setup\` submits the complete declarative plan to \`onboarding.setup\`: staging succeeds with exit code 0 and prints the pending confirmation id plus the exact approval URL (with \`--json\`, the full pending-confirmation object). \`onboard setup-status\` re-submits the identical plan to discover state through the command's idempotent contract: after approval it returns the immutable applied receipt (application id, receipt revision, input digest) without staging anything; while approval is still pending it returns the current approval card \u2014 an identical still-valid card is reused with the same confirmation id and URL, and only a changed server-derived projection supersedes the stale card and mints a fresh one. After application, a same-key re-submission with a different plan digest is a typed conflict.
54266
+ Every tenant-scoped \`onboard\` verb (\`status\`, \`resume\`, \`source-ingest\`, \`setup\`, \`setup-status\`, \`rehearse\`, \`activate\` \u2014 \`onboard run\` is an offline public print) authenticates with an existing implementation-bootstrap credential first and falls back to the user session, so the agent-led composite flow works without a personal login. \`onboard source-ingest\` reads one local business file client-side, base64-encodes it, and calls \`onboarding.source_ingest\`; the server computes the digest and family manifest and returns the opaque \`source_ref\` to reference from the setup plan's \`sources[]\` (paths and client digests are rejected). Two size ceilings apply to this upload and the smaller one wins. The application's command-body cap is 1 MiB for most commands, but \`onboarding.source_ingest\` gets a selectively raised cap (\u2248 6.7 MB, on both the REST and MCP command transports) sized for base64 expansion (\xD74/3). In front of that, the hosting platform enforces a lower request-body ceiling \u2014 measured at at least 4 MiB, the largest body proven to reach the function \u2014 and rejects a larger body at the edge before {{brand}} sees it, so no {{brand}} error can describe that failure. **The platform ceiling is what sets the maximum size.** The raised 6.7 MB application cap sits above it and so never rejects a body the platform would have delivered. The 5,000,000-byte protocol bound is still enforced \u2014 a larger file is refused on that ground first \u2014 but it too sits above the reachable size, so it never decides how large a source can actually be. Only the platform ceiling does, which is why raising the 6.7 MB cap on its own would not make a bigger source uploadable. After base64 expansion the largest source file this command can carry is therefore about **3.1 MB**, short of the protocol's documented 5,000,000-byte source range; reaching that full range needs the platform ceiling raised, which is a separate change. The CLI derives its pre-check from the platform ceiling and names the exact fitting size before sending \u2014 split a larger export. \`onboard setup\` submits the complete declarative plan to \`onboarding.setup\`: staging succeeds with exit code 0 and prints the pending confirmation id plus the exact approval URL (with \`--json\`, the full pending-confirmation object). \`onboard setup-status\` re-submits the identical plan to discover state through the command's idempotent contract: after approval it returns the immutable applied receipt (application id, receipt revision, input digest) without staging anything; while approval is still pending it returns the current approval card \u2014 an identical still-valid card is reused with the same confirmation id and URL, and only a changed server-derived projection supersedes the stale card and mints a fresh one. After application, a same-key re-submission with a different plan digest is a typed conflict.
54246
54267
 
54247
54268
  | Command | Purpose | Scope | Safe example |
54248
54269
  |---|---|---|---|
@@ -59058,8 +59079,18 @@ function formatStagedConfirmation(commandId, details, overrides = {}) {
59058
59079
  var REHEARSE_USAGE = `${cliBrand.binName} onboard rehearse --setup-application-id <uuid> --expected-input-digest <sha256:digest> --expected-receipt-revision <integer> --idempotency-key <key> [--json]`;
59059
59080
  var ACTIVATE_USAGE = `${cliBrand.binName} onboard activate --setup-application-id <uuid> --expected-input-digest <sha256:digest> --expected-receipt-revision <integer> --terminal-rehearsal-batch-receipt-id <uuid> --rehearsal-runs '<json-array>' --configuration-digests '<json-array>' --idempotency-key <key> [--json]`;
59060
59081
  var SOURCE_INGEST_USAGE = `${cliBrand.binName} onboard source-ingest --file <path> --source-key <key> --kind <kind> --title <title> [--json]`;
59061
- var SERVER_COMMAND_BODY_CAP_BYTES = 1048576;
59082
+ var SERVER_COMMAND_BODY_CAP_BYTES = Math.min(
59083
+ ONBOARDING_SOURCE_INGEST_BODY_CAP_BYTES,
59084
+ COMMAND_TRANSPORT_PLATFORM_BODY_CEILING_BYTES
59085
+ );
59062
59086
  var COMMAND_BODY_SAFETY_MARGIN_BYTES = 4096;
59087
+ function maxSendableSourceFileBytes(overheadBytes, bodyCapBytes = SERVER_COMMAND_BODY_CAP_BYTES) {
59088
+ const preflightCap = bodyCapBytes - COMMAND_BODY_SAFETY_MARGIN_BYTES;
59089
+ return Math.min(
59090
+ Math.floor((preflightCap - overheadBytes) / 4) * 3,
59091
+ ONBOARDING_SOURCE_MAX_BYTES
59092
+ );
59093
+ }
59063
59094
  var SETUP_USAGE = `${cliBrand.binName} onboard setup --input '<json-plan>' | --input-file <path> [--json]`;
59064
59095
  var SETUP_STATUS_USAGE = `${cliBrand.binName} onboard setup-status --input '<json-plan>' | --input-file <path> [--json]`;
59065
59096
  function sourceIngestKinds() {
@@ -59126,15 +59157,23 @@ async function resolveOnboardingInvocationFiles(invocation, readFileImpl = readF
59126
59157
  if (bytes.length === 0) {
59127
59158
  throw new OnboardingUsageError(`--file ${invocation.sourceFile} is empty.`);
59128
59159
  }
59160
+ const overheadBytes = Buffer.byteLength(
59161
+ JSON.stringify({ ...invocation.body, content_base64: "" }),
59162
+ "utf8"
59163
+ );
59164
+ const preflightCap = SERVER_COMMAND_BODY_CAP_BYTES - COMMAND_BODY_SAFETY_MARGIN_BYTES;
59165
+ const maxSendableFileBytes = maxSendableSourceFileBytes(overheadBytes);
59166
+ if (bytes.length > ONBOARDING_SOURCE_MAX_BYTES) {
59167
+ throw new OnboardingUsageError(
59168
+ `--file ${invocation.sourceFile} is ${bytes.length} bytes, over the onboarding.source_ingest protocol's documented ${ONBOARDING_SOURCE_MAX_BYTES}-byte source range. The largest file this invocation can actually send is about ${maxSendableFileBytes} bytes. Split the export or trim rows/columns to fit.`
59169
+ );
59170
+ }
59129
59171
  const contentBase64 = bytes.toString("base64");
59130
59172
  invocation.body.content_base64 = contentBase64;
59131
59173
  const bodyBytes = Buffer.byteLength(JSON.stringify(invocation.body), "utf8");
59132
- const preflightCap = SERVER_COMMAND_BODY_CAP_BYTES - COMMAND_BODY_SAFETY_MARGIN_BYTES;
59133
59174
  if (bodyBytes > preflightCap) {
59134
- const overheadBytes = bodyBytes - contentBase64.length;
59135
- const effectiveMaxFileBytes = Math.floor((preflightCap - overheadBytes) / 4) * 3;
59136
59175
  throw new OnboardingUsageError(
59137
- `--file ${invocation.sourceFile} is ${bytes.length} bytes; base64-encoded it makes a ${bodyBytes}-byte command body, over the server's authoritative ${SERVER_COMMAND_BODY_CAP_BYTES}-byte command-transport cap (this check stops ${COMMAND_BODY_SAFETY_MARGIN_BYTES} bytes early on purpose). The largest file this invocation can send is about ${effectiveMaxFileBytes} bytes. The onboarding.source_ingest protocol documents sources up to 5,000,000 bytes; reaching that range needs the server-side transport follow-up. Split the export or trim rows/columns to fit.`
59176
+ `--file ${invocation.sourceFile} is ${bytes.length} bytes; base64-encoded it makes a ${bodyBytes}-byte command body, over the ${preflightCap}-byte preflight budget for this command (the ${SERVER_COMMAND_BODY_CAP_BYTES}-byte request-body ceiling it has to get through, minus a deliberate ${COMMAND_BODY_SAFETY_MARGIN_BYTES}-byte margin). The largest file this invocation can send is about ${maxSendableFileBytes} bytes. Split the export or trim rows/columns to fit.`
59138
59177
  );
59139
59178
  }
59140
59179
  delete invocation.sourceFile;