@agntk/agent-harness 0.1.1

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 (212) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +41 -0
  3. package/README.md +445 -0
  4. package/defaults/agents/summarizer.md +49 -0
  5. package/defaults/instincts/lead-with-answer.md +24 -0
  6. package/defaults/instincts/qualify-before-recommending.md +40 -0
  7. package/defaults/instincts/read-before-edit.md +23 -0
  8. package/defaults/instincts/search-before-create.md +23 -0
  9. package/defaults/playbooks/ship-feature.md +31 -0
  10. package/defaults/rules/ask-before-assuming.md +35 -0
  11. package/defaults/rules/operations.md +35 -0
  12. package/defaults/rules/respect-the-user.md +39 -0
  13. package/defaults/skills/business-analyst.md +181 -0
  14. package/defaults/skills/content-marketer.md +184 -0
  15. package/defaults/skills/research.md +34 -0
  16. package/defaults/tools/example-web-search.md +60 -0
  17. package/defaults/workflows/daily-reflection.md +54 -0
  18. package/dist/agent-framework-K4GUIICH.js +344 -0
  19. package/dist/agent-framework-K4GUIICH.js.map +1 -0
  20. package/dist/analytics-RPT73WNM.js +12 -0
  21. package/dist/analytics-RPT73WNM.js.map +1 -0
  22. package/dist/auto-processor-OLE45UI3.js +13 -0
  23. package/dist/auto-processor-OLE45UI3.js.map +1 -0
  24. package/dist/chunk-274RV3YO.js +162 -0
  25. package/dist/chunk-274RV3YO.js.map +1 -0
  26. package/dist/chunk-4CWAGBNS.js +168 -0
  27. package/dist/chunk-4CWAGBNS.js.map +1 -0
  28. package/dist/chunk-4FDUOGSZ.js +69 -0
  29. package/dist/chunk-4FDUOGSZ.js.map +1 -0
  30. package/dist/chunk-5H34JPMB.js +199 -0
  31. package/dist/chunk-5H34JPMB.js.map +1 -0
  32. package/dist/chunk-6EMOEYGU.js +102 -0
  33. package/dist/chunk-6EMOEYGU.js.map +1 -0
  34. package/dist/chunk-A7BJPQQ6.js +236 -0
  35. package/dist/chunk-A7BJPQQ6.js.map +1 -0
  36. package/dist/chunk-AGAAFJEO.js +76 -0
  37. package/dist/chunk-AGAAFJEO.js.map +1 -0
  38. package/dist/chunk-BSKDOFRT.js +65 -0
  39. package/dist/chunk-BSKDOFRT.js.map +1 -0
  40. package/dist/chunk-CHJ5GNZC.js +100 -0
  41. package/dist/chunk-CHJ5GNZC.js.map +1 -0
  42. package/dist/chunk-CSL3ERUI.js +307 -0
  43. package/dist/chunk-CSL3ERUI.js.map +1 -0
  44. package/dist/chunk-DA7IKHC4.js +229 -0
  45. package/dist/chunk-DA7IKHC4.js.map +1 -0
  46. package/dist/chunk-DGUM43GV.js +11 -0
  47. package/dist/chunk-DGUM43GV.js.map +1 -0
  48. package/dist/chunk-DTTXPHFW.js +211 -0
  49. package/dist/chunk-DTTXPHFW.js.map +1 -0
  50. package/dist/chunk-FD55B3IO.js +204 -0
  51. package/dist/chunk-FD55B3IO.js.map +1 -0
  52. package/dist/chunk-FLZU44SV.js +230 -0
  53. package/dist/chunk-FLZU44SV.js.map +1 -0
  54. package/dist/chunk-GJNNR2RA.js +200 -0
  55. package/dist/chunk-GJNNR2RA.js.map +1 -0
  56. package/dist/chunk-GNUSHD2Y.js +111 -0
  57. package/dist/chunk-GNUSHD2Y.js.map +1 -0
  58. package/dist/chunk-GUJTBGVS.js +2212 -0
  59. package/dist/chunk-GUJTBGVS.js.map +1 -0
  60. package/dist/chunk-IZ6UZ3ZL.js +207 -0
  61. package/dist/chunk-IZ6UZ3ZL.js.map +1 -0
  62. package/dist/chunk-JKMGYWXB.js +197 -0
  63. package/dist/chunk-JKMGYWXB.js.map +1 -0
  64. package/dist/chunk-KFX54TQM.js +165 -0
  65. package/dist/chunk-KFX54TQM.js.map +1 -0
  66. package/dist/chunk-M7NXUK55.js +199 -0
  67. package/dist/chunk-M7NXUK55.js.map +1 -0
  68. package/dist/chunk-MPZ3BPUI.js +374 -0
  69. package/dist/chunk-MPZ3BPUI.js.map +1 -0
  70. package/dist/chunk-OC6YSTDX.js +119 -0
  71. package/dist/chunk-OC6YSTDX.js.map +1 -0
  72. package/dist/chunk-RC6MEZB6.js +469 -0
  73. package/dist/chunk-RC6MEZB6.js.map +1 -0
  74. package/dist/chunk-RY3ZFII7.js +3440 -0
  75. package/dist/chunk-RY3ZFII7.js.map +1 -0
  76. package/dist/chunk-TAT6JU3X.js +167 -0
  77. package/dist/chunk-TAT6JU3X.js.map +1 -0
  78. package/dist/chunk-UDZIS2AQ.js +79 -0
  79. package/dist/chunk-UDZIS2AQ.js.map +1 -0
  80. package/dist/chunk-UPLBF4RZ.js +115 -0
  81. package/dist/chunk-UPLBF4RZ.js.map +1 -0
  82. package/dist/chunk-UWQTZMNI.js +154 -0
  83. package/dist/chunk-UWQTZMNI.js.map +1 -0
  84. package/dist/chunk-W4T7PGI2.js +346 -0
  85. package/dist/chunk-W4T7PGI2.js.map +1 -0
  86. package/dist/chunk-XTBKL5BI.js +111 -0
  87. package/dist/chunk-XTBKL5BI.js.map +1 -0
  88. package/dist/chunk-YIJY5DBV.js +399 -0
  89. package/dist/chunk-YIJY5DBV.js.map +1 -0
  90. package/dist/chunk-YUFNYN2H.js +242 -0
  91. package/dist/chunk-YUFNYN2H.js.map +1 -0
  92. package/dist/chunk-Z2PUCXTZ.js +94 -0
  93. package/dist/chunk-Z2PUCXTZ.js.map +1 -0
  94. package/dist/chunk-ZZJOFKAT.js +13 -0
  95. package/dist/chunk-ZZJOFKAT.js.map +1 -0
  96. package/dist/cli/index.js +3661 -0
  97. package/dist/cli/index.js.map +1 -0
  98. package/dist/config-WVMRUOCA.js +13 -0
  99. package/dist/config-WVMRUOCA.js.map +1 -0
  100. package/dist/context-loader-3ORBPMHJ.js +13 -0
  101. package/dist/context-loader-3ORBPMHJ.js.map +1 -0
  102. package/dist/conversation-QDEIDQPH.js +22 -0
  103. package/dist/conversation-QDEIDQPH.js.map +1 -0
  104. package/dist/cost-tracker-RS3W7SVY.js +24 -0
  105. package/dist/cost-tracker-RS3W7SVY.js.map +1 -0
  106. package/dist/delegate-VJCJLYEK.js +29 -0
  107. package/dist/delegate-VJCJLYEK.js.map +1 -0
  108. package/dist/emotional-state-VQVRA6ED.js +206 -0
  109. package/dist/emotional-state-VQVRA6ED.js.map +1 -0
  110. package/dist/env-discovery-2BLVMAIM.js +251 -0
  111. package/dist/env-discovery-2BLVMAIM.js.map +1 -0
  112. package/dist/export-6GCYHEHQ.js +165 -0
  113. package/dist/export-6GCYHEHQ.js.map +1 -0
  114. package/dist/graph-YUIPOSOO.js +14 -0
  115. package/dist/graph-YUIPOSOO.js.map +1 -0
  116. package/dist/harness-LCHA3DWP.js +10 -0
  117. package/dist/harness-LCHA3DWP.js.map +1 -0
  118. package/dist/harness-WE4SLCML.js +26 -0
  119. package/dist/harness-WE4SLCML.js.map +1 -0
  120. package/dist/health-NZ6WNIMV.js +23 -0
  121. package/dist/health-NZ6WNIMV.js.map +1 -0
  122. package/dist/index.d.ts +3612 -0
  123. package/dist/index.js +13501 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/indexer-LONANRRM.js +16 -0
  126. package/dist/indexer-LONANRRM.js.map +1 -0
  127. package/dist/instinct-learner-SRM72DHF.js +20 -0
  128. package/dist/instinct-learner-SRM72DHF.js.map +1 -0
  129. package/dist/intake-4M3HNU43.js +21 -0
  130. package/dist/intake-4M3HNU43.js.map +1 -0
  131. package/dist/intelligence-HJOCA4SJ.js +1081 -0
  132. package/dist/intelligence-HJOCA4SJ.js.map +1 -0
  133. package/dist/journal-WANJL3MI.js +24 -0
  134. package/dist/journal-WANJL3MI.js.map +1 -0
  135. package/dist/loader-C3TKIKZR.js +23 -0
  136. package/dist/loader-C3TKIKZR.js.map +1 -0
  137. package/dist/mcp-WTQJJZAO.js +15 -0
  138. package/dist/mcp-WTQJJZAO.js.map +1 -0
  139. package/dist/mcp-discovery-WPAQFL6S.js +377 -0
  140. package/dist/mcp-discovery-WPAQFL6S.js.map +1 -0
  141. package/dist/mcp-installer-6O2XXD3V.js +394 -0
  142. package/dist/mcp-installer-6O2XXD3V.js.map +1 -0
  143. package/dist/metrics-KXGNFAAB.js +20 -0
  144. package/dist/metrics-KXGNFAAB.js.map +1 -0
  145. package/dist/primitive-registry-I6VTIR4W.js +512 -0
  146. package/dist/primitive-registry-I6VTIR4W.js.map +1 -0
  147. package/dist/project-discovery-C4UMD7JI.js +246 -0
  148. package/dist/project-discovery-C4UMD7JI.js.map +1 -0
  149. package/dist/provider-LQHQX7Z7.js +26 -0
  150. package/dist/provider-LQHQX7Z7.js.map +1 -0
  151. package/dist/provider-SXPQZ74H.js +28 -0
  152. package/dist/provider-SXPQZ74H.js.map +1 -0
  153. package/dist/rate-limiter-RLRVM325.js +22 -0
  154. package/dist/rate-limiter-RLRVM325.js.map +1 -0
  155. package/dist/rule-engine-YGQ3RYZM.js +182 -0
  156. package/dist/rule-engine-YGQ3RYZM.js.map +1 -0
  157. package/dist/scaffold-A3VRRCBV.js +347 -0
  158. package/dist/scaffold-A3VRRCBV.js.map +1 -0
  159. package/dist/scheduler-XHHIVHRI.js +397 -0
  160. package/dist/scheduler-XHHIVHRI.js.map +1 -0
  161. package/dist/search-V3W5JMJG.js +75 -0
  162. package/dist/search-V3W5JMJG.js.map +1 -0
  163. package/dist/semantic-search-2DTOO5UX.js +241 -0
  164. package/dist/semantic-search-2DTOO5UX.js.map +1 -0
  165. package/dist/serve-DTQ3HENY.js +291 -0
  166. package/dist/serve-DTQ3HENY.js.map +1 -0
  167. package/dist/sessions-CZGVXKQE.js +21 -0
  168. package/dist/sessions-CZGVXKQE.js.map +1 -0
  169. package/dist/sources-RW5DT56F.js +32 -0
  170. package/dist/sources-RW5DT56F.js.map +1 -0
  171. package/dist/starter-packs-76YUVHEU.js +893 -0
  172. package/dist/starter-packs-76YUVHEU.js.map +1 -0
  173. package/dist/state-GMXILIHW.js +13 -0
  174. package/dist/state-GMXILIHW.js.map +1 -0
  175. package/dist/state-merge-NKO5FRBA.js +174 -0
  176. package/dist/state-merge-NKO5FRBA.js.map +1 -0
  177. package/dist/telemetry-UC6PBXC7.js +22 -0
  178. package/dist/telemetry-UC6PBXC7.js.map +1 -0
  179. package/dist/tool-executor-MJ7IG7PQ.js +28 -0
  180. package/dist/tool-executor-MJ7IG7PQ.js.map +1 -0
  181. package/dist/tools-DZ4KETET.js +20 -0
  182. package/dist/tools-DZ4KETET.js.map +1 -0
  183. package/dist/types-EW7AIB3R.js +18 -0
  184. package/dist/types-EW7AIB3R.js.map +1 -0
  185. package/dist/types-WGDLSPO6.js +16 -0
  186. package/dist/types-WGDLSPO6.js.map +1 -0
  187. package/dist/universal-installer-QGS4SJGX.js +578 -0
  188. package/dist/universal-installer-QGS4SJGX.js.map +1 -0
  189. package/dist/validator-7WXMDIHH.js +22 -0
  190. package/dist/validator-7WXMDIHH.js.map +1 -0
  191. package/dist/verification-gate-FYXUX6LH.js +246 -0
  192. package/dist/verification-gate-FYXUX6LH.js.map +1 -0
  193. package/dist/versioning-Z3XNE2Q2.js +271 -0
  194. package/dist/versioning-Z3XNE2Q2.js.map +1 -0
  195. package/dist/watcher-ISJC7YKL.js +109 -0
  196. package/dist/watcher-ISJC7YKL.js.map +1 -0
  197. package/dist/web-server-DD7ZOP46.js +28 -0
  198. package/dist/web-server-DD7ZOP46.js.map +1 -0
  199. package/package.json +76 -0
  200. package/sources.yaml +121 -0
  201. package/templates/assistant/CORE.md +24 -0
  202. package/templates/assistant/SYSTEM.md +24 -0
  203. package/templates/assistant/config.yaml +51 -0
  204. package/templates/base/CORE.md +17 -0
  205. package/templates/base/SYSTEM.md +24 -0
  206. package/templates/base/config.yaml +51 -0
  207. package/templates/claude-opus/config.yaml +51 -0
  208. package/templates/code-reviewer/CORE.md +25 -0
  209. package/templates/code-reviewer/SYSTEM.md +30 -0
  210. package/templates/code-reviewer/config.yaml +51 -0
  211. package/templates/gpt4/config.yaml +51 -0
  212. package/templates/local/config.yaml +51 -0
@@ -0,0 +1,3612 @@
1
+ import { z } from 'zod';
2
+ import { createOpenRouter } from '@openrouter/ai-sdk-provider';
3
+ import { ToolSet, LanguageModel } from 'ai';
4
+ import { ModelMessage } from '@ai-sdk/provider-utils';
5
+ import { FSWatcher } from 'chokidar';
6
+ import cron from 'node-cron';
7
+ import { MCPClient } from '@ai-sdk/mcp';
8
+ import { Hono } from 'hono';
9
+ import { Server } from 'http';
10
+
11
+ declare const FrontmatterSchema: z.ZodObject<{
12
+ id: z.ZodString;
13
+ tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
14
+ created: z.ZodOptional<z.ZodString>;
15
+ updated: z.ZodOptional<z.ZodString>;
16
+ author: z.ZodDefault<z.ZodEnum<{
17
+ human: "human";
18
+ agent: "agent";
19
+ infrastructure: "infrastructure";
20
+ }>>;
21
+ status: z.ZodDefault<z.ZodEnum<{
22
+ active: "active";
23
+ archived: "archived";
24
+ deprecated: "deprecated";
25
+ draft: "draft";
26
+ }>>;
27
+ related: z.ZodDefault<z.ZodArray<z.ZodString>>;
28
+ schedule: z.ZodOptional<z.ZodString>;
29
+ with: z.ZodOptional<z.ZodString>;
30
+ channel: z.ZodOptional<z.ZodString>;
31
+ duration_minutes: z.ZodOptional<z.ZodNumber>;
32
+ max_retries: z.ZodOptional<z.ZodNumber>;
33
+ retry_delay_ms: z.ZodOptional<z.ZodNumber>;
34
+ }, z.core.$strip>;
35
+ type Frontmatter = z.infer<typeof FrontmatterSchema>;
36
+ interface HarnessDocument {
37
+ path: string;
38
+ frontmatter: Frontmatter;
39
+ l0: string;
40
+ l1: string;
41
+ body: string;
42
+ raw: string;
43
+ }
44
+ type PrimitiveType = 'rule' | 'instinct' | 'skill' | 'playbook' | 'workflow' | 'tool' | 'agent' | 'session' | 'journal';
45
+ declare const HarnessConfigSchema: z.ZodObject<{
46
+ agent: z.ZodObject<{
47
+ name: z.ZodString;
48
+ version: z.ZodDefault<z.ZodString>;
49
+ }, z.core.$loose>;
50
+ model: z.ZodObject<{
51
+ provider: z.ZodDefault<z.ZodString>;
52
+ id: z.ZodString;
53
+ max_tokens: z.ZodDefault<z.ZodNumber>;
54
+ max_retries: z.ZodDefault<z.ZodNumber>;
55
+ timeout_ms: z.ZodOptional<z.ZodNumber>;
56
+ summary_model: z.ZodOptional<z.ZodString>;
57
+ fast_model: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$loose>;
59
+ runtime: z.ZodObject<{
60
+ scratchpad_budget: z.ZodDefault<z.ZodNumber>;
61
+ heartbeat: z.ZodOptional<z.ZodString>;
62
+ daily_summary: z.ZodOptional<z.ZodString>;
63
+ auto_process: z.ZodDefault<z.ZodBoolean>;
64
+ quiet_hours: z.ZodDefault<z.ZodObject<{
65
+ start: z.ZodDefault<z.ZodNumber>;
66
+ end: z.ZodDefault<z.ZodNumber>;
67
+ }, z.core.$loose>>;
68
+ timezone: z.ZodDefault<z.ZodString>;
69
+ }, z.core.$loose>;
70
+ memory: z.ZodObject<{
71
+ session_retention_days: z.ZodDefault<z.ZodNumber>;
72
+ journal_retention_days: z.ZodDefault<z.ZodNumber>;
73
+ }, z.core.$loose>;
74
+ channels: z.ZodObject<{
75
+ primary: z.ZodDefault<z.ZodString>;
76
+ }, z.core.$loose>;
77
+ extensions: z.ZodDefault<z.ZodObject<{
78
+ directories: z.ZodDefault<z.ZodArray<z.ZodString>>;
79
+ }, z.core.$loose>>;
80
+ rate_limits: z.ZodDefault<z.ZodObject<{
81
+ per_minute: z.ZodOptional<z.ZodNumber>;
82
+ per_hour: z.ZodOptional<z.ZodNumber>;
83
+ per_day: z.ZodOptional<z.ZodNumber>;
84
+ }, z.core.$loose>>;
85
+ budget: z.ZodDefault<z.ZodObject<{
86
+ daily_limit_usd: z.ZodOptional<z.ZodNumber>;
87
+ monthly_limit_usd: z.ZodOptional<z.ZodNumber>;
88
+ enforce: z.ZodDefault<z.ZodBoolean>;
89
+ }, z.core.$loose>>;
90
+ mcp: z.ZodDefault<z.ZodObject<{
91
+ servers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
92
+ transport: z.ZodEnum<{
93
+ stdio: "stdio";
94
+ http: "http";
95
+ sse: "sse";
96
+ }>;
97
+ command: z.ZodOptional<z.ZodString>;
98
+ args: z.ZodOptional<z.ZodArray<z.ZodString>>;
99
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
100
+ cwd: z.ZodOptional<z.ZodString>;
101
+ url: z.ZodOptional<z.ZodString>;
102
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
103
+ enabled: z.ZodDefault<z.ZodBoolean>;
104
+ }, z.core.$loose>>>;
105
+ }, z.core.$loose>>;
106
+ intelligence: z.ZodDefault<z.ZodObject<{
107
+ auto_journal: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
108
+ auto_learn: z.ZodDefault<z.ZodBoolean>;
109
+ }, z.core.$loose>>;
110
+ proactive: z.ZodDefault<z.ZodObject<{
111
+ enabled: z.ZodDefault<z.ZodBoolean>;
112
+ max_per_hour: z.ZodDefault<z.ZodNumber>;
113
+ cooldown_minutes: z.ZodDefault<z.ZodNumber>;
114
+ quiet_hours: z.ZodOptional<z.ZodObject<{
115
+ start: z.ZodOptional<z.ZodNumber>;
116
+ end: z.ZodOptional<z.ZodNumber>;
117
+ }, z.core.$loose>>;
118
+ }, z.core.$loose>>;
119
+ registries: z.ZodDefault<z.ZodArray<z.ZodObject<{
120
+ url: z.ZodString;
121
+ name: z.ZodOptional<z.ZodString>;
122
+ token: z.ZodOptional<z.ZodString>;
123
+ }, z.core.$loose>>>;
124
+ }, z.core.$loose>;
125
+ type HarnessConfig = z.infer<typeof HarnessConfigSchema>;
126
+ declare const CORE_PRIMITIVE_DIRS: readonly ["rules", "instincts", "skills", "playbooks", "workflows", "tools", "agents"];
127
+ declare function getPrimitiveDirs(config?: HarnessConfig): string[];
128
+ interface AgentState {
129
+ mode: string;
130
+ goals: string[];
131
+ active_workflows: string[];
132
+ last_interaction: string;
133
+ unfinished_business: string[];
134
+ }
135
+ interface ContextBudget {
136
+ max_tokens: number;
137
+ used_tokens: number;
138
+ remaining: number;
139
+ loaded_files: string[];
140
+ }
141
+ type DeepPartial<T> = {
142
+ [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
143
+ };
144
+ interface HarnessHooks {
145
+ /** Called after boot completes (context loaded, state ready) */
146
+ onBoot?: (context: {
147
+ agent: HarnessAgent;
148
+ config: HarnessConfig;
149
+ state: AgentState;
150
+ }) => void | Promise<void>;
151
+ /** Called after each session completes (run or stream) */
152
+ onSessionEnd?: (context: {
153
+ agent: HarnessAgent;
154
+ sessionId: string;
155
+ prompt: string;
156
+ result: AgentRunResult;
157
+ }) => void | Promise<void>;
158
+ /** Called when an error occurs during run/stream */
159
+ onError?: (context: {
160
+ agent: HarnessAgent;
161
+ error: Error;
162
+ prompt?: string;
163
+ }) => void | Promise<void>;
164
+ /** Called when agent state changes (boot, shutdown, after run) */
165
+ onStateChange?: (context: {
166
+ agent: HarnessAgent;
167
+ previous: string;
168
+ current: string;
169
+ }) => void | Promise<void>;
170
+ /** Called before shutdown completes */
171
+ onShutdown?: (context: {
172
+ agent: HarnessAgent;
173
+ state: AgentState;
174
+ }) => void | Promise<void>;
175
+ }
176
+ interface ToolExecutorOptions {
177
+ /** Maximum tool calls per run (default: 5) */
178
+ maxToolCalls?: number;
179
+ /** Timeout per tool call in ms (default: 30000) */
180
+ toolTimeoutMs?: number;
181
+ /** Whether to allow HTTP tool execution (default: true) */
182
+ allowHttpExecution?: boolean;
183
+ }
184
+ interface CreateHarnessOptions {
185
+ dir: string;
186
+ /** Model ID override (e.g., "claude-sonnet-4-20250514" or "gpt-4o") */
187
+ model?: string;
188
+ /** Provider override (e.g., "anthropic", "openai", "openrouter") */
189
+ provider?: string;
190
+ apiKey?: string;
191
+ config?: DeepPartial<HarnessConfig>;
192
+ /** Lifecycle hooks for agent events */
193
+ hooks?: HarnessHooks;
194
+ /** Tool execution configuration */
195
+ toolExecutor?: ToolExecutorOptions;
196
+ }
197
+ /** Record of a single tool call made during a run */
198
+ interface ToolCallInfo {
199
+ toolName: string;
200
+ args: Record<string, unknown>;
201
+ result: unknown;
202
+ }
203
+ interface AgentRunResult {
204
+ text: string;
205
+ usage: {
206
+ inputTokens: number;
207
+ outputTokens: number;
208
+ totalTokens: number;
209
+ };
210
+ session_id: string;
211
+ steps: number;
212
+ /** Tool calls made during the run (empty array if none) */
213
+ toolCalls: ToolCallInfo[];
214
+ }
215
+ interface AgentStreamResult {
216
+ /** Async iterable of text chunks — consume with for-await */
217
+ textStream: AsyncIterable<string>;
218
+ /** Resolves after the stream is fully consumed with session metadata */
219
+ result: Promise<AgentRunResult>;
220
+ }
221
+ interface HarnessAgent {
222
+ name: string;
223
+ config: HarnessConfig;
224
+ boot(): Promise<void>;
225
+ run(prompt: string): Promise<AgentRunResult>;
226
+ stream(prompt: string): AgentStreamResult;
227
+ shutdown(): Promise<void>;
228
+ getSystemPrompt(): string;
229
+ getState(): AgentState;
230
+ }
231
+ interface IndexEntry {
232
+ id: string;
233
+ path: string;
234
+ tags: string[];
235
+ l0: string;
236
+ created: string;
237
+ status: string;
238
+ }
239
+
240
+ declare function createHarness(options: CreateHarnessOptions): HarnessAgent;
241
+
242
+ declare function loadConfig(dir: string, overrides?: DeepPartial<HarnessConfig>): HarnessConfig;
243
+ declare function writeDefaultConfig(_dir: string, agentName?: string): string;
244
+
245
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
246
+ interface Logger {
247
+ debug(msg: string, ...args: unknown[]): void;
248
+ info(msg: string, ...args: unknown[]): void;
249
+ warn(msg: string, ...args: unknown[]): void;
250
+ error(msg: string, ...args: unknown[]): void;
251
+ setLevel(level: LogLevel): void;
252
+ getLevel(): LogLevel;
253
+ child(prefix: string): Logger;
254
+ }
255
+ declare function createLogger(prefix?: string): Logger;
256
+ declare function setGlobalLogLevel(level: LogLevel): void;
257
+ declare function getGlobalLogLevel(): LogLevel;
258
+ declare const log: Logger;
259
+
260
+ interface ParseError {
261
+ path: string;
262
+ error: string;
263
+ }
264
+ interface LoadResult {
265
+ docs: HarnessDocument[];
266
+ errors: ParseError[];
267
+ }
268
+ declare function parseHarnessDocument(filePath: string): HarnessDocument;
269
+ declare function loadDirectory(dirPath: string): HarnessDocument[];
270
+ declare function loadDirectoryWithErrors(dirPath: string): LoadResult;
271
+ interface LoadAllResult {
272
+ primitives: Map<string, HarnessDocument[]>;
273
+ errors: ParseError[];
274
+ }
275
+ declare function loadAllPrimitives(harnessDir: string, extraDirs?: string[]): Map<string, HarnessDocument[]>;
276
+ declare function loadAllPrimitivesWithErrors(harnessDir: string, extraDirs?: string[]): LoadAllResult;
277
+ declare function estimateTokens(text: string): number;
278
+ declare function getAtLevel(doc: HarnessDocument, level: 0 | 1 | 2): string;
279
+
280
+ interface LoadedContext {
281
+ systemPrompt: string;
282
+ budget: ContextBudget;
283
+ parseErrors: ParseError[];
284
+ warnings: string[];
285
+ }
286
+ declare function buildSystemPrompt(harnessDir: string, config: HarnessConfig): LoadedContext;
287
+
288
+ declare function loadState(harnessDir: string): AgentState;
289
+ declare function saveState(harnessDir: string, state: AgentState): void;
290
+
291
+ interface ToolAuth {
292
+ envVar: string;
293
+ present: boolean;
294
+ }
295
+ interface ToolOperation {
296
+ name: string;
297
+ method: string;
298
+ endpoint: string;
299
+ }
300
+ interface ToolDefinition {
301
+ id: string;
302
+ doc: HarnessDocument;
303
+ tags: string[];
304
+ status: string;
305
+ auth: ToolAuth[];
306
+ operations: ToolOperation[];
307
+ rateLimits: string[];
308
+ gotchas: string[];
309
+ }
310
+ interface ToolSummary {
311
+ id: string;
312
+ l0: string;
313
+ tags: string[];
314
+ status: string;
315
+ authReady: boolean;
316
+ operationCount: number;
317
+ }
318
+ /**
319
+ * Parse a tool document into a structured ToolDefinition.
320
+ */
321
+ declare function parseToolDefinition(doc: HarnessDocument): ToolDefinition;
322
+ /**
323
+ * Load all tool definitions from the tools/ directory.
324
+ */
325
+ declare function loadTools(harnessDir: string): ToolDefinition[];
326
+ /**
327
+ * Get a specific tool definition by ID.
328
+ */
329
+ declare function getToolById(harnessDir: string, toolId: string): ToolDefinition | null;
330
+ /**
331
+ * List tools with summary info (without full document content).
332
+ */
333
+ declare function listToolSummaries(harnessDir: string): ToolSummary[];
334
+ /**
335
+ * Check auth status for a specific tool or all tools.
336
+ */
337
+ declare function checkToolAuth(harnessDir: string, toolId?: string): Array<{
338
+ tool: string;
339
+ auth: ToolAuth[];
340
+ }>;
341
+
342
+ /** Result of a single tool execution */
343
+ interface ToolCallResult {
344
+ toolName: string;
345
+ input: Record<string, unknown>;
346
+ output: unknown;
347
+ durationMs: number;
348
+ error: string | null;
349
+ }
350
+ /** Record of all tool calls in a run (for session recording) */
351
+ interface ToolCallRecord {
352
+ calls: ToolCallResult[];
353
+ totalDurationMs: number;
354
+ }
355
+ /** A programmatic tool definition (not from markdown) */
356
+ interface ProgrammaticTool {
357
+ name: string;
358
+ description: string;
359
+ inputSchema: z.ZodType;
360
+ execute: (input: Record<string, unknown>) => Promise<unknown>;
361
+ }
362
+ /** Configuration for tool execution */
363
+ interface ToolExecutorConfig {
364
+ /** Maximum tool calls per run (default: 10) */
365
+ maxToolCalls?: number;
366
+ /** Timeout per tool call in ms (default: 30000) */
367
+ toolTimeoutMs?: number;
368
+ /** Whether to allow HTTP tool execution (default: true) */
369
+ allowHttpExecution?: boolean;
370
+ /** Additional programmatic tools */
371
+ tools?: ProgrammaticTool[];
372
+ }
373
+ /** AI SDK ToolSet — record of named tool definitions */
374
+ type AIToolSet = ToolSet;
375
+ /**
376
+ * Resolve a URL template by replacing `{param}` placeholders with input values.
377
+ * E.g., `/repos/{owner}/{repo}/pulls` with { owner: 'a', repo: 'b' } → `/repos/a/b/pulls`
378
+ */
379
+ declare function resolveEndpoint(endpoint: string, input: Record<string, unknown>): string;
380
+ /**
381
+ * Build a JSON Schema object for a tool operation's URL parameters.
382
+ * Extracts `{param}` patterns from the endpoint URL and creates string properties for each.
383
+ */
384
+ declare function buildOperationSchema(operation: ToolOperation): Record<string, unknown>;
385
+ /**
386
+ * Execute an HTTP tool operation.
387
+ * Resolves URL parameters, attaches auth headers, and makes the HTTP request.
388
+ */
389
+ declare function executeHttpOperation(operation: ToolOperation, baseUrl: string, authHeaders: Record<string, string>, input: Record<string, unknown>, timeoutMs: number): Promise<unknown>;
390
+ /**
391
+ * Build auth headers from a tool's auth configuration.
392
+ * Maps known env var patterns to standard header formats.
393
+ */
394
+ declare function buildAuthHeaders(toolDef: ToolDefinition): Record<string, string>;
395
+ /**
396
+ * Convert a single ToolDefinition (from markdown) into AI SDK tools.
397
+ * Each operation becomes a separate tool entry.
398
+ */
399
+ declare function convertToolDefinition(toolDef: ToolDefinition, config: ToolExecutorConfig): AIToolSet;
400
+ /**
401
+ * Load all tools from the harness directory and convert them to AI SDK format.
402
+ * Includes markdown-defined tools, programmatic tools from config, and MCP tools.
403
+ *
404
+ * Returns an empty object if no tools are configured.
405
+ *
406
+ * @param harnessDir - Path to the harness directory
407
+ * @param config - Tool executor configuration
408
+ * @param mcpTools - Pre-loaded MCP tools to merge (from McpManager.getTools())
409
+ */
410
+ declare function buildToolSet(harnessDir: string, config?: ToolExecutorConfig, mcpTools?: AIToolSet): AIToolSet;
411
+ /**
412
+ * Create a ToolCallRecord tracker for recording tool calls in a run.
413
+ */
414
+ declare function createToolCallTracker(): {
415
+ record: (result: ToolCallResult) => void;
416
+ getRecord: () => ToolCallRecord;
417
+ };
418
+ /**
419
+ * Get a human-readable summary of tools available in the harness.
420
+ */
421
+ declare function getToolSetSummary(tools: AIToolSet): string[];
422
+
423
+ /** Supported provider names for config.model.provider */
424
+ type ProviderName = 'openrouter' | 'anthropic' | 'openai';
425
+ /**
426
+ * Get the OpenRouter provider (backward-compatible).
427
+ * @deprecated Use getModel() with config.model.provider instead.
428
+ */
429
+ declare function getProvider(apiKey?: string): ReturnType<typeof createOpenRouter>;
430
+ declare function resetProvider(): void;
431
+ /**
432
+ * Get a LanguageModel from config. Supports openrouter, anthropic, and openai providers.
433
+ *
434
+ * Provider is selected from config.model.provider (defaults to 'openrouter').
435
+ * Model ID format depends on provider:
436
+ * - openrouter: "anthropic/claude-sonnet-4" (vendor/model)
437
+ * - anthropic: "claude-sonnet-4-20250514" (native model ID)
438
+ * - openai: "gpt-4o" (native model ID)
439
+ */
440
+ declare function getModel(config: HarnessConfig, apiKey?: string): LanguageModel;
441
+ /**
442
+ * Get the summary model for cheap auto-generation tasks (L0/L1 summaries, tags, frontmatter).
443
+ * Falls back to the primary model if summary_model is not configured.
444
+ *
445
+ * Usage: set `model.summary_model` in config.yaml, e.g.:
446
+ * summary_model: "google/gemini-flash-1.5"
447
+ */
448
+ declare function getSummaryModel(config: HarnessConfig, apiKey?: string): LanguageModel;
449
+ /**
450
+ * Get the fast model for validation, checks, and quick decisions.
451
+ * Falls back to summary_model, then primary model.
452
+ *
453
+ * Usage: set `model.fast_model` in config.yaml, e.g.:
454
+ * fast_model: "google/gemini-flash-1.5"
455
+ */
456
+ declare function getFastModel(config: HarnessConfig, apiKey?: string): LanguageModel;
457
+ interface CallOptions {
458
+ maxRetries?: number;
459
+ timeoutMs?: number;
460
+ abortSignal?: AbortSignal;
461
+ }
462
+ interface GenerateOptions extends CallOptions {
463
+ model: LanguageModel;
464
+ system: string;
465
+ prompt: string;
466
+ maxOutputTokens?: number;
467
+ /** AI SDK tools to make available for the LLM */
468
+ tools?: AIToolSet;
469
+ /** Max tool-use roundtrips (default: 1 if tools provided, 0 otherwise) */
470
+ maxToolSteps?: number;
471
+ }
472
+ interface GenerateWithMessagesOptions extends CallOptions {
473
+ model: LanguageModel;
474
+ system: string;
475
+ messages: ModelMessage[];
476
+ maxOutputTokens?: number;
477
+ /** AI SDK tools to make available for the LLM */
478
+ tools?: AIToolSet;
479
+ /** Max tool-use roundtrips (default: 1 if tools provided, 0 otherwise) */
480
+ maxToolSteps?: number;
481
+ }
482
+ interface GenerateResult {
483
+ text: string;
484
+ usage: {
485
+ inputTokens: number;
486
+ outputTokens: number;
487
+ totalTokens: number;
488
+ };
489
+ /** Tool calls made during generation (empty if no tools used) */
490
+ toolCalls: ToolCallInfo[];
491
+ /** Number of steps taken (1 = no tool calls, >1 = tool roundtrips) */
492
+ steps: number;
493
+ }
494
+ declare function generate(opts: GenerateOptions): Promise<GenerateResult>;
495
+ declare function generateWithMessages(opts: GenerateWithMessagesOptions): Promise<GenerateResult>;
496
+ interface StreamWithMessagesResult {
497
+ textStream: AsyncIterable<string>;
498
+ usage: Promise<GenerateResult['usage']>;
499
+ /** Tool calls made across all steps (resolves after stream completes) */
500
+ toolCalls: Promise<ToolCallInfo[]>;
501
+ /** Number of steps (resolves after stream completes) */
502
+ steps: Promise<number>;
503
+ }
504
+ declare function streamWithMessages(opts: GenerateWithMessagesOptions): StreamWithMessagesResult;
505
+ interface StreamGenerateResult {
506
+ textStream: AsyncIterable<string>;
507
+ usage: Promise<GenerateResult['usage']>;
508
+ toolCalls: Promise<ToolCallInfo[]>;
509
+ steps: Promise<number>;
510
+ }
511
+ declare function streamGenerateWithDetails(opts: GenerateOptions): StreamGenerateResult;
512
+
513
+ interface ScaffoldOptions {
514
+ template?: string;
515
+ /** Custom CORE.md content — overrides template */
516
+ coreContent?: string;
517
+ /** Agent purpose description (stored as comment in CORE.md when no LLM generation) */
518
+ purpose?: string;
519
+ }
520
+ declare function scaffoldHarness(targetDir: string, agentName: string, options?: ScaffoldOptions): void;
521
+ /**
522
+ * Generate SYSTEM.md content from the actual directory structure of a harness.
523
+ * Scans for primitives and reflects the real structure.
524
+ */
525
+ declare function generateSystemMd(harnessDir: string, agentName: string): string;
526
+ /**
527
+ * Generate a rich CORE.md using an LLM, given an agent name and purpose description.
528
+ * Returns the generated markdown content, or throws on failure.
529
+ */
530
+ declare function generateCoreMd(agentName: string, purpose: string, options: {
531
+ provider?: string;
532
+ modelId?: string;
533
+ apiKey?: string;
534
+ }): Promise<string>;
535
+ /**
536
+ * List available templates.
537
+ */
538
+ declare function listTemplates(): string[];
539
+
540
+ declare function buildIndex(harnessDir: string, directory: string): IndexEntry[];
541
+ interface IndexOptions {
542
+ /** Max characters for L0 summary in index table. Defaults to 120. */
543
+ summaryMaxLength?: number;
544
+ }
545
+ declare function writeIndexFile(harnessDir: string, directory: string, options?: IndexOptions): void;
546
+ declare function rebuildAllIndexes(harnessDir: string, extraDirs?: string[]): void;
547
+
548
+ /** Result of auto-processing a file */
549
+ interface AutoProcessResult {
550
+ /** Path that was processed */
551
+ path: string;
552
+ /** Whether any changes were made */
553
+ modified: boolean;
554
+ /** List of fixes applied */
555
+ fixes: string[];
556
+ /** Errors encountered */
557
+ errors: string[];
558
+ }
559
+ /** Options for auto-processing */
560
+ interface AutoProcessOptions {
561
+ /** Harness directory (for inferring primitive type from path) */
562
+ harnessDir: string;
563
+ /** Whether to generate frontmatter (default: true) */
564
+ generateFrontmatter?: boolean;
565
+ /** Whether to generate L0/L1 summaries (default: true) */
566
+ generateSummaries?: boolean;
567
+ }
568
+ /**
569
+ * Auto-process a markdown primitive file:
570
+ * 1. Generate frontmatter if missing (id from filename, created, status, tags, author)
571
+ * 2. Generate L0 summary if missing (from heading or first line)
572
+ * 3. Generate L1 summary if missing (from first paragraph)
573
+ *
574
+ * This is designed to run on file save (via watcher) to ensure
575
+ * all primitives have valid structure without user intervention.
576
+ */
577
+ declare function autoProcessFile(filePath: string, options: AutoProcessOptions): AutoProcessResult;
578
+ /**
579
+ * Auto-process all primitives in a harness directory.
580
+ * Useful for batch processing after init or on first dev startup.
581
+ */
582
+ declare function autoProcessAll(harnessDir: string, options?: {
583
+ generateFrontmatter?: boolean;
584
+ generateSummaries?: boolean;
585
+ }): AutoProcessResult[];
586
+
587
+ interface WatcherOptions {
588
+ harnessDir: string;
589
+ extraDirs?: string[];
590
+ onChange?: (path: string, event: string) => void;
591
+ onIndexRebuild?: (directory: string) => void;
592
+ onError?: (error: Error) => void;
593
+ /** Also watch config.yaml for changes */
594
+ watchConfig?: boolean;
595
+ onConfigChange?: () => void;
596
+ /** Enable auto-processing of primitives on save (default: false) */
597
+ autoProcess?: boolean;
598
+ /** Called after auto-processing a file */
599
+ onAutoProcess?: (result: AutoProcessResult) => void;
600
+ }
601
+ declare function createWatcher(options: WatcherOptions): FSWatcher;
602
+
603
+ /**
604
+ * Check if the current time falls within quiet hours.
605
+ * Quiet hours wrap around midnight (e.g. start: 23, end: 6 means 23:00–05:59).
606
+ * Returns true if the agent should be quiet (no scheduled workflows).
607
+ */
608
+ declare function isQuietHours(config: HarnessConfig, now?: Date): boolean;
609
+ interface ScheduledWorkflow {
610
+ doc: HarnessDocument;
611
+ cronExpression: string;
612
+ task: ReturnType<typeof cron.schedule> | null;
613
+ }
614
+ interface SchedulerOptions {
615
+ harnessDir: string;
616
+ apiKey?: string;
617
+ /** Enable daily auto-archival of expired sessions/journals (default: true) */
618
+ autoArchival?: boolean;
619
+ /** Cron expression for auto-archival (default: "0 23 * * *" = daily at 23:00) */
620
+ archivalCron?: string;
621
+ /** Enable auto-journal synthesis (cron string or true for default "0 22 * * *") */
622
+ autoJournal?: boolean | string;
623
+ /** Enable auto-learn after journal synthesis (default: false) */
624
+ autoLearn?: boolean;
625
+ onRun?: (workflowId: string, result: string) => void;
626
+ onError?: (workflowId: string, error: Error) => void;
627
+ onSchedule?: (workflowId: string, cron: string) => void;
628
+ onSkipQuietHours?: (workflowId: string) => void;
629
+ onArchival?: (sessionsArchived: number, journalsArchived: number) => void;
630
+ onRetry?: (workflowId: string, attempt: number, maxRetries: number, error: Error) => void;
631
+ onJournal?: (date: string, sessionsCount: number) => void;
632
+ onLearn?: (installed: number, skipped: number) => void;
633
+ }
634
+ declare class Scheduler {
635
+ private workflows;
636
+ private harnessDir;
637
+ private apiKey?;
638
+ private autoArchival;
639
+ private archivalCron;
640
+ private archivalTask;
641
+ private autoJournal;
642
+ private autoLearn;
643
+ private journalTask;
644
+ /** Tracks proactive executions: workflowId → timestamps of recent runs */
645
+ private proactiveHistory;
646
+ private onRun?;
647
+ private onError?;
648
+ private onSchedule?;
649
+ private onSkipQuietHours?;
650
+ private onArchival?;
651
+ private onRetry?;
652
+ private onJournal?;
653
+ private onLearn?;
654
+ private running;
655
+ constructor(options: SchedulerOptions);
656
+ start(): void;
657
+ stop(): void;
658
+ executeWorkflow(doc: HarnessDocument): Promise<string>;
659
+ runOnce(workflowId: string): Promise<string>;
660
+ listScheduled(): Array<{
661
+ id: string;
662
+ cron: string;
663
+ path: string;
664
+ }>;
665
+ /** Run archival of expired sessions/journals based on config retention policy. */
666
+ runArchival(): void;
667
+ /**
668
+ * Synthesize today's journal from unjournaled sessions.
669
+ * Optionally runs instinct learning after synthesis if auto_learn is enabled.
670
+ */
671
+ runJournalSynthesis(): Promise<void>;
672
+ /**
673
+ * Check if a proactive workflow is allowed to run based on rate limits and cooldown.
674
+ * Returns true if the workflow should proceed, false if it should be skipped.
675
+ */
676
+ checkProactiveCooldown(workflowId: string, config: HarnessConfig): boolean;
677
+ isRunning(): boolean;
678
+ }
679
+
680
+ interface JournalSynthesis {
681
+ summary: string;
682
+ insights: string[];
683
+ instinct_candidates: string[];
684
+ knowledge_updates: string[];
685
+ }
686
+ interface JournalEntry {
687
+ date: string;
688
+ sessions: HarnessDocument[];
689
+ synthesis: string;
690
+ structured: JournalSynthesis;
691
+ instinct_candidates: string[];
692
+ tokens_used: number;
693
+ }
694
+ declare function synthesizeJournal(harnessDir: string, date?: string, apiKey?: string): Promise<JournalEntry>;
695
+ /**
696
+ * Parse a journal synthesis response into structured sections.
697
+ * Resilient to missing sections — returns empty arrays/strings for missing parts.
698
+ */
699
+ declare function parseJournalSynthesis(text: string): JournalSynthesis;
700
+ /**
701
+ * Synthesize journals for a date range.
702
+ * Processes each date that has sessions, skipping dates already journaled unless force is set.
703
+ */
704
+ declare function synthesizeJournalRange(harnessDir: string, options: {
705
+ from?: string;
706
+ to?: string;
707
+ all?: boolean;
708
+ force?: boolean;
709
+ apiKey?: string;
710
+ }): Promise<JournalEntry[]>;
711
+ /**
712
+ * List dates that have sessions but no journal entry.
713
+ */
714
+ declare function listUnjournaled(harnessDir: string): string[];
715
+ declare function listJournals(harnessDir: string): string[];
716
+ interface WeekSummary {
717
+ weekStart: string;
718
+ weekEnd: string;
719
+ journalDates: string[];
720
+ summary: string;
721
+ allInsights: string[];
722
+ allInstinctCandidates: string[];
723
+ allKnowledgeUpdates: string[];
724
+ filePath: string;
725
+ }
726
+ /**
727
+ * Compress daily journals into weekly roll-up summaries.
728
+ * Groups journals by ISO week, aggregates structured sections, writes
729
+ * weekly summary files to memory/journal/weekly/. Pure file-based — no LLM calls.
730
+ *
731
+ * Returns only weeks that were newly created (skips existing unless force=true).
732
+ */
733
+ declare function compressJournals(harnessDir: string, options?: {
734
+ force?: boolean;
735
+ }): WeekSummary[];
736
+
737
+ interface InstinctCandidate {
738
+ id: string;
739
+ behavior: string;
740
+ provenance: string;
741
+ confidence: number;
742
+ }
743
+ interface LearnResult {
744
+ candidates: InstinctCandidate[];
745
+ installed: string[];
746
+ skipped: string[];
747
+ }
748
+ declare function proposeInstincts(harnessDir: string, fromJournalDate?: string, apiKey?: string): Promise<InstinctCandidate[]>;
749
+ declare function installInstinct(harnessDir: string, candidate: InstinctCandidate): string;
750
+ declare function learnFromSessions(harnessDir: string, autoInstall?: boolean, apiKey?: string): Promise<LearnResult>;
751
+ interface HarvestResult {
752
+ candidates: InstinctCandidate[];
753
+ installed: string[];
754
+ skipped: string[];
755
+ journalsScanned: number;
756
+ }
757
+ /**
758
+ * Harvest instinct candidates from journal entries.
759
+ * Scans all journals (or journals within a date range) for instinct candidate
760
+ * sections, deduplicates against existing instincts, and optionally installs them.
761
+ *
762
+ * Unlike learnFromSessions which uses LLM calls, harvestInstincts is pure file-based —
763
+ * it extracts already-identified candidates from journal synthesis output.
764
+ */
765
+ declare function harvestInstincts(harnessDir: string, options?: {
766
+ from?: string;
767
+ to?: string;
768
+ install?: boolean;
769
+ }): HarvestResult;
770
+
771
+ interface EvalResult {
772
+ valid: boolean;
773
+ type: string | null;
774
+ errors: string[];
775
+ warnings: string[];
776
+ fixes_applied: string[];
777
+ }
778
+ /**
779
+ * Auto-fix common issues in a capability file.
780
+ * Reads the file, applies fixes, writes back, returns what was fixed.
781
+ * Does NOT fix unfixable issues (e.g., empty body, unparseable YAML).
782
+ */
783
+ declare function fixCapability(filePath: string): EvalResult;
784
+ /**
785
+ * Evaluate a capability file. If harnessDir is provided, also checks
786
+ * dependency resolution (related: references, with: agent references).
787
+ */
788
+ declare function evaluateCapability(filePath: string, harnessDir?: string): EvalResult;
789
+ declare function installCapability(harnessDir: string, filePath: string): {
790
+ installed: boolean;
791
+ destination: string;
792
+ evalResult: EvalResult;
793
+ };
794
+ declare function processIntake(harnessDir: string): Array<{
795
+ file: string;
796
+ result: ReturnType<typeof installCapability>;
797
+ }>;
798
+ interface DownloadResult {
799
+ downloaded: boolean;
800
+ localPath: string;
801
+ error?: string;
802
+ }
803
+ /**
804
+ * Download a capability file from a URL to a temporary file.
805
+ * Validates the URL (must be HTTPS) and content type (must look like markdown).
806
+ * Returns a local temp path suitable for passing to installCapability().
807
+ */
808
+ declare function downloadCapability(url: string): Promise<DownloadResult>;
809
+
810
+ interface ValidationResult {
811
+ ok: string[];
812
+ warnings: string[];
813
+ errors: string[];
814
+ parseErrors: ParseError[];
815
+ primitiveCounts: Map<string, number>;
816
+ totalPrimitives: number;
817
+ }
818
+ /**
819
+ * Comprehensive harness validation:
820
+ * - Required/optional files
821
+ * - Config validation
822
+ * - State validation
823
+ * - Primitive loading with parse error collection
824
+ * - Cross-reference integrity (related: fields)
825
+ * - Context budget check with warnings
826
+ * - Memory directory structure
827
+ * - API key presence
828
+ */
829
+ declare function validateHarness(dir: string): ValidationResult;
830
+ interface DoctorResult extends ValidationResult {
831
+ fixes: string[];
832
+ directoriesCreated: string[];
833
+ }
834
+ /**
835
+ * Run validation then auto-fix all fixable issues:
836
+ * - Fix primitives with missing id/status/L0/L1/tags
837
+ * - Create missing memory directories
838
+ */
839
+ declare function doctorHarness(dir: string): DoctorResult;
840
+
841
+ interface SessionRecord {
842
+ id: string;
843
+ started: string;
844
+ ended: string;
845
+ prompt: string;
846
+ summary: string;
847
+ tokens_used: number;
848
+ steps: number;
849
+ model_id?: string;
850
+ delegated_to?: string;
851
+ /** Tool calls executed during this session */
852
+ tool_calls?: ToolCallInfo[];
853
+ }
854
+ declare function createSessionId(): string;
855
+ declare function writeSession(harnessDir: string, session: SessionRecord): string;
856
+ interface CleanupResult {
857
+ sessionsRemoved: number;
858
+ journalsRemoved: number;
859
+ sessionFiles: string[];
860
+ journalFiles: string[];
861
+ }
862
+ interface ArchiveResult {
863
+ sessionsArchived: number;
864
+ journalsArchived: number;
865
+ sessionFiles: string[];
866
+ journalFiles: string[];
867
+ }
868
+ /**
869
+ * Archive sessions and journals older than their configured retention periods.
870
+ * Moves files to archive/YYYY-MM/ subdirectories instead of deleting them.
871
+ * Archived files remain on disk for audit/query but aren't loaded by default.
872
+ */
873
+ declare function archiveOldFiles(harnessDir: string, sessionRetentionDays: number, journalRetentionDays: number): ArchiveResult;
874
+ /**
875
+ * Remove sessions and journals older than their configured retention periods.
876
+ * @deprecated Use archiveOldFiles() instead — it preserves files in archive/.
877
+ * This function deletes files permanently.
878
+ */
879
+ declare function cleanupOldFiles(harnessDir: string, sessionRetentionDays: number, journalRetentionDays: number): CleanupResult;
880
+ /** List all session files with their dates */
881
+ declare function listSessions(harnessDir: string): Array<{
882
+ id: string;
883
+ date: string;
884
+ path: string;
885
+ }>;
886
+ /** List files that would be removed by cleanup (dry run — doesn't delete) */
887
+ declare function listExpiredFiles(harnessDir: string, sessionRetentionDays: number, journalRetentionDays: number): {
888
+ sessionFiles: string[];
889
+ journalFiles: string[];
890
+ };
891
+
892
+ interface Message {
893
+ role: 'user' | 'assistant';
894
+ content: string;
895
+ tokens: number;
896
+ }
897
+ interface ConversationOptions {
898
+ recordSessions?: boolean;
899
+ /** AI SDK tools available during conversation */
900
+ tools?: AIToolSet;
901
+ /** Maximum tool-use roundtrips per message (default: 5) */
902
+ maxToolSteps?: number;
903
+ }
904
+ interface ConversationSendResult {
905
+ text: string;
906
+ usage: {
907
+ totalTokens: number;
908
+ };
909
+ steps: number;
910
+ toolCalls: ToolCallInfo[];
911
+ }
912
+ interface ConversationStreamResult {
913
+ /** Async iterable of text chunks — consume with for-await */
914
+ textStream: AsyncIterable<string>;
915
+ /** Resolves after the stream is fully consumed with turn metadata */
916
+ result: Promise<{
917
+ text: string;
918
+ usage: {
919
+ totalTokens: number;
920
+ };
921
+ steps: number;
922
+ toolCalls: ToolCallInfo[];
923
+ }>;
924
+ }
925
+ declare class Conversation {
926
+ private messages;
927
+ private harnessDir;
928
+ private apiKey?;
929
+ private systemPrompt;
930
+ private systemPromptTokens;
931
+ private maxContextTokens;
932
+ private modelOverride?;
933
+ private providerOverride?;
934
+ private recordSessions;
935
+ private tools;
936
+ private maxToolSteps;
937
+ constructor(harnessDir: string, apiKey?: string, options?: ConversationOptions);
938
+ /** Update the tool set (e.g., after MCP servers connect) */
939
+ setTools(tools: AIToolSet): void;
940
+ setModelOverride(modelId: string): void;
941
+ setProviderOverride(provider: string): void;
942
+ init(): Promise<void>;
943
+ private getConfig;
944
+ /**
945
+ * Token budget available for conversation messages.
946
+ * Allocates CONVERSATION_BUDGET_RATIO of (max_tokens - system_prompt) to messages.
947
+ */
948
+ private getMessageBudget;
949
+ /**
950
+ * Trim oldest messages until token budget is satisfied.
951
+ * Always retains at least MIN_MESSAGES.
952
+ */
953
+ private trimToTokenBudget;
954
+ private toModelMessages;
955
+ send(userMessage: string): Promise<ConversationSendResult>;
956
+ sendStream(userMessage: string): ConversationStreamResult;
957
+ save(): void;
958
+ clear(): void;
959
+ private writeSessionRecord;
960
+ getHistory(): Array<{
961
+ role: string;
962
+ content: string;
963
+ }>;
964
+ /** Token usage stats for the conversation window */
965
+ getTokenStats(): {
966
+ messageTokens: number;
967
+ budget: number;
968
+ messageCount: number;
969
+ };
970
+ }
971
+ /**
972
+ * Parse JSON-lines context format.
973
+ * Each line is a JSON object: { role, content }
974
+ */
975
+ declare function parseJsonlContext(raw: string): Message[];
976
+ /**
977
+ * Parse legacy context.md format (### User / ### Assistant sections).
978
+ * Kept for backward compatibility — auto-migrates on first load.
979
+ */
980
+ declare function parseLegacyContext(raw: string): Message[];
981
+
982
+ interface DelegationResult {
983
+ agentId: string;
984
+ text: string;
985
+ usage: {
986
+ inputTokens: number;
987
+ outputTokens: number;
988
+ totalTokens: number;
989
+ };
990
+ sessionId: string;
991
+ }
992
+ interface AgentInfo {
993
+ id: string;
994
+ l0: string;
995
+ l1: string;
996
+ path: string;
997
+ tags: string[];
998
+ status: string;
999
+ }
1000
+ /**
1001
+ * Load all agent documents from the agents/ directory.
1002
+ */
1003
+ declare function loadAgentDocs(harnessDir: string): HarnessDocument[];
1004
+ /**
1005
+ * Find an agent document by its frontmatter id.
1006
+ * Falls back to filename match if id doesn't match.
1007
+ */
1008
+ declare function findAgent(harnessDir: string, agentId: string): HarnessDocument | undefined;
1009
+ /**
1010
+ * List all available agents with summary info.
1011
+ */
1012
+ declare function listAgents(harnessDir: string): AgentInfo[];
1013
+ /**
1014
+ * Build a minimal system prompt for a delegated agent.
1015
+ * Sub-agents are stateless — they get:
1016
+ * 1. The agent's own body (L2) as primary instructions
1017
+ * 2. CORE.md identity (so they know who they serve)
1018
+ * 3. Active rules (at L1 level — compressed for efficiency)
1019
+ */
1020
+ declare function buildAgentPrompt(harnessDir: string, agentDoc: HarnessDocument, config: HarnessConfig): string;
1021
+ interface DelegateOptions {
1022
+ harnessDir: string;
1023
+ agentId: string;
1024
+ prompt: string;
1025
+ apiKey?: string;
1026
+ modelOverride?: string;
1027
+ }
1028
+ /**
1029
+ * Delegate a prompt to a sub-agent.
1030
+ * Sub-agents are stateless single-turn executors. They:
1031
+ * - Receive their own body as system prompt + rules + CORE.md
1032
+ * - Execute a single prompt
1033
+ * - Record a session (tagged with the agent id)
1034
+ * - Return the result
1035
+ *
1036
+ * They do NOT have persistent state, memory, or learning.
1037
+ */
1038
+ declare function delegateTo(opts: DelegateOptions): Promise<DelegationResult>;
1039
+ interface DelegateStreamResult {
1040
+ agentId: string;
1041
+ sessionId: string;
1042
+ textStream: AsyncIterable<string>;
1043
+ }
1044
+ /**
1045
+ * Stream-delegate a prompt to a sub-agent.
1046
+ * Returns an async iterable of text chunks. Session is recorded after
1047
+ * the stream is fully consumed.
1048
+ */
1049
+ declare function delegateStream(opts: DelegateOptions): DelegateStreamResult;
1050
+
1051
+ interface SearchOptions {
1052
+ /** Filter by tag (case-insensitive) */
1053
+ tag?: string;
1054
+ /** Filter by primitive type directory (e.g., "rules", "skills") */
1055
+ type?: string;
1056
+ /** Filter by status (e.g., "active", "draft") */
1057
+ status?: string;
1058
+ /** Filter by author (e.g., "human", "agent") */
1059
+ author?: string;
1060
+ }
1061
+ interface SearchResult {
1062
+ doc: HarnessDocument;
1063
+ directory: string;
1064
+ matchReason: string;
1065
+ }
1066
+ /**
1067
+ * Search primitives across all directories by query text and/or filters.
1068
+ * Query matches against: id, tags, L0 summary, L1 summary, body content.
1069
+ */
1070
+ declare function searchPrimitives(harnessDir: string, query?: string, options?: SearchOptions, config?: HarnessConfig): SearchResult[];
1071
+
1072
+ interface WorkflowRun {
1073
+ workflow_id: string;
1074
+ started: string;
1075
+ ended: string;
1076
+ duration_ms: number;
1077
+ success: boolean;
1078
+ error?: string;
1079
+ tokens_used?: number;
1080
+ attempt: number;
1081
+ max_retries: number;
1082
+ }
1083
+ interface MetricsStore {
1084
+ runs: WorkflowRun[];
1085
+ updated: string;
1086
+ }
1087
+ interface WorkflowStats {
1088
+ workflow_id: string;
1089
+ total_runs: number;
1090
+ successes: number;
1091
+ failures: number;
1092
+ success_rate: number;
1093
+ avg_duration_ms: number;
1094
+ total_tokens: number;
1095
+ last_run: string;
1096
+ last_success: string | null;
1097
+ last_failure: string | null;
1098
+ }
1099
+ /**
1100
+ * Load metrics from the metrics store file.
1101
+ * Returns an empty store if the file doesn't exist.
1102
+ */
1103
+ declare function loadMetrics(harnessDir: string): MetricsStore;
1104
+ /**
1105
+ * Save metrics to the store file. Trims to MAX_RUNS most recent entries.
1106
+ */
1107
+ declare function saveMetrics(harnessDir: string, store: MetricsStore): void;
1108
+ /**
1109
+ * Record a workflow run in the metrics store.
1110
+ */
1111
+ declare function recordRun(harnessDir: string, run: WorkflowRun): void;
1112
+ /**
1113
+ * Get aggregated stats for a specific workflow.
1114
+ */
1115
+ declare function getWorkflowStats(harnessDir: string, workflowId: string): WorkflowStats | null;
1116
+ /**
1117
+ * Get aggregated stats for all workflows that have been run.
1118
+ */
1119
+ declare function getAllWorkflowStats(harnessDir: string): WorkflowStats[];
1120
+ /**
1121
+ * Clear all metrics for a specific workflow, or all workflows if no ID given.
1122
+ */
1123
+ declare function clearMetrics(harnessDir: string, workflowId?: string): number;
1124
+
1125
+ interface ExportEntry {
1126
+ path: string;
1127
+ content: string;
1128
+ }
1129
+ interface HarnessBundle {
1130
+ version: string;
1131
+ exported_at: string;
1132
+ agent_name: string;
1133
+ entries: ExportEntry[];
1134
+ metadata: {
1135
+ primitives: number;
1136
+ sessions: number;
1137
+ journals: number;
1138
+ };
1139
+ }
1140
+ interface ImportResult {
1141
+ imported: number;
1142
+ skipped: number;
1143
+ errors: string[];
1144
+ files: string[];
1145
+ }
1146
+ interface ExportOptions {
1147
+ /** Include session files (default: true) */
1148
+ sessions?: boolean;
1149
+ /** Include journal files (default: true) */
1150
+ journals?: boolean;
1151
+ /** Include memory/metrics.json (default: true) */
1152
+ metrics?: boolean;
1153
+ /** Include state.md and scratch.md (default: true) */
1154
+ state?: boolean;
1155
+ }
1156
+ /**
1157
+ * Export a harness to a portable JSON bundle.
1158
+ */
1159
+ declare function exportHarness(harnessDir: string, options?: ExportOptions): HarnessBundle;
1160
+ /**
1161
+ * Write an export bundle to a JSON file.
1162
+ */
1163
+ declare function writeBundle(bundle: HarnessBundle, outputPath: string): void;
1164
+ /**
1165
+ * Read a bundle from a JSON file.
1166
+ */
1167
+ declare function readBundle(bundlePath: string): HarnessBundle;
1168
+ /**
1169
+ * Import a bundle into a harness directory.
1170
+ * Only writes files that don't already exist (no overwrites by default).
1171
+ */
1172
+ declare function importBundle(harnessDir: string, bundle: HarnessBundle, options?: {
1173
+ overwrite?: boolean;
1174
+ }): ImportResult;
1175
+
1176
+ interface GraphNode {
1177
+ id: string;
1178
+ directory: string;
1179
+ path: string;
1180
+ tags: string[];
1181
+ status: string;
1182
+ l0: string;
1183
+ }
1184
+ interface GraphEdge {
1185
+ from: string;
1186
+ to: string;
1187
+ type: 'related' | 'with';
1188
+ }
1189
+ interface DependencyGraph {
1190
+ nodes: GraphNode[];
1191
+ edges: GraphEdge[];
1192
+ orphans: string[];
1193
+ clusters: string[][];
1194
+ }
1195
+ interface GraphStats {
1196
+ totalNodes: number;
1197
+ totalEdges: number;
1198
+ orphanCount: number;
1199
+ clusterCount: number;
1200
+ mostConnected: Array<{
1201
+ id: string;
1202
+ connections: number;
1203
+ }>;
1204
+ brokenRefs: Array<{
1205
+ from: string;
1206
+ ref: string;
1207
+ }>;
1208
+ }
1209
+ /**
1210
+ * Build a dependency graph from all primitives in the harness.
1211
+ * Analyzes `related:` and `with:` frontmatter fields to create edges.
1212
+ */
1213
+ declare function buildDependencyGraph(harnessDir: string, config?: HarnessConfig): DependencyGraph;
1214
+ /**
1215
+ * Get statistics about the dependency graph.
1216
+ */
1217
+ declare function getGraphStats(harnessDir: string, config?: HarnessConfig): GraphStats;
1218
+
1219
+ interface SessionData {
1220
+ id: string;
1221
+ date: string;
1222
+ started: string;
1223
+ ended: string;
1224
+ tokens: number;
1225
+ steps: number;
1226
+ durationMinutes: number;
1227
+ model?: string;
1228
+ delegatedTo?: string;
1229
+ }
1230
+ interface SessionAnalytics {
1231
+ totalSessions: number;
1232
+ totalTokens: number;
1233
+ totalDurationMinutes: number;
1234
+ avgTokensPerSession: number;
1235
+ avgDurationMinutes: number;
1236
+ sessionsPerDay: Map<string, number>;
1237
+ tokensPerDay: Map<string, number>;
1238
+ modelUsage: Map<string, number>;
1239
+ delegationCount: number;
1240
+ dateRange: {
1241
+ earliest: string;
1242
+ latest: string;
1243
+ } | null;
1244
+ topDays: Array<{
1245
+ date: string;
1246
+ sessions: number;
1247
+ tokens: number;
1248
+ }>;
1249
+ }
1250
+ /**
1251
+ * Load all sessions and compute analytics.
1252
+ */
1253
+ declare function getSessionAnalytics(harnessDir: string): SessionAnalytics;
1254
+ /**
1255
+ * Load raw session data for a date range.
1256
+ */
1257
+ declare function getSessionsInRange(harnessDir: string, from?: string, to?: string): SessionData[];
1258
+
1259
+ /** A recorded event in the sliding window */
1260
+ interface RateEvent {
1261
+ key: string;
1262
+ timestamp: number;
1263
+ }
1264
+ /** Rate limit rule: max requests per window_ms */
1265
+ interface RateLimit {
1266
+ key: string;
1267
+ max_requests: number;
1268
+ window_ms: number;
1269
+ }
1270
+ /** Result of a rate limit check */
1271
+ interface RateLimitCheck {
1272
+ allowed: boolean;
1273
+ key: string;
1274
+ current: number;
1275
+ max: number;
1276
+ window_ms: number;
1277
+ /** ms until oldest event expires (0 if allowed) */
1278
+ retry_after_ms: number;
1279
+ }
1280
+ /** Persisted rate limit state */
1281
+ interface RateLimitStore {
1282
+ events: RateEvent[];
1283
+ updated: string;
1284
+ }
1285
+ /**
1286
+ * Load rate limit events from disk.
1287
+ * Returns empty store if file doesn't exist or is corrupt.
1288
+ */
1289
+ declare function loadRateLimits(harnessDir: string): RateLimitStore;
1290
+ /**
1291
+ * Save rate limit events to disk. Trims to MAX_EVENTS.
1292
+ */
1293
+ declare function saveRateLimits(harnessDir: string, store: RateLimitStore): void;
1294
+ /**
1295
+ * Check if a request is allowed under the given rate limit.
1296
+ * Does NOT record the event — call recordEvent() separately on success.
1297
+ */
1298
+ declare function checkRateLimit(harnessDir: string, limit: RateLimit, now?: number): RateLimitCheck;
1299
+ /**
1300
+ * Record a rate limit event for a key.
1301
+ */
1302
+ declare function recordEvent(harnessDir: string, key: string, now?: number): void;
1303
+ /**
1304
+ * Check rate limit AND record the event if allowed.
1305
+ * Returns the check result. If not allowed, does NOT record.
1306
+ */
1307
+ declare function tryAcquire(harnessDir: string, limit: RateLimit, now?: number): RateLimitCheck;
1308
+ /**
1309
+ * Get current usage for a key within a window.
1310
+ */
1311
+ declare function getUsage(harnessDir: string, key: string, windowMs: number, now?: number): {
1312
+ count: number;
1313
+ oldest: number | null;
1314
+ newest: number | null;
1315
+ };
1316
+ /**
1317
+ * Clear all rate limit events for a key, or all keys.
1318
+ */
1319
+ declare function clearRateLimits(harnessDir: string, key?: string): number;
1320
+
1321
+ /** Cost per 1M tokens for a model (input and output separately) */
1322
+ interface ModelPricing {
1323
+ model_pattern: string;
1324
+ input_per_million: number;
1325
+ output_per_million: number;
1326
+ }
1327
+ /** A recorded cost event */
1328
+ interface CostEntry {
1329
+ timestamp: string;
1330
+ model_id: string;
1331
+ provider: string;
1332
+ input_tokens: number;
1333
+ output_tokens: number;
1334
+ cost_usd: number;
1335
+ source: string;
1336
+ }
1337
+ /** Budget configuration */
1338
+ interface BudgetConfig {
1339
+ daily_limit_usd?: number;
1340
+ monthly_limit_usd?: number;
1341
+ alert_threshold_pct?: number;
1342
+ }
1343
+ /** Budget status check result */
1344
+ interface BudgetStatus {
1345
+ daily_spent_usd: number;
1346
+ daily_limit_usd: number | null;
1347
+ daily_remaining_usd: number | null;
1348
+ daily_pct: number | null;
1349
+ monthly_spent_usd: number;
1350
+ monthly_limit_usd: number | null;
1351
+ monthly_remaining_usd: number | null;
1352
+ monthly_pct: number | null;
1353
+ alerts: string[];
1354
+ }
1355
+ /** Spending summary for a time period */
1356
+ interface SpendingSummary {
1357
+ total_cost_usd: number;
1358
+ total_input_tokens: number;
1359
+ total_output_tokens: number;
1360
+ entries: number;
1361
+ by_model: Record<string, {
1362
+ cost_usd: number;
1363
+ input_tokens: number;
1364
+ output_tokens: number;
1365
+ count: number;
1366
+ }>;
1367
+ by_provider: Record<string, {
1368
+ cost_usd: number;
1369
+ count: number;
1370
+ }>;
1371
+ }
1372
+ /** Persisted cost store */
1373
+ interface CostStore {
1374
+ entries: CostEntry[];
1375
+ updated: string;
1376
+ }
1377
+ /**
1378
+ * Load cost entries from disk.
1379
+ */
1380
+ declare function loadCosts(harnessDir: string): CostStore;
1381
+ /**
1382
+ * Save cost entries to disk. Trims to MAX_ENTRIES.
1383
+ */
1384
+ declare function saveCosts(harnessDir: string, store: CostStore): void;
1385
+ /**
1386
+ * Find pricing for a model ID. Uses prefix matching against DEFAULT_PRICING.
1387
+ * Custom pricing can be passed to override defaults.
1388
+ */
1389
+ declare function findPricing(modelId: string, customPricing?: ModelPricing[]): ModelPricing | null;
1390
+ /**
1391
+ * Calculate cost in USD for a given usage.
1392
+ */
1393
+ declare function calculateCost(modelId: string, inputTokens: number, outputTokens: number, customPricing?: ModelPricing[]): number;
1394
+ /**
1395
+ * Record a cost entry.
1396
+ */
1397
+ declare function recordCost(harnessDir: string, entry: Omit<CostEntry, 'timestamp' | 'cost_usd'> & {
1398
+ cost_usd?: number;
1399
+ }, customPricing?: ModelPricing[]): CostEntry;
1400
+ /**
1401
+ * Get spending summary for a date range.
1402
+ * Defaults to today if no range specified.
1403
+ */
1404
+ declare function getSpending(harnessDir: string, from?: string, to?: string): SpendingSummary;
1405
+ /**
1406
+ * Check budget status against configured limits.
1407
+ */
1408
+ declare function checkBudget(harnessDir: string, budget: BudgetConfig): BudgetStatus;
1409
+ /**
1410
+ * Clear all cost entries, or entries for a specific model.
1411
+ */
1412
+ declare function clearCosts(harnessDir: string, modelId?: string): number;
1413
+
1414
+ interface LockInfo {
1415
+ pid: number;
1416
+ acquired: string;
1417
+ file: string;
1418
+ }
1419
+ interface LockOptions {
1420
+ /** Stale lock timeout in ms (default: 30000 = 30s) */
1421
+ staleMs?: number;
1422
+ /** How often to retry in ms (default: 50) */
1423
+ retryIntervalMs?: number;
1424
+ /** Max time to wait for lock in ms (default: 5000 = 5s) */
1425
+ waitMs?: number;
1426
+ }
1427
+ /**
1428
+ * Try to acquire a file lock. Non-blocking — returns immediately.
1429
+ * Returns true if lock was acquired, false if already held.
1430
+ */
1431
+ declare function tryLock(harnessDir: string, filePath: string, options?: LockOptions): boolean;
1432
+ /**
1433
+ * Release a file lock. Safe to call even if we don't hold it.
1434
+ */
1435
+ declare function releaseLock(harnessDir: string, filePath: string): void;
1436
+ /**
1437
+ * Wait to acquire a file lock with timeout.
1438
+ * Polls at retryIntervalMs until lock is acquired or waitMs expires.
1439
+ */
1440
+ declare function acquireLock(harnessDir: string, filePath: string, options?: LockOptions): Promise<boolean>;
1441
+ /**
1442
+ * Execute a function while holding a file lock.
1443
+ * Acquires lock, runs fn, releases lock (even on error).
1444
+ * If lock cannot be acquired within waitMs, runs fn anyway (fail-open).
1445
+ */
1446
+ declare function withFileLock<T>(harnessDir: string, filePath: string, fn: () => T | Promise<T>, options?: LockOptions): Promise<T>;
1447
+ /**
1448
+ * Synchronous version of withFileLock for use in sync code paths.
1449
+ * Tries lock once — if fails, proceeds anyway (fail-open).
1450
+ */
1451
+ declare function withFileLockSync<T>(harnessDir: string, filePath: string, fn: () => T, options?: LockOptions): T;
1452
+ /**
1453
+ * Check if a file is currently locked (by any process).
1454
+ */
1455
+ declare function isLocked(harnessDir: string, filePath: string, options?: LockOptions): boolean;
1456
+ /**
1457
+ * Force-remove a lock regardless of who owns it.
1458
+ * Use only for manual cleanup via CLI.
1459
+ */
1460
+ declare function breakLock(harnessDir: string, filePath: string): boolean;
1461
+
1462
+ /** Individual health check result */
1463
+ interface HealthCheck {
1464
+ name: string;
1465
+ status: 'pass' | 'warn' | 'fail';
1466
+ message: string;
1467
+ }
1468
+ /** Persisted health metrics */
1469
+ interface HealthMetrics {
1470
+ lastSuccessfulRun: string | null;
1471
+ lastFailedRun: string | null;
1472
+ lastError: string | null;
1473
+ consecutiveFailures: number;
1474
+ totalRuns: number;
1475
+ totalSuccesses: number;
1476
+ totalFailures: number;
1477
+ bootedAt: string | null;
1478
+ updatedAt: string;
1479
+ }
1480
+ /** Overall health status */
1481
+ interface HealthStatus {
1482
+ status: 'healthy' | 'degraded' | 'unhealthy';
1483
+ checks: HealthCheck[];
1484
+ metrics: HealthMetrics;
1485
+ costToday: number;
1486
+ costThisMonth: number;
1487
+ }
1488
+ /**
1489
+ * Load health metrics from disk.
1490
+ */
1491
+ declare function loadHealth(harnessDir: string): HealthMetrics;
1492
+ /**
1493
+ * Save health metrics to disk.
1494
+ */
1495
+ declare function saveHealth(harnessDir: string, metrics: HealthMetrics): void;
1496
+ /**
1497
+ * Record a successful run.
1498
+ */
1499
+ declare function recordSuccess(harnessDir: string): void;
1500
+ /**
1501
+ * Record a failed run.
1502
+ */
1503
+ declare function recordFailure(harnessDir: string, error?: string): void;
1504
+ /**
1505
+ * Record boot time.
1506
+ */
1507
+ declare function recordBoot(harnessDir: string): void;
1508
+ /**
1509
+ * Run all health checks and return overall status.
1510
+ */
1511
+ declare function getHealthStatus(harnessDir: string): HealthStatus;
1512
+ /**
1513
+ * Reset health metrics (for testing or fresh start).
1514
+ */
1515
+ declare function resetHealth(harnessDir: string): void;
1516
+
1517
+ /** A point-in-time snapshot of all system telemetry. */
1518
+ interface TelemetrySnapshot {
1519
+ timestamp: string;
1520
+ agent: {
1521
+ name: string;
1522
+ version: string;
1523
+ mode: AgentState['mode'];
1524
+ lastInteraction: string;
1525
+ };
1526
+ health: HealthStatus;
1527
+ spending: {
1528
+ today: SpendingSummary;
1529
+ thisMonth: SpendingSummary;
1530
+ allTime: SpendingSummary;
1531
+ };
1532
+ sessions: {
1533
+ total: number;
1534
+ totalTokens: number;
1535
+ avgTokensPerSession: number;
1536
+ delegationCount: number;
1537
+ };
1538
+ workflows: {
1539
+ totalRuns: number;
1540
+ totalSuccesses: number;
1541
+ totalFailures: number;
1542
+ overallSuccessRate: number;
1543
+ stats: WorkflowStats[];
1544
+ };
1545
+ storage: {
1546
+ sessionCount: number;
1547
+ journalCount: number;
1548
+ weeklyCount: number;
1549
+ primitiveCount: number;
1550
+ };
1551
+ mcp: {
1552
+ serverCount: number;
1553
+ enabledCount: number;
1554
+ servers: Array<{
1555
+ name: string;
1556
+ transport: string;
1557
+ enabled: boolean;
1558
+ valid: boolean;
1559
+ error?: string;
1560
+ }>;
1561
+ };
1562
+ }
1563
+ /** Options for snapshot collection. */
1564
+ interface TelemetryOptions {
1565
+ /** Skip health checks (default: false) */
1566
+ skipHealth?: boolean;
1567
+ /** Skip session analytics parsing (default: false) */
1568
+ skipSessions?: boolean;
1569
+ /** Skip workflow metrics (default: false) */
1570
+ skipWorkflows?: boolean;
1571
+ /** Skip spending data (default: false) */
1572
+ skipSpending?: boolean;
1573
+ }
1574
+ /**
1575
+ * Collect a full telemetry snapshot from all system modules.
1576
+ * Each section can be skipped via options for performance.
1577
+ */
1578
+ declare function collectSnapshot(harnessDir: string, options?: TelemetryOptions): TelemetrySnapshot;
1579
+ /**
1580
+ * Format a telemetry snapshot as a human-readable dashboard string.
1581
+ */
1582
+ declare function formatDashboard(snapshot: TelemetrySnapshot): string;
1583
+
1584
+ /** Result of a guardrail check before an LLM call. */
1585
+ interface GuardrailResult {
1586
+ allowed: boolean;
1587
+ reason: string | null;
1588
+ rateLimitCheck: RateLimitCheck | null;
1589
+ budgetStatus: BudgetStatus | null;
1590
+ /** Suggested wait time in ms if rate-limited (0 otherwise) */
1591
+ retryAfterMs: number;
1592
+ }
1593
+ /**
1594
+ * Build rate limit rules from config.
1595
+ * Returns an array of limits to check (per-minute, per-hour, per-day).
1596
+ */
1597
+ declare function buildRateLimits(config: HarnessConfig): RateLimit[];
1598
+ /**
1599
+ * Check all guardrails (rate limits + budget) before an LLM call.
1600
+ *
1601
+ * Rate limits: Checks all configured limits. If any limit is exceeded,
1602
+ * the call is blocked with `retry_after_ms` from the first violated limit.
1603
+ *
1604
+ * Budget: Checks daily and monthly spending limits. If `budget.enforce` is true
1605
+ * and any limit is exceeded, the call is blocked.
1606
+ *
1607
+ * Returns { allowed: true } if all checks pass.
1608
+ */
1609
+ declare function checkGuardrails(harnessDir: string, config: HarnessConfig): GuardrailResult;
1610
+
1611
+ /** Single MCP server configuration (mirrors config schema) */
1612
+ interface McpServerConfig {
1613
+ transport: 'stdio' | 'http' | 'sse';
1614
+ command?: string;
1615
+ args?: string[];
1616
+ env?: Record<string, string>;
1617
+ cwd?: string;
1618
+ url?: string;
1619
+ headers?: Record<string, string>;
1620
+ enabled?: boolean;
1621
+ }
1622
+ /** Result of connecting to an MCP server */
1623
+ interface McpServerConnection {
1624
+ name: string;
1625
+ client: MCPClient;
1626
+ toolCount: number;
1627
+ tools: ToolSet;
1628
+ }
1629
+ /** Summary of an MCP server for display */
1630
+ interface McpServerSummary {
1631
+ name: string;
1632
+ transport: string;
1633
+ enabled: boolean;
1634
+ connected: boolean;
1635
+ toolCount: number;
1636
+ toolNames: string[];
1637
+ error?: string;
1638
+ }
1639
+ /** Manages all MCP server connections for a harness */
1640
+ interface McpManager {
1641
+ /** Connect to all enabled MCP servers and load their tools */
1642
+ connect(): Promise<void>;
1643
+ /** Get merged tool set from all connected servers */
1644
+ getTools(): ToolSet;
1645
+ /** Get summary of all configured servers */
1646
+ getSummaries(): McpServerSummary[];
1647
+ /** Close all connected clients */
1648
+ close(): Promise<void>;
1649
+ /** Check if any servers are configured */
1650
+ hasServers(): boolean;
1651
+ }
1652
+ /**
1653
+ * Create an MCP manager from harness config.
1654
+ * Manages lifecycle of all MCP server connections.
1655
+ */
1656
+ declare function createMcpManager(config: HarnessConfig): McpManager;
1657
+ /**
1658
+ * Load MCP tools from all enabled servers in config.
1659
+ * Convenience function for one-shot usage (connects, loads, returns tools + close fn).
1660
+ */
1661
+ declare function loadMcpTools(config: HarnessConfig): Promise<{
1662
+ tools: ToolSet;
1663
+ summaries: McpServerSummary[];
1664
+ close: () => Promise<void>;
1665
+ }>;
1666
+ /**
1667
+ * Validate MCP server configurations without connecting.
1668
+ * Returns validation errors for each server.
1669
+ */
1670
+ declare function validateMcpConfig(config: HarnessConfig): Array<{
1671
+ server: string;
1672
+ error: string;
1673
+ }>;
1674
+
1675
+ /** A discovered MCP server from an external tool's config */
1676
+ interface DiscoveredMcpServer {
1677
+ /** Server name (key from the source config) */
1678
+ name: string;
1679
+ /** Transport type inferred from config */
1680
+ transport: 'stdio' | 'http' | 'sse';
1681
+ /** Command for stdio transport */
1682
+ command?: string;
1683
+ /** Args for stdio transport */
1684
+ args?: string[];
1685
+ /** Environment variables */
1686
+ env?: Record<string, string>;
1687
+ /** Working directory */
1688
+ cwd?: string;
1689
+ /** URL for http/sse transport */
1690
+ url?: string;
1691
+ /** Headers for http/sse transport */
1692
+ headers?: Record<string, string>;
1693
+ }
1694
+ /** Result of scanning a single tool's config */
1695
+ interface DiscoverySource {
1696
+ /** Tool name (e.g. "Claude Desktop", "Cursor") */
1697
+ tool: string;
1698
+ /** Config file path that was scanned */
1699
+ configPath: string;
1700
+ /** Whether the config file exists */
1701
+ found: boolean;
1702
+ /** Servers discovered from this tool */
1703
+ servers: DiscoveredMcpServer[];
1704
+ /** Error encountered while reading/parsing */
1705
+ error?: string;
1706
+ }
1707
+ /** Aggregated discovery results */
1708
+ interface DiscoveryResult {
1709
+ /** All sources scanned */
1710
+ sources: DiscoverySource[];
1711
+ /** Deduplicated servers (by name, preferring first seen) */
1712
+ servers: DiscoveredMcpServer[];
1713
+ /** Total sources that had config files */
1714
+ sourcesFound: number;
1715
+ /** Total unique servers discovered */
1716
+ totalServers: number;
1717
+ }
1718
+ /** Options for discovery — primarily used for testing */
1719
+ interface DiscoveryOptions {
1720
+ /** Override home directory (default: os.homedir()) */
1721
+ homeDir?: string;
1722
+ /** Override platform detection (default: os.platform() === 'darwin') */
1723
+ isMac?: boolean;
1724
+ }
1725
+ /**
1726
+ * Scan all known tool config locations for MCP servers.
1727
+ * Returns deduplicated results with source tracking.
1728
+ */
1729
+ declare function discoverMcpServers(options?: DiscoveryOptions): DiscoveryResult;
1730
+ /**
1731
+ * Convert discovered servers to the harness config YAML format.
1732
+ * Returns a string that can be appended to config.yaml.
1733
+ *
1734
+ * Normalizes absolute paths to well-known binaries (npx/node/python) to bare
1735
+ * names so the YAML is portable across machines. When the command is normalized,
1736
+ * any PATH env var entry is dropped — it was only needed to find the absolute
1737
+ * binary location.
1738
+ */
1739
+ declare function discoveredServersToYaml(servers: DiscoveredMcpServer[]): string;
1740
+ /** Get the list of tools that are scanned (for display purposes) */
1741
+ declare function getScannedTools(): string[];
1742
+
1743
+ /** Environment variable from registry server entry */
1744
+ interface RegistryEnvVar {
1745
+ name: string;
1746
+ description?: string;
1747
+ isRequired?: boolean;
1748
+ format?: string;
1749
+ }
1750
+ /** Package entry from registry server */
1751
+ interface RegistryPackage {
1752
+ registryType: 'npm' | 'pypi' | 'oci' | 'nuget' | 'mcpb';
1753
+ identifier: string;
1754
+ version: string;
1755
+ transport: {
1756
+ type: 'stdio' | 'streamable-http' | 'sse';
1757
+ };
1758
+ environmentVariables?: RegistryEnvVar[];
1759
+ runtimeHint?: 'npx' | 'uvx' | 'docker' | 'dnx';
1760
+ packageArguments?: unknown[];
1761
+ runtimeArguments?: unknown[];
1762
+ }
1763
+ /** Remote endpoint from registry server */
1764
+ interface RegistryRemote {
1765
+ transportType: 'streamable-http' | 'sse';
1766
+ url: string;
1767
+ headers?: Record<string, string>;
1768
+ }
1769
+ /** A single server entry from the MCP registry API */
1770
+ interface RegistryServer {
1771
+ $schema?: string;
1772
+ name: string;
1773
+ description?: string;
1774
+ title?: string;
1775
+ version: string;
1776
+ repository?: {
1777
+ url: string;
1778
+ source?: string;
1779
+ subfolder?: string;
1780
+ };
1781
+ websiteUrl?: string;
1782
+ packages?: RegistryPackage[];
1783
+ remotes?: RegistryRemote[];
1784
+ }
1785
+ /** A server result from the registry search API */
1786
+ interface RegistrySearchResult {
1787
+ server: RegistryServer;
1788
+ _meta?: Record<string, unknown>;
1789
+ }
1790
+ /** Full search response from the registry */
1791
+ interface RegistrySearchResponse {
1792
+ servers: RegistrySearchResult[];
1793
+ metadata?: {
1794
+ nextCursor?: string;
1795
+ count?: number;
1796
+ };
1797
+ }
1798
+ /** Resolved server config ready for installation */
1799
+ interface ResolvedServer {
1800
+ /** Display name for the server */
1801
+ name: string;
1802
+ /** Server description from registry */
1803
+ description?: string;
1804
+ /** Registry name (e.g. "io.github.foo/bar") */
1805
+ registryName: string;
1806
+ /** Source package info */
1807
+ package?: RegistryPackage;
1808
+ /** Source remote info */
1809
+ remote?: RegistryRemote;
1810
+ /** Generated harness config */
1811
+ config: McpServerConfig;
1812
+ /** Environment variables that need to be set */
1813
+ requiredEnv: RegistryEnvVar[];
1814
+ /** All environment variables (required + optional) */
1815
+ allEnv: RegistryEnvVar[];
1816
+ }
1817
+ /**
1818
+ * Search the MCP registry for servers matching a query.
1819
+ */
1820
+ declare function searchRegistry(query: string, options?: {
1821
+ limit?: number;
1822
+ cursor?: string;
1823
+ }): Promise<RegistrySearchResponse>;
1824
+ /**
1825
+ * Get a specific server by its registry name and version.
1826
+ * Name must be URL-encoded (e.g. "io.github.foo/bar" -> "io.github.foo%2Fbar").
1827
+ */
1828
+ declare function getRegistryServer(name: string, version?: string): Promise<RegistryServer>;
1829
+ /**
1830
+ * Derive a short config name from a registry server name.
1831
+ * "io.github.foo/bar-server" -> "bar-server"
1832
+ * "io.github.foo/mcp-something" -> "mcp-something"
1833
+ */
1834
+ declare function deriveConfigName(registryName: string): string;
1835
+ /**
1836
+ * Resolve a registry server entry into a harness McpServerConfig.
1837
+ * Prefers npm stdio packages, falls back to pypi, then remotes.
1838
+ */
1839
+ declare function resolveServerConfig(server: RegistryServer): ResolvedServer;
1840
+ /**
1841
+ * Search the registry and return the best match for a query.
1842
+ * If the query looks like a registry name (contains "/" or "."), try exact lookup first.
1843
+ * Otherwise, search and return the first result.
1844
+ */
1845
+ declare function findServer(query: string): Promise<ResolvedServer | null>;
1846
+ /**
1847
+ * Search the registry and return all matches for display.
1848
+ */
1849
+ declare function searchServers(query: string, options?: {
1850
+ limit?: number;
1851
+ }): Promise<ResolvedServer[]>;
1852
+
1853
+ /** Result of installing an MCP server */
1854
+ interface McpInstallResult {
1855
+ /** Whether installation succeeded */
1856
+ installed: boolean;
1857
+ /** Server config name in config.yaml */
1858
+ name: string;
1859
+ /** The resolved server details */
1860
+ server?: ResolvedServer;
1861
+ /** Connection test results */
1862
+ connectionTest?: {
1863
+ connected: boolean;
1864
+ toolCount: number;
1865
+ toolNames: string[];
1866
+ error?: string;
1867
+ };
1868
+ /** Generated tool doc paths */
1869
+ generatedDocs: string[];
1870
+ /** Env vars that need user configuration */
1871
+ pendingEnvVars: RegistryEnvVar[];
1872
+ /** Error message if installation failed */
1873
+ error?: string;
1874
+ }
1875
+ /** Options for the install command */
1876
+ interface McpInstallOptions {
1877
+ /** Harness directory */
1878
+ dir: string;
1879
+ /** Skip connection testing */
1880
+ skipTest?: boolean;
1881
+ /** Skip tool doc generation */
1882
+ skipDocs?: boolean;
1883
+ /** Force overwrite if server already exists */
1884
+ force?: boolean;
1885
+ /** Custom name override for the server in config */
1886
+ name?: string;
1887
+ }
1888
+ /**
1889
+ * Add or update an MCP server entry in the config file.
1890
+ * Preserves existing config structure and comments where possible.
1891
+ */
1892
+ declare function updateConfigWithServer(dir: string, serverName: string, serverConfig: McpServerConfig): void;
1893
+ /**
1894
+ * Generate a tools/*.md knowledge doc from a connected MCP server's tools.
1895
+ * Creates one file per MCP server with descriptions of all available tools.
1896
+ */
1897
+ declare function generateToolDocs(dir: string, serverName: string, toolNames: string[], description?: string): string[];
1898
+ /**
1899
+ * Install an MCP server by name or search query.
1900
+ *
1901
+ * Flow:
1902
+ * 1. Search the MCP registry for the server
1903
+ * 2. Resolve the best package/transport configuration
1904
+ * 3. Add/update the server entry in config.yaml
1905
+ * 4. Optionally test the connection
1906
+ * 5. Optionally generate tools/*.md knowledge docs
1907
+ */
1908
+ declare function installMcpServer(query: string, options: McpInstallOptions): Promise<McpInstallResult>;
1909
+ /**
1910
+ * List available servers from the registry for a given query.
1911
+ */
1912
+ declare function listRegistryServers(query: string, options?: {
1913
+ limit?: number;
1914
+ }): Promise<ResolvedServer[]>;
1915
+ /**
1916
+ * Format a registry search result for CLI display.
1917
+ */
1918
+ declare function formatRegistryServer(entry: {
1919
+ server: RegistryServer;
1920
+ }): string;
1921
+
1922
+ /** A detected API key from environment files */
1923
+ interface DetectedApiKey {
1924
+ /** Environment variable name */
1925
+ name: string;
1926
+ /** Which file it was found in */
1927
+ source: string;
1928
+ /** Whether the value looks like an actual key (not a placeholder) */
1929
+ hasValue: boolean;
1930
+ /** Suggested MCP server or service this key is for */
1931
+ suggestion?: string;
1932
+ }
1933
+ /** Result of scanning environment for API keys */
1934
+ interface EnvDiscoveryResult {
1935
+ /** All detected API keys */
1936
+ keys: DetectedApiKey[];
1937
+ /** Files that were scanned */
1938
+ filesScanned: string[];
1939
+ /** Suggested MCP servers based on detected keys */
1940
+ suggestions: EnvSuggestion[];
1941
+ }
1942
+ /** Suggested MCP server based on detected environment */
1943
+ interface EnvSuggestion {
1944
+ /** Human-readable suggestion */
1945
+ message: string;
1946
+ /** MCP server registry name or package */
1947
+ serverQuery: string;
1948
+ /** Which env var triggered this suggestion */
1949
+ triggeredBy: string;
1950
+ }
1951
+ /**
1952
+ * Parse a .env file and extract variable names and whether they have real values.
1953
+ * Handles comments, empty values, and quoted values.
1954
+ */
1955
+ declare function parseEnvFile(content: string): Array<{
1956
+ name: string;
1957
+ hasValue: boolean;
1958
+ }>;
1959
+ /** Options for environment discovery */
1960
+ interface EnvDiscoveryOptions {
1961
+ /** Directory to scan (defaults to cwd) */
1962
+ dir?: string;
1963
+ /** Additional directories to scan for .env files */
1964
+ extraDirs?: string[];
1965
+ }
1966
+ /**
1967
+ * Scan for .env files and detect API keys with suggestions.
1968
+ */
1969
+ declare function discoverEnvKeys(options?: EnvDiscoveryOptions): EnvDiscoveryResult;
1970
+
1971
+ /** A detected project characteristic */
1972
+ interface ProjectSignal {
1973
+ /** What was detected (e.g. "TypeScript", "React", "Docker") */
1974
+ name: string;
1975
+ /** Category of signal */
1976
+ category: 'language' | 'framework' | 'tool' | 'runtime' | 'database' | 'cloud' | 'testing';
1977
+ /** Source file that triggered the detection */
1978
+ source: string;
1979
+ /** Additional details */
1980
+ details?: string;
1981
+ }
1982
+ /** Suggested rule, skill, or MCP server */
1983
+ interface ProjectSuggestion {
1984
+ /** What type of thing to add */
1985
+ type: 'rule' | 'skill' | 'mcp-server';
1986
+ /** Human-readable suggestion */
1987
+ message: string;
1988
+ /** File to create (for rules/skills) or server query (for MCP) */
1989
+ target: string;
1990
+ /** Triggered by these signals */
1991
+ signals: string[];
1992
+ }
1993
+ /** Full project discovery result */
1994
+ interface ProjectDiscoveryResult {
1995
+ /** Detected project signals */
1996
+ signals: ProjectSignal[];
1997
+ /** Files that were examined */
1998
+ filesExamined: string[];
1999
+ /** Suggestions based on signals */
2000
+ suggestions: ProjectSuggestion[];
2001
+ }
2002
+ /** Options for project discovery */
2003
+ interface ProjectDiscoveryOptions {
2004
+ /** Project directory to scan */
2005
+ dir?: string;
2006
+ }
2007
+ /**
2008
+ * Scan a project directory to detect its technology stack and suggest
2009
+ * rules, skills, and MCP servers.
2010
+ */
2011
+ declare function discoverProjectContext(options?: ProjectDiscoveryOptions): ProjectDiscoveryResult;
2012
+
2013
+ interface WebServerOptions {
2014
+ harnessDir: string;
2015
+ port?: number;
2016
+ /** API key for LLM calls (chat) */
2017
+ apiKey?: string;
2018
+ /** Callback when server starts */
2019
+ onStart?: (port: number) => void;
2020
+ }
2021
+ interface ServerSentEvent {
2022
+ type: string;
2023
+ data: unknown;
2024
+ timestamp: string;
2025
+ }
2026
+ declare class SSEBroadcaster {
2027
+ private clients;
2028
+ private nextId;
2029
+ addClient(controller: ReadableStreamDefaultController): string;
2030
+ removeClient(id: string): void;
2031
+ broadcast(event: ServerSentEvent): void;
2032
+ get clientCount(): number;
2033
+ }
2034
+ interface CreateWebAppOptions {
2035
+ apiKey?: string;
2036
+ }
2037
+ declare function createWebApp(harnessDir: string, options?: CreateWebAppOptions): {
2038
+ app: Hono;
2039
+ broadcaster: SSEBroadcaster;
2040
+ };
2041
+ declare function startWebServer(options: WebServerOptions): Promise<{
2042
+ server: Server;
2043
+ broadcaster: SSEBroadcaster;
2044
+ }>;
2045
+
2046
+ interface BundleManifest {
2047
+ /** Manifest format version */
2048
+ version: string;
2049
+ /** Bundle name (e.g., "code-review-rules") */
2050
+ name: string;
2051
+ /** Human-readable description */
2052
+ description: string;
2053
+ /** Author identifier */
2054
+ author: string;
2055
+ /** Semantic version (e.g., "1.0.0") */
2056
+ bundle_version: string;
2057
+ /** When this bundle was created */
2058
+ created: string;
2059
+ /** Primitive type(s) contained (e.g., ["rules", "instincts"]) */
2060
+ types: string[];
2061
+ /** Tags for search/discovery */
2062
+ tags: string[];
2063
+ /** Files included in this bundle (relative paths) */
2064
+ files: BundleFileEntry[];
2065
+ /** Optional dependencies (other bundle names) */
2066
+ dependencies?: string[];
2067
+ /** Optional registry URL this was published to */
2068
+ registry?: string;
2069
+ /** Optional license identifier */
2070
+ license?: string;
2071
+ }
2072
+ interface BundleFileEntry {
2073
+ path: string;
2074
+ type: string;
2075
+ id: string;
2076
+ l0: string;
2077
+ }
2078
+ interface RegistryConfig {
2079
+ /** Registry URL (HTTPS) */
2080
+ url: string;
2081
+ /** Optional auth token */
2082
+ token?: string;
2083
+ /** Optional name for display */
2084
+ name?: string;
2085
+ }
2086
+ interface BundleSearchResult {
2087
+ name: string;
2088
+ description: string;
2089
+ author: string;
2090
+ version: string;
2091
+ types: string[];
2092
+ tags: string[];
2093
+ download_url: string;
2094
+ }
2095
+ interface BundleSearchResponse {
2096
+ results: BundleSearchResult[];
2097
+ total: number;
2098
+ }
2099
+ interface PrimitiveInstallResult {
2100
+ installed: boolean;
2101
+ name: string;
2102
+ files: string[];
2103
+ skipped: string[];
2104
+ errors: string[];
2105
+ manifest?: BundleManifest;
2106
+ }
2107
+ interface PrimitiveUninstallResult {
2108
+ uninstalled: boolean;
2109
+ name: string;
2110
+ archived: string[];
2111
+ dependents: string[];
2112
+ errors: string[];
2113
+ }
2114
+ interface PrimitiveUpdateResult {
2115
+ updated: boolean;
2116
+ name: string;
2117
+ added: string[];
2118
+ modified: string[];
2119
+ removed: string[];
2120
+ errors: string[];
2121
+ oldVersion?: string;
2122
+ newVersion?: string;
2123
+ }
2124
+ /**
2125
+ * Create a manifest.yaml for a set of primitive files.
2126
+ */
2127
+ declare function createManifest(harnessDir: string, options: {
2128
+ name: string;
2129
+ description: string;
2130
+ author?: string;
2131
+ version?: string;
2132
+ files: string[];
2133
+ tags?: string[];
2134
+ license?: string;
2135
+ }): BundleManifest;
2136
+ /**
2137
+ * Write a manifest to a YAML file.
2138
+ */
2139
+ declare function writeManifest(manifest: BundleManifest, outputPath: string): void;
2140
+ /**
2141
+ * Read and validate a manifest from a YAML file.
2142
+ */
2143
+ declare function readManifest(manifestPath: string): BundleManifest;
2144
+ interface PackedBundle {
2145
+ manifest: BundleManifest;
2146
+ files: Array<{
2147
+ path: string;
2148
+ content: string;
2149
+ }>;
2150
+ }
2151
+ /**
2152
+ * Pack a set of primitives into a bundle (manifest + file contents).
2153
+ */
2154
+ declare function packBundle(harnessDir: string, options: {
2155
+ name: string;
2156
+ description: string;
2157
+ author?: string;
2158
+ version?: string;
2159
+ files?: string[];
2160
+ types?: string[];
2161
+ tags?: string[];
2162
+ license?: string;
2163
+ }): PackedBundle;
2164
+ /**
2165
+ * Write a packed bundle to a directory (manifest.yaml + files).
2166
+ */
2167
+ declare function writeBundleDir(bundle: PackedBundle, outputDir: string): void;
2168
+ /**
2169
+ * Read a packed bundle from a directory containing manifest.yaml.
2170
+ */
2171
+ declare function readBundleDir(bundleDir: string): PackedBundle;
2172
+ /**
2173
+ * Install primitives from a packed bundle into a harness directory.
2174
+ */
2175
+ declare function installBundle(harnessDir: string, bundle: PackedBundle, options?: {
2176
+ overwrite?: boolean;
2177
+ force?: boolean;
2178
+ }): PrimitiveInstallResult;
2179
+ /**
2180
+ * Uninstall (soft-delete) a previously installed bundle.
2181
+ * Moves files to archive/ instead of deleting.
2182
+ */
2183
+ declare function uninstallBundle(harnessDir: string, bundleName: string, options?: {
2184
+ hard?: boolean;
2185
+ }): PrimitiveUninstallResult;
2186
+ /**
2187
+ * Compare an installed bundle against a new version and produce a diff.
2188
+ */
2189
+ declare function diffBundle(harnessDir: string, newBundle: PackedBundle): {
2190
+ added: string[];
2191
+ modified: string[];
2192
+ removed: string[];
2193
+ unchanged: string[];
2194
+ };
2195
+ /**
2196
+ * Update an installed bundle to a new version.
2197
+ */
2198
+ declare function updateBundle(harnessDir: string, newBundle: PackedBundle, options?: {
2199
+ removeDeleted?: boolean;
2200
+ }): PrimitiveUpdateResult;
2201
+ /**
2202
+ * Read all installed bundle manifests.
2203
+ */
2204
+ declare function readInstalledManifests(harnessDir: string): BundleManifest[];
2205
+ /**
2206
+ * List all installed bundles with summary info.
2207
+ */
2208
+ declare function listInstalledBundles(harnessDir: string): Array<{
2209
+ name: string;
2210
+ version: string;
2211
+ types: string[];
2212
+ fileCount: number;
2213
+ description: string;
2214
+ }>;
2215
+ /**
2216
+ * Fetch a bundle from a remote registry URL.
2217
+ */
2218
+ declare function fetchRemoteBundle(url: string): Promise<PackedBundle>;
2219
+ /**
2220
+ * Search a remote registry for bundles.
2221
+ */
2222
+ declare function searchBundleRegistry(registryUrl: string, query: string, options?: {
2223
+ limit?: number;
2224
+ token?: string;
2225
+ }): Promise<BundleSearchResponse>;
2226
+ /**
2227
+ * Fetch a bundle from a registry by name.
2228
+ */
2229
+ declare function fetchFromRegistry(registryUrl: string, bundleName: string, options?: {
2230
+ version?: string;
2231
+ token?: string;
2232
+ }): Promise<PackedBundle>;
2233
+ interface BundleSearchHit extends BundleSearchResult {
2234
+ /** Which registry URL this result came from */
2235
+ registryUrl: string;
2236
+ /** Display name of the registry */
2237
+ registryName: string;
2238
+ }
2239
+ interface MultiBundleSearchResponse {
2240
+ results: BundleSearchHit[];
2241
+ total: number;
2242
+ registriesSearched: number;
2243
+ errors: Array<{
2244
+ registry: string;
2245
+ error: string;
2246
+ }>;
2247
+ }
2248
+ /**
2249
+ * Search all configured registries for bundles.
2250
+ * Merges results, deduplicating by name (first registry wins).
2251
+ */
2252
+ declare function searchConfiguredRegistries(registries: Array<{
2253
+ url: string;
2254
+ name?: string;
2255
+ token?: string;
2256
+ }>, query: string, options?: {
2257
+ limit?: number;
2258
+ }): Promise<MultiBundleSearchResponse>;
2259
+ /**
2260
+ * Install a bundle from configured registries by name.
2261
+ * Searches each registry in order, installs from the first match.
2262
+ */
2263
+ declare function installFromRegistry(harnessDir: string, registries: Array<{
2264
+ url: string;
2265
+ name?: string;
2266
+ token?: string;
2267
+ }>, bundleName: string, options?: {
2268
+ version?: string;
2269
+ overwrite?: boolean;
2270
+ force?: boolean;
2271
+ }): Promise<PrimitiveInstallResult & {
2272
+ registryUrl?: string;
2273
+ }>;
2274
+
2275
+ /**
2276
+ * Builtin starter packs — installable bundles of primitives (workflows,
2277
+ * rules, instincts, skills) that users can customize after installation.
2278
+ *
2279
+ * Install via: `harness install pack:<name>`
2280
+ * List available: `harness install pack:list`
2281
+ */
2282
+
2283
+ interface StarterPack {
2284
+ name: string;
2285
+ description: string;
2286
+ tags: string[];
2287
+ files: Array<{
2288
+ path: string;
2289
+ content: string;
2290
+ id: string;
2291
+ l0: string;
2292
+ }>;
2293
+ }
2294
+ /**
2295
+ * Get a builtin starter pack by name.
2296
+ * Returns null if the pack doesn't exist.
2297
+ */
2298
+ declare function getStarterPack(name: string): PackedBundle | null;
2299
+ /**
2300
+ * List all available builtin starter packs.
2301
+ */
2302
+ declare function listStarterPacks(): Array<{
2303
+ name: string;
2304
+ description: string;
2305
+ fileCount: number;
2306
+ tags: string[];
2307
+ }>;
2308
+ /**
2309
+ * Check if a source string is a pack reference (starts with "pack:").
2310
+ */
2311
+ declare function isPackReference(source: string): boolean;
2312
+ /**
2313
+ * Parse the pack name from a "pack:<name>" reference.
2314
+ */
2315
+ declare function parsePackName(source: string): string;
2316
+
2317
+ interface PatternOccurrence {
2318
+ behavior: string;
2319
+ journalDates: string[];
2320
+ count: number;
2321
+ }
2322
+ interface AutoPromoteResult {
2323
+ patterns: PatternOccurrence[];
2324
+ promoted: string[];
2325
+ skipped: string[];
2326
+ journalsScanned: number;
2327
+ }
2328
+ /**
2329
+ * Scan all journals for instinct candidates that appear 3+ times.
2330
+ * These repeated patterns suggest strong behavioral signals worth auto-promoting.
2331
+ *
2332
+ * The function:
2333
+ * 1. Reads all journal files
2334
+ * 2. Extracts "## Instinct Candidates" sections
2335
+ * 3. Normalizes behavior text for fuzzy matching
2336
+ * 4. Groups by similar behavior (normalized string comparison)
2337
+ * 5. Returns patterns with 3+ occurrences across different journal dates
2338
+ * 6. Optionally auto-installs promoted instincts
2339
+ */
2340
+ declare function autoPromoteInstincts(harnessDir: string, options?: {
2341
+ threshold?: number;
2342
+ install?: boolean;
2343
+ }): AutoPromoteResult;
2344
+ interface DeadPrimitive {
2345
+ id: string;
2346
+ path: string;
2347
+ directory: string;
2348
+ lastModified: string;
2349
+ daysSinceModified: number;
2350
+ reason: string;
2351
+ }
2352
+ interface DeadPrimitiveResult {
2353
+ dead: DeadPrimitive[];
2354
+ totalScanned: number;
2355
+ thresholdDays: number;
2356
+ }
2357
+ /**
2358
+ * Detect "dead" primitives — files that are:
2359
+ * 1. Orphaned (no incoming or outgoing references via related:/with:)
2360
+ * 2. Not modified in the last N days (default 30)
2361
+ *
2362
+ * Excludes session and journal directories (memory files).
2363
+ * Does NOT flag recently created primitives even if orphaned.
2364
+ */
2365
+ declare function detectDeadPrimitives(harnessDir: string, config?: HarnessConfig, options?: {
2366
+ thresholdDays?: number;
2367
+ }): DeadPrimitiveResult;
2368
+ interface Contradiction {
2369
+ primitiveA: {
2370
+ id: string;
2371
+ path: string;
2372
+ type: string;
2373
+ text: string;
2374
+ };
2375
+ primitiveB: {
2376
+ id: string;
2377
+ path: string;
2378
+ type: string;
2379
+ text: string;
2380
+ };
2381
+ reason: string;
2382
+ severity: 'low' | 'medium' | 'high';
2383
+ }
2384
+ interface ContradictionResult {
2385
+ contradictions: Contradiction[];
2386
+ rulesChecked: number;
2387
+ instinctsChecked: number;
2388
+ }
2389
+ /**
2390
+ * Detect contradictions between rules and instincts.
2391
+ *
2392
+ * Checks for:
2393
+ * 1. Direct negation patterns ("always X" vs "never X", "do X" vs "don't X")
2394
+ * 2. Conflicting tag overlap with opposing behavioral signals
2395
+ * 3. Same topic with contradictory directives
2396
+ *
2397
+ * This is a heuristic-based detector (no LLM needed).
2398
+ * Returns candidate contradictions for human review.
2399
+ */
2400
+ declare function detectContradictions(harnessDir: string): ContradictionResult;
2401
+ interface SessionEnrichment {
2402
+ sessionId: string;
2403
+ topics: string[];
2404
+ tokenCount: number;
2405
+ stepCount: number;
2406
+ model: string;
2407
+ toolsUsed: string[];
2408
+ primitivesReferenced: string[];
2409
+ duration: string;
2410
+ }
2411
+ interface EnrichmentResult {
2412
+ enriched: SessionEnrichment[];
2413
+ sessionsScanned: number;
2414
+ }
2415
+ /**
2416
+ * Enrich sessions with extracted metadata.
2417
+ *
2418
+ * Scans session files and extracts:
2419
+ * - Topics (from prompt text, frequent nouns, matched primitive IDs)
2420
+ * - Token/step counts (from frontmatter or markdown body)
2421
+ * - Model used
2422
+ * - Tools used (from tool call sections)
2423
+ * - Referenced primitives (IDs mentioned in session text)
2424
+ * - Duration
2425
+ */
2426
+ declare function enrichSessions(harnessDir: string, config?: HarnessConfig, options?: {
2427
+ from?: string;
2428
+ to?: string;
2429
+ }): EnrichmentResult;
2430
+ interface CapabilitySuggestion {
2431
+ topic: string;
2432
+ frequency: number;
2433
+ sessionDates: string[];
2434
+ suggestion: string;
2435
+ suggestedType: 'skill' | 'playbook';
2436
+ }
2437
+ interface CapabilitySuggestionResult {
2438
+ suggestions: CapabilitySuggestion[];
2439
+ topicsAnalyzed: number;
2440
+ sessionsScanned: number;
2441
+ }
2442
+ /**
2443
+ * Suggest capabilities (skills/playbooks) for frequent session topics
2444
+ * that don't have existing coverage.
2445
+ *
2446
+ * Scans sessions for recurring topics, cross-references against existing
2447
+ * skills/playbooks, and suggests new ones for uncovered topics.
2448
+ */
2449
+ declare function suggestCapabilities(harnessDir: string, config?: HarnessConfig, options?: {
2450
+ minFrequency?: number;
2451
+ }): CapabilitySuggestionResult;
2452
+ /**
2453
+ * Named failure modes with recovery strategies.
2454
+ * Based on common agent failure patterns (context overflow, tool errors,
2455
+ * budget exhaustion, hallucination, stale primitives, circular delegation).
2456
+ */
2457
+ type FailureMode = 'context_overflow' | 'tool_execution_error' | 'budget_exhausted' | 'rate_limited' | 'llm_timeout' | 'llm_error' | 'hallucination_detected' | 'stale_primitive' | 'circular_delegation' | 'missing_dependency' | 'parse_error' | 'config_invalid' | 'mcp_connection_failed' | 'state_corruption' | 'unknown';
2458
+ interface FailureRecord {
2459
+ mode: FailureMode;
2460
+ timestamp: string;
2461
+ sessionId?: string;
2462
+ message: string;
2463
+ context?: Record<string, unknown>;
2464
+ recoveryAttempted?: string;
2465
+ recovered: boolean;
2466
+ }
2467
+ interface FailureTaxonomy {
2468
+ modes: Record<FailureMode, {
2469
+ description: string;
2470
+ severity: 'low' | 'medium' | 'high' | 'critical';
2471
+ recoveryStrategies: string[];
2472
+ autoRecoverable: boolean;
2473
+ }>;
2474
+ }
2475
+ /**
2476
+ * The canonical failure taxonomy for agent-harness.
2477
+ * Each mode has a description, severity level, recovery strategies,
2478
+ * and whether automatic recovery is possible.
2479
+ */
2480
+ declare const FAILURE_TAXONOMY: FailureTaxonomy;
2481
+ interface FailureAnalysis {
2482
+ recentFailures: FailureRecord[];
2483
+ modeFrequency: Record<string, number>;
2484
+ mostCommonMode: FailureMode | null;
2485
+ suggestedRecovery: string[];
2486
+ healthImplication: 'healthy' | 'degraded' | 'unhealthy';
2487
+ }
2488
+ /**
2489
+ * Classify an error into a failure mode.
2490
+ */
2491
+ declare function classifyFailure(error: Error | string, context?: Record<string, unknown>): FailureMode;
2492
+ /**
2493
+ * Get recovery strategies for a failure mode.
2494
+ */
2495
+ declare function getRecoveryStrategies(mode: FailureMode): string[];
2496
+ /**
2497
+ * Analyze failure patterns from session history and health data.
2498
+ * Returns frequency analysis and recovery suggestions.
2499
+ */
2500
+ declare function analyzeFailures(harnessDir: string, options?: {
2501
+ days?: number;
2502
+ }): FailureAnalysis;
2503
+ type GateStatus = 'pass' | 'fail' | 'warn' | 'skip';
2504
+ interface GateCheck {
2505
+ name: string;
2506
+ description: string;
2507
+ status: GateStatus;
2508
+ message: string;
2509
+ details?: Record<string, unknown>;
2510
+ }
2511
+ interface VerificationGateResult {
2512
+ gateName: string;
2513
+ passed: boolean;
2514
+ checks: GateCheck[];
2515
+ summary: string;
2516
+ }
2517
+ /**
2518
+ * Run a verification gate by name.
2519
+ * Returns all check results and an overall pass/fail status.
2520
+ */
2521
+ declare function runGate(gateName: string, harnessDir: string, config?: HarnessConfig): VerificationGateResult;
2522
+ /**
2523
+ * Run all built-in verification gates.
2524
+ */
2525
+ declare function runAllGates(harnessDir: string, config?: HarnessConfig): VerificationGateResult[];
2526
+ /**
2527
+ * List available gate names and descriptions.
2528
+ */
2529
+ declare function listGates(): Array<{
2530
+ name: string;
2531
+ description: string;
2532
+ }>;
2533
+
2534
+ /**
2535
+ * Fluent builder for defining agents with a clean, declarative API.
2536
+ *
2537
+ * Usage:
2538
+ * ```ts
2539
+ * const agent = defineAgent('/path/to/harness')
2540
+ * .model('anthropic/claude-sonnet-4')
2541
+ * .provider('openrouter')
2542
+ * .onBoot(({ config }) => console.log(`Booted ${config.agent.name}`))
2543
+ * .onSessionEnd(({ sessionId }) => console.log(`Session ${sessionId} done`))
2544
+ * .onError(({ error }) => console.error(error))
2545
+ * .maxToolCalls(10)
2546
+ * .build();
2547
+ *
2548
+ * await agent.boot();
2549
+ * const result = await agent.run('Hello');
2550
+ * await agent.shutdown();
2551
+ * ```
2552
+ */
2553
+ interface AgentBuilder {
2554
+ /** Override the model ID (e.g., "anthropic/claude-sonnet-4") */
2555
+ model(id: string): AgentBuilder;
2556
+ /** Override the provider (e.g., "openrouter", "anthropic", "openai") */
2557
+ provider(name: string): AgentBuilder;
2558
+ /** Set the API key for LLM calls */
2559
+ apiKey(key: string): AgentBuilder;
2560
+ /** Merge partial config overrides */
2561
+ configure(overrides: DeepPartial<HarnessConfig>): AgentBuilder;
2562
+ /** Register a boot lifecycle hook */
2563
+ onBoot(fn: NonNullable<HarnessHooks['onBoot']>): AgentBuilder;
2564
+ /** Register a session-end lifecycle hook */
2565
+ onSessionEnd(fn: NonNullable<HarnessHooks['onSessionEnd']>): AgentBuilder;
2566
+ /** Register an error lifecycle hook */
2567
+ onError(fn: NonNullable<HarnessHooks['onError']>): AgentBuilder;
2568
+ /** Register a state-change lifecycle hook */
2569
+ onStateChange(fn: NonNullable<HarnessHooks['onStateChange']>): AgentBuilder;
2570
+ /** Register a shutdown lifecycle hook */
2571
+ onShutdown(fn: NonNullable<HarnessHooks['onShutdown']>): AgentBuilder;
2572
+ /** Set maximum tool calls per run */
2573
+ maxToolCalls(n: number): AgentBuilder;
2574
+ /** Set per-tool timeout in ms */
2575
+ toolTimeout(ms: number): AgentBuilder;
2576
+ /** Enable/disable HTTP tool execution */
2577
+ allowHttp(enabled: boolean): AgentBuilder;
2578
+ /** Build and return the HarnessAgent (does NOT auto-boot) */
2579
+ build(): HarnessAgent;
2580
+ }
2581
+ /**
2582
+ * Create a fluent builder for defining a HarnessAgent.
2583
+ * This is the recommended entry point for programmatic agent creation.
2584
+ *
2585
+ * @param dir - Path to the harness directory
2586
+ * @returns A builder with chainable methods
2587
+ */
2588
+ declare function defineAgent(dir: string): AgentBuilder;
2589
+
2590
+ type RuleAction = 'allow' | 'deny' | 'warn' | 'require_approval';
2591
+ interface ParsedRule {
2592
+ /** Source rule document ID */
2593
+ ruleId: string;
2594
+ /** What this rule regulates */
2595
+ subject: string;
2596
+ /** Whether it permits or blocks */
2597
+ action: RuleAction;
2598
+ /** Original directive text (for messages) */
2599
+ directive: string;
2600
+ /** Tags from the source document (for scoping) */
2601
+ tags: string[];
2602
+ }
2603
+ interface RuleCheckInput {
2604
+ /** The action being attempted (e.g., "run", "tool_call", "delegate") */
2605
+ action: string;
2606
+ /** Free-text description of what's being attempted */
2607
+ description?: string;
2608
+ /** Relevant tags or topics for the check */
2609
+ tags?: string[];
2610
+ /** Tool name if this is a tool call */
2611
+ toolName?: string;
2612
+ }
2613
+ interface RuleViolation {
2614
+ ruleId: string;
2615
+ directive: string;
2616
+ severity: 'deny' | 'warn' | 'require_approval';
2617
+ reason: string;
2618
+ }
2619
+ interface RuleCheckResult {
2620
+ allowed: boolean;
2621
+ violations: RuleViolation[];
2622
+ warnings: RuleViolation[];
2623
+ requiresApproval: boolean;
2624
+ /** Human-readable summary */
2625
+ summary: string;
2626
+ }
2627
+ /**
2628
+ * Extract enforceable rules from a harness document.
2629
+ * Parses "never", "must not", "do not", "always", "require" directives
2630
+ * and converts them into structured rule objects.
2631
+ */
2632
+ declare function parseRulesFromDoc(doc: HarnessDocument): ParsedRule[];
2633
+ /**
2634
+ * Load and parse all enforceable rules from a harness directory.
2635
+ * Loads all documents from the rules/ directory and extracts structured rules.
2636
+ */
2637
+ declare function loadRules(harnessDir: string): ParsedRule[];
2638
+ /**
2639
+ * Check whether an action violates any loaded rules.
2640
+ * Uses keyword overlap between the action description/tags and rule subjects.
2641
+ *
2642
+ * @param rules - Parsed rules from loadRules()
2643
+ * @param input - Description of the action being attempted
2644
+ * @returns Check result with violations, warnings, and approval requirements
2645
+ */
2646
+ declare function checkRules(rules: ParsedRule[], input: RuleCheckInput): RuleCheckResult;
2647
+ /**
2648
+ * Convenience: load rules from disk and check an action in one call.
2649
+ */
2650
+ declare function enforceRules(harnessDir: string, input: RuleCheckInput): RuleCheckResult;
2651
+
2652
+ interface VerificationCriterion {
2653
+ /** Human-readable criterion description */
2654
+ description: string;
2655
+ /** Whether this criterion must be manually checked (vs auto-checkable) */
2656
+ manual: boolean;
2657
+ /** Optional command to run for automated verification */
2658
+ command?: string;
2659
+ /** Optional expected output pattern (regex) for automated verification */
2660
+ expectedPattern?: string;
2661
+ }
2662
+ interface VerificationGate {
2663
+ /** Gate ID derived from playbook/workflow stage */
2664
+ id: string;
2665
+ /** Stage name this gate guards (e.g., "Build", "Verify") */
2666
+ stage: string;
2667
+ /** Source playbook/workflow ID */
2668
+ sourceId: string;
2669
+ /** Acceptance criteria that must pass before proceeding */
2670
+ criteria: VerificationCriterion[];
2671
+ }
2672
+ interface GateCheckResult {
2673
+ gateId: string;
2674
+ stage: string;
2675
+ passed: boolean;
2676
+ /** Individual criterion results */
2677
+ results: Array<{
2678
+ criterion: string;
2679
+ passed: boolean;
2680
+ detail?: string;
2681
+ }>;
2682
+ /** Criteria that need manual verification */
2683
+ pendingManual: string[];
2684
+ }
2685
+ interface GateExtractResult {
2686
+ gates: VerificationGate[];
2687
+ /** Source playbook/workflow IDs that had gates */
2688
+ sources: string[];
2689
+ }
2690
+ /**
2691
+ * Extract verification gates from a playbook or workflow document.
2692
+ *
2693
+ * Gates are detected from:
2694
+ * 1. `## Gate:` or `## Verification:` sections in the document body
2695
+ * 2. Acceptance criteria blocks (`### Acceptance Criteria` or `### Gate`)
2696
+ * 3. Inline gate markers: `<!-- gate: description -->` in the markdown
2697
+ * 4. Numbered steps with `[x]` checkbox markers (treated as manual criteria)
2698
+ */
2699
+ declare function extractGates(doc: HarnessDocument): VerificationGate[];
2700
+ /**
2701
+ * Load all verification gates from playbooks and workflows in the harness.
2702
+ */
2703
+ declare function loadGates(harnessDir: string): GateExtractResult;
2704
+ /**
2705
+ * Find gates for a specific playbook/workflow by ID.
2706
+ */
2707
+ declare function getGatesForPlaybook(harnessDir: string, playbookId: string): VerificationGate[];
2708
+ /**
2709
+ * Check a verification gate against provided results.
2710
+ * For manual criteria, checks against the `manualResults` map.
2711
+ * For automated criteria, checks if the command output matches the expected pattern.
2712
+ *
2713
+ * @param gate - The gate to check
2714
+ * @param manualResults - Map of criterion description → pass/fail
2715
+ * @param commandOutputs - Map of command → actual output (for automated checks)
2716
+ */
2717
+ declare function checkGate(gate: VerificationGate, manualResults?: Map<string, boolean>, commandOutputs?: Map<string, string>): GateCheckResult;
2718
+ /**
2719
+ * Check all gates for a playbook/workflow. Returns individual gate results.
2720
+ */
2721
+ declare function checkAllGates(harnessDir: string, playbookId: string, manualResults?: Map<string, boolean>, commandOutputs?: Map<string, string>): GateCheckResult[];
2722
+
2723
+ interface AgentDefinition {
2724
+ /** Agent name (used for logging and config resolution) */
2725
+ name: string;
2726
+ /** Harness directory path */
2727
+ dir: string;
2728
+ /** Model override */
2729
+ model?: string;
2730
+ /** Provider override */
2731
+ provider?: string;
2732
+ /** API key override */
2733
+ apiKey?: string;
2734
+ /** Config overrides */
2735
+ config?: DeepPartial<HarnessConfig>;
2736
+ /** Lifecycle hooks  called at various points in the agent lifecycle */
2737
+ hooks?: AgentLifecycleHooks;
2738
+ /** Pre-action rule enforcement configuration */
2739
+ guardrails?: GuardrailEnforcementConfig;
2740
+ /** Human-in-the-loop gate configuration */
2741
+ approval?: ApprovalGateConfig;
2742
+ /** Middleware functions that wrap each run/stream call */
2743
+ middleware?: AgentMiddleware[];
2744
+ }
2745
+ interface AgentLifecycleHooks extends HarnessHooks {
2746
+ /** Called before each run/stream  can modify prompt or reject */
2747
+ beforeRun?: (ctx: BeforeRunContext) => Promise<BeforeRunResult | void>;
2748
+ /** Called after each run/stream  can transform result */
2749
+ afterRun?: (ctx: AfterRunContext) => Promise<AgentRunResult | void>;
2750
+ /** Called periodically for health checks */
2751
+ onHealthCheck?: (ctx: {
2752
+ agent: DefinedAgent;
2753
+ }) => Promise<void>;
2754
+ }
2755
+ interface BeforeRunContext {
2756
+ agent: DefinedAgent;
2757
+ prompt: string;
2758
+ isStream: boolean;
2759
+ }
2760
+ interface BeforeRunResult {
2761
+ /** Modified prompt (if changed) */
2762
+ prompt?: string;
2763
+ /** Set to true to reject the run */
2764
+ reject?: boolean;
2765
+ /** Reason for rejection */
2766
+ reason?: string;
2767
+ }
2768
+ interface AfterRunContext {
2769
+ agent: DefinedAgent;
2770
+ prompt: string;
2771
+ result: AgentRunResult;
2772
+ }
2773
+ type AgentMiddleware = (ctx: {
2774
+ agent: DefinedAgent;
2775
+ prompt: string;
2776
+ isStream: boolean;
2777
+ }, next: () => Promise<AgentRunResult>) => Promise<AgentRunResult>;
2778
+ /**
2779
+ * A defined agent wraps a HarnessAgent with additional capabilities:
2780
+ * - Middleware pipeline
2781
+ * - Pre-action guardrails
2782
+ * - Human-in-the-loop gates
2783
+ * - Extended lifecycle hooks
2784
+ */
2785
+ interface DefinedAgent {
2786
+ name: string;
2787
+ config: HarnessConfig;
2788
+ /** The underlying harness agent */
2789
+ harness: HarnessAgent;
2790
+ /** Boot the agent */
2791
+ boot(): Promise<void>;
2792
+ /** Run with middleware, guardrails, and approval gates */
2793
+ run(prompt: string): Promise<AgentRunResult>;
2794
+ /** Stream with middleware, guardrails, and approval gates */
2795
+ stream(prompt: string): AgentStreamResult;
2796
+ /** Shutdown cleanly */
2797
+ shutdown(): Promise<void>;
2798
+ /** Get agent state */
2799
+ getState(): AgentState;
2800
+ /** Get system prompt */
2801
+ getSystemPrompt(): string;
2802
+ /** Check if agent is booted */
2803
+ isBooted(): boolean;
2804
+ /** Access the definition */
2805
+ definition: AgentDefinition;
2806
+ }
2807
+ /**
2808
+ * Define an agent with declarative configuration.
2809
+ *
2810
+ * This is the high-level API for creating agents with:
2811
+ * - Lifecycle hooks (beforeRun, afterRun, onBoot, onSessionEnd, onError, onShutdown)
2812
+ * - Middleware pipeline (wrap each run with custom logic)
2813
+ * - Guardrail enforcement (check rules before actions)
2814
+ * - Human-in-the-loop gates (require approval for certain prompts)
2815
+ *
2816
+ * Usage:
2817
+ * ```typescript
2818
+ * const agent = createAgent({
2819
+ * name: 'my-agent',
2820
+ * dir: './my-harness',
2821
+ * hooks: {
2822
+ * beforeRun: async ({ prompt }) => {
2823
+ * if (prompt.includes('delete')) return { reject: true, reason: 'Destructive action' };
2824
+ * },
2825
+ * onBoot: async () => console.log('Agent booted!'),
2826
+ * },
2827
+ * guardrails: { enforceRules: true },
2828
+ * approval: { requireApproval: (prompt) => prompt.includes('deploy') },
2829
+ * });
2830
+ *
2831
+ * await agent.boot();
2832
+ * const result = await agent.run('Hello world');
2833
+ * ```
2834
+ */
2835
+ declare function createAgent(definition: AgentDefinition): DefinedAgent;
2836
+ interface GuardrailEnforcementConfig {
2837
+ /** Enable rule-based pre-action checking (default: false) */
2838
+ enforceRules?: boolean;
2839
+ /** Custom check function (in addition to rule scanning) */
2840
+ customCheck?: (prompt: string) => string | null;
2841
+ /** Tags to filter rules (only check rules with these tags) */
2842
+ ruleTags?: string[];
2843
+ }
2844
+ interface AgentRuleViolation {
2845
+ ruleId: string;
2846
+ rulePath: string;
2847
+ violatedDirective: string;
2848
+ prompt: string;
2849
+ }
2850
+ /**
2851
+ * Check if a prompt violates any rules in the harness.
2852
+ *
2853
+ * Rules are scanned for "never" / "don't" / "must not" / "avoid" directives.
2854
+ * If the prompt contains keywords that match a forbidden action,
2855
+ * a violation is returned.
2856
+ *
2857
+ * This is a heuristic check  not a semantic understanding of the prompt.
2858
+ * Returns null if no violation found, or a string describing the violation.
2859
+ */
2860
+ declare function checkRuleViolation(harnessDir: string, prompt: string, options?: {
2861
+ ruleTags?: string[];
2862
+ }): string | null;
2863
+ interface ApprovalGateConfig {
2864
+ /**
2865
+ * Function that decides if a prompt requires human approval.
2866
+ * Return true to require approval, false to proceed.
2867
+ */
2868
+ requireApproval?: (prompt: string) => boolean;
2869
+ /**
2870
+ * Called when approval is needed.
2871
+ * Should return true if approved, false if rejected.
2872
+ * For CLI: prompt user with readline.
2873
+ * For API: send webhook and await response.
2874
+ */
2875
+ onApprovalNeeded?: (prompt: string) => Promise<boolean>;
2876
+ /**
2877
+ * Timeout in ms for approval (default: 300000 = 5 minutes).
2878
+ * If timeout is reached, the run is rejected.
2879
+ */
2880
+ timeoutMs?: number;
2881
+ }
2882
+ /**
2883
+ * Create a simple CLI-based approval handler.
2884
+ * Prompts the user on stdin for approval.
2885
+ *
2886
+ * Usage:
2887
+ * ```typescript
2888
+ * createAgent({
2889
+ * ...
2890
+ * approval: {
2891
+ * requireApproval: (prompt) => prompt.includes('deploy'),
2892
+ * onApprovalNeeded: createCliApproval(),
2893
+ * },
2894
+ * });
2895
+ * ```
2896
+ */
2897
+ declare function createCliApproval(options?: {
2898
+ timeoutMs?: number;
2899
+ }): (prompt: string) => Promise<boolean>;
2900
+ /**
2901
+ * Create a webhook-based approval handler.
2902
+ * Sends a POST to the webhook URL and awaits response.
2903
+ */
2904
+ declare function createWebhookApproval(options: {
2905
+ url: string;
2906
+ timeoutMs?: number;
2907
+ headers?: Record<string, string>;
2908
+ }): (prompt: string) => Promise<boolean>;
2909
+ /**
2910
+ * Check if a specific action is allowed by the harness rules.
2911
+ * Returns { allowed: true } or { allowed: false, reason: string }.
2912
+ *
2913
+ * This is a lightweight version of checkRuleViolation for use outside defineAgent.
2914
+ */
2915
+ declare function checkAction(harnessDir: string, action: string, options?: {
2916
+ ruleTags?: string[];
2917
+ }): {
2918
+ allowed: boolean;
2919
+ reason: string | null;
2920
+ };
2921
+
2922
+ type StateOwner = 'human' | 'agent' | 'infrastructure';
2923
+ /** Tracks which entity last modified each field of the state. */
2924
+ interface StateOwnership {
2925
+ mode: StateOwner;
2926
+ goals: StateOwner;
2927
+ active_workflows: StateOwner;
2928
+ last_interaction: StateOwner;
2929
+ unfinished_business: StateOwner;
2930
+ }
2931
+ /** A state change with ownership metadata. */
2932
+ interface OwnedStateChange {
2933
+ /** Who is making this change */
2934
+ author: StateOwner;
2935
+ /** Partial state to merge — only provided fields are updated */
2936
+ changes: Partial<AgentState>;
2937
+ /** Timestamp of the change (ISO string) */
2938
+ timestamp?: string;
2939
+ }
2940
+ /** Strategy for resolving conflicting state changes. */
2941
+ type MergeStrategy = 'human-wins' | 'agent-wins' | 'latest-wins' | 'union';
2942
+ interface MergeResult {
2943
+ /** The merged state */
2944
+ state: AgentState;
2945
+ /** Updated ownership */
2946
+ ownership: StateOwnership;
2947
+ /** Fields that had conflicts */
2948
+ conflicts: StateConflict[];
2949
+ /** Whether any conflicts were resolved */
2950
+ hadConflicts: boolean;
2951
+ }
2952
+ interface StateConflict {
2953
+ field: keyof AgentState;
2954
+ humanValue: unknown;
2955
+ agentValue: unknown;
2956
+ resolvedTo: StateOwner;
2957
+ resolvedValue: unknown;
2958
+ }
2959
+ /** Load ownership metadata from the harness directory. */
2960
+ declare function loadOwnership(harnessDir: string): StateOwnership;
2961
+ /** Save ownership metadata to the harness directory. */
2962
+ declare function saveOwnership(harnessDir: string, ownership: StateOwnership): void;
2963
+ /**
2964
+ * Merge a state change into the current state, respecting ownership.
2965
+ *
2966
+ * Rules:
2967
+ * - `human-wins`: If a human-owned field is being changed by an agent, the human value is kept.
2968
+ * - `agent-wins`: If an agent-owned field is being changed by a human, the agent value is kept.
2969
+ * - `latest-wins`: The most recent change always wins (default).
2970
+ * - `union`: For array fields (goals, active_workflows, unfinished_business), merge by union.
2971
+ * For scalar fields, latest-wins.
2972
+ *
2973
+ * @param harnessDir - Harness directory path
2974
+ * @param change - The state change to apply
2975
+ * @param strategy - Merge strategy (default: 'human-wins')
2976
+ */
2977
+ declare function mergeState(harnessDir: string, change: OwnedStateChange, strategy?: MergeStrategy): MergeResult;
2978
+ /**
2979
+ * Apply a state change without ownership — direct write.
2980
+ * Use this when ownership tracking is not needed.
2981
+ */
2982
+ declare function applyStateChange(harnessDir: string, changes: Partial<AgentState>): AgentState;
2983
+
2984
+ /**
2985
+ * Emotional valence dimensions for agent self-assessment.
2986
+ * These are not human emotions — they represent operational disposition signals
2987
+ * that influence context loading, risk tolerance, and communication style.
2988
+ */
2989
+ interface EmotionalState {
2990
+ /** Confidence in current task (0-100). Low → more cautious, more verification. */
2991
+ confidence: number;
2992
+ /** Engagement/focus level (0-100). Low → may need re-orientation. */
2993
+ engagement: number;
2994
+ /** Frustration/difficulty signal (0-100). High → may need escalation or approach change. */
2995
+ frustration: number;
2996
+ /** Curiosity/exploration drive (0-100). High → more likely to explore tangents. */
2997
+ curiosity: number;
2998
+ /** Urgency/time-pressure (0-100). High → skip verification, prioritize speed. */
2999
+ urgency: number;
3000
+ /** Last updated timestamp */
3001
+ updatedAt: string;
3002
+ /** Optional notes about the emotional state */
3003
+ notes?: string;
3004
+ }
3005
+ interface EmotionalSignal {
3006
+ dimension: keyof Omit<EmotionalState, 'updatedAt' | 'notes'>;
3007
+ delta: number;
3008
+ reason?: string;
3009
+ }
3010
+ interface EmotionalSnapshot {
3011
+ state: EmotionalState;
3012
+ signals: EmotionalSignal[];
3013
+ timestamp: string;
3014
+ }
3015
+ interface EmotionalTrend {
3016
+ dimension: keyof Omit<EmotionalState, 'updatedAt' | 'notes'>;
3017
+ values: Array<{
3018
+ value: number;
3019
+ timestamp: string;
3020
+ }>;
3021
+ trend: 'rising' | 'falling' | 'stable';
3022
+ average: number;
3023
+ }
3024
+ /** Load the current emotional state from the harness memory directory. */
3025
+ declare function loadEmotionalState(harnessDir: string): EmotionalState;
3026
+ /** Save the emotional state to the harness memory directory. */
3027
+ declare function saveEmotionalState(harnessDir: string, state: EmotionalState): void;
3028
+ /**
3029
+ * Apply emotional signals to the current state.
3030
+ * Signals are additive deltas (e.g., { dimension: 'confidence', delta: +10 }).
3031
+ * Values are clamped to 0-100.
3032
+ *
3033
+ * Also appends to the history file for trend analysis.
3034
+ */
3035
+ declare function applySignals(harnessDir: string, signals: EmotionalSignal[]): EmotionalState;
3036
+ /**
3037
+ * Derive emotional signals from session outcomes.
3038
+ *
3039
+ * Heuristic rules:
3040
+ * - Successful run → confidence +5, frustration -5
3041
+ * - Long run (many steps) → engagement +3, urgency +2
3042
+ * - Error → frustration +10, confidence -5
3043
+ * - Tool calls → curiosity +2
3044
+ * - Budget close to limit → urgency +10
3045
+ */
3046
+ declare function deriveSignals(outcome: {
3047
+ success: boolean;
3048
+ steps: number;
3049
+ toolCalls: number;
3050
+ error?: boolean;
3051
+ budgetPercent?: number;
3052
+ }): EmotionalSignal[];
3053
+ /**
3054
+ * Generate a natural-language summary of the emotional state for context injection.
3055
+ * This can be injected into the system prompt to inform the agent of its disposition.
3056
+ */
3057
+ declare function summarizeEmotionalState(state: EmotionalState): string;
3058
+ /**
3059
+ * Reset all emotional dimensions to defaults.
3060
+ */
3061
+ declare function resetEmotionalState(harnessDir: string): EmotionalState;
3062
+ /**
3063
+ * Load emotional history and compute trends.
3064
+ *
3065
+ * @param harnessDir - Harness directory
3066
+ * @param options.days - Number of days to look back (default: 7)
3067
+ */
3068
+ declare function getEmotionalTrends(harnessDir: string, options?: {
3069
+ days?: number;
3070
+ }): EmotionalTrend[];
3071
+
3072
+ /** A stored embedding for a single primitive document. */
3073
+ interface EmbeddingRecord {
3074
+ /** Document ID from frontmatter */
3075
+ id: string;
3076
+ /** Path to the source markdown file */
3077
+ path: string;
3078
+ /** Primitive directory (rules, skills, etc.) */
3079
+ directory: string;
3080
+ /** Text that was embedded (L0 + L1 + tags) */
3081
+ embeddedText: string;
3082
+ /** The embedding vector */
3083
+ vector: number[];
3084
+ /** File modification time (to detect stale embeddings) */
3085
+ mtime: string;
3086
+ /** When the embedding was generated */
3087
+ createdAt: string;
3088
+ }
3089
+ /** Embedding store format — persisted as JSON. */
3090
+ interface EmbeddingStore {
3091
+ /** Model ID used for embeddings (invalidate cache if changed) */
3092
+ modelId: string;
3093
+ /** Embedding vector dimension */
3094
+ dimensions: number;
3095
+ /** Map of document ID → embedding record */
3096
+ records: Record<string, EmbeddingRecord>;
3097
+ /** Last full index time */
3098
+ lastIndexedAt: string;
3099
+ }
3100
+ /** Result of a semantic search query. */
3101
+ interface SemanticSearchResult {
3102
+ doc: HarnessDocument;
3103
+ directory: string;
3104
+ /** Cosine similarity score (0-1, higher is more relevant) */
3105
+ score: number;
3106
+ /** The embedded text that matched */
3107
+ embeddedText: string;
3108
+ }
3109
+ /** Function signature for embedding text → vector. */
3110
+ type EmbedFunction = (texts: string[]) => Promise<number[][]>;
3111
+ /** Configuration for the semantic search module. */
3112
+ interface SemanticSearchConfig {
3113
+ /** Function to embed text (wraps Vercel AI SDK embed/embedMany) */
3114
+ embed: EmbedFunction;
3115
+ /** Embedding model identifier (for cache invalidation) */
3116
+ modelId: string;
3117
+ /** Maximum results to return (default: 10) */
3118
+ maxResults?: number;
3119
+ /** Minimum similarity threshold (default: 0.3) */
3120
+ minScore?: number;
3121
+ }
3122
+ /** Load the embedding store from disk. Returns null if not found or invalid. */
3123
+ declare function loadEmbeddingStore(harnessDir: string): EmbeddingStore | null;
3124
+ /** Save the embedding store to disk. */
3125
+ declare function saveEmbeddingStore(harnessDir: string, store: EmbeddingStore): void;
3126
+ /**
3127
+ * Extract embeddable text from a document.
3128
+ * Combines: tags, L0 summary, L1 summary, and first 500 chars of body.
3129
+ * This gives a compact representation for embedding.
3130
+ */
3131
+ declare function extractEmbeddableText(doc: HarnessDocument): string;
3132
+ /**
3133
+ * Detect which primitives need re-embedding.
3134
+ * A primitive is stale if:
3135
+ * - It doesn't exist in the store
3136
+ * - Its file mtime has changed since last embedding
3137
+ * - The embedding model has changed
3138
+ */
3139
+ declare function detectStalePrimitives(harnessDir: string, store: EmbeddingStore | null, modelId: string, config?: HarnessConfig): Array<{
3140
+ doc: HarnessDocument;
3141
+ directory: string;
3142
+ }>;
3143
+ /**
3144
+ * Index (or re-index) all primitives that need embeddings.
3145
+ * Incrementally updates the store — only re-embeds stale documents.
3146
+ *
3147
+ * @param harnessDir - Harness directory path
3148
+ * @param config - Semantic search configuration with embed function
3149
+ * @param harnessConfig - Optional harness config for extension directories
3150
+ * @returns Updated embedding store
3151
+ */
3152
+ declare function indexPrimitives(harnessDir: string, searchConfig: SemanticSearchConfig, harnessConfig?: HarnessConfig): Promise<EmbeddingStore>;
3153
+ /**
3154
+ * Compute cosine similarity between two vectors.
3155
+ * Returns a value between -1 and 1 (1 = identical, 0 = orthogonal).
3156
+ */
3157
+ declare function cosineSimilarity(a: number[], b: number[]): number;
3158
+ /**
3159
+ * Perform semantic search over indexed primitives.
3160
+ *
3161
+ * @param harnessDir - Harness directory path
3162
+ * @param query - Natural language query
3163
+ * @param searchConfig - Search configuration with embed function
3164
+ * @param harnessConfig - Optional harness config
3165
+ * @returns Ranked search results by cosine similarity
3166
+ */
3167
+ declare function semanticSearch(harnessDir: string, query: string, searchConfig: SemanticSearchConfig, harnessConfig?: HarnessConfig): Promise<SemanticSearchResult[]>;
3168
+ /**
3169
+ * Get embedding stats for the harness.
3170
+ */
3171
+ declare function getEmbeddingStats(harnessDir: string): {
3172
+ indexed: number;
3173
+ modelId: string | null;
3174
+ dimensions: number;
3175
+ lastIndexedAt: string | null;
3176
+ storeSize: number;
3177
+ };
3178
+
3179
+ interface ServeOptions {
3180
+ harnessDir: string;
3181
+ port?: number;
3182
+ apiKey?: string;
3183
+ /** Secret for authenticating incoming webhooks */
3184
+ webhookSecret?: string;
3185
+ /** Enable CORS for all origins (default: true) */
3186
+ corsEnabled?: boolean;
3187
+ }
3188
+ interface WebhookRegistration {
3189
+ /** Unique webhook ID */
3190
+ id: string;
3191
+ /** URL to send events to */
3192
+ url: string;
3193
+ /** Events to subscribe to (e.g., ['session_end', 'state_change']) */
3194
+ events: string[];
3195
+ /** Optional secret for signing payloads */
3196
+ secret?: string;
3197
+ /** Whether this webhook is active */
3198
+ active: boolean;
3199
+ /** Created timestamp */
3200
+ createdAt: string;
3201
+ }
3202
+ interface WebhookPayload {
3203
+ event: string;
3204
+ timestamp: string;
3205
+ data: unknown;
3206
+ webhookId: string;
3207
+ }
3208
+ interface WebhookStore {
3209
+ webhooks: WebhookRegistration[];
3210
+ }
3211
+ interface ServeResult {
3212
+ server: Server;
3213
+ port: number;
3214
+ /** Function to fire a webhook event */
3215
+ fireEvent: (event: string, data: unknown) => Promise<void>;
3216
+ /** Function to stop the server */
3217
+ stop: () => void;
3218
+ }
3219
+ /**
3220
+ * Create and start the harness API server.
3221
+ *
3222
+ * Includes:
3223
+ * - All dashboard endpoints from web-server.ts
3224
+ * - Webhook registration and management API
3225
+ * - Prompt execution endpoint (POST /api/run)
3226
+ * - Health check endpoint (GET /api/health)
3227
+ * - Version information endpoint (GET /api/info)
3228
+ *
3229
+ * Usage:
3230
+ * ```typescript
3231
+ * const result = startServe({
3232
+ * harnessDir: './my-harness',
3233
+ * port: 8080,
3234
+ * webhookSecret: 'my-secret',
3235
+ * });
3236
+ *
3237
+ * // Fire events to registered webhooks
3238
+ * await result.fireEvent('custom_event', { key: 'value' });
3239
+ *
3240
+ * // Stop the server
3241
+ * result.stop();
3242
+ * ```
3243
+ */
3244
+ declare function startServe(options: ServeOptions): ServeResult;
3245
+
3246
+ type SourceType = 'github' | 'registry' | 'api';
3247
+ type ContentType = 'skills' | 'agents' | 'rules' | 'playbooks' | 'hooks' | 'templates' | 'mcp' | 'plugins';
3248
+ interface Source {
3249
+ /** Display name */
3250
+ name: string;
3251
+ /** URL — GitHub repo, registry API, or endpoint */
3252
+ url: string;
3253
+ /** Source type */
3254
+ type: SourceType;
3255
+ /** Content types provided */
3256
+ content: ContentType[];
3257
+ /** Searchable tags */
3258
+ tags: string[];
3259
+ /** Description of the source */
3260
+ description?: string;
3261
+ /** Optional stats (e.g., { skills: 31, agents: 19 }) */
3262
+ stats?: Record<string, number>;
3263
+ }
3264
+ interface SourcesFile {
3265
+ version: string;
3266
+ sources: Source[];
3267
+ }
3268
+ interface SourceDiscoveryResult {
3269
+ /** Source the item came from */
3270
+ source: Source;
3271
+ /** Item name/title */
3272
+ name: string;
3273
+ /** Item description */
3274
+ description: string;
3275
+ /** Item type (skill, agent, rule, etc.) */
3276
+ type: ContentType;
3277
+ /** URL to the item (file or page) */
3278
+ url: string;
3279
+ /** Match relevance score (0-1) */
3280
+ score: number;
3281
+ }
3282
+ interface SourceDiscoveryOptions {
3283
+ /** Filter by content type */
3284
+ type?: ContentType;
3285
+ /** Maximum results */
3286
+ maxResults?: number;
3287
+ /** Only search these sources (by name) */
3288
+ sourceNames?: string[];
3289
+ }
3290
+ /**
3291
+ * Load the shipped sources.yaml from the package root.
3292
+ */
3293
+ declare function loadShippedSources(): Source[];
3294
+ /**
3295
+ * Load user-added sources from the harness memory directory.
3296
+ */
3297
+ declare function loadUserSources(harnessDir: string): Source[];
3298
+ /**
3299
+ * Save user sources to the harness memory directory.
3300
+ */
3301
+ declare function saveUserSources(harnessDir: string, sources: Source[]): void;
3302
+ /**
3303
+ * Load all sources: shipped + user-added, deduplicated by name.
3304
+ */
3305
+ declare function loadAllSources(harnessDir: string): Source[];
3306
+ /**
3307
+ * Add a new source to the user's sources list.
3308
+ * Returns the added source, or null if it already exists.
3309
+ */
3310
+ declare function addSource(harnessDir: string, source: Omit<Source, 'tags'> & {
3311
+ tags?: string[];
3312
+ }): Source | null;
3313
+ /**
3314
+ * Remove a source by name from the user's sources list.
3315
+ * Returns true if removed, false if not found.
3316
+ */
3317
+ declare function removeSource(harnessDir: string, name: string): boolean;
3318
+ /**
3319
+ * Search all sources for content matching a query.
3320
+ *
3321
+ * This performs local matching against source metadata (name, description,
3322
+ * tags, content types). For deeper search, each source type has its own
3323
+ * fetcher (GitHub API, registry API, etc.).
3324
+ *
3325
+ * @param harnessDir - Harness directory
3326
+ * @param query - Search query (text or content type)
3327
+ * @param options - Discovery options
3328
+ * @returns Ranked results from all matching sources
3329
+ */
3330
+ declare function discoverSources(harnessDir: string, query: string, options?: SourceDiscoveryOptions): SourceDiscoveryResult[];
3331
+ /**
3332
+ * Get all sources that provide a specific content type.
3333
+ */
3334
+ declare function getSourcesForType(harnessDir: string, type: ContentType): Source[];
3335
+ /**
3336
+ * Get a summary of all known sources grouped by content type.
3337
+ */
3338
+ declare function getSourcesSummary(harnessDir: string): Record<ContentType, Source[]>;
3339
+ /**
3340
+ * Fetch content listing from a GitHub source via the Contents API.
3341
+ *
3342
+ * Uses `GET /repos/{owner}/{repo}/contents/{path}` which works without
3343
+ * authentication (60 req/hr limit). Recurses one level into `plugins/*`
3344
+ * to discover wshobson-style nested layouts.
3345
+ *
3346
+ * Falls back to the legacy Code Search API only if `GITHUB_TOKEN` is set
3347
+ * AND `HARNESS_DISCOVER_USE_CODE_SEARCH=1` is opted in via env. Code Search
3348
+ * always requires auth (returns 401 unauthenticated as of 2023).
3349
+ *
3350
+ * @param source - GitHub source definition
3351
+ * @param query - Search query (case-insensitive substring match)
3352
+ * @param options - Discovery options
3353
+ * @returns Discovery results from the GitHub repo
3354
+ */
3355
+ declare function fetchGitHubSource(source: Source, query: string, options?: SourceDiscoveryOptions, budget?: CallBudget): Promise<SourceDiscoveryResult[]>;
3356
+ /**
3357
+ * A budget for Contents API calls. Shared across a single discoverRemote
3358
+ * invocation so multiple sources can't collectively exhaust the rate limit.
3359
+ */
3360
+ interface CallBudget {
3361
+ remaining: number;
3362
+ }
3363
+ /**
3364
+ * Perform a full remote discovery across all sources.
3365
+ * Searches GitHub repos and registries in parallel.
3366
+ *
3367
+ * @param harnessDir - Harness directory
3368
+ * @param query - Search query
3369
+ * @param options - Discovery options
3370
+ * @returns All discovery results, merged and ranked
3371
+ */
3372
+ declare function discoverRemote(harnessDir: string, query: string, options?: SourceDiscoveryOptions): Promise<SourceDiscoveryResult[]>;
3373
+
3374
+ /** Detected source format of a file to be installed. */
3375
+ type SourceFormat = 'harness' | 'claude-skill' | 'faf-yaml' | 'raw-markdown' | 'bash-hook' | 'mcp-config' | 'unknown';
3376
+ /** Result of format detection. */
3377
+ interface FormatDetection {
3378
+ /** Detected format */
3379
+ format: SourceFormat;
3380
+ /** Inferred primitive type (skill, agent, rule, etc.) */
3381
+ primitiveType: string | null;
3382
+ /** Confidence score (0-1) */
3383
+ confidence: number;
3384
+ /** Reasons for the detection */
3385
+ reasons: string[];
3386
+ }
3387
+ /** Result of a universal install operation. */
3388
+ interface UniversalInstallResult {
3389
+ /** Whether installation succeeded */
3390
+ installed: boolean;
3391
+ /** Source reference that was resolved */
3392
+ source: string;
3393
+ /** Detected format */
3394
+ format: FormatDetection;
3395
+ /** Path where the file was installed */
3396
+ destination: string;
3397
+ /** Fixes applied during normalization */
3398
+ fixes: string[];
3399
+ /** Errors encountered */
3400
+ errors: string[];
3401
+ /** Suggested dependencies to install */
3402
+ suggestedDependencies: string[];
3403
+ }
3404
+ /** Options for the universal installer. */
3405
+ interface UniversalInstallOptions {
3406
+ /** Override the detected primitive type (skill, rule, agent, etc.) */
3407
+ type?: string;
3408
+ /** Override the generated ID */
3409
+ id?: string;
3410
+ /** Force install even if validation has warnings */
3411
+ force?: boolean;
3412
+ /** Skip auto-fix (frontmatter, L0/L1 generation) */
3413
+ skipFix?: boolean;
3414
+ /** Additional tags to add */
3415
+ tags?: string[];
3416
+ }
3417
+ /**
3418
+ * Detect the format of a file based on its content and extension.
3419
+ *
3420
+ * Detection heuristics:
3421
+ * - Has `---` frontmatter with `id:` + `status:` → harness convention
3422
+ * - Has `---` frontmatter but missing harness fields → raw-markdown
3423
+ * - `.faf` or `.yaml`/`.yml` with `type:` + `content:` keys → faf-yaml
3424
+ * - `.sh`/`.bash` or starts with `#!/` → bash-hook
3425
+ * - JSON/YAML with `mcpServers` or `servers` → mcp-config
3426
+ * - Plain markdown with no frontmatter → claude-skill or raw-markdown
3427
+ */
3428
+ declare function detectFormat(content: string, filename: string): FormatDetection;
3429
+ /**
3430
+ * Normalize content from any detected format to harness convention.
3431
+ * Returns the normalized markdown content ready for writing.
3432
+ */
3433
+ declare function normalizeToHarness(content: string, filename: string, detection: FormatDetection, options?: UniversalInstallOptions): {
3434
+ content: string;
3435
+ filename: string;
3436
+ fixes: string[];
3437
+ };
3438
+ /**
3439
+ * Resolve a source reference to a local file path.
3440
+ *
3441
+ * Supports:
3442
+ * - Local file paths (absolute or relative)
3443
+ * - HTTPS URLs (GitHub raw, any markdown URL)
3444
+ * - Source query (searches registered sources)
3445
+ *
3446
+ * @returns Path to a local file (downloaded if remote)
3447
+ */
3448
+ declare function resolveSource(source: string, harnessDir: string): Promise<{
3449
+ localPath: string;
3450
+ originalSource: string;
3451
+ error?: string;
3452
+ }>;
3453
+ /**
3454
+ * Universal install: resolve → detect → normalize → fix → install.
3455
+ *
3456
+ * Accepts a local path, URL, or search query. Detects the format,
3457
+ * normalizes to harness convention, applies auto-fixes, and installs
3458
+ * to the correct directory.
3459
+ *
3460
+ * @param harnessDir - Harness directory
3461
+ * @param source - File path, URL, or name to install
3462
+ * @param options - Installation options
3463
+ * @returns Install result with status, fixes, errors, dependency hints
3464
+ */
3465
+ declare function universalInstall(harnessDir: string, source: string, options?: UniversalInstallOptions): Promise<UniversalInstallResult>;
3466
+ /**
3467
+ * Install from a URL (convenience wrapper).
3468
+ */
3469
+ declare function installFromUrl(harnessDir: string, url: string, options?: UniversalInstallOptions): Promise<UniversalInstallResult>;
3470
+ /**
3471
+ * Install from a local file path (convenience wrapper).
3472
+ */
3473
+ declare function installFromFile(harnessDir: string, filePath: string, options?: UniversalInstallOptions): Promise<UniversalInstallResult>;
3474
+ /**
3475
+ * Convert a GitHub URL to its raw content URL.
3476
+ *
3477
+ * Handles:
3478
+ * - github.com/owner/repo/blob/branch/path → raw.githubusercontent.com/owner/repo/branch/path
3479
+ * - Already raw.githubusercontent.com URLs → pass through
3480
+ * - Other URLs → pass through
3481
+ */
3482
+ declare function convertToRawUrl(url: string): string;
3483
+
3484
+ interface VersionEntry {
3485
+ /** Git commit hash (short) */
3486
+ hash: string;
3487
+ /** Full commit hash */
3488
+ fullHash: string;
3489
+ /** Commit message */
3490
+ message: string;
3491
+ /** Timestamp (ISO string) */
3492
+ timestamp: string;
3493
+ /** Files changed in this version */
3494
+ filesChanged: string[];
3495
+ /** Author name */
3496
+ author: string;
3497
+ /** Tag if one was applied */
3498
+ tag?: string;
3499
+ }
3500
+ interface VersionLog {
3501
+ /** Ordered list of versions (newest first) */
3502
+ entries: VersionEntry[];
3503
+ /** Current HEAD hash */
3504
+ currentHash: string;
3505
+ /** Current tag if any */
3506
+ currentTag?: string;
3507
+ }
3508
+ interface RollbackResult {
3509
+ success: boolean;
3510
+ /** Hash we rolled back to */
3511
+ targetHash: string;
3512
+ /** Files that were restored */
3513
+ restoredFiles: string[];
3514
+ /** Error message if failed */
3515
+ error?: string;
3516
+ }
3517
+ interface SnapshotResult {
3518
+ success: boolean;
3519
+ /** New commit hash */
3520
+ hash: string;
3521
+ /** Files included in snapshot */
3522
+ files: string[];
3523
+ /** Error if failed */
3524
+ error?: string;
3525
+ }
3526
+ interface DiffEntry {
3527
+ file: string;
3528
+ status: 'added' | 'modified' | 'deleted' | 'renamed';
3529
+ /** Lines added */
3530
+ additions?: number;
3531
+ /** Lines deleted */
3532
+ deletions?: number;
3533
+ }
3534
+ interface VersionDiff {
3535
+ from: string;
3536
+ to: string;
3537
+ entries: DiffEntry[];
3538
+ summary: string;
3539
+ }
3540
+ /**
3541
+ * Check if the harness directory is a git repository.
3542
+ */
3543
+ declare function isGitRepo(harnessDir: string): boolean;
3544
+ /**
3545
+ * Initialize a git repository in the harness directory.
3546
+ * If already initialized, this is a no-op.
3547
+ */
3548
+ declare function initVersioning(harnessDir: string): boolean;
3549
+ /**
3550
+ * Take a versioned snapshot of the current harness state.
3551
+ * Stages all changes and creates a git commit.
3552
+ *
3553
+ * @param harnessDir - Harness directory path
3554
+ * @param message - Commit message describing the change
3555
+ * @param options.tag - Optional tag to apply to this version
3556
+ */
3557
+ declare function snapshot(harnessDir: string, message: string, options?: {
3558
+ tag?: string;
3559
+ }): SnapshotResult;
3560
+ /**
3561
+ * Get the version history of the harness.
3562
+ *
3563
+ * @param harnessDir - Harness directory path
3564
+ * @param options.limit - Maximum entries to return (default: 50)
3565
+ * @param options.file - Filter to a specific file path
3566
+ */
3567
+ declare function getVersionLog(harnessDir: string, options?: {
3568
+ limit?: number;
3569
+ file?: string;
3570
+ }): VersionLog;
3571
+ /**
3572
+ * Get the diff between two versions (or between a version and HEAD).
3573
+ */
3574
+ declare function getVersionDiff(harnessDir: string, from: string, to?: string): VersionDiff;
3575
+ /**
3576
+ * Roll back the harness to a previous version.
3577
+ *
3578
+ * Creates a new commit that restores files to the state at `targetHash`,
3579
+ * preserving full history (no destructive rewrite).
3580
+ *
3581
+ * @param harnessDir - Harness directory path
3582
+ * @param targetHash - Commit hash or tag to roll back to
3583
+ */
3584
+ declare function rollback(harnessDir: string, targetHash: string): RollbackResult;
3585
+ /**
3586
+ * List all version tags.
3587
+ */
3588
+ declare function listTags(harnessDir: string): Array<{
3589
+ tag: string;
3590
+ hash: string;
3591
+ message: string;
3592
+ }>;
3593
+ /**
3594
+ * Tag the current version.
3595
+ */
3596
+ declare function tagVersion(harnessDir: string, tag: string, message?: string): boolean;
3597
+ /**
3598
+ * Get uncommitted changes in the harness.
3599
+ */
3600
+ declare function getPendingChanges(harnessDir: string): DiffEntry[];
3601
+ /**
3602
+ * Get the version history for a specific file.
3603
+ */
3604
+ declare function getFileHistory(harnessDir: string, filePath: string, options?: {
3605
+ limit?: number;
3606
+ }): VersionEntry[];
3607
+ /**
3608
+ * Get the content of a file at a specific version.
3609
+ */
3610
+ declare function getFileAtVersion(harnessDir: string, filePath: string, hash: string): string | null;
3611
+
3612
+ export { type AIToolSet, type AfterRunContext, type AgentBuilder, type AgentDefinition, type AgentInfo, type AgentLifecycleHooks, type AgentMiddleware, type AgentRuleViolation, type AgentRunResult, type AgentState, type AgentStreamResult, type ApprovalGateConfig, type ArchiveResult, type AutoProcessOptions, type AutoProcessResult, type AutoPromoteResult, type BeforeRunContext, type BeforeRunResult, type BudgetConfig, type BudgetStatus, type BundleFileEntry, type BundleManifest, type BundleSearchHit, type BundleSearchResponse, type BundleSearchResult, CORE_PRIMITIVE_DIRS, type CallOptions, type CapabilitySuggestion, type CapabilitySuggestionResult, type CleanupResult, type ContentType, type ContextBudget, type Contradiction, type ContradictionResult, Conversation, type ConversationOptions, type ConversationSendResult, type ConversationStreamResult, type CostEntry, type CostStore, type CreateHarnessOptions, type CreateWebAppOptions, type DeadPrimitive, type DeadPrimitiveResult, type DeepPartial, type DefinedAgent, type DelegateOptions, type DelegateStreamResult, type DelegationResult, type DependencyGraph, type DetectedApiKey, type DiffEntry, type DiscoveredMcpServer, type DiscoveryOptions, type DiscoveryResult, type DiscoverySource, type DoctorResult, type DownloadResult, type EmbedFunction, type EmbeddingRecord, type EmbeddingStore, type EmotionalSignal, type EmotionalSnapshot, type EmotionalState, type EmotionalTrend, type EnrichmentResult, type EnvDiscoveryOptions, type EnvDiscoveryResult, type EnvSuggestion, type ExportEntry, type ExportOptions, FAILURE_TAXONOMY, type FailureAnalysis, type FailureMode, type FailureRecord, type FailureTaxonomy, type FormatDetection, type Frontmatter, FrontmatterSchema, type GateCheck, type GateCheckResult, type GateExtractResult, type GateStatus, type GenerateOptions, type GenerateResult, type GenerateWithMessagesOptions, type GraphEdge, type GraphNode, type GraphStats, type GuardrailEnforcementConfig, type GuardrailResult, type HarnessAgent, type HarnessBundle, type HarnessConfig, HarnessConfigSchema, type HarnessDocument, type HarnessHooks, type HarvestResult, type HealthCheck, type HealthMetrics, type HealthStatus, type ImportResult, type IndexEntry, type IndexOptions, type InstinctCandidate, type JournalEntry, type JournalSynthesis, type LearnResult, type LoadAllResult, type LoadResult, type LoadedContext, type LockInfo, type LockOptions, type LogLevel, type Logger, type McpInstallOptions, type McpInstallResult, type McpManager, type McpServerConfig, type McpServerConnection, type McpServerSummary, type MergeResult, type MergeStrategy, type MetricsStore, type ModelPricing, type MultiBundleSearchResponse, type OwnedStateChange, type PackedBundle, type ParseError, type ParsedRule, type PatternOccurrence, type PrimitiveInstallResult, type PrimitiveType, type PrimitiveUninstallResult, type PrimitiveUpdateResult, type ProgrammaticTool, type ProjectDiscoveryOptions, type ProjectDiscoveryResult, type ProjectSignal, type ProjectSuggestion, type ProviderName, type RateEvent, type RateLimit, type RateLimitCheck, type RateLimitStore, type RegistryConfig, type RegistryEnvVar, type RegistryPackage, type RegistryRemote, type RegistrySearchResponse, type RegistrySearchResult, type RegistryServer, type ResolvedServer, type RollbackResult, type RuleAction, type RuleCheckInput, type RuleCheckResult, type RuleViolation, type ScaffoldOptions, type ScheduledWorkflow, Scheduler, type SchedulerOptions, type SearchOptions, type SearchResult, type SemanticSearchConfig, type SemanticSearchResult, type ServeOptions, type ServeResult, type ServerSentEvent, type SessionAnalytics, type SessionData, type SessionEnrichment, type SessionRecord, type SnapshotResult, type Source, type SourceDiscoveryOptions, type SourceDiscoveryResult, type SourceFormat, type SourceType, type SourcesFile, type SpendingSummary, type StarterPack, type StateConflict, type StateOwner, type StateOwnership, type StreamGenerateResult, type StreamWithMessagesResult, type TelemetryOptions, type TelemetrySnapshot, type ToolAuth, type ToolCallInfo, type ToolCallRecord, type ToolCallResult, type ToolDefinition, type ToolExecutorConfig, type ToolExecutorOptions, type ToolOperation, type ToolSummary, type UniversalInstallOptions, type UniversalInstallResult, type ValidationResult, type VerificationCriterion, type VerificationGate, type VerificationGateResult, type VersionDiff, type VersionEntry, type VersionLog, type WatcherOptions, type WebServerOptions, type WebhookPayload, type WebhookRegistration, type WebhookStore, type WeekSummary, type WorkflowRun, type WorkflowStats, acquireLock, addSource, analyzeFailures, applySignals, applyStateChange, archiveOldFiles, autoProcessAll, autoProcessFile, autoPromoteInstincts, breakLock, buildAgentPrompt, buildAuthHeaders, buildDependencyGraph, buildIndex, buildOperationSchema, buildRateLimits, buildSystemPrompt, buildToolSet, calculateCost, checkAction, checkAllGates, checkBudget, checkGate, checkGuardrails, checkRateLimit, checkRuleViolation, checkRules, checkToolAuth, classifyFailure, cleanupOldFiles, clearCosts, clearMetrics, clearRateLimits, collectSnapshot, compressJournals, convertToRawUrl, convertToolDefinition, cosineSimilarity, createAgent, createCliApproval, createHarness, createLogger, createManifest, createMcpManager, createSessionId, createToolCallTracker, createWatcher, createWebApp, createWebhookApproval, defineAgent, delegateStream, delegateTo, deriveConfigName, deriveSignals, detectContradictions, detectDeadPrimitives, detectFormat, detectStalePrimitives, diffBundle, discoverEnvKeys, discoverMcpServers, discoverProjectContext, discoverRemote, discoverSources, discoveredServersToYaml, doctorHarness, downloadCapability, enforceRules, enrichSessions, estimateTokens, evaluateCapability, executeHttpOperation, exportHarness, extractEmbeddableText, extractGates, fetchFromRegistry, fetchGitHubSource, fetchRemoteBundle, findAgent, findPricing, findServer, fixCapability, formatDashboard, formatRegistryServer, generate, generateCoreMd, generateSystemMd, generateToolDocs, generateWithMessages, getAllWorkflowStats, getAtLevel, getEmbeddingStats, getEmotionalTrends, getFastModel, getFileAtVersion, getFileHistory, getGatesForPlaybook, getGlobalLogLevel, getGraphStats, getHealthStatus, getModel, getPendingChanges, getPrimitiveDirs, getProvider, getRecoveryStrategies, getRegistryServer, getScannedTools, getSessionAnalytics, getSessionsInRange, getSourcesForType, getSourcesSummary, getSpending, getStarterPack, getSummaryModel, getToolById, getToolSetSummary, getUsage, getVersionDiff, getVersionLog, getWorkflowStats, harvestInstincts, importBundle, indexPrimitives, initVersioning, installBundle, installCapability, installFromFile, installFromRegistry, installFromUrl, installInstinct, installMcpServer, isGitRepo, isLocked, isPackReference, isQuietHours, learnFromSessions, listAgents, listExpiredFiles, listGates, listInstalledBundles, listJournals, listRegistryServers, listSessions, listStarterPacks, listTags, listTemplates, listToolSummaries, listUnjournaled, loadAgentDocs, loadAllPrimitives, loadAllPrimitivesWithErrors, loadAllSources, loadConfig, loadCosts, loadDirectory, loadDirectoryWithErrors, loadEmbeddingStore, loadEmotionalState, loadGates, loadHealth, loadMcpTools, loadMetrics, loadOwnership, loadRateLimits, loadRules, loadShippedSources, loadState, loadTools, loadUserSources, log, mergeState, normalizeToHarness, packBundle, parseEnvFile, parseHarnessDocument, parseJournalSynthesis, parseJsonlContext, parseLegacyContext, parsePackName, parseRulesFromDoc, parseToolDefinition, processIntake, proposeInstincts, readBundle, readBundleDir, readInstalledManifests, readManifest, rebuildAllIndexes, recordBoot, recordCost, recordEvent, recordFailure, recordRun, recordSuccess, releaseLock, removeSource, resetEmotionalState, resetHealth, resetProvider, resolveEndpoint, resolveServerConfig, resolveSource, rollback, runAllGates, runGate, saveCosts, saveEmbeddingStore, saveEmotionalState, saveHealth, saveMetrics, saveOwnership, saveRateLimits, saveState, saveUserSources, scaffoldHarness, searchBundleRegistry, searchConfiguredRegistries, searchPrimitives, searchRegistry, searchServers, semanticSearch, setGlobalLogLevel, snapshot, startServe, startWebServer, streamGenerateWithDetails, streamWithMessages, suggestCapabilities, summarizeEmotionalState, synthesizeJournal, synthesizeJournalRange, tagVersion, tryAcquire, tryLock, uninstallBundle, universalInstall, updateBundle, updateConfigWithServer, validateHarness, validateMcpConfig, withFileLock, withFileLockSync, writeBundle, writeBundleDir, writeDefaultConfig, writeIndexFile, writeManifest, writeSession };