@rosthq/cli 0.7.22 → 0.7.24

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/dist/index.js CHANGED
@@ -37979,6 +37979,147 @@ var CATALOG_ENTRIES = [
37979
37979
  scope_tiers: ["read"],
37980
37980
  credential_required: false,
37981
37981
  default_access_policy: "always_allow"
37982
+ },
37983
+ // DER-1293 (tool-id canonicalization): the stock agent templates
37984
+ // (`packages/agents/src/templates.ts`) grant these dotted business-tool ids, so a
37985
+ // signed AP-Clerk / SDR / Support / QA / Signal manifest derived from a template
37986
+ // already carries them. They were missing from the catalog, which (1) made a Skill
37987
+ // that requires one resolve `unknown_tool` at `skill.check_dependencies`, and (2)
37988
+ // left the runtime guard's scope-tier lookup (`resolveToolScopeTier`) unresolved →
37989
+ // fail-closed `critical` for an autonomous read/draft grant. Adding them here — the
37990
+ // single source of truth for scope tier and access policy — reconciles all three
37991
+ // surfaces (catalog ↔ templates ↔ skills). Conservative-by-default (invariant #10):
37992
+ // read/draft tiers only, drafts never send, and the ids never mint new authority —
37993
+ // authorization stays with the signed manifest + guard (invariant #6).
37994
+ {
37995
+ id: "accounting.bills.read",
37996
+ title: "Read payable bills",
37997
+ provider: "accounting",
37998
+ description: "Call this to read payable bills, vendor records, and matching evidence when preparing accounts-payable work. Read-only: no payment release, coding change, or vendor send.",
37999
+ default_scope_tier: "read",
38000
+ scope_tiers: ["read"],
38001
+ credential_required: true,
38002
+ default_access_policy: "always_allow"
38003
+ },
38004
+ {
38005
+ id: "accounting.invoices.read",
38006
+ title: "Read receivable invoices",
38007
+ provider: "accounting",
38008
+ description: "Call this to read receivable invoice aging and payment status for collections and reconciliation. Read-only: it never changes terms, applies credits, or sends.",
38009
+ default_scope_tier: "read",
38010
+ scope_tiers: ["read"],
38011
+ credential_required: true,
38012
+ default_access_policy: "always_allow"
38013
+ },
38014
+ {
38015
+ id: "inbox.ap.read",
38016
+ title: "Read AP inbox",
38017
+ provider: "email",
38018
+ description: "Call this to read messages in the assigned accounts-payable inbox for triage and invoice matching. Read-only and scoped to the AP inbox.",
38019
+ default_scope_tier: "read",
38020
+ scope_tiers: ["read"],
38021
+ credential_required: true,
38022
+ default_access_policy: "always_allow"
38023
+ },
38024
+ {
38025
+ id: "inbox.ap.draft",
38026
+ title: "Draft AP reply",
38027
+ provider: "email",
38028
+ description: "Call this to draft an accounts-payable reply for a human to review. Draft-only: it never sends.",
38029
+ default_scope_tier: "draft",
38030
+ scope_tiers: ["draft"],
38031
+ credential_required: true,
38032
+ default_access_policy: "always_allow"
38033
+ },
38034
+ {
38035
+ id: "email.collections.draft",
38036
+ title: "Draft collections reminder",
38037
+ provider: "email",
38038
+ description: "Call this to draft a collections reminder for human approval. Draft-only: it never sends, changes terms, or applies credits.",
38039
+ default_scope_tier: "draft",
38040
+ scope_tiers: ["draft"],
38041
+ credential_required: true,
38042
+ default_access_policy: "always_allow"
38043
+ },
38044
+ {
38045
+ id: "helpdesk.ticket.read",
38046
+ title: "Read support tickets",
38047
+ provider: "helpdesk",
38048
+ description: "Call this to read assigned support tickets and their history for triage. Read-only and scoped to the assigned queues.",
38049
+ default_scope_tier: "read",
38050
+ scope_tiers: ["read"],
38051
+ credential_required: true,
38052
+ default_access_policy: "always_allow"
38053
+ },
38054
+ {
38055
+ id: "helpdesk.ticket.classify",
38056
+ title: "Classify support ticket",
38057
+ provider: "helpdesk",
38058
+ description: "Call this to tag and route a support ticket to the correct queue. Classification and routing only \u2014 it never replies, changes account state, or closes a ticket.",
38059
+ default_scope_tier: "draft",
38060
+ scope_tiers: ["draft"],
38061
+ credential_required: true,
38062
+ default_access_policy: "always_allow"
38063
+ },
38064
+ {
38065
+ id: "helpdesk.reply.draft",
38066
+ title: "Draft support reply",
38067
+ provider: "helpdesk",
38068
+ description: "Call this to draft a first support response from approved knowledge-base content. Draft-only: it never sends or promises a fix.",
38069
+ default_scope_tier: "draft",
38070
+ scope_tiers: ["draft"],
38071
+ credential_required: true,
38072
+ default_access_policy: "always_allow"
38073
+ },
38074
+ {
38075
+ id: "crm.contacts.read",
38076
+ title: "Read CRM contacts",
38077
+ provider: "crm",
38078
+ description: "Call this to read assigned inbound leads and account records for enrichment and briefing. Read-only: it never changes lifecycle stage or sends outreach.",
38079
+ default_scope_tier: "read",
38080
+ scope_tiers: ["read"],
38081
+ credential_required: true,
38082
+ default_access_policy: "always_allow"
38083
+ },
38084
+ {
38085
+ id: "content.calendar.draft_update",
38086
+ title: "Draft content calendar",
38087
+ provider: "content",
38088
+ description: "Call this to draft content-calendar entries for review. Drafts only \u2014 it never publishes, schedules, or sends.",
38089
+ default_scope_tier: "draft",
38090
+ scope_tiers: ["draft"],
38091
+ credential_required: true,
38092
+ default_access_policy: "always_allow"
38093
+ },
38094
+ {
38095
+ id: "release.artifacts.read",
38096
+ title: "Read release artifacts",
38097
+ provider: "release",
38098
+ description: "Call this to read assigned release artifacts, checklists, and test results for review. Read-only: it never approves a release or changes production state.",
38099
+ default_scope_tier: "read",
38100
+ scope_tiers: ["read"],
38101
+ credential_required: true,
38102
+ default_access_policy: "always_allow"
38103
+ },
38104
+ {
38105
+ id: "issues.draft",
38106
+ title: "Draft tracker issue",
38107
+ provider: "issues",
38108
+ description: "Call this to draft a release-risk or tracker issue for human review. Draft-only: it never closes, assigns, or changes issue state autonomously.",
38109
+ default_scope_tier: "draft",
38110
+ scope_tiers: ["draft"],
38111
+ credential_required: true,
38112
+ default_access_policy: "always_allow"
38113
+ },
38114
+ {
38115
+ id: "signal.report",
38116
+ title: "Draft Signal reading",
38117
+ provider: "rost",
38118
+ description: "Call this to propose a draft Signal reading for one of the seat's agent-sourced measurables, with a cited source. Draft-only: a human confirms the reading; it never fabricates a value or changes a measurable definition.",
38119
+ default_scope_tier: "draft",
38120
+ scope_tiers: ["draft"],
38121
+ credential_required: false,
38122
+ default_access_policy: "always_allow"
37982
38123
  }
37983
38124
  ];
37984
38125
  var catalogById = new Map(CATALOG_ENTRIES.map((entry) => [entry.id, entry]));
@@ -42206,6 +42347,34 @@ var softwareGithubActionSchema = external_exports.enum([
42206
42347
  ]);
42207
42348
  var softwareGithubPolicyDecisionSchema = external_exports.enum(["allowed", "denied", "requires_human"]);
42208
42349
  var softwarePhaseRunStatusSchema = external_exports.enum(["pending", "running", "passed", "failed", "blocked", "skipped"]);
42350
+ var softwarePlanVersionStatusSchema = external_exports.enum([
42351
+ "draft",
42352
+ "needs_clarification",
42353
+ "ready_for_plan_review",
42354
+ "approved",
42355
+ "rejected"
42356
+ ]);
42357
+ var softwareChangesetSplitCriterionSchema = external_exports.enum([
42358
+ "single",
42359
+ "risk_isolation",
42360
+ "reviewability_budget",
42361
+ "deploy_ordering",
42362
+ "independent_revert"
42363
+ ]);
42364
+ var softwareChangesetStatusSchema = external_exports.enum(["planned", "in_progress", "in_review", "merged", "declined"]);
42365
+ var softwareTaskStatusSchema = external_exports.enum(["planned", "in_progress", "blocked", "done"]);
42366
+ var softwareConformanceSeveritySchema = external_exports.enum(["blocker", "major", "minor"]);
42367
+ var softwareConformanceCategorySchema = external_exports.enum([
42368
+ "scope_gap",
42369
+ "plan_deviation",
42370
+ "missing_test",
42371
+ "security_constraint",
42372
+ "secret_handling",
42373
+ "authority_limit",
42374
+ "skipped_scope",
42375
+ "other"
42376
+ ]);
42377
+ var softwareConformanceStatusSchema = external_exports.enum(["open", "accepted", "resolved"]);
42209
42378
  var softwareGateTypeSchema = external_exports.enum([
42210
42379
  "plan_review",
42211
42380
  "security_signoff",
@@ -42308,6 +42477,54 @@ var softwareGateSummarySchema = external_exports.object({
42308
42477
  rationale: external_exports.string().nullable(),
42309
42478
  created_at: external_exports.string()
42310
42479
  });
42480
+ var softwareChangesetSummarySchema = external_exports.object({
42481
+ id: uuid10,
42482
+ build_request_id: uuid10,
42483
+ ordinal: external_exports.number().int(),
42484
+ title: external_exports.string(),
42485
+ split_criterion: softwareChangesetSplitCriterionSchema,
42486
+ status: softwareChangesetStatusSchema,
42487
+ branch_name: external_exports.string().nullable(),
42488
+ pr_number: external_exports.number().int().nullable(),
42489
+ pr_url: external_exports.string().nullable(),
42490
+ pr_draft: external_exports.boolean(),
42491
+ inferred_risk: softwareRiskLevelSchema.nullable(),
42492
+ merged_at: external_exports.string().nullable(),
42493
+ created_at: external_exports.string()
42494
+ });
42495
+ var softwareTaskSummarySchema = external_exports.object({
42496
+ id: uuid10,
42497
+ build_request_id: uuid10,
42498
+ changeset_id: uuid10,
42499
+ plan_version_id: uuid10,
42500
+ ordinal: external_exports.number().int(),
42501
+ task_key: external_exports.string(),
42502
+ title: external_exports.string(),
42503
+ status: softwareTaskStatusSchema,
42504
+ depends_on: external_exports.array(external_exports.string()),
42505
+ parallelizable: external_exports.boolean(),
42506
+ est_turns: external_exports.number().int().nullable(),
42507
+ actual_turns: external_exports.number().int().nullable(),
42508
+ actual_files: external_exports.number().int().nullable(),
42509
+ started_at: external_exports.string().nullable(),
42510
+ completed_at: external_exports.string().nullable(),
42511
+ created_at: external_exports.string()
42512
+ });
42513
+ var softwarePlanConformanceFindingSummarySchema = external_exports.object({
42514
+ id: uuid10,
42515
+ build_request_id: uuid10,
42516
+ changeset_id: uuid10.nullable(),
42517
+ phase_run_id: uuid10.nullable(),
42518
+ plan_version_id: uuid10.nullable(),
42519
+ severity: softwareConformanceSeveritySchema,
42520
+ category: softwareConformanceCategorySchema,
42521
+ summary: external_exports.string(),
42522
+ detail: external_exports.string().nullable(),
42523
+ status: softwareConformanceStatusSchema,
42524
+ accepted_by_decision_id: uuid10.nullable(),
42525
+ resolved_at: external_exports.string().nullable(),
42526
+ created_at: external_exports.string()
42527
+ });
42311
42528
  var softwareAuthorityProfileSummarySchema = external_exports.object({
42312
42529
  id: uuid10,
42313
42530
  software_project_id: uuid10.nullable(),
@@ -42415,6 +42632,58 @@ var softwareGateDecideOutputSchema = external_exports.object({
42415
42632
  resolved_by_user_id: uuid10,
42416
42633
  decision_id: uuid10.nullable()
42417
42634
  });
42635
+ var forgeClarificationAnswer = external_exports.object({
42636
+ question: external_exports.string().trim().min(1).max(2e3),
42637
+ answer: external_exports.string().trim().min(1).max(4e3)
42638
+ }).strict();
42639
+ var softwareRequestAnswerClarificationInputSchema = external_exports.object({
42640
+ build_request_id: uuid10,
42641
+ answers: external_exports.array(forgeClarificationAnswer).min(1).max(50),
42642
+ // The planner marks the plan ready once its questions are resolved; the human/COS can
42643
+ // signal that here. Default false keeps the plan in needs_clarification.
42644
+ mark_ready_for_plan_review: external_exports.boolean().default(false)
42645
+ }).strict();
42646
+ var softwareRequestAnswerClarificationOutputSchema = external_exports.object({
42647
+ build_request_id: uuid10,
42648
+ plan_version_id: uuid10,
42649
+ status: softwarePlanVersionStatusSchema,
42650
+ answered_count: external_exports.number().int()
42651
+ });
42652
+ var softwarePlanApproveInputSchema = external_exports.object({
42653
+ build_request_id: uuid10,
42654
+ rationale: external_exports.string().trim().min(1).max(4e3).optional()
42655
+ }).strict();
42656
+ var softwarePlanRejectInputSchema = external_exports.object({
42657
+ build_request_id: uuid10,
42658
+ // A rejection must say why (it routes the request back to discovery/scoping).
42659
+ rationale: external_exports.string().trim().min(1).max(4e3)
42660
+ }).strict();
42661
+ var softwarePlanDecisionOutputSchema = external_exports.object({
42662
+ build_request_id: uuid10,
42663
+ plan_version_id: uuid10,
42664
+ status: external_exports.enum(["approved", "rejected"]),
42665
+ decision_id: uuid10,
42666
+ current_phase: softwarePhaseSchema
42667
+ });
42668
+ var forgeConformanceFindingInput = external_exports.object({
42669
+ severity: softwareConformanceSeveritySchema,
42670
+ category: softwareConformanceCategorySchema.default("other"),
42671
+ summary: external_exports.string().trim().min(1).max(2e3),
42672
+ detail: external_exports.string().trim().min(1).max(8e3).optional(),
42673
+ changeset_id: uuid10.optional(),
42674
+ plan_version_id: uuid10.optional()
42675
+ }).strict();
42676
+ var softwareConformanceRecordFindingsInputSchema = external_exports.object({
42677
+ build_request_id: uuid10,
42678
+ phase_run_id: uuid10.optional(),
42679
+ findings: external_exports.array(forgeConformanceFindingInput).min(1).max(50)
42680
+ }).strict();
42681
+ var softwareConformanceRecordFindingsOutputSchema = external_exports.object({
42682
+ build_request_id: uuid10,
42683
+ recorded_count: external_exports.number().int(),
42684
+ finding_ids: external_exports.array(uuid10),
42685
+ open_finding_count: external_exports.number().int()
42686
+ }).strict();
42418
42687
  var softwareAuthorityProfileListInputSchema = external_exports.object({
42419
42688
  software_project_id: uuid10.nullable().optional()
42420
42689
  }).strict();
@@ -42650,14 +42919,63 @@ var softwareDeveloperTeamInstallOutputSchema = external_exports.object({
42650
42919
  });
42651
42920
  var forgeArtifactText = external_exports.string().trim().min(1).max(4e3);
42652
42921
  var forgeArtifactList = external_exports.array(forgeArtifactText).max(50).default([]);
42922
+ var forgeTaskKey = external_exports.string().trim().min(1).max(200);
42923
+ var forgeTaskTitle = external_exports.string().trim().min(1).max(300);
42924
+ var forgeTaskPathList = external_exports.array(external_exports.string().trim().min(1).max(300)).max(20).default([]);
42925
+ var forgeTaskVerificationList = external_exports.array(external_exports.string().trim().min(1).max(500)).max(25).default([]);
42926
+ var forgeTaskDefinitionSchema = external_exports.object({
42927
+ task_key: forgeTaskKey,
42928
+ title: forgeTaskTitle,
42929
+ // task_keys this task depends on (dependency DAG); disjoint-file tasks may be parallel.
42930
+ depends_on: external_exports.array(forgeTaskKey).max(50).default([]),
42931
+ parallelizable: external_exports.boolean().default(false),
42932
+ // ≤ ~40% of the phase session budget (headroom for fix loops); split above the ceiling.
42933
+ est_turns: external_exports.number().int().positive().max(1e3).nullable().default(null),
42934
+ files_likely: forgeTaskPathList,
42935
+ // verification commands + expected proof, stated BEFORE implementation.
42936
+ verification: forgeTaskVerificationList
42937
+ }).strict();
42938
+ var forgeChangesetPlanSchema = external_exports.object({
42939
+ ordinal: external_exports.number().int().positive().max(100),
42940
+ title: forgeTaskTitle,
42941
+ split_criterion: softwareChangesetSplitCriterionSchema.default("single"),
42942
+ // task_keys grouped into this PR-boundary unit.
42943
+ task_keys: external_exports.array(forgeTaskKey).max(200).default([])
42944
+ }).strict();
42653
42945
  var forgePlanArtifact = external_exports.object({
42654
42946
  scope: forgeArtifactText,
42655
42947
  plan_steps: forgeArtifactList,
42656
42948
  files_or_systems: forgeArtifactList,
42657
42949
  verification: forgeArtifactList,
42658
42950
  risks: forgeArtifactList,
42659
- clarifying_questions: forgeArtifactList
42660
- }).strict();
42951
+ clarifying_questions: forgeArtifactList,
42952
+ // DER-1197 changeset B: structured human answers to the clarifying questions, written
42953
+ // by software_factory.request.answer_clarification. Default [] keeps older artifacts valid.
42954
+ clarification_answers: external_exports.array(forgeClarificationAnswer).max(50).default([]),
42955
+ // DER-1197 decomposition. Default [] keeps pre-decomposition artifacts valid.
42956
+ tasks: external_exports.array(forgeTaskDefinitionSchema).max(200).default([]),
42957
+ changesets: external_exports.array(forgeChangesetPlanSchema).max(100).default([])
42958
+ }).strict().superRefine((artifact, ctx) => {
42959
+ const taskKeys = /* @__PURE__ */ new Set();
42960
+ for (const [i, task] of artifact.tasks.entries()) {
42961
+ if (taskKeys.has(task.task_key)) {
42962
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["tasks", i, "task_key"], message: `Duplicate task_key "${task.task_key}"` });
42963
+ }
42964
+ taskKeys.add(task.task_key);
42965
+ }
42966
+ const ordinals = /* @__PURE__ */ new Set();
42967
+ for (const [i, cs] of artifact.changesets.entries()) {
42968
+ if (ordinals.has(cs.ordinal)) {
42969
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["changesets", i, "ordinal"], message: `Duplicate changeset ordinal ${cs.ordinal}` });
42970
+ }
42971
+ ordinals.add(cs.ordinal);
42972
+ for (const [j, key] of cs.task_keys.entries()) {
42973
+ if (!taskKeys.has(key)) {
42974
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["changesets", i, "task_keys", j], message: `Changeset references unknown task_key "${key}"` });
42975
+ }
42976
+ }
42977
+ }
42978
+ });
42661
42979
  var forgeImplementationArtifact = external_exports.object({
42662
42980
  changes: forgeArtifactList,
42663
42981
  verification: forgeArtifactList,
@@ -43757,7 +44075,7 @@ Treat AICOS as a coordinator over the operating system. It can become more usefu
43757
44075
  order: 20,
43758
44076
  title: "Responsibility Graph playbook",
43759
44077
  summary: "How to build a functions-first graph with seats, owners, Stewards, vacancies, and clean authority.",
43760
- version: "2026-06-30.1",
44078
+ version: "2026-07-04.3",
43761
44079
  public: true,
43762
44080
  audiences: ["human", "cli", "mcp", "in_app_agent"],
43763
44081
  stages: ["graph_design", "staffing"],
@@ -43815,10 +44133,25 @@ The graph is also where you land after onboarding \u2014 it is the mission contr
43815
44133
 
43816
44134
  The graph also carries a mission-control panel. It pulls the same operational state visible on the agent and setup-health surfaces: held actions that need steward decisions, failed runs, open Friction, pending Signal readings, stale agents, and setup recommendations. Each item can focus the affected seat on the canvas and links to the route where the operator can act.
43817
44135
 
44136
+ ## An agent seat's profile
44137
+
44138
+ A staffed agent's seat page opens on a profile built to answer one question in ten seconds: what is this agent, what does it know, what can it touch, and who is accountable. The hero shows live/paused/draft status, a one-line description, and when it last ran; a right-hand fact sheet stays visible on every tab with the Charter version, Skills, Connections (with a "connect" prompt when a Skill needs a provider that is not yet linked), an Access summary, and tool/held/model counts. Four tabs organize the rest: **Overview** (recent runs as one-line summaries, 30-day cost by model, and a version-history feed that tracks the agent itself as an actor alongside human Charter decisions), **Charter** (the accepted Charter rendered as a document \u2014 purpose, responsibilities, owned measurables, decision authority \u2014 with its version chip, signer, and an Amend action that opens the same draft-and-confirm amendment flow as the Charter Builder), **Access** (plain-language cards for what the agent does while you are watching versus running unattended, then every granted tool grouped under its Connection with a one-line description and Read/Draft/Held status), and **Activity** (the full Trust Card below). AICOS's seat keeps its own operations panel instead of this profile, because it is the company's foundation seat rather than a generic staffed agent.
44139
+
43818
44140
  ## Review an agent seat's delivered work
43819
44141
 
43820
44142
  Agent seat pages show the operator-facing output trail, not just low-level run telemetry. The completed work area combines explicit \`agent_deliverables\`, successful \`work.log\` evidence, and recent successful run summaries into one readable list. Each item shows what was delivered, when it happened, what kind of work it was, and safe evidence links labelled as internal, Linear, GitHub, or external. Secret-shaped values are redacted before display, and run or task context is shown only when it belongs to the same seat.
43821
44143
 
44144
+ ## Read a human seat's page
44145
+
44146
+ A human seat's page opens on one computed answer line \u2014 for example "On track \u2014 4 of 5 measurables on target \xB7 1 held draft awaiting review" \u2014 instead of a wall of always-shown sections. Below it:
44147
+
44148
+ - **Exceptions are fully visible**: off-target measurables, escalations addressed to this seat as Steward (a held draft awaiting the Steward's decision), and open Friction filed by or owned by this seat all render as rows up top, each with a one-click way to act (log a reading, review, or resolve).
44149
+ - **Healthy content collapses to a count**: on-target measurables and measurables with no reading yet fold into one expandable "N measurables on target" row so the calm majority does not compete with the exceptions for attention.
44150
+ - **Three lens tabs** \u2014 Overview, Activity, Access \u2014 are views of the same seat, not separate sub-pages: Overview holds the answer line, exceptions, Purpose and accountabilities, and the Cascade goal summary; Activity is the event feed and the seat's task queue; Access is occupancy, Charter status, decision authority, and the permission manifest.
44151
+ - **One Manage drawer** replaces the inline staffing panel: it opens to Occupancy (staffing controls, when this seat is eligible to be staffed, and Let go), Charter (a link to the Charter Builder), and Measurables (a link to log a reading in Signal). Opening the drawer calls the exact same commands as before \u2014 nothing moved out of it changed behavior.
44152
+
44153
+ Agent seat pages keep their own dedicated Overview/Charter/Access layout with an always-visible fact sheet; see "Review an agent seat's delivered work" above for the agent-specific completed-work view.
44154
+
43822
44155
  ## First-pass structure
43823
44156
 
43824
44157
  Start with the operating root, then major functions, then the few seats that own the most important recurring work. Do not over-model. A graph with eight clear seats is better than a graph with thirty vague boxes.
@@ -44195,7 +44528,7 @@ The dry run is a real sandbox rehearsal, not a stamp. It executes a mock-provide
44195
44528
  order: 80,
44196
44529
  title: "Sync rhythm playbook",
44197
44530
  summary: "How Signal, Friction, Cascade, and Sync Briefs turn weekly meetings into decision time.",
44198
- version: "2026-06-30.1",
44531
+ version: "2026-07-04.1",
44199
44532
  public: true,
44200
44533
  audiences: ["human", "cli", "mcp", "in_app_agent"],
44201
44534
  stages: ["operating_rhythm"],
@@ -44241,7 +44574,7 @@ The Sync Brief should answer:
44241
44574
  - Which agent escalations are aging?
44242
44575
  - Which goals lack current evidence?
44243
44576
 
44244
- On screen the brief reads in plain terms: Signal exceptions, goal progress, task review, ranked Friction, and agent activity. Where a section has no source data, it lists gaps to confirm \u2014 the missing inputs a human should know about before the meeting \u2014 rather than a blank section.
44577
+ On screen the brief reads exceptions-first. One computed answer line states what changed in plain terms, then every exception \u2014 Signal breaches, slipped or at-risk Cascade goals, escalation-grade Friction, agent Charter exceedances, and stalled or overdue tasks \u2014 is fully visible in a single agenda; the agenda is the exceptions, not a tour of every seat. Friction, task review, and agent activity collapse to an expandable count when they hold nothing above their escalation threshold, so the page stays calm when nothing there needs attention. Signal and Cascade have no such collapsed count by design: the brief only ever records exceptions for those two sections, not a reviewed total, so the screen never blends a live count with this frozen, already-compiled snapshot. Where a section has no source data at all, it lists gaps to confirm \u2014 the missing inputs a human should know about before the meeting \u2014 rather than a blank section; a brief with open gaps but no exception rows says so plainly instead of reporting an all-clear. Compile now and Run current Sync live behind one Manage control so the read view stays uncluttered.
44245
44578
 
44246
44579
  Before the first brief exists, the Sync pages are readiness views. They show the next scheduled compile and the source areas that will feed it: Signal, Cascade, Tasks, Friction, and Agents. Use those links to add missing source data, or use Compile now to run the same idempotent persisted compile operation immediately when the company uses company-wide Sync Briefs. If the company is configured for per-cluster briefs, compile the target cluster from CLI or MCP with a cluster id until the UI offers a cluster selector. Once a brief exists, the page shows whether it covers the current period, when it was compiled, and which sections were omitted or compiled with gaps.
44247
44580
 
@@ -44270,7 +44603,7 @@ Decisions should be recorded as human decisions. Handoffs should attach to seats
44270
44603
  order: 45,
44271
44604
  title: "How agents work",
44272
44605
  summary: "How {{brand}} agents operate inside seats, use Charters, report work, and escalate beyond authority.",
44273
- version: "2026-07-02.1",
44606
+ version: "2026-07-04.1",
44274
44607
  public: true,
44275
44608
  audiences: ["human", "cli", "mcp", "in_app_agent"],
44276
44609
  stages: ["staffing", "operating_rhythm"],
@@ -44353,7 +44686,7 @@ The model is only ever offered the tools the seat's manifest grants \u2014 a den
44353
44686
 
44354
44687
  1. The manifest guard runs first and decides: allowed, denied, or must-escalate. A denied or must-escalate call never runs the action; an escalation is raised for a human.
44355
44688
  2. For an allowed call, the proposed input is validated against the tool's schema. Malformed input fails closed \u2014 the action does not run, and the model is told to correct it.
44356
- 3. The action runs bound to the seat's vaulted credential. The secret stays inside the call and never reaches the result, the audit row, the logs, or the model.
44689
+ 3. The action runs bound to the seat's vaulted credential. The secret stays inside the call and never reaches the result, the audit row, the logs, or the model. Brokered secret access applies the same rule on every attempt, including a denied or missing grant: it records a redacted, constraint-safe access-log entry and never opens the vault when the grant does not match.
44357
44690
  4. Every call \u2014 allowed, denied, escalated, or invalid \u2014 writes a tool-call audit row you can review.
44358
44691
 
44359
44692
  When operational evidence appears in the app, it is formatted for review instead of shown as primary raw JSON. Tool arguments, escalation evidence, status evidence, Sync inputs, and task context are summarized as labeled fields; secret-looking values stay redacted. Raw identifiers remain available only as supporting detail when they help an operator trace the record.
@@ -44472,7 +44805,7 @@ There is exactly one way to give a connected tool its credential, and it is the
44472
44805
  order: 47,
44473
44806
  title: "Available tools guide",
44474
44807
  summary: "How to think about tool categories available to seats and what each category should be used for.",
44475
- version: "2026-06-30.1",
44808
+ version: "2026-07-04.1",
44476
44809
  public: true,
44477
44810
  audiences: ["human", "cli", "mcp", "in_app_agent"],
44478
44811
  stages: ["staffing"],
@@ -44510,6 +44843,8 @@ Start from the seat's responsibility, not the tool list. If a tool does not dire
44510
44843
 
44511
44844
  Skills are reusable procedures a seat can learn from; they are not tools and they never grant authority. A skill package may declare required or optional tool dependencies so setup can identify blockers before assignment. Those dependencies are checked against the discoverable \`tool.catalog\` ids and scope tiers, then compared to the seat's Charter permission manifest. Missing required tools block approval; optional tools produce setup warnings. A published skill version is immutable, so later corrections create a new version instead of rewriting what a run may have used.
44512
44845
 
44846
+ The catalog covers both the platform verbs (status, escalation, Signal readings) and the business tools the stock-agent templates grant \u2014 accounts-payable and receivable reads, AP-inbox and collections drafts, helpdesk triage, CRM reads, and content-calendar, release-artifact, and issue drafts. Each is listed at a conservative scope tier (read for the reads, draft for the drafts, where a draft never sends), and the business tools are credential-gated. Because a skill's required tool id is matched against these ids, a skill that requires one of them resolves against the catalog rather than reporting an unknown tool. Catalog membership is configuration only: it still confers no authority, and a listed id runs only once a live handler exists behind the seat's signed permission manifest, the server guard, and any required credential \u2014 the manifest and guard remain the control plane.
44847
+
44513
44848
  ## How agents should request tools
44514
44849
 
44515
44850
  Agents should explain the job, the required tool category, the minimum permission needed, and the escalation boundary. Humans approve or decline the request.
@@ -44525,7 +44860,7 @@ External connectors are being rolled out provider by provider, conservatively (r
44525
44860
  order: 48,
44526
44861
  title: "CLI and MCP installation guide",
44527
44862
  summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
44528
- version: "2026-07-04.14",
44863
+ version: "2026-07-04.16",
44529
44864
  public: true,
44530
44865
  audiences: ["human", "cli", "mcp", "in_app_agent"],
44531
44866
  stages: ["company_setup", "staffing"],
@@ -45249,6 +45584,10 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
45249
45584
  | \`rost_show_a_forge_build_request\` | \`software_factory.request.show\` | The Forge request detail: the request, current phase, phase-run history, and gates. Read-only; requires the Forge add-on. | Tenant | Call with \`{"build_request_id":"<request-id>"}\`. |
45250
45585
  | \`rost_advance_a_forge_build_request_phase\` | \`software_factory.phase.advance\` | Advance a build request to its next phase; the server enforces the closed phase state machine and rejects an illegal transition. | Tenant | Call with \`{"build_request_id":"<request-id>","to_phase":"discovery_scoping"}\`. |
45251
45586
  | \`rost_decide_a_forge_gate\` | \`software_factory.gate.decide\` | A human approves or rejects a Forge gate; an agent caller routes to \`/approvals\` and can never self-approve. Sensitive gates record a linked human decision. | Tenant | Call with \`{"gate_id":"<gate-id>","decision":"approve"}\`; non-interactive callers receive a confirmation handoff. |
45587
+ | \`rost_answer_forge_plan_clarifications\` | \`software_factory.request.answer_clarification\` | Write structured human answers to a draft plan's clarifying questions and optionally mark it ready for plan review; answers append to the versioned planning artifact and never widen authority or automation mode. | Tenant | Call with \`{"build_request_id":"<request-id>","answers":[{"question":"Which database?","answer":"Postgres"}],"mark_ready_for_plan_review":true}\`. |
45588
+ | \`rost_approve_a_forge_plan\` | \`software_factory.plan.approve\` | A human approves the current plan at the plan_review gate; records a human decision and advances the request to implementation. Owner-only and human-gated. | Tenant-admin | Call with \`{"build_request_id":"<request-id>"}\`; non-interactive callers receive a confirmation handoff. |
45589
+ | \`rost_reject_a_forge_plan\` | \`software_factory.plan.reject\` | A human rejects the current plan (with a required rationale) and routes the request back to discovery/scoping for re-planning. Owner-only and human-gated. | Tenant-admin | Call with \`{"build_request_id":"<request-id>","rationale":"Scope too broad"}\`; non-interactive callers receive a confirmation handoff. |
45590
+ | \`rost_record_forge_conformance_findings\` | \`software_factory.conformance.record_findings\` | Record structured plan-conformance findings as reviewer evidence. Open findings route the request back to implementation; accepting a gap remains a separate human gate. | Tenant | Call with \`{"build_request_id":"<request-id>","findings":[{"severity":"major","category":"scope_gap","summary":"Missing migration verification"}]}\`. |
45252
45591
  | \`rost_list_forge_authority_profiles\` | \`software_factory.authority_profile.list\` | List the tenant's Forge authority profiles (seat capability presets, read-only by default). Read-only; requires the Forge add-on. | Tenant | Call with \`{}\`. |
45253
45592
  | \`rost_create_a_forge_authority_profile\` | \`software_factory.authority_profile.create\` | Define a Forge authority profile (a named seat capability preset). Owner-only; defaults to the read_only preset. | Tenant-admin | Call with \`{"name":"Builder","preset":"contributor"}\`. |
45254
45593
  | \`rost_grant_forge_seat_authority\` | \`software_factory.authority.grant\` | Grant a seat a Forge authority profile on a project (seat \u2192 project \u2192 profile). Owner-only and human-gated; emits a durable authority-change event. | Tenant-admin | Call with \`{"software_project_id":"<project-id>","seat_id":"<seat-id>","authority_profile_id":"<profile-id>"}\`; non-interactive callers receive a confirmation handoff. |
@@ -45750,7 +46089,7 @@ Retrieve the narrowest relevant guide before making a setup recommendation. Pref
45750
46089
  order: 60,
45751
46090
  title: "Cascade guide",
45752
46091
  summary: "How to connect company goals to seat-level work without turning {{brand}} into a project-management tool.",
45753
- version: "2026-07-01.1",
46092
+ version: "2026-07-04.1",
45754
46093
  public: true,
45755
46094
  audiences: ["human", "cli", "mcp", "in_app_agent"],
45756
46095
  stages: ["operating_rhythm"],
@@ -45822,7 +46161,7 @@ On \`/cascade\`, the screen renders the full goal depth, not just one or two lev
45822
46161
 
45823
46162
  ## Goal progress and at-risk goals
45824
46163
 
45825
- A goal can carry a quantified progress (0-100) distinct from its on/off/done status. Report it with \`goal.set_progress\`; when an agent reports progress it lands as a proposal a human approves before the goal moves. A seat goal that has milestones takes its progress from milestone completion instead \u2014 the percentage is the share of its non-dropped milestones marked done, recomputed automatically as milestones complete, drop, or re-open. \`goal.list_at_risk\` projects which goals are off pace by comparing progress against the elapsed fraction of the cycle window (deterministic date math, no forecast model). Off-pace goals surface on \`/cascade\`, on the owner home, in the weekly Sync Brief, and as a weekly owner alert. Status-only goals (no progress recorded) are excluded from the projection and render as pending measurement, not as proven on track.
46164
+ A goal can carry a quantified progress (0-100) distinct from its on/off/done status. Report it with \`goal.set_progress\`; when an agent reports progress it lands as a proposal a human approves before the goal moves. A seat goal that has milestones takes its progress from milestone completion instead \u2014 the percentage is the share of its non-dropped milestones marked done, recomputed automatically as milestones complete, drop, or re-open. \`goal.list_at_risk\` projects which goals are off pace by comparing progress against the elapsed fraction of the cycle window (deterministic date math, no forecast model). Off-pace goals surface on \`/cascade\`, in the owner-only band on \`/home\`, in the weekly Sync Brief, and as a weekly owner alert. Status-only goals (no progress recorded) are excluded from the projection and render as pending measurement, not as proven on track.
45826
46165
 
45827
46166
  On human and function seat pages, goal visibility includes both direct goals and descendant seat goals from the Responsibility Graph subtree, so a manager can review team progress without double-owning the agent's work.
45828
46167
 
@@ -45856,7 +46195,7 @@ Agents can suggest commitments and report progress. They should not create a new
45856
46195
  order: 61,
45857
46196
  title: "Signal guide",
45858
46197
  summary: "How to define and read measurables so the company runs on evidence instead of status theater.",
45859
- version: "2026-07-04.1",
46198
+ version: "2026-07-04.2",
45860
46199
  public: true,
45861
46200
  audiences: ["human", "cli", "mcp", "in_app_agent"],
45862
46201
  stages: ["operating_rhythm"],
@@ -45917,11 +46256,11 @@ Avoid vanity numbers, manual-only status fields, and metrics nobody can act on.
45917
46256
 
45918
46257
  ## Run Signal without an agent
45919
46258
 
45920
- A human can run the whole loop from the Signal page. Each measurable has a "Log this period's number" control that records a human reading (the same \`signal.correct_reading\` path), and an "Add a measurable" form creates one against a seat (the \`measurable.create\` path). You do not need an agent to keep Signal current.
46259
+ A human can run the whole loop from the Signal page. The page opens answer-first \u2014 one computed line ("2 of 14 measurables need attention," or "All 14 measurables on target" when nothing needs you) with only the exception rows fully visible; healthy measurables collapse to a single "N on target" count you can expand. Every create/edit action lives behind the one "+ Add" button, which opens a drawer with four segments: **Log reading** records a human reading (the same \`signal.correct_reading\` path, or a row's own "Log reading" button seeds the drawer to that measurable), **New measurable** creates one against a seat (the \`measurable.create\` path, plus adopting from the template catalog), **Sources**, and **CSV import**. You do not need an agent to keep Signal current.
45921
46260
 
45922
46261
  ## Import a scorecard from CSV
45923
46262
 
45924
- To move off a spreadsheet or another operating tool, upload a scorecard export from the Signal page "Import from CSV" panel (the \`signal.import\` command, also available on CLI/MCP). Each row becomes a measurable owned by the seat whose name matches the row's owner, with its target, unit, direction, cadence, and trailing readings. Import is idempotent \u2014 re-importing upserts by period \u2014 and a row whose cadence conflicts with an existing measurable is reported and skipped, not overwritten.
46263
+ To move off a spreadsheet or another operating tool, open the Signal page's "+ Add" drawer and choose the "CSV import" segment (the \`signal.import\` command, also available on CLI/MCP). Each row becomes a measurable owned by the seat whose name matches the row's owner, with its target, unit, direction, cadence, and trailing readings. Import is idempotent \u2014 re-importing upserts by period \u2014 and a row whose cadence conflicts with an existing measurable is reported and skipped, not overwritten.
45925
46264
 
45926
46265
  ## Adopt a measurable template
45927
46266
 
@@ -45944,7 +46283,7 @@ Discovery always returns a \`recipe_presets\` array; it is empty when {{brand}}
45944
46283
 
45945
46284
  Recipes are validated data, never code: a read-only GET, a closed set of non-secret headers, and a restricted scalar path to the value. Every fetch passes one SSRF guard (HTTPS only, a steward-confirmed host allowlist set at bind, and a runtime check that the host does not resolve to a private address). The preset output never contains \`nango://\` handles, vault refs, tokens, or static credential headers. Deterministic pulls write \`integration\`-sourced readings on the measurable's cadence.
45946
46285
 
45947
- In the web app, the same workflow lives on \`/signal\` in the "Connect a self-filling source" panel. It shows each measurable's setup state \u2014 manual, agent draft, source draft, or auto-filled \u2014 plus the latest safe pull outcome when one exists. Choose a connected source, discover its non-secret metadata, preview a GET URL and value path, bind the working preview as a draft, then confirm the draft before scheduled pulls can write readings. The UI never displays credential material, vault refs, raw response bodies, or recipe secrets; if no connected source exists, connect one from Settings first.
46286
+ In the web app, the same workflow lives on \`/signal\` in the "+ Add" drawer's "Sources" segment. It shows each measurable's setup state \u2014 manual, agent draft, source draft, or auto-filled \u2014 plus the latest safe pull outcome when one exists. Choose a connected source, discover its non-secret metadata, preview a GET URL and value path, bind the working preview as a draft, then confirm the draft before scheduled pulls can write readings. The UI never displays credential material, vault refs, raw response bodies, or recipe secrets; if no connected source exists, connect one from Settings first.
45948
46287
 
45949
46288
  A source binding can inform a measurable without automatically changing a Cascade goal. The proven Leiluna Baserow binding uses \`informs\`. Use \`drives_status\` only after a second business anchor confirms that this exact measurable should compute a childless goal's status; otherwise the Signal should stay visible as evidence and exception context, not an automatic goal-status driver.
45950
46289
 
@@ -46044,7 +46383,7 @@ Resolving Friction should produce one of four outcomes: a decision, a task, a Ch
46044
46383
  order: 70,
46045
46384
  title: "Steward queue guide",
46046
46385
  summary: "How Stewards review escalations, approve agent boundaries, and keep agents accountable.",
46047
- version: "2026-06-27.2",
46386
+ version: "2026-07-04.1",
46048
46387
  public: true,
46049
46388
  audiences: ["human", "cli", "mcp", "in_app_agent"],
46050
46389
  stages: ["staffing", "operating_rhythm"],
@@ -46083,6 +46422,8 @@ In the app, the evidence is shown as a legible card, not raw data: a proposed to
46083
46422
 
46084
46423
  When nothing is waiting, the Steward page still proves the governance loop. It shows which agent or hybrid seats the human stewards, how many escalations were raised or decided recently, and whether any are open. That empty state is an operating summary, not a dead end.
46085
46424
 
46425
+ The Steward page itself only lists charter-clause escalations (Queue, Escalations). Agent-raised confirmations that need a sign-off \u2014 Charter approvals, tool/permission grants, and other gated commands \u2014 live in the consolidated \`/approvals\` queue, one click away from a header link on the Steward page. See the confirmations guide for how that queue works.
46426
+
46086
46427
  ## How escalations reach you
46087
46428
 
46088
46429
  An escalation reaches you the same way no matter how the agent raised it \u2014 in a chat or CLI session, or on its own scheduled cloud run. When the agent stops at a boundary it opens the queue item and sends a notification to the accountable human along the steward chain, preferring a connected Slack channel and falling back to email. If no human occupies the agent's seat, the chain walks up to the next Steward. Delivery is idempotent: a retried run never notifies you twice for the same escalation, and the notification carries only summarized, redacted evidence \u2014 never secret material.
@@ -46456,7 +46797,7 @@ Every notification should include the seat, cause, evidence, and requested decis
46456
46797
  order: 75,
46457
46798
  title: "Local runner guide",
46458
46799
  summary: "How local agent sessions and runner surfaces should operate through {{brand}} without bypassing Charters or audit.",
46459
- version: "2026-07-04.1",
46800
+ version: "2026-07-04.3",
46460
46801
  public: true,
46461
46802
  audiences: ["human", "cli", "mcp", "in_app_agent"],
46462
46803
  stages: ["staffing", "operating_rhythm"],
@@ -46510,6 +46851,10 @@ AICOS runner chat uses the same runner process but not the scheduled work-order
46510
46851
 
46511
46852
  When the Forge add-on is enabled, Forge phase work uses the same runner work-order lane. A Forge phase with an owning runner-agent Seat is linked to a normal \`work_orders\` row; the runner claims it, starts it, reports the result, and the server advances the linked phase. There is no separate local lease store.
46512
46853
 
46854
+ A build request decomposes into changesets and tasks tracked as queryable execution state. A changeset is the pull-request boundary and the revert unit (default one per request; additional changesets only on a named split criterion such as risk isolation or a reviewability-size budget). A task is one coding session inside a changeset, carrying its own verification and a per-task checkpoint that is the safe resume and pause boundary. Plan-conformance findings loop a changeset back to implementation; a finding can only be accepted, rather than resolved, through a recorded human decision.
46855
+
46856
+ The plan-review step is human-driven through tri-surface commands. A person answers a draft plan's clarifying questions and can mark it ready for review; approving the plan records a human decision and moves the request into implementation, while rejecting it records the decision and routes the request back to discovery and scoping for re-planning. Approving or rejecting a plan is owner-only and human-gated \u2014 an agent can never decide a plan on its own.
46857
+
46513
46858
  Runner heartbeats can include advisory capacity telemetry: OS, runner version, CPU and memory, active session count, detected local runtimes, and a model-account alias plus usage-limit state. Missing, empty, or whitespace model-account aliases are treated as the same \`default\` account so the scheduler can enforce a conservative one-session default-account cap. The scheduler also caps active runner work per tenant, project, runner, and model account.
46514
46859
 
46515
46860
  Forge context packets are deliberately bounded. The runner receives ids, phase state, authority-profile metadata, config metadata, and secret-grant metadata. It does not receive request free text, source refs, repo source dumps, raw secrets, vault refs, or a model-visible runner bearer secret. A short-lived seat-scoped MCP token is written only to the local MCP config file for the claimed turn.
@@ -48444,6 +48789,7 @@ var COMMAND_MANIFEST = [
48444
48789
  { "id": "software_factory.capacity.list", "namespace": "software_factory", "action": "capacity.list", "title": "List Forge runner capacity", "description": "List the tenant's Forge runner capacity observations (OS, CPU, memory, active sessions, usage-limit telemetry). Advisory scheduling input only, never an authority input. Read-only, entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "runner_id", "flag": "runner-id", "type": "string", "required": false }, { "name": "limit", "flag": "limit", "type": "integer", "required": false }], "hasComplexInput": false, "help": "List Forge runner capacity observations (advisory scheduling input only, never an authority input). Read-only; requires the Forge add-on." },
48445
48790
  { "id": "software_factory.config.list", "namespace": "software_factory", "action": "config.list", "title": "List Forge config", "description": "List active Forge config metadata for project environments. Plain config values may be returned; secret refs are represented only as has_secret_ref.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": false }, { "name": "environment", "flag": "environment", "type": "enum", "required": false, "enumValues": ["development", "preview", "production"] }], "hasComplexInput": false, "help": "List active Forge config entries. Plain config may be shown; secret refs are represented only as metadata." },
48446
48791
  { "id": "software_factory.config.set", "namespace": "software_factory", "action": "config.set", "title": "Set Forge config", "description": "Create or rotate a Forge project config entry. Secret config stores only a vault ref pointer; raw values are never accepted for secret_ref entries.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": true }, { "name": "environment", "flag": "environment", "type": "enum", "required": true, "enumValues": ["development", "preview", "production"] }, { "name": "key_name", "flag": "key-name", "type": "string", "required": true }, { "name": "value_kind", "flag": "value-kind", "type": "enum", "required": true, "enumValues": ["plain", "secret_ref"] }, { "name": "plain_value", "flag": "plain-value", "type": "string", "required": false }, { "name": "vault_ref", "flag": "vault-ref", "type": "string", "required": false }], "hasComplexInput": false, "help": "Set or rotate a Forge project config key. Secret entries store only vault refs and are human-gated." },
48792
+ { "id": "software_factory.conformance.record_findings", "namespace": "software_factory", "action": "conformance.record_findings", "title": "Record Forge conformance findings", "description": "The plan-conformance reviewer records one or more findings against a build request; open findings route the request back to implementation. Recording is evidence, not a decision \u2014 accepting a gap is a separate human gate. Requires the Forge add-on.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "phase_run_id", "flag": "phase-run-id", "type": "string", "required": false }], "hasComplexInput": true, "help": "Record structured Forge plan-conformance findings as reviewer evidence. Open findings route the request back to implementation; accepting a gap remains a separate human gate." },
48447
48793
  { "id": "software_factory.developer_team.install", "namespace": "software_factory", "action": "developer_team.install", "title": "Install Forge Developer Team", "description": "Install AND activate the governed Forge Developer Team: 7 seats (1 human lead + 6 agents), first-party skills, authority presets, and a conservative token budget. Approving this ACTIVATES the 6 agents as live occupancies at a pr_only, observe-first posture: they open pull requests but never merge or deploy without a human. Entitlement-gated and human-confirmed.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "steward_seat_id", "flag": "steward-seat-id", "type": "string", "required": true }, { "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": false }, { "name": "assign_skills", "flag": "assign-skills", "type": "boolean", "required": false }, { "name": "acknowledge_autonomy_ceiling", "flag": "acknowledge-autonomy-ceiling", "type": "boolean", "required": false }], "hasComplexInput": false, "help": "Install the governed Forge Developer Team template with seats, draft Charters, skills, project authority grants, and audit records. Tenant-admin and human-gated; creates no live agent occupancy." },
48448
48794
  { "id": "software_factory.gate.decide", "namespace": "software_factory", "action": "gate.decide", "title": "Decide a Forge gate", "description": "A human approves or rejects a Forge gate. The resolver is recorded (never an agent \u2014 invariant #7); sensitive gates (security sign-off, merge/deploy, authority change, production deploy) also write a linked human decision. Requires confirmation.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "gate_id", "flag": "gate-id", "type": "string", "required": true }, { "name": "decision", "flag": "decision", "type": "enum", "required": true, "enumValues": ["approve", "reject"] }, { "name": "rationale", "flag": "rationale", "type": "string", "required": false }], "hasComplexInput": false, "help": "A human approves or rejects a Forge gate; an agent caller routes to /approvals and can never self-approve. Sensitive gates record a human decision." },
48449
48795
  { "id": "software_factory.github.installation_token.create", "namespace": "software_factory", "action": "github.installation_token.create", "title": "Create a Forge GitHub installation token", "description": "Mint a short-lived GitHub App installation token for one bound repository after server-side policy evaluation. The token is returned once and never persisted.", "requiredScope": "tenant", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": true }, { "name": "repository_id", "flag": "repository-id", "type": "integer", "required": true }, { "name": "requested_actions", "flag": "requested-actions", "type": "array", "required": true, "itemType": "string" }, { "name": "requested_automation_mode", "flag": "requested-automation-mode", "type": "enum", "required": false, "enumValues": ["plan_only", "pr_only", "merge_after_checks", "deploy_preview", "deploy_production"] }, { "name": "seat_id", "flag": "seat-id", "type": "string", "required": false }], "hasComplexInput": false, "help": "Mint a short-lived GitHub App installation token for one bound repository after policy evaluation; token material is returned once and never stored." },
@@ -48453,8 +48799,11 @@ var COMMAND_MANIFEST = [
48453
48799
  { "id": "software_factory.github.policy.upsert", "namespace": "software_factory", "action": "github.policy.upsert", "title": "Set a Forge GitHub automation policy", "description": "Set the server-side policy for GitHub actions and automation-mode ceilings. Owner-only and human-gated; production deploy remains human-gated.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": true }, { "name": "authority_profile_id", "flag": "authority-profile-id", "type": "string", "required": false }, { "name": "automation_mode_ceiling", "flag": "automation-mode-ceiling", "type": "enum", "required": false, "enumValues": ["plan_only", "pr_only", "merge_after_checks", "deploy_preview", "deploy_production"] }, { "name": "allowed_actions", "flag": "allowed-actions", "type": "array", "required": true, "itemType": "string" }, { "name": "requires_human_for", "flag": "requires-human-for", "type": "array", "required": true, "itemType": "string" }], "hasComplexInput": false, "help": "Set Forge's server-side GitHub automation policy for actions, mode ceilings, and human-gated operations." },
48454
48800
  { "id": "software_factory.github.repository.unbind", "namespace": "software_factory", "action": "github.repository.unbind", "title": "Unbind a Forge GitHub repository", "description": "Remove a GitHub repository's Forge project binding. By default the repository stays connected (unbound) and can be re-bound later; pass disconnect to remove it entirely. Owner-only and human-gated.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": false, "fields": [{ "name": "app_slug", "flag": "app-slug", "type": "string", "required": false }, { "name": "installation_id", "flag": "installation-id", "type": "integer", "required": true }, { "name": "repository_id", "flag": "repository-id", "type": "integer", "required": true }, { "name": "disconnect", "flag": "disconnect", "type": "boolean", "required": false }], "hasComplexInput": false, "help": "Remove a GitHub repository's Forge project binding; the repository stays connected for re-binding unless disconnect is set. Owner-only and human-gated." },
48455
48801
  { "id": "software_factory.phase.advance", "namespace": "software_factory", "action": "phase.advance", "title": "Advance a Forge build request phase", "description": "Advance a build request to the next phase, enforcing the closed phase state machine server-side (an illegal transition is rejected). Writes a phase-run row and updates the current phase. Entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "to_phase", "flag": "to-phase", "type": "enum", "required": true, "enumValues": ["intake", "discovery_scoping", "plan_review", "implementation", "plan_conformance_review", "security_review", "qa_verification", "release_preview", "merge_or_deploy_gate", "closeout"] }, { "name": "owning_seat_id", "flag": "owning-seat-id", "type": "string", "required": false }, { "name": "note", "flag": "note", "type": "string", "required": false }], "hasComplexInput": false, "help": "Advance a build request to its next phase; the server enforces the closed phase state machine and rejects an illegal transition." },
48802
+ { "id": "software_factory.plan.approve", "namespace": "software_factory", "action": "plan.approve", "title": "Approve a Forge plan", "description": "A human approves the current plan at the plan_review gate; records a human decision and advances the request to implementation. Owner-only and human-gated (invariant #7).", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "rationale", "flag": "rationale", "type": "string", "required": false }], "hasComplexInput": false, "help": "A human approves the current plan at the plan_review gate; records a human decision and advances the request to implementation. Owner-only and human-gated." },
48803
+ { "id": "software_factory.plan.reject", "namespace": "software_factory", "action": "plan.reject", "title": "Reject a Forge plan", "description": "A human rejects the current plan at the plan_review gate; records a human decision (with a required rationale) and routes the request back to discovery/scoping for re-planning. Owner-only and human-gated (invariant #7).", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "rationale", "flag": "rationale", "type": "string", "required": true }], "hasComplexInput": false, "help": "A human rejects the current plan (with a required rationale) and routes the request back to discovery/scoping for re-planning. Owner-only and human-gated." },
48456
48804
  { "id": "software_factory.project.create", "namespace": "software_factory", "action": "project.create", "title": "Create a Forge project", "description": "Create an active Forge software project before binding repositories or opening build requests. Tenant-admin, human-gated, and entitlement-gated.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "name", "flag": "name", "type": "string", "required": true }, { "name": "slug", "flag": "slug", "type": "string", "required": false }, { "name": "base_branch", "flag": "base-branch", "type": "string", "required": false }, { "name": "repo_ref", "flag": "repo-ref", "type": "string", "required": false }], "hasComplexInput": false, "help": "Create an active Forge software project before binding repositories or opening build requests. Tenant-admin and human-gated; requires the Forge add-on." },
48457
48805
  { "id": "software_factory.project.list", "namespace": "software_factory", "action": "project.list", "title": "List Forge projects", "description": "List active Forge software projects so a tenant can choose a project for build requests, GitHub repository bindings, and config. Read-only and entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [], "hasComplexInput": false, "help": "List active Forge software projects so a tenant can choose a project for build requests, GitHub repository bindings, and config. Read-only; requires the Forge add-on." },
48806
+ { "id": "software_factory.request.answer_clarification", "namespace": "software_factory", "action": "request.answer_clarification", "title": "Answer Forge plan clarifications", "description": "Write structured human answers to a draft plan's clarifying questions and optionally mark it ready for plan review. Answers append to the versioned planning artifact; this never widens authority or automation mode.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "mark_ready_for_plan_review", "flag": "mark-ready-for-plan-review", "type": "boolean", "required": false }], "hasComplexInput": true, "help": "Write structured human answers to a draft plan's clarifying questions and optionally mark it ready for plan review. Never widens authority or automation mode." },
48458
48807
  { "id": "software_factory.request.create", "namespace": "software_factory", "action": "request.create", "title": "Create a Forge build request", "description": "Open a governed Forge build request against a connected software project. Records the request plus its initial intake phase run. Entitlement-gated (Forge add-on); the title is untrusted display text, never an instruction.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": true }, { "name": "title", "flag": "title", "type": "string", "required": true }, { "name": "source_channel", "flag": "source-channel", "type": "enum", "required": false, "enumValues": ["ui", "cli", "github_issue", "linear", "api"] }, { "name": "source_ref", "flag": "source-ref", "type": "string", "required": false }], "hasComplexInput": true, "help": "Open a governed Forge build request against a connected software project; the title is untrusted display text. Requires the Forge add-on." },
48459
48808
  { "id": "software_factory.request.list", "namespace": "software_factory", "action": "request.list", "title": "List Forge build requests", "description": "The Forge control-room board: the tenant's build requests with status, current phase, and risk/automation mode. Read-only, entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "limit", "flag": "limit", "type": "integer", "required": false }], "hasComplexInput": false, "help": "List Forge build requests (the control-room board) with status, current phase, and risk. Read-only; requires the Forge add-on." },
48460
48809
  { "id": "software_factory.request.show", "namespace": "software_factory", "action": "request.show", "title": "Show a Forge build request", "description": "The Forge request detail: the build request, its current phase, phase-run history, and gates. Read-only, entitlement-gated, tenant-scoped.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }], "hasComplexInput": false, "help": "Show a Forge build request's detail: current phase, phase-run history, and gates. Read-only; requires the Forge add-on." },