@pi-agents/orchid 0.1.0-beta.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 (163) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.md +246 -0
  4. package/agents/AGENTS-MANIFEST.md +42 -0
  5. package/agents/brain.md +42 -0
  6. package/agents/context-builder.md +46 -0
  7. package/agents/delegate.md +12 -0
  8. package/agents/dev-1.md +42 -0
  9. package/agents/oracle.md +73 -0
  10. package/agents/planner.md +55 -0
  11. package/agents/researcher.md +52 -0
  12. package/agents/reviewer.md +79 -0
  13. package/agents/scout.md +50 -0
  14. package/agents/tester.md +45 -0
  15. package/agents/worker.md +55 -0
  16. package/extensions/ralph.ts +1 -0
  17. package/extensions/reviewer-extension.ts +125 -0
  18. package/extensions/task-orchestrator.ts +28 -0
  19. package/package.json +63 -0
  20. package/prompts/gather-context-and-clarify.md +13 -0
  21. package/prompts/parallel-cleanup.md +59 -0
  22. package/prompts/parallel-context-build.md +53 -0
  23. package/prompts/parallel-handoff-plan.md +59 -0
  24. package/prompts/parallel-research.md +50 -0
  25. package/prompts/parallel-review.md +54 -0
  26. package/prompts/review-loop.md +41 -0
  27. package/skills/orchid/SKILL.md +214 -0
  28. package/skills/orchid/orchid-cleanup/SKILL.md +122 -0
  29. package/skills/orchid/orchid-converge/SKILL.md +124 -0
  30. package/skills/orchid/orchid-decompose/SKILL.md +201 -0
  31. package/skills/orchid/orchid-doctor/SKILL.md +162 -0
  32. package/skills/orchid/orchid-investigate/SKILL.md +102 -0
  33. package/skills/orchid/orchid-launch/SKILL.md +147 -0
  34. package/skills/ralph/SKILL.md +73 -0
  35. package/skills/subagents/pi-subagents/SKILL.md +813 -0
  36. package/src/index.ts +7 -0
  37. package/src/orchestrator/abort.ts +534 -0
  38. package/src/orchestrator/agent-bridge-extension.ts +1020 -0
  39. package/src/orchestrator/agent-host.ts +954 -0
  40. package/src/orchestrator/cleanup.ts +776 -0
  41. package/src/orchestrator/config-loader.ts +1412 -0
  42. package/src/orchestrator/config-schema.ts +690 -0
  43. package/src/orchestrator/config.ts +81 -0
  44. package/src/orchestrator/context-window.ts +66 -0
  45. package/src/orchestrator/diagnostic-reports.ts +475 -0
  46. package/src/orchestrator/diagnostics.ts +394 -0
  47. package/src/orchestrator/discovery.ts +1833 -0
  48. package/src/orchestrator/engine-worker.ts +415 -0
  49. package/src/orchestrator/engine.ts +5940 -0
  50. package/src/orchestrator/execution.ts +3104 -0
  51. package/src/orchestrator/extension.ts +5934 -0
  52. package/src/orchestrator/formatting.ts +785 -0
  53. package/src/orchestrator/git.ts +88 -0
  54. package/src/orchestrator/index.ts +28 -0
  55. package/src/orchestrator/lane-runner.ts +1787 -0
  56. package/src/orchestrator/mailbox.ts +780 -0
  57. package/src/orchestrator/merge.ts +3414 -0
  58. package/src/orchestrator/messages.ts +1062 -0
  59. package/src/orchestrator/migrations.ts +278 -0
  60. package/src/orchestrator/naming.ts +117 -0
  61. package/src/orchestrator/path-resolver.ts +275 -0
  62. package/src/orchestrator/persistence.ts +2625 -0
  63. package/src/orchestrator/process-registry.ts +452 -0
  64. package/src/orchestrator/quality-gate.ts +1085 -0
  65. package/src/orchestrator/resume.ts +3488 -0
  66. package/src/orchestrator/sessions.ts +57 -0
  67. package/src/orchestrator/settings-loader.ts +136 -0
  68. package/src/orchestrator/settings-tui.ts +2208 -0
  69. package/src/orchestrator/sidecar-telemetry.ts +267 -0
  70. package/src/orchestrator/supervisor.ts +4548 -0
  71. package/src/orchestrator/task-executor-core.ts +675 -0
  72. package/src/orchestrator/tmux-compat.ts +37 -0
  73. package/src/orchestrator/tool-allowlist-constants.ts +37 -0
  74. package/src/orchestrator/types.ts +4465 -0
  75. package/src/orchestrator/verification.ts +547 -0
  76. package/src/orchestrator/waves.ts +1564 -0
  77. package/src/orchestrator/workspace.ts +707 -0
  78. package/src/orchestrator/worktree.ts +2725 -0
  79. package/src/ralph/index.ts +825 -0
  80. package/src/subagents/agents/agent-management.ts +648 -0
  81. package/src/subagents/agents/agent-scope.ts +6 -0
  82. package/src/subagents/agents/agent-selection.ts +23 -0
  83. package/src/subagents/agents/agent-serializer.ts +86 -0
  84. package/src/subagents/agents/agents.ts +832 -0
  85. package/src/subagents/agents/chain-serializer.ts +137 -0
  86. package/src/subagents/agents/frontmatter.ts +29 -0
  87. package/src/subagents/agents/identity.ts +30 -0
  88. package/src/subagents/agents/skills.ts +632 -0
  89. package/src/subagents/extension/config.ts +16 -0
  90. package/src/subagents/extension/control-notices.ts +92 -0
  91. package/src/subagents/extension/doctor.ts +199 -0
  92. package/src/subagents/extension/fanout-child.ts +170 -0
  93. package/src/subagents/extension/index.ts +573 -0
  94. package/src/subagents/extension/schemas.ts +168 -0
  95. package/src/subagents/intercom/intercom-bridge.ts +379 -0
  96. package/src/subagents/intercom/result-intercom.ts +377 -0
  97. package/src/subagents/runs/background/async-execution.ts +712 -0
  98. package/src/subagents/runs/background/async-job-tracker.ts +310 -0
  99. package/src/subagents/runs/background/async-resume.ts +345 -0
  100. package/src/subagents/runs/background/async-status.ts +325 -0
  101. package/src/subagents/runs/background/completion-dedupe.ts +63 -0
  102. package/src/subagents/runs/background/notify.ts +108 -0
  103. package/src/subagents/runs/background/parallel-groups.ts +45 -0
  104. package/src/subagents/runs/background/result-watcher.ts +307 -0
  105. package/src/subagents/runs/background/run-id-resolver.ts +83 -0
  106. package/src/subagents/runs/background/run-status.ts +269 -0
  107. package/src/subagents/runs/background/stale-run-reconciler.ts +336 -0
  108. package/src/subagents/runs/background/subagent-runner.ts +1808 -0
  109. package/src/subagents/runs/background/top-level-async.ts +13 -0
  110. package/src/subagents/runs/foreground/chain-clarify.ts +1333 -0
  111. package/src/subagents/runs/foreground/chain-execution.ts +938 -0
  112. package/src/subagents/runs/foreground/execution.ts +918 -0
  113. package/src/subagents/runs/foreground/subagent-executor.ts +2527 -0
  114. package/src/subagents/runs/shared/completion-guard.ts +147 -0
  115. package/src/subagents/runs/shared/long-running-guard.ts +175 -0
  116. package/src/subagents/runs/shared/mcp-direct-tool-allowlist.ts +365 -0
  117. package/src/subagents/runs/shared/model-fallback.ts +103 -0
  118. package/src/subagents/runs/shared/nested-events.ts +819 -0
  119. package/src/subagents/runs/shared/nested-path.ts +52 -0
  120. package/src/subagents/runs/shared/nested-render.ts +115 -0
  121. package/src/subagents/runs/shared/parallel-utils.ts +109 -0
  122. package/src/subagents/runs/shared/pi-args.ts +220 -0
  123. package/src/subagents/runs/shared/pi-spawn.ts +115 -0
  124. package/src/subagents/runs/shared/run-history.ts +60 -0
  125. package/src/subagents/runs/shared/single-output.ts +164 -0
  126. package/src/subagents/runs/shared/subagent-control.ts +226 -0
  127. package/src/subagents/runs/shared/subagent-prompt-runtime.ts +170 -0
  128. package/src/subagents/runs/shared/worktree.ts +577 -0
  129. package/src/subagents/shared/artifacts.ts +98 -0
  130. package/src/subagents/shared/atomic-json.ts +16 -0
  131. package/src/subagents/shared/file-coalescer.ts +40 -0
  132. package/src/subagents/shared/fork-context.ts +76 -0
  133. package/src/subagents/shared/formatters.ts +133 -0
  134. package/src/subagents/shared/jsonl-writer.ts +81 -0
  135. package/src/subagents/shared/model-info.ts +78 -0
  136. package/src/subagents/shared/post-exit-stdio-guard.ts +85 -0
  137. package/src/subagents/shared/session-identity.ts +10 -0
  138. package/src/subagents/shared/session-tokens.ts +44 -0
  139. package/src/subagents/shared/settings.ts +397 -0
  140. package/src/subagents/shared/status-format.ts +49 -0
  141. package/src/subagents/shared/types.ts +822 -0
  142. package/src/subagents/shared/utils.ts +450 -0
  143. package/src/subagents/slash/prompt-template-bridge.ts +397 -0
  144. package/src/subagents/slash/slash-bridge.ts +174 -0
  145. package/src/subagents/slash/slash-commands.ts +528 -0
  146. package/src/subagents/slash/slash-live-state.ts +292 -0
  147. package/src/subagents/tui/render-helpers.ts +80 -0
  148. package/src/subagents/tui/render.ts +1358 -0
  149. package/templates/agents/local/supervisor.md +33 -0
  150. package/templates/agents/local/task-merger.md +27 -0
  151. package/templates/agents/local/task-reviewer.md +30 -0
  152. package/templates/agents/local/task-worker.md +34 -0
  153. package/templates/agents/supervisor-routing.md +92 -0
  154. package/templates/agents/supervisor.md +229 -0
  155. package/templates/agents/task-merger.md +214 -0
  156. package/templates/agents/task-reviewer.md +260 -0
  157. package/templates/agents/task-worker-segment.md +44 -0
  158. package/templates/agents/task-worker.md +557 -0
  159. package/templates/tasks/CONTEXT.md +30 -0
  160. package/templates/tasks/EXAMPLE-001-hello-world/PROMPT.md +98 -0
  161. package/templates/tasks/EXAMPLE-001-hello-world/STATUS.md +73 -0
  162. package/templates/tasks/EXAMPLE-002-parallel-smoke/PROMPT.md +97 -0
  163. package/templates/tasks/EXAMPLE-002-parallel-smoke/STATUS.md +73 -0
@@ -0,0 +1,690 @@
1
+ /**
2
+ * Unified project configuration schema for orchid-config.json
3
+ *
4
+ * Merges all settings from task-runner.yaml and task-orchestrator.yaml
5
+ * into a single JSON-first configuration file with clear sections.
6
+ *
7
+ * Key naming policy:
8
+ * - JSON uses camelCase (e.g., `maxLanes`, `workerContextWindow`)
9
+ * - YAML fallback loader maps snake_case keys to camelCase equivalents
10
+ * - The runtime config object always uses the interfaces defined here
11
+ *
12
+ * Section map (old YAML → new JSON):
13
+ * task-runner.yaml:
14
+ * project → taskRunner.project
15
+ * paths → taskRunner.paths
16
+ * testing → taskRunner.testing
17
+ * standards → taskRunner.standards
18
+ * standards_overrides → taskRunner.standardsOverrides
19
+ * worker → taskRunner.worker
20
+ * reviewer → taskRunner.reviewer
21
+ * context → taskRunner.context
22
+ * task_areas → taskRunner.taskAreas
23
+ * reference_docs → taskRunner.referenceDocs
24
+ * never_load → taskRunner.neverLoad
25
+ * self_doc_targets → taskRunner.selfDocTargets
26
+ * protected_docs → taskRunner.protectedDocs
27
+ *
28
+ * task-orchestrator.yaml:
29
+ * orchestrator → orchestrator.orchestrator
30
+ * dependencies → orchestrator.dependencies
31
+ * assignment → orchestrator.assignment
32
+ * pre_warm → orchestrator.preWarm
33
+ * merge → orchestrator.merge
34
+ * failure → orchestrator.failure
35
+ * monitoring → orchestrator.monitoring
36
+ *
37
+ * @module config/schema
38
+ */
39
+
40
+ // TP-189 (Cluster B): single source of truth for the worker user-tools
41
+ // default literal. This is a deliberately import-free module so we can
42
+ // import it here without pulling `agent-host.ts`'s `child_process`/`fs`
43
+ // imports into the schema layer.
44
+ import { DEFAULT_WORKER_USER_TOOLS } from "./tool-allowlist-constants.ts";
45
+
46
+ // ── Config Version ───────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Current config schema version.
50
+ *
51
+ * Semantics:
52
+ * - Required field in orchid-config.json (must be present and valid)
53
+ * - Initial version: 1
54
+ * - Loader behavior for unknown future versions: reject with a clear
55
+ * error message telling the user to upgrade OrchID
56
+ * - YAML fallback files have no version field; the loader treats them
57
+ * as implicitly version 1
58
+ */
59
+ export const CONFIG_VERSION = 1;
60
+
61
+ // ── Canonical Config Path ────────────────────────────────────────────
62
+
63
+ /**
64
+ * Canonical filename for the unified JSON config.
65
+ * Resolved relative to project root: `.pi/orchid-config.json`
66
+ */
67
+ export const PROJECT_CONFIG_FILENAME = "orchid-config.json";
68
+
69
+ // ── Task Runner Section Interfaces ───────────────────────────────────
70
+
71
+ /** Project metadata */
72
+ export interface ProjectMetadataConfig {
73
+ /** Project display name used in prompts/status UI context */
74
+ name: string;
75
+ /** Short project description for agent context */
76
+ description: string;
77
+ }
78
+
79
+ /** Path metadata for the project */
80
+ export interface PathsConfig {
81
+ /** Logical tasks root path metadata */
82
+ tasks: string;
83
+ /** Path to architecture document used in context references */
84
+ architecture?: string;
85
+ }
86
+
87
+ /** Verification commands available to agents/reviewers */
88
+ export interface TestingConfig {
89
+ /** Named commands (e.g., { test: "npm test", build: "npm run build" }) */
90
+ commands: Record<string, string>;
91
+ }
92
+
93
+ /** Coding standards for agent context */
94
+ export interface StandardsConfig {
95
+ /** Docs to treat as coding/review standards references */
96
+ docs: string[];
97
+ /** Plain-language rules injected into agent context */
98
+ rules: string[];
99
+ }
100
+
101
+ /** Per-area standards override */
102
+ export interface StandardsOverride {
103
+ /** Override docs for this area */
104
+ docs?: string[];
105
+ /** Override rules for this area */
106
+ rules?: string[];
107
+ }
108
+
109
+ /** Worker agent configuration */
110
+ export interface WorkerConfig {
111
+ /** Worker model. Empty string = inherit from active pi session model */
112
+ model: string;
113
+ /** Tool allowlist passed to worker agent invocations */
114
+ tools: string;
115
+ /** Thinking mode setting passed to worker agent */
116
+ thinking: string;
117
+ /** Optional spawn mode override for task-runner (Runtime V2 subprocess-only). */
118
+ spawnMode?: "subprocess";
119
+ /** Package specifiers to exclude from extension forwarding for worker agents (exact match). @since TP-180 */
120
+ excludeExtensions?: string[];
121
+ }
122
+
123
+ /** Reviewer agent configuration */
124
+ export interface ReviewerConfig {
125
+ /** Reviewer model (empty = inherit session model) */
126
+ model: string;
127
+ /** Tool allowlist for reviewer agent */
128
+ tools: string;
129
+ /** Thinking mode for reviewer */
130
+ thinking: string;
131
+ /** Package specifiers to exclude from extension forwarding for reviewer agents (exact match). @since TP-180 */
132
+ excludeExtensions?: string[];
133
+ }
134
+
135
+ /** Context/resource limits for task execution */
136
+ export interface ContextConfig {
137
+ /** Context window size used for worker context pressure tracking.
138
+ * Set to 0 (default) for auto-detection from the pi model registry.
139
+ * When 0, the task-runner resolves at runtime: ctx.model.contextWindow → 200K fallback. */
140
+ workerContextWindow: number;
141
+ /** Warn threshold for context utilization (percent) */
142
+ warnPercent: number;
143
+ /** Hard-stop threshold for context utilization (percent) */
144
+ killPercent: number;
145
+ /** Max worker iterations per step before failure */
146
+ maxWorkerIterations: number;
147
+ /** Max revise loops per review stage */
148
+ maxReviewCycles: number;
149
+ /** Max no-progress iterations before marking failure */
150
+ noProgressLimit: number;
151
+ /** Optional per-worker wall-clock cap (minutes, used in orchestrated flows) */
152
+ maxWorkerMinutes?: number;
153
+ }
154
+
155
+ /** Task area definition */
156
+ export interface TaskAreaConfig {
157
+ /** Directory containing task folders */
158
+ path: string;
159
+ /** Task ID prefix convention for that area */
160
+ prefix: string;
161
+ /** Area context file path (CONTEXT.md) */
162
+ context: string;
163
+ /** Optional repo ID for routing tasks in this area (workspace mode only) */
164
+ repoId?: string;
165
+ }
166
+
167
+ /** Self-documentation target definition */
168
+ export interface SelfDocTarget {
169
+ /** File path where agents should log discoveries */
170
+ [key: string]: string;
171
+ }
172
+
173
+ /**
174
+ * Severity threshold for quality gate pass decisions.
175
+ *
176
+ * - `no_critical`: PASS if no critical findings (important/suggestion allowed)
177
+ * - `no_important`: PASS if no critical and fewer than 3 important findings
178
+ * - `all_clear`: PASS only if zero findings of any severity
179
+ */
180
+ export type PassThreshold = "no_critical" | "no_important" | "all_clear";
181
+
182
+ /**
183
+ * Model fallback behavior when a configured agent model becomes unavailable mid-batch.
184
+ *
185
+ * - `"inherit"`: Fall back to the session model and retry (default). The task is
186
+ * retried without an explicit --model flag, so pi uses whatever model the
187
+ * session is configured with.
188
+ * - `"fail"`: Fail immediately — the normal failure/retry path handles the error
189
+ * without any model substitution.
190
+ *
191
+ * @since TP-055
192
+ */
193
+ export type ModelFallbackMode = "inherit" | "fail";
194
+
195
+ /** Quality gate configuration — opt-in post-completion review */
196
+ export interface QualityGateConfig {
197
+ /** Enable quality gate review before .DONE creation (default: false) */
198
+ enabled: boolean;
199
+ /** Model used for quality gate review agent (empty = inherit session model) */
200
+ reviewModel: string;
201
+ /** Max total review cycles before marking task failed (default: 2) */
202
+ maxReviewCycles: number;
203
+ /** Max fix agent cycles per quality gate run (default: 1) */
204
+ maxFixCycles: number;
205
+ /** Severity threshold for PASS decision (default: "no_critical") */
206
+ passThreshold: PassThreshold;
207
+ }
208
+
209
+ // ── Task Runner Combined Section ─────────────────────────────────────
210
+
211
+ /**
212
+ * All task-runner settings, previously from `.pi/task-runner.yaml`.
213
+ *
214
+ * Contains sections consumed by both the task-runner extension directly
215
+ * and by broader ecosystem tooling (skills, workflows, orchestrator).
216
+ */
217
+ export interface TaskRunnerSection {
218
+ /** Project metadata */
219
+ project: ProjectMetadataConfig;
220
+ /** Path metadata */
221
+ paths: PathsConfig;
222
+ /** Verification commands */
223
+ testing: TestingConfig;
224
+ /** Coding standards */
225
+ standards: StandardsConfig;
226
+ /** Per-area standards overrides, keyed by area name */
227
+ standardsOverrides: Record<string, StandardsOverride>;
228
+ /** Worker agent configuration */
229
+ worker: WorkerConfig;
230
+ /** Reviewer agent configuration */
231
+ reviewer: ReviewerConfig;
232
+ /** Context/resource limits */
233
+ context: ContextConfig;
234
+ /** Task area definitions, keyed by area name */
235
+ taskAreas: Record<string, TaskAreaConfig>;
236
+ /** Named reference docs catalog */
237
+ referenceDocs: Record<string, string>;
238
+ /** Files/docs that should not be loaded into task execution context */
239
+ neverLoad: string[];
240
+ /** Target anchors where agents should log discoveries */
241
+ selfDocTargets: Record<string, string>;
242
+ /** Paths requiring explicit user approval before modification */
243
+ protectedDocs: string[];
244
+ /** Quality gate configuration — opt-in post-completion review */
245
+ qualityGate: QualityGateConfig;
246
+ /**
247
+ * Model fallback behavior when a configured model becomes unavailable mid-batch.
248
+ *
249
+ * - `"inherit"` (default): Retry the task without an explicit model flag,
250
+ * falling back to the session model.
251
+ * - `"fail"`: Fail immediately without model substitution.
252
+ *
253
+ * @since TP-055
254
+ */
255
+ modelFallback: ModelFallbackMode;
256
+ }
257
+
258
+ // ── Orchestrator Section Interfaces ──────────────────────────────────
259
+
260
+ /** Core orchestrator settings */
261
+ export interface OrchestratorCoreConfig {
262
+ /** Maximum parallel execution lanes/worktrees */
263
+ maxLanes: number;
264
+ /** Where lane worktree directories are created */
265
+ worktreeLocation: "sibling" | "subdirectory";
266
+ /** Prefix used for worktree directory names and lane branch naming */
267
+ worktreePrefix: string;
268
+ /** Batch ID format used in logs/branch naming */
269
+ batchIdFormat: "timestamp" | "sequential";
270
+ /** How lane sessions are spawned (Runtime V2 subprocess-only). */
271
+ spawnMode: "subprocess";
272
+ /** Prefix for orchestrator session naming */
273
+ sessionPrefix: string;
274
+ /** Operator identifier. Auto-detected from OS username if empty */
275
+ operatorId: string;
276
+ /** How completed batches are integrated. manual = user runs /orch-integrate. supervised = supervisor proposes plan, asks confirmation. auto = supervisor executes without asking. */
277
+ integration: "manual" | "supervised" | "auto";
278
+ }
279
+
280
+ /** Dependency resolution settings */
281
+ export interface DependenciesConfig {
282
+ /** Dependency extraction source */
283
+ source: "prompt" | "agent";
284
+ /** Cache dependency analysis results between runs */
285
+ cache: boolean;
286
+ }
287
+
288
+ /** Lane assignment settings */
289
+ export interface AssignmentConfig {
290
+ /** Lane assignment strategy */
291
+ strategy: "affinity-first" | "round-robin" | "load-balanced";
292
+ /** Relative weights used by size-aware assignment logic */
293
+ sizeWeights: Record<string, number>;
294
+ }
295
+
296
+ /** Pre-warm settings */
297
+ export interface PreWarmConfig {
298
+ /** Enable automatic pre-warm command detection */
299
+ autoDetect: boolean;
300
+ /** Named pre-warm commands */
301
+ commands: Record<string, string>;
302
+ /** Commands always run before wave execution */
303
+ always: string[];
304
+ }
305
+
306
+ /** Merge settings */
307
+ export interface MergeConfig {
308
+ /** Merge-agent model (empty = inherit active session model) */
309
+ model: string;
310
+ /** Merge-agent tool allowlist */
311
+ tools: string;
312
+ /** Merge-agent thinking mode (empty = inherit session thinking) */
313
+ thinking: string;
314
+ /** Verification commands run after merge operations */
315
+ verify: string[];
316
+ /** Lane merge ordering policy */
317
+ order: "fewest-files-first" | "sequential";
318
+ /** Merge-agent timeout in minutes */
319
+ timeoutMinutes?: number;
320
+ /** Package specifiers to exclude from extension forwarding for merge agents (exact match). @since TP-180 */
321
+ excludeExtensions?: string[];
322
+ }
323
+
324
+ /** Failure policy settings */
325
+ export interface FailureConfig {
326
+ /** Batch behavior when a task fails */
327
+ onTaskFailure: "skip-dependents" | "stop-wave" | "stop-all";
328
+ /** Behavior when a merge step fails */
329
+ onMergeFailure: "pause" | "abort";
330
+ /** Stall detection threshold (minutes) */
331
+ stallTimeout: number;
332
+ /** Max worker runtime budget per task in orchestrated mode (minutes) */
333
+ maxWorkerMinutes: number;
334
+ /** Graceful abort wait time (seconds) before forced termination */
335
+ abortGracePeriod: number;
336
+ }
337
+
338
+ /** Monitoring settings */
339
+ export interface MonitoringConfig {
340
+ /** Poll interval (seconds) for lane/task monitoring loop */
341
+ pollInterval: number;
342
+ }
343
+
344
+ /**
345
+ * Verification baseline fingerprinting settings.
346
+ *
347
+ * Controls orchestrator-side baseline capture and post-merge comparison.
348
+ * When enabled, test commands from `taskRunner.testing.commands` are run
349
+ * before and after each lane merge to detect genuinely new failures.
350
+ *
351
+ * This is separate from `merge.verify` (agent-side verification) which
352
+ * handles revert-on-failure logic within the merge agent.
353
+ */
354
+ export interface VerificationConfig {
355
+ /**
356
+ * Enable verification baseline fingerprinting.
357
+ *
358
+ * When false (default), no baseline capture or comparison is performed,
359
+ * regardless of whether `taskRunner.testing.commands` are configured.
360
+ *
361
+ * When true, requires `taskRunner.testing.commands` to have at least
362
+ * one command configured. If enabled but no commands are configured:
363
+ * - strict mode: treats as baseline-unavailable (triggers merge failure)
364
+ * - permissive mode: logs a warning and continues without verification
365
+ */
366
+ enabled: boolean;
367
+ /**
368
+ * Verification mode controlling behavior when baseline is unavailable.
369
+ *
370
+ * - "strict": Baseline capture failure or missing commands triggers a
371
+ * merge failure. The `failure.onMergeFailure` policy then determines
372
+ * whether the batch pauses or aborts.
373
+ * - "permissive": Baseline capture failure or missing commands logs a
374
+ * warning and continues without orchestrator-side verification.
375
+ * Merge-agent verification (`merge.verify`) still applies independently.
376
+ *
377
+ * Default: "permissive"
378
+ */
379
+ mode: "strict" | "permissive";
380
+ /**
381
+ * Number of flaky re-runs when new failures are detected.
382
+ *
383
+ * When new failures are found after a lane merge, only the commands that
384
+ * produced failures are re-run this many times. If failures disappear on
385
+ * any re-run, the lane is classified as "flaky_suspected" (warning only).
386
+ *
387
+ * Set to 0 to disable flaky re-runs (any new failure immediately blocks).
388
+ * Default: 1
389
+ */
390
+ flakyReruns: number;
391
+ }
392
+
393
+ // ── Orchestrator Combined Section ────────────────────────────────────
394
+
395
+ /**
396
+ * All orchestrator settings, previously from `.pi/task-orchestrator.yaml`.
397
+ */
398
+ /** Supervisor agent settings (TP-041). */
399
+ export interface SupervisorSectionConfig {
400
+ /** Supervisor model (empty = inherit active session model) */
401
+ model: string;
402
+ /** Autonomy level for recovery actions */
403
+ autonomy: "interactive" | "supervised" | "autonomous";
404
+ }
405
+
406
+ export interface OrchestratorSection {
407
+ /** Core orchestrator settings */
408
+ orchestrator: OrchestratorCoreConfig;
409
+ /** Dependency resolution */
410
+ dependencies: DependenciesConfig;
411
+ /** Lane assignment */
412
+ assignment: AssignmentConfig;
413
+ /** Pre-warm */
414
+ preWarm: PreWarmConfig;
415
+ /** Merge */
416
+ merge: MergeConfig;
417
+ /** Failure policy */
418
+ failure: FailureConfig;
419
+ /** Monitoring */
420
+ monitoring: MonitoringConfig;
421
+ /** Verification baseline fingerprinting (TP-032) */
422
+ verification: VerificationConfig;
423
+ /** Supervisor agent (TP-041) */
424
+ supervisor: SupervisorSectionConfig;
425
+ }
426
+
427
+ // ── Workspace Section Interfaces ─────────────────────────────────────
428
+
429
+ /** Workspace repo definition (JSON config shape). */
430
+ export interface WorkspaceRepoSectionConfig {
431
+ /** Repo root path (relative to workspace root or absolute). */
432
+ path: string;
433
+ /** Optional default branch override. */
434
+ defaultBranch?: string;
435
+ }
436
+
437
+ /** Workspace routing definition (JSON config shape). */
438
+ export interface WorkspaceRoutingSectionConfig {
439
+ /** Shared task packet root directory. */
440
+ tasksRoot: string;
441
+ /** Default repo for unqualified operations. */
442
+ defaultRepo: string;
443
+ /** Packet-home repo owning PROMPT/STATUS/.DONE. */
444
+ taskPacketRepo: string;
445
+ /** Strict repo routing mode. */
446
+ strict?: boolean;
447
+ }
448
+
449
+ /** Optional workspace section in orchid-config.json. */
450
+ export interface WorkspaceSectionConfig {
451
+ /** Repo map keyed by repo ID. */
452
+ repos: Record<string, WorkspaceRepoSectionConfig>;
453
+ /** Routing contract for workspace mode. */
454
+ routing: WorkspaceRoutingSectionConfig;
455
+ }
456
+
457
+ // ── Unified Config ───────────────────────────────────────────────────
458
+
459
+ /**
460
+ * Unified project configuration — the single source of truth.
461
+ *
462
+ * This is the runtime config object produced by `loadProjectConfig()`.
463
+ * It merges all settings from both YAML files (or the single JSON file)
464
+ * into one typed structure.
465
+ *
466
+ * File: `.pi/orchid-config.json`
467
+ *
468
+ * Example JSON structure:
469
+ * ```json
470
+ * {
471
+ * "configVersion": 1,
472
+ * "taskRunner": { ... },
473
+ * "orchestrator": { ... }
474
+ * }
475
+ * ```
476
+ */
477
+ export interface TaskplaneConfig {
478
+ /** Schema version — must equal CONFIG_VERSION */
479
+ configVersion: number;
480
+ /** Task runner settings */
481
+ taskRunner: TaskRunnerSection;
482
+ /** Orchestrator settings */
483
+ orchestrator: OrchestratorSection;
484
+ /** Optional workspace config (JSON-first; legacy YAML fallback supported). */
485
+ workspace?: WorkspaceSectionConfig;
486
+ }
487
+
488
+ // ── Global Preferences (Layer 2) ─────────────────────────────────────
489
+
490
+ /**
491
+ * Global preferences — personal settings stored per-user.
492
+ *
493
+ * File: `~/.pi/agent/orchid/preferences.json`
494
+ * (or `$PI_CODING_AGENT_DIR/orchid/preferences.json` if set)
495
+ *
496
+ * These are "Layer 2" fields — they override project config (Layer 1)
497
+ * for user-scoped settings only. The merge is allowlist-based: only
498
+ * the fields defined here can be overridden by global preferences.
499
+ * Unknown keys in the preferences file are silently ignored.
500
+ *
501
+ * Preferences JSON uses camelCase keys matching the runtime config shape.
502
+ *
503
+ * Layer 2 allowlist:
504
+ * - Config-shaped nested overrides (`taskRunner`, `orchestrator`, `workspace`)
505
+ * - Legacy flat aliases (`workerModel`, `reviewerModel`, etc.) for backward compatibility
506
+ * - Preferences-only keys (`dashboardPort`, `initAgentDefaults`)
507
+ */
508
+ export interface InitAgentDefaultsPreferences {
509
+ /** Worker model default for `orchid init` prompts (empty = inherit) */
510
+ workerModel?: string;
511
+ /** Reviewer model default for `orchid init` prompts (empty = inherit) */
512
+ reviewerModel?: string;
513
+ /** Merger model default for `orchid init` prompts (empty = inherit) */
514
+ mergeModel?: string;
515
+ /** Worker thinking default for `orchid init` prompts (`""`/`on`/`off`) */
516
+ workerThinking?: string;
517
+ /** Reviewer thinking default for `orchid init` prompts (`""`/`on`/`off`) */
518
+ reviewerThinking?: string;
519
+ /** Merger thinking default for `orchid init` prompts (`""`/`on`/`off`) */
520
+ mergeThinking?: string;
521
+ }
522
+
523
+ export type DeepPartial<T> =
524
+ T extends Array<infer U>
525
+ ? Array<DeepPartial<U>>
526
+ : T extends object
527
+ ? { [K in keyof T]?: DeepPartial<T[K]> }
528
+ : T;
529
+
530
+ export interface GlobalPreferences {
531
+ /**
532
+ * Global baseline overrides using the same shape as project config.
533
+ * All fields are optional and merged deeply into schema defaults.
534
+ */
535
+ taskRunner?: DeepPartial<TaskRunnerSection>;
536
+ orchestrator?: DeepPartial<OrchestratorSection>;
537
+ workspace?: DeepPartial<WorkspaceSectionConfig>;
538
+
539
+ /** Legacy flat aliases (backward compatibility for existing preferences.json files). */
540
+ operatorId?: string;
541
+ sessionPrefix?: string;
542
+ spawnMode?: "subprocess";
543
+ workerModel?: string;
544
+ reviewerModel?: string;
545
+ mergeModel?: string;
546
+ mergeThinking?: string;
547
+ supervisorModel?: string;
548
+
549
+ /** Preferences-only values (stored globally, not merged into runtime config). */
550
+ dashboardPort?: number;
551
+ /** Saved defaults used to pre-populate `orchid init` model/thinking prompts */
552
+ initAgentDefaults?: InitAgentDefaultsPreferences;
553
+ }
554
+
555
+ /** Default (empty) global preferences — all fields undefined means "no override". */
556
+ export const DEFAULT_GLOBAL_PREFERENCES: GlobalPreferences = {};
557
+
558
+ /**
559
+ * Seed values used when first bootstrapping preferences.json.
560
+ *
561
+ * Kept separate from DEFAULT_GLOBAL_PREFERENCES so runtime fallback semantics
562
+ * remain "no override", while first-install scaffolding can provide
563
+ * user-friendly init defaults.
564
+ */
565
+ export const DEFAULT_BOOTSTRAP_GLOBAL_PREFERENCES: GlobalPreferences = {
566
+ initAgentDefaults: {
567
+ workerModel: "",
568
+ reviewerModel: "",
569
+ mergeModel: "",
570
+ workerThinking: "high",
571
+ reviewerThinking: "high",
572
+ mergeThinking: "high",
573
+ },
574
+ };
575
+
576
+ /**
577
+ * Canonical filename for global preferences.
578
+ * Resolved relative to agent directory: `<agentDir>/orchid/preferences.json`
579
+ */
580
+ export const GLOBAL_PREFERENCES_FILENAME = "preferences.json";
581
+
582
+ /**
583
+ * Subdirectory under the agent dir for orchid preferences.
584
+ */
585
+ export const GLOBAL_PREFERENCES_SUBDIR = "orchid";
586
+
587
+ // ── Defaults ─────────────────────────────────────────────────────────
588
+
589
+ /** Default task runner section values */
590
+ export const DEFAULT_TASK_RUNNER_SECTION: TaskRunnerSection = {
591
+ project: { name: "Project", description: "" },
592
+ paths: { tasks: "docs/task-management" },
593
+ testing: { commands: {} },
594
+ standards: { docs: [], rules: [] },
595
+ standardsOverrides: {},
596
+ // TP-189 (Cluster B): user-tools default sourced from
597
+ // `tool-allowlist-constants.ts` (single source of truth). Engine
598
+ // bridge tools are appended at the lane-runner spawn site by
599
+ // `buildWorkerToolsAllowlist()`, not here.
600
+ worker: { model: "", tools: DEFAULT_WORKER_USER_TOOLS, thinking: "", excludeExtensions: [] },
601
+ reviewer: { model: "", tools: "read,bash,grep,find,ls", thinking: "on", excludeExtensions: [] },
602
+ context: {
603
+ workerContextWindow: 0,
604
+ warnPercent: 85,
605
+ killPercent: 95,
606
+ maxWorkerIterations: 20,
607
+ maxReviewCycles: 2,
608
+ noProgressLimit: 3,
609
+ },
610
+ taskAreas: {},
611
+ referenceDocs: {},
612
+ neverLoad: [],
613
+ selfDocTargets: {},
614
+ protectedDocs: [],
615
+ qualityGate: {
616
+ enabled: false,
617
+ reviewModel: "",
618
+ maxReviewCycles: 2,
619
+ maxFixCycles: 1,
620
+ passThreshold: "no_critical",
621
+ },
622
+ modelFallback: "inherit",
623
+ };
624
+
625
+ /** Default orchestrator section values */
626
+ export const DEFAULT_ORCHESTRATOR_SECTION: OrchestratorSection = {
627
+ orchestrator: {
628
+ maxLanes: 3,
629
+ worktreeLocation: "subdirectory",
630
+ worktreePrefix: "orchid-wt",
631
+ batchIdFormat: "timestamp",
632
+ spawnMode: "subprocess",
633
+ sessionPrefix: "orch",
634
+ operatorId: "",
635
+ integration: "manual",
636
+ },
637
+ dependencies: {
638
+ source: "prompt",
639
+ cache: true,
640
+ },
641
+ assignment: {
642
+ strategy: "affinity-first",
643
+ sizeWeights: { S: 1, M: 2, L: 4 },
644
+ },
645
+ preWarm: {
646
+ autoDetect: false,
647
+ commands: {},
648
+ always: [],
649
+ },
650
+ merge: {
651
+ model: "",
652
+ // TP-189 (Cluster B): merge default mirrors the worker user-tools
653
+ // constant. The merge agent does NOT run through
654
+ // `buildWorkerToolsAllowlist()` (no bridge-tool needs), so this
655
+ // reference is purely for default-value parity — not a hard
656
+ // coupling to the worker allowlist plumbing.
657
+ tools: DEFAULT_WORKER_USER_TOOLS,
658
+ thinking: "off",
659
+ verify: [],
660
+ order: "fewest-files-first",
661
+ timeoutMinutes: 90,
662
+ excludeExtensions: [],
663
+ },
664
+ failure: {
665
+ onTaskFailure: "skip-dependents",
666
+ onMergeFailure: "pause",
667
+ stallTimeout: 60,
668
+ maxWorkerMinutes: 120,
669
+ abortGracePeriod: 60,
670
+ },
671
+ monitoring: {
672
+ pollInterval: 5,
673
+ },
674
+ verification: {
675
+ enabled: false,
676
+ mode: "permissive",
677
+ flakyReruns: 1,
678
+ },
679
+ supervisor: {
680
+ model: "",
681
+ autonomy: "supervised",
682
+ },
683
+ };
684
+
685
+ /** Default unified config */
686
+ export const DEFAULT_PROJECT_CONFIG: TaskplaneConfig = {
687
+ configVersion: CONFIG_VERSION,
688
+ taskRunner: DEFAULT_TASK_RUNNER_SECTION,
689
+ orchestrator: DEFAULT_ORCHESTRATOR_SECTION,
690
+ };