pi-subagents 0.67.0 → 0.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +1 -1
  3. package/docs/agents.md +41 -12
  4. package/docs/configuration.md +61 -19
  5. package/docs/extension-api.md +5 -1
  6. package/docs/missions.md +2 -2
  7. package/docs/models.md +11 -79
  8. package/docs/observability.md +18 -8
  9. package/docs/standalone-background.md +13 -3
  10. package/docs/tool-reference.md +38 -14
  11. package/docs/watchdog.md +10 -12
  12. package/docs/workflows.md +59 -1
  13. package/index.ts +5 -2
  14. package/package.json +4 -2
  15. package/runner-peer-loader.mjs +24 -0
  16. package/runner-peer-preload.mjs +25 -11
  17. package/skills/pi-subagents/SKILL.md +18 -21
  18. package/skills/pi-subagents/references/constraints-and-recipes.md +3 -2
  19. package/skills/pi-subagents/references/execution-controls.md +6 -4
  20. package/skills/pi-subagents/references/management-authoring-rpc.md +0 -1
  21. package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
  22. package/skills/pi-subagents/references/prompting-and-roles.md +16 -12
  23. package/skills/pi-subagents/references/review-and-validation.md +3 -3
  24. package/src/agents/agent-management.ts +57 -58
  25. package/src/agents/agent-serializer.ts +4 -3
  26. package/src/agents/agents.ts +185 -72
  27. package/src/agents/chain-serializer.ts +5 -0
  28. package/src/agents/runtime-agent-registry.ts +7 -6
  29. package/src/agents/skills.ts +1 -1
  30. package/src/api/preflight.ts +20 -16
  31. package/src/api/required-child-extensions.ts +6 -0
  32. package/src/extension/config.ts +10 -37
  33. package/src/extension/fanout-child.ts +3 -0
  34. package/src/extension/herdr-pi-bridge.ts +160 -0
  35. package/src/extension/index.ts +42 -31
  36. package/src/extension/public-execution.ts +3 -3
  37. package/src/extension/schemas.ts +23 -6
  38. package/src/extension/tool-description.ts +8 -7
  39. package/src/inspectors/ghostty/plugin.ts +13 -1
  40. package/src/intercom/native-supervisor-channel.ts +22 -18
  41. package/src/policy/authority.ts +4 -0
  42. package/src/profiles/profiles.ts +12 -6
  43. package/src/runs/background/active-run-index.ts +17 -1
  44. package/src/runs/background/async-execution.ts +309 -126
  45. package/src/runs/background/async-job-tracker.ts +8 -6
  46. package/src/runs/background/async-resume.ts +13 -4
  47. package/src/runs/background/async-status.ts +15 -4
  48. package/src/runs/background/auto-drain.ts +20 -10
  49. package/src/runs/background/binary-bootstrap.ts +5 -0
  50. package/src/runs/background/chain-append.ts +1 -1
  51. package/src/runs/background/chain-root-attachment.ts +14 -33
  52. package/src/runs/background/notify.ts +74 -6
  53. package/src/runs/background/result-files.ts +8 -4
  54. package/src/runs/background/result-watcher.ts +19 -2
  55. package/src/runs/background/run-child-session.ts +20 -29
  56. package/src/runs/background/runner-aliases.ts +4 -33
  57. package/src/runs/background/runner-child-launch.ts +4 -1
  58. package/src/runs/background/runner-child-sessions.ts +2 -2
  59. package/src/runs/background/runner-http-dispatcher.ts +119 -0
  60. package/src/runs/background/scheduled-runs.ts +11 -5
  61. package/src/runs/background/stale-run-reconciler.ts +35 -11
  62. package/src/runs/background/subagent-runner.ts +413 -276
  63. package/src/runs/background/subagent-wait.ts +128 -23
  64. package/src/runs/background/wait-completions.ts +75 -27
  65. package/src/runs/background/wait-subscriptions.ts +9 -3
  66. package/src/runs/background/wait-tool.ts +4 -2
  67. package/src/runs/foreground/async-stop-action.ts +93 -3
  68. package/src/runs/foreground/execution.ts +115 -219
  69. package/src/runs/foreground/foreground-history.ts +2 -1
  70. package/src/runs/foreground/subagent-executor.ts +281 -80
  71. package/src/runs/shared/acceptance.ts +194 -37
  72. package/src/runs/shared/async-status-projection.ts +123 -33
  73. package/src/runs/shared/child-launch-plan.ts +15 -3
  74. package/src/runs/shared/child-launch.ts +19 -6
  75. package/src/runs/shared/child-runtime-config.ts +5 -0
  76. package/src/runs/shared/child-session.ts +94 -50
  77. package/src/runs/shared/child-tool-plan.ts +28 -16
  78. package/src/runs/shared/dynamic-fanout.ts +2 -2
  79. package/src/runs/shared/external-cli-contract.ts +11 -1
  80. package/src/runs/shared/external-cli-preflight.ts +6 -2
  81. package/src/runs/shared/herdr-connection.ts +134 -0
  82. package/src/runs/shared/herdr-external-adapters.ts +169 -0
  83. package/src/runs/shared/herdr-machine.ts +279 -0
  84. package/src/runs/shared/herdr-pi-protocol.ts +59 -0
  85. package/src/runs/shared/herdr-placed-run.ts +263 -0
  86. package/src/runs/shared/model-resolution-diagnostic.ts +76 -0
  87. package/src/runs/shared/{model-fallback.ts → model-resolution.ts} +22 -237
  88. package/src/runs/shared/model-scope.ts +1 -1
  89. package/src/runs/shared/nested-events.ts +11 -2
  90. package/src/runs/shared/parallel-utils.ts +7 -2
  91. package/src/runs/shared/pi-spawn.ts +1 -1
  92. package/src/runs/shared/subagent-prompt-runtime.ts +4 -2
  93. package/src/runs/shared/worktree-setup-command.ts +27 -4
  94. package/src/runs/shared/worktree.ts +30 -8
  95. package/src/shared/child-cache-retention.ts +43 -0
  96. package/src/shared/launch-contract.ts +6 -9
  97. package/src/shared/pruned-fork.ts +1 -1
  98. package/src/shared/required-child-extensions.ts +81 -0
  99. package/src/shared/settings.ts +5 -2
  100. package/src/shared/shortcuts.ts +0 -4
  101. package/src/shared/types.ts +81 -29
  102. package/src/slash/slash-commands.ts +0 -6
  103. package/src/slash/subagents-admin.ts +13 -9
  104. package/src/tui/render.ts +20 -10
  105. package/src/watchdog/child-status.ts +28 -36
  106. package/src/watchdog/lsp-diagnostics.ts +1 -1
  107. package/src/watchdog/model-selection.ts +1 -1
  108. package/src/watchdog/register-child.ts +10 -3
  109. package/src/watchdog/register-main.ts +20 -20
  110. package/src/watchdog/render.ts +1 -1
  111. package/src/watchdog/review.ts +14 -30
  112. package/src/watchdog/rules.ts +1 -1
  113. package/src/watchdog/runtime.ts +23 -12
  114. package/src/watchdog/settings.ts +3 -6
  115. package/src/watchdog/types.ts +3 -5
  116. package/src/watchdog/warning-format.ts +1 -1
  117. package/src/workflows/scripted-workflow.ts +68 -7
  118. package/src/workflows/workflow-receipt.ts +21 -3
  119. package/src/workflows/workflow-resources.ts +13 -2
  120. package/src/runs/shared/model-exclusions.ts +0 -374
  121. package/src/runs/shared/readonly-model-continuation.ts +0 -69
  122. package/src/runs/shared/readonly-session-evidence.ts +0 -307
@@ -28,9 +28,9 @@ import {
28
28
  } from "./proactive-skills.ts";
29
29
  import { parseFrontmatter, parseFrontmatterList } from "./frontmatter.ts";
30
30
  import { resolveEffectiveThinking, toModelInfo } from "../shared/model-info.ts";
31
- import { resolveSubagentModelOverride, type ParentModel } from "../runs/shared/model-fallback.ts";
31
+ import { resolveSubagentModelOverride, type ParentModel } from "../runs/shared/model-resolution.ts";
32
32
  import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
33
- import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
33
+ import { formatReviewGateLabel, validateAcceptanceInput } from "../runs/shared/acceptance.ts";
34
34
  import { CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL, isCodeOwnedExternalCliAdapterId, resolveExternalCliRunnerStatus, validateCodeOwnedProfileRunner } from "../runs/shared/external-cli-contract.ts";
35
35
  import { resolveExternalCliBinaryAvailability, type ExternalCliBinaryAvailability } from "../runs/shared/external-cli-preflight.ts";
36
36
  import type { AcceptanceInput, AgentCapabilitiesSnapshot, AgentCapabilityRow, Details, ExtensionConfig, ToolBudgetConfig } from "../shared/types.ts";
@@ -218,13 +218,6 @@ function modelWarning(ctx: ManagementContext, model: string | undefined): string
218
218
  return `Warning: model '${model}' is not in the current model registry. Run subagent({ action: "models" }) to list valid provider/id selectors, then use the exact provider/id form (bare ids resolve only when unique).`;
219
219
  }
220
220
 
221
- function fallbackModelsWarning(ctx: ManagementContext, fallbackModels: string[] | undefined): string | undefined {
222
- if (!fallbackModels || fallbackModels.length === 0) return undefined;
223
- const available = new Set(ctx.modelRegistry.getAvailable().flatMap((m) => [`${m.provider}/${m.id}`, m.id]));
224
- const missing = fallbackModels.filter((model) => !available.has(model));
225
- return missing.length ? `Warning: fallback models not in the current model registry: ${missing.join(", ")}.` : undefined;
226
- }
227
-
228
221
  function skillsWarning(cwd: string, agent: Pick<AgentConfig, "skills" | "skillPath" | "filePath">): string | undefined {
229
222
  if (!agent.skills?.length) return undefined;
230
223
  const { missing } = resolveSkills(
@@ -268,7 +261,6 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
268
261
  outputMode: _outputMode,
269
262
  defaultReads: _defaultReads,
270
263
  model: _model,
271
- fallbackModels: _fallbackModels,
272
264
  fast: _fast,
273
265
  thinking: _thinking,
274
266
  systemPromptMode: _systemPromptMode,
@@ -305,7 +297,6 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
305
297
  ...(base.outputMode !== undefined ? { outputMode: base.outputMode } : {}),
306
298
  ...(base.defaultReads !== undefined ? { defaultReads: [...base.defaultReads] } : {}),
307
299
  ...(base.model !== undefined && hasDeclaredField("model") ? { model: base.model } : {}),
308
- ...(base.fallbackModels !== undefined ? { fallbackModels: [...base.fallbackModels] } : {}),
309
300
  ...(base.fast !== undefined ? { fast: base.fast } : {}),
310
301
  ...(base.thinking !== undefined && hasDeclaredField("thinking") ? { thinking: base.thinking } : {}),
311
302
  systemPromptMode: base.systemPromptMode,
@@ -353,7 +344,6 @@ export function preservedAgentFrontmatterFields(agent: AgentConfig, cfg: Record<
353
344
  if (hasKey(cfg, "systemPrompt")) changed("systemPrompt");
354
345
  if (hasKey(cfg, "runner")) changed("runner");
355
346
  if (hasKey(cfg, "model")) changed("model");
356
- if (hasKey(cfg, "fallbackModels")) changed("fallbackModels");
357
347
  if (hasKey(cfg, "tools")) changed("tools");
358
348
  if (hasKey(cfg, "excludeTools")) changed("excludeTools");
359
349
  if (hasKey(cfg, "skills")) changed("skill", "skills");
@@ -466,21 +456,7 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
466
456
  else delete target.model;
467
457
  } else return "config.model must be a string or false when provided.";
468
458
  }
469
- if (hasKey(cfg, "fallbackModels")) {
470
- if (cfg.fallbackModels === false || cfg.fallbackModels === "") delete target.fallbackModels;
471
- else if (typeof cfg.fallbackModels === "string") {
472
- const models = parseCsv(cfg.fallbackModels);
473
- if (models.length) target.fallbackModels = models;
474
- else delete target.fallbackModels;
475
- } else if (Array.isArray(cfg.fallbackModels)) {
476
- const models = cfg.fallbackModels
477
- .filter((value): value is string => typeof value === "string")
478
- .map((value) => value.trim())
479
- .filter(Boolean);
480
- if (models.length) target.fallbackModels = [...new Set(models)];
481
- else delete target.fallbackModels;
482
- } else return "config.fallbackModels must be a comma-separated string, string array, or false when provided.";
483
- }
459
+ if (hasKey(cfg, "fallbackModels")) return "config.fallbackModels was removed; configure one model instead.";
484
460
  if (hasKey(cfg, "tools")) {
485
461
  if (cfg.tools === false || cfg.tools === "") { delete target.tools; delete target.mcpDirectTools; }
486
462
  else if (typeof cfg.tools === "string") {
@@ -637,7 +613,6 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
637
613
  target.tools?.length || target.mcpDirectTools?.length ? "tools" : undefined,
638
614
  target.excludeTools?.length ? "excludeTools" : undefined,
639
615
  target.model ? "model" : undefined,
640
- target.fallbackModels?.length ? "fallbackModels" : undefined,
641
616
  target.thinking ? "thinking" : undefined,
642
617
  target.extensions?.length ? "extensions" : undefined,
643
618
  target.subagentOnlyExtensions?.length ? "subagentOnlyExtensions" : undefined,
@@ -713,13 +688,19 @@ function externalJobProviderSuffix(provider: string, names: Set<string> | undefi
713
688
 
714
689
  type ExternalCliAvailabilityByCommand = ReadonlyMap<string, ExternalCliBinaryAvailability>;
715
690
 
691
+ /** A placed agent checks only local ssh; machine catalog and remote CLI validation happen at launch. */
692
+ function externalCliAvailabilityKey(command: string, machine: string | undefined): string {
693
+ return machine ? `ssh@${machine}` : command;
694
+ }
695
+
716
696
  function externalCliAvailabilityForAgents(agents: readonly AgentConfig[]): ExternalCliAvailabilityByCommand {
717
697
  const availability = new Map<string, ExternalCliBinaryAvailability>();
718
698
  for (const agent of agents) {
719
699
  const runner = agent.runner;
720
- if (runner?.type === "external-cli" && !availability.has(runner.command)) {
721
- availability.set(runner.command, resolveExternalCliBinaryAvailability(runner.command, process.env));
722
- }
700
+ if (runner?.type !== "external-cli") continue;
701
+ const key = externalCliAvailabilityKey(runner.command, agent.machine);
702
+ if (availability.has(key)) continue;
703
+ availability.set(key, resolveExternalCliBinaryAvailability(agent.machine ? "ssh" : runner.command, process.env));
723
704
  }
724
705
  return availability;
725
706
  }
@@ -727,10 +708,13 @@ function externalCliAvailabilityForAgents(agents: readonly AgentConfig[]): Exter
727
708
  function runnerListBadge(agent: AgentConfig, providerNames: Set<string> | undefined, externalCliAvailability?: ExternalCliAvailabilityByCommand): string | undefined {
728
709
  if (agent.runner?.type === "external-job") return `external-job:${agent.runner.provider} ${externalJobProviderSuffix(agent.runner.provider, providerNames)}`;
729
710
  if (agent.runner?.type === "external-cli") {
730
- const availability = externalCliAvailability?.get(agent.runner.command);
731
- if (!availability) return "external-cli";
732
- return `external-cli:${agent.runner.command} ${availability.available ? "✓" : "missing"}`;
711
+ const placed = agent.machine ? `${agent.runner.command} @ ${agent.machine}` : agent.runner.command;
712
+ const availability = externalCliAvailability?.get(externalCliAvailabilityKey(agent.runner.command, agent.machine));
713
+ if (!availability) return `external-cli:${placed}`;
714
+ if (agent.machine) return `external-cli:${placed} saved Herdr placement; transport ${availability.available ? "✓" : "missing"}; machine not preflighted`;
715
+ return `external-cli:${placed} ${availability.available ? "✓" : "missing"}`;
733
716
  }
717
+ if (agent.machine) return `machine: ${agent.machine} (saved Herdr placement)`;
734
718
  return undefined;
735
719
  }
736
720
 
@@ -766,7 +750,39 @@ function formatAgentCapabilitiesLine(agent: AgentConfig, providerNames: Set<stri
766
750
  if (agent.modelProvider && !agent.model.includes("/")) model = `${agent.modelProvider}/${agent.model}`;
767
751
  }
768
752
  const thinking = agent.thinking === false ? "off" : agent.thinking ?? "default";
769
- return `- ${agent.name} (${agentListMetadata(agent, providerNames, externalCliAvailability)}): Description: ${previewDisplayText(agent.description, 240)}; Tools: ${tools}; Model: ${model}; Thinking: ${thinking}`;
753
+ const machine = agent.machine ? `; Machine: ${agent.machine} (saved Herdr placement)` : "";
754
+ const acceptance = formatAcceptanceSummary(agent);
755
+ return `- ${agent.name} (${agentListMetadata(agent, providerNames, externalCliAvailability)}): Description: ${previewDisplayText(agent.description, 240)}; Tools: ${tools}; Model: ${model}; Thinking: ${thinking}${machine}${acceptance ? `; ${acceptance}` : ""}`;
756
+ }
757
+
758
+ function formatAcceptanceSummary(agent: AgentConfig): string | undefined {
759
+ const policy = agent.defaultAcceptance;
760
+ const summary: string[] = [];
761
+ if (policy === false) summary.push("Acceptance: disabled");
762
+ else if (typeof policy === "string") summary.push(`Acceptance: ${policy}`);
763
+ else if (policy) {
764
+ const modifiers = [
765
+ ...(policy.evidence ?? []),
766
+ ...(policy.verify ?? []).map((command) => `verify: ${formatAcceptanceDisplayLabel(command.id)}`),
767
+ ...(policy.criteria?.length ? [`criteria: ${policy.criteria.length}`] : []),
768
+ ...(policy.stopRules?.length ? [`stopRules: ${policy.stopRules.length}`] : []),
769
+ ];
770
+ if (policy.review === false) modifiers.push("review: off");
771
+ else if (policy.review) {
772
+ const displayReview = policy.review.agent
773
+ ? { ...policy.review, agent: formatAcceptanceDisplayLabel(policy.review.agent) }
774
+ : policy.review;
775
+ modifiers.push(`review: ${formatReviewGateLabel(displayReview)}`);
776
+ }
777
+ if (policy.report) modifiers.push(`report: ${policy.report}`);
778
+ summary.push(`Acceptance: ${policy.level ?? "auto"}${modifiers.length > 0 ? ` (${modifiers.join(", ")})` : ""}`);
779
+ }
780
+ if (agent.acceptanceRole) summary.push(`Acceptance role: ${agent.acceptanceRole}`);
781
+ return summary.length > 0 ? summary.join("; ") : undefined;
782
+ }
783
+
784
+ function formatAcceptanceDisplayLabel(value: string): string {
785
+ return JSON.stringify(previewDisplayText(value, 80));
770
786
  }
771
787
 
772
788
  const EXTERNAL_JOB_CAPABILITIES = { stop: false, steer: false, resume: false, structuredOutput: false, toolEvents: false } as const;
@@ -780,11 +796,12 @@ function agentCapabilityRunner(agent: AgentConfig, providerNames: Set<string> |
780
796
  const runner = agent.runner;
781
797
  if (!runner || runner.type === "pi") return PI_AGENT_RUNNER;
782
798
  if (runner.type === "external-cli") {
783
- const availability = externalCliAvailability.get(runner.command)!;
799
+ const availability = externalCliAvailability.get(externalCliAvailabilityKey(runner.command, agent.machine))!;
784
800
  return {
785
801
  type: "external-cli",
786
802
  adapter: runner.adapter,
787
803
  command: runner.command,
804
+ ...(agent.machine ? { machine: agent.machine } : {}),
788
805
  ...availability,
789
806
  capabilities: resolveExternalCliRunnerStatus(runner).capabilities,
790
807
  };
@@ -812,8 +829,9 @@ function agentCapabilityRow(agent: AgentConfig, options: { executable: boolean;
812
829
  aliases: agent.aliases ? [...agent.aliases] : undefined,
813
830
  runner: agentCapabilityRunner(agent, options.providerNames, options.externalCliAvailability),
814
831
  tools: agentCapabilityTools(agent),
815
- model: presentDetails({ value: agent.model, fallbackModels: agent.fallbackModels, thinking: agent.thinking }),
832
+ model: presentDetails({ value: agent.model, thinking: agent.thinking }),
816
833
  execution: presentDetails({ defaultAsync: agent.defaultAsync, timeoutMs: agent.defaultTimeoutMs }),
834
+ acceptance: presentDetails({ policy: agent.defaultAcceptance, role: agent.acceptanceRole }),
817
835
  output: presentDetails({ path: agent.output, mode: agent.outputMode }),
818
836
  extensions: presentDetails({ names: agent.extensions, subagentOnly: agent.subagentOnlyExtensions, skills: agent.skills }),
819
837
  };
@@ -914,7 +932,6 @@ function formatAgentDetail(agent: AgentConfig): string {
914
932
  }
915
933
  if (agent.aliases?.length) lines.push(`Aliases: ${agent.aliases.join(", ")}`);
916
934
  if (agent.model) lines.push(`Model: ${agent.model}`);
917
- if (agent.fallbackModels?.length) lines.push(`Fallback models: ${agent.fallbackModels.join(", ")}`);
918
935
  if (tools.length) lines.push(`Tools: ${tools.join(", ")}`);
919
936
  if (agent.excludeTools?.length) lines.push(`Excluded tools: ${agent.excludeTools.join(", ")}`);
920
937
  if (agent.skills?.length) lines.push(`Skills: ${agent.skills.join(", ")}`);
@@ -1057,12 +1074,6 @@ function handleModels(params: ManagementParams, ctx: ManagementContext): AgentTo
1057
1074
  lines.push(` ${resolvedModel ?? "(unresolved)"}`);
1058
1075
  lines.push(`Source: ${source}`);
1059
1076
  lines.push(`Thinking: ${effectiveThinking ?? "default"}`);
1060
- if (agent.fallbackModels?.length) {
1061
- lines.push("Fallback models:");
1062
- for (const fallback of agent.fallbackModels) {
1063
- lines.push(` ${resolveSubagentModelOverride(fallback, currentModel, availableModels, agent.modelProvider ?? preferredProvider) ?? fallback}`);
1064
- }
1065
- }
1066
1077
  if (agent.override) {
1067
1078
  lines.push("Override file:");
1068
1079
  lines.push(` ${agent.override.path}`);
@@ -1082,12 +1093,6 @@ function handleModels(params: ManagementParams, ctx: ManagementContext): AgentTo
1082
1093
  lines.push(` ${resolvedModel ?? "(unresolved)"}`);
1083
1094
  lines.push(` source: ${source}`);
1084
1095
  lines.push(` thinking: ${effectiveThinking ?? "default"}`);
1085
- if (agent.fallbackModels?.length) {
1086
- lines.push(" fallback models:");
1087
- for (const fallback of agent.fallbackModels) {
1088
- lines.push(` ${resolveSubagentModelOverride(fallback, currentModel, availableModels, agent.modelProvider ?? preferredProvider) ?? fallback}`);
1089
- }
1090
- }
1091
1096
  if (agent.override) {
1092
1097
  lines.push(" override file:");
1093
1098
  lines.push(` ${agent.override.path}`);
@@ -1177,8 +1182,6 @@ export function handleCreate(params: ManagementParams, ctx: ManagementContext):
1177
1182
  if (profileError) return result(profileError, true);
1178
1183
  const mw = modelWarning(ctx, agent.model);
1179
1184
  if (mw) warnings.push(mw);
1180
- const fmw = fallbackModelsWarning(ctx, agent.fallbackModels);
1181
- if (fmw) warnings.push(fmw);
1182
1185
  const sw = skillsWarning(ctx.cwd, agent);
1183
1186
  if (sw) warnings.push(sw);
1184
1187
  fs.writeFileSync(targetPath, serializeAgent(agent), "utf-8");
@@ -1234,10 +1237,6 @@ export function handleUpdate(params: ManagementParams, ctx: ManagementContext):
1234
1237
  const mw = modelWarning(ctx, updated.model);
1235
1238
  if (mw) warnings.push(mw);
1236
1239
  }
1237
- if (hasKey(cfg, "fallbackModels")) {
1238
- const fmw = fallbackModelsWarning(ctx, updated.fallbackModels);
1239
- if (fmw) warnings.push(fmw);
1240
- }
1241
1240
  if (hasKey(cfg, "skills") || hasKey(cfg, "skillPath")) {
1242
1241
  const sw = skillsWarning(ctx.cwd, updated);
1243
1242
  if (sw) warnings.push(sw);
@@ -1385,8 +1384,8 @@ function handleReset(params: ManagementParams, ctx: ManagementContext): AgentToo
1385
1384
  fs.unlinkSync(custom.filePath);
1386
1385
  lines.push(`Deleted custom ${scope} agent file at ${custom.filePath}.`);
1387
1386
  }
1388
- const overrideRemoval = removeBuiltinAgentOverride(ctx.cwd, runtimeName, scope);
1389
- if (overrideRemoval.removed) lines.push(`Removed ${scope} settings override at ${overrideRemoval.path}.`);
1387
+ const overrideRemoval = removeBuiltinAgentOverride(ctx.cwd, runtimeName, scope, { preserveMachine: true });
1388
+ if (overrideRemoval.removed) lines.push(`${overrideRemoval.machinePreserved ? "Cleared customization in" : "Removed"} ${scope} settings override at ${overrideRemoval.path}.${overrideRemoval.machinePreserved ? " Retained machine placement." : ""}`);
1390
1389
  if (lines.length === 0) {
1391
1390
  const otherScope = scope === "user" ? "project" : "user";
1392
1391
  const otherCustom = (otherScope === "user" ? d.user : d.project).find((a) => a.name === raw || a.name === sanitized);
@@ -13,7 +13,6 @@ export const KNOWN_FIELDS = new Set([
13
13
  "excludeTools",
14
14
  "allowNestedSubagents",
15
15
  "model",
16
- "fallbackModels",
17
16
  "fast",
18
17
  "thinking",
19
18
  "systemPromptMode",
@@ -32,8 +31,10 @@ export const KNOWN_FIELDS = new Set([
32
31
  "extensions",
33
32
  "subagentOnlyExtensions",
34
33
  "mutationTools",
34
+ "machine",
35
35
  "output",
36
36
  "outputMode",
37
+ "outputSchema",
37
38
  "defaultReads",
38
39
  "defaultProgress",
39
40
  "interactive",
@@ -80,8 +81,6 @@ export function serializeAgent(config: AgentConfig, options: SerializeAgentOptio
80
81
  }
81
82
 
82
83
  if (config.model || preserve("model")) lines.push(`model: ${config.model ?? ""}`);
83
- const fallbackModelsValue = joinComma(config.fallbackModels);
84
- if (fallbackModelsValue || preserve("fallbackModels")) lines.push(`fallbackModels: ${fallbackModelsValue ?? ""}`);
85
84
  if (config.fast === true || preserve("fast")) lines.push(`fast: ${config.fast === undefined ? "" : config.fast ? "true" : "false"}`);
86
85
  if ((config.thinking && (config.thinking !== "off" || preserve("thinking"))) || (!config.thinking && preserve("thinking"))) {
87
86
  lines.push(`thinking: ${config.thinking ?? ""}`);
@@ -127,8 +126,10 @@ export function serializeAgent(config: AgentConfig, options: SerializeAgentOptio
127
126
  const mutationToolsValue = joinComma(config.mutationTools);
128
127
  if (mutationToolsValue || preserve("mutationTools")) lines.push(`mutationTools: ${mutationToolsValue ?? ""}`);
129
128
 
129
+ if (config.machine || preserve("machine")) lines.push(`machine: ${config.machine ?? ""}`);
130
130
  if (config.output || preserve("output")) lines.push(`output: ${config.output ?? ""}`);
131
131
  if (config.outputMode || preserve("outputMode")) lines.push(`outputMode: ${config.outputMode ?? ""}`);
132
+ if (config.outputSchema || preserve("outputSchema")) lines.push(`outputSchema: ${config.outputSchema ? JSON.stringify(config.outputSchema) : ""}`);
132
133
 
133
134
  const readsValue = joinComma(config.defaultReads);
134
135
  if (readsValue || preserve("defaultReads")) lines.push(`defaultReads: ${readsValue ?? ""}`);