agentix-cli 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +75 -27
  2. package/dist/agent-57MG4LBM.js +2 -0
  3. package/dist/audit-JU3HWISB.js +3 -0
  4. package/dist/audit-JU3HWISB.js.map +1 -0
  5. package/dist/{board-dashboard-CXIVJKDP.js → board-dashboard-HXDOYGIG.js} +2237 -69
  6. package/dist/board-dashboard-HXDOYGIG.js.map +1 -0
  7. package/dist/chunk-23AUU4S2.js +102 -0
  8. package/dist/chunk-23AUU4S2.js.map +1 -0
  9. package/dist/{chunk-EKTPCSN4.js → chunk-4ITQP3XL.js} +2 -2
  10. package/dist/chunk-4MREHZP5.js +111 -0
  11. package/dist/chunk-4MREHZP5.js.map +1 -0
  12. package/dist/chunk-4YCH6IZV.js +2 -0
  13. package/dist/chunk-53NRX2NA.js +2 -0
  14. package/dist/chunk-53NRX2NA.js.map +1 -0
  15. package/dist/chunk-6B74TO2J.js +743 -0
  16. package/dist/chunk-6B74TO2J.js.map +1 -0
  17. package/dist/chunk-7P5QRX5W.js +108 -0
  18. package/dist/chunk-7P5QRX5W.js.map +1 -0
  19. package/dist/chunk-A6BKSZQA.js +3 -0
  20. package/dist/chunk-A6BKSZQA.js.map +1 -0
  21. package/dist/{chunk-6PPIFDOQ.js → chunk-CNNLREHD.js} +67 -22
  22. package/dist/{chunk-6PPIFDOQ.js.map → chunk-CNNLREHD.js.map} +1 -1
  23. package/dist/chunk-DJEZ2HVU.js +5 -0
  24. package/dist/chunk-DJEZ2HVU.js.map +1 -0
  25. package/dist/chunk-DLVOHCTA.js +5 -0
  26. package/dist/{chunk-MBEQASP3.js.map → chunk-DLVOHCTA.js.map} +1 -1
  27. package/dist/chunk-E4ZZILAK.js +15 -0
  28. package/dist/chunk-E4ZZILAK.js.map +1 -0
  29. package/dist/{chunk-63UYRJIC.js → chunk-IKBHHTIT.js} +2 -2
  30. package/dist/chunk-JGXE2YNV.js +46 -0
  31. package/dist/chunk-JGXE2YNV.js.map +1 -0
  32. package/dist/chunk-JTJIPNXY.js +2 -0
  33. package/dist/chunk-JTJIPNXY.js.map +1 -0
  34. package/dist/chunk-MBOLXKA2.js +6 -0
  35. package/dist/chunk-MBOLXKA2.js.map +1 -0
  36. package/dist/{inbox-L5ZZ623Y.js → chunk-MTRWXRFF.js} +69 -4
  37. package/dist/chunk-MTRWXRFF.js.map +1 -0
  38. package/dist/{processes-XF5CV4LK.js → chunk-NOF4HSGK.js} +3 -3
  39. package/dist/{processes-XF5CV4LK.js.map → chunk-NOF4HSGK.js.map} +1 -1
  40. package/dist/chunk-QW2OYR3N.js +7 -0
  41. package/dist/chunk-QW2OYR3N.js.map +1 -0
  42. package/dist/chunk-SR3X25TN.js +3 -0
  43. package/dist/chunk-SR3X25TN.js.map +1 -0
  44. package/dist/chunk-SV3I4CI7.js +440 -0
  45. package/dist/chunk-SV3I4CI7.js.map +1 -0
  46. package/dist/{chunk-TT2Q7YMZ.js → chunk-TC3BSUP7.js} +6 -6
  47. package/dist/{chunk-TT2Q7YMZ.js.map → chunk-TC3BSUP7.js.map} +1 -1
  48. package/dist/chunk-VJUTQAPJ.js +2 -0
  49. package/dist/chunk-VJUTQAPJ.js.map +1 -0
  50. package/dist/chunk-VWTBHLMX.js +1 -0
  51. package/dist/chunk-WFHIIVLL.js +719 -0
  52. package/dist/chunk-WFHIIVLL.js.map +1 -0
  53. package/dist/chunk-WPPUOTY6.js +6 -0
  54. package/dist/chunk-WPPUOTY6.js.map +1 -0
  55. package/dist/cli.js +1 -1
  56. package/dist/cli.js.map +1 -1
  57. package/dist/{compaction-X46EQEPS.js → compaction-BTUJJ3LJ.js} +4 -4
  58. package/dist/config-QXWKEQON.js +2 -0
  59. package/dist/config-mutator-53XGR2NT.js +2 -0
  60. package/dist/conflict-detector-D7VIYPDI.js +2 -0
  61. package/dist/conflict-detector-D7VIYPDI.js.map +1 -0
  62. package/dist/{context-planner-G2J7FNNU.js → context-planner-I7ID7XF3.js} +3 -3
  63. package/dist/debug-N3B5NVJU.js +2 -0
  64. package/dist/discover-XJXQXXIO.js +4 -0
  65. package/dist/discover-XJXQXXIO.js.map +1 -0
  66. package/dist/doctor-SEOUFHSL.js +2 -0
  67. package/dist/{editor-chat-R54E65W5.js → editor-chat-RVLCKKB7.js} +2 -2
  68. package/dist/heal-YEQYWX2L.js +2 -0
  69. package/dist/inbox-BIN2S5XN.js +2 -0
  70. package/dist/index.d.ts +1292 -122
  71. package/dist/index.js +8 -8
  72. package/dist/index.js.map +1 -1
  73. package/dist/{ingest-whatsapp-NS4OWDOU.js → ingest-whatsapp-LZE62INA.js} +2 -2
  74. package/dist/loader-5CA3O5GM.js +2 -0
  75. package/dist/loader-6IHUCPVO.js +2 -0
  76. package/dist/memory-extract-KRCHD3OP.js +2 -0
  77. package/dist/migrate-v2-QO7SLKIM.js +4 -0
  78. package/dist/migrate-v2-QO7SLKIM.js.map +1 -0
  79. package/dist/processes-RJ6RDP32.js +2 -0
  80. package/dist/program-SASDC2GV.js +2 -0
  81. package/dist/providers-WVCMIW67.js +2 -0
  82. package/dist/query-HZYYRCLU.js +2 -0
  83. package/dist/recipes-EPLE2SNT.js +2 -0
  84. package/dist/registry-HM4ELSXS.js +2 -0
  85. package/dist/rotation-memo-GMTZPMNE.js +13 -0
  86. package/dist/rotation-memo-GMTZPMNE.js.map +1 -0
  87. package/dist/scheduler-XVFIK4XH.js +2 -0
  88. package/dist/{slack-PSQLVTGB.js → slack-6P7ZJ32Y.js} +2 -2
  89. package/dist/store-BAPDZHXE.js +2 -0
  90. package/dist/{subagent-2SJHSSJS.js → subagent-WV7QKQ3L.js} +2 -2
  91. package/dist/{task-store-NM7VKNLE.js → task-store-RHISEU6V.js} +2 -2
  92. package/dist/task-store-RHISEU6V.js.map +1 -0
  93. package/dist/{telegram-W4SLFMNY.js → telegram-PIYDRM46.js} +2 -2
  94. package/dist/timers-5LPZN55J.js +2 -0
  95. package/dist/timers-5LPZN55J.js.map +1 -0
  96. package/dist/types-VECTMYTO.js +2 -0
  97. package/dist/types-VECTMYTO.js.map +1 -0
  98. package/dist/types-ZRLHHCGB.js +2 -0
  99. package/dist/types-ZRLHHCGB.js.map +1 -0
  100. package/dist/web/activity-graph.global.js +654 -0
  101. package/dist/web/activity-graph.global.js.map +1 -0
  102. package/dist/web/workflow-editor.global.js +35 -12
  103. package/dist/web/workflow-editor.global.js.map +1 -1
  104. package/dist/{whatsapp-DCHRBRVV.js → whatsapp-PFRDMUMT.js} +2 -2
  105. package/dist/{whatsapp-state-6D6FHHD2.js → whatsapp-state-XMTCSRXU.js} +2 -2
  106. package/dist/wiki-53W5NLZV.js +2 -0
  107. package/dist/wiki-53W5NLZV.js.map +1 -0
  108. package/dist/workspace-setup-FPGN5VNY.js +2 -0
  109. package/dist/workspace-setup-FPGN5VNY.js.map +1 -0
  110. package/package.json +13 -2
  111. package/dist/agent-4AOMVXRJ.js +0 -2
  112. package/dist/board-dashboard-CXIVJKDP.js.map +0 -1
  113. package/dist/chunk-34NG7UDX.js +0 -11
  114. package/dist/chunk-34NG7UDX.js.map +0 -1
  115. package/dist/chunk-4HP6UC2X.js +0 -13
  116. package/dist/chunk-4HP6UC2X.js.map +0 -1
  117. package/dist/chunk-5WNGHDFC.js +0 -164
  118. package/dist/chunk-5WNGHDFC.js.map +0 -1
  119. package/dist/chunk-ABCHHNG6.js +0 -625
  120. package/dist/chunk-ABCHHNG6.js.map +0 -1
  121. package/dist/chunk-FIOB3MEX.js +0 -2
  122. package/dist/chunk-HCFSHGK4.js +0 -46
  123. package/dist/chunk-HCFSHGK4.js.map +0 -1
  124. package/dist/chunk-HHJGKD5B.js +0 -71
  125. package/dist/chunk-HHJGKD5B.js.map +0 -1
  126. package/dist/chunk-LEIYC3BF.js +0 -104
  127. package/dist/chunk-LEIYC3BF.js.map +0 -1
  128. package/dist/chunk-MBEQASP3.js +0 -5
  129. package/dist/chunk-MCJUAE6V.js +0 -6
  130. package/dist/chunk-MCJUAE6V.js.map +0 -1
  131. package/dist/chunk-SRHLXZRF.js +0 -7
  132. package/dist/chunk-SRHLXZRF.js.map +0 -1
  133. package/dist/chunk-WZEYII2S.js +0 -6
  134. package/dist/chunk-WZEYII2S.js.map +0 -1
  135. package/dist/chunk-XDJSYQST.js +0 -6
  136. package/dist/chunk-XDJSYQST.js.map +0 -1
  137. package/dist/chunk-YPOELN6Z.js +0 -798
  138. package/dist/chunk-YPOELN6Z.js.map +0 -1
  139. package/dist/config-KCYHMKCT.js +0 -2
  140. package/dist/config-mutator-QP4GLBOE.js +0 -2
  141. package/dist/debug-3MEUO2P2.js +0 -2
  142. package/dist/heal-JDXUPRET.js +0 -2
  143. package/dist/inbox-L5ZZ623Y.js.map +0 -1
  144. package/dist/loader-PTCXLJEX.js +0 -2
  145. package/dist/memory-extract-WH4FZ456.js +0 -2
  146. package/dist/program-FFWEILAS.js +0 -2
  147. package/dist/providers-AKQ4HTB4.js +0 -2
  148. package/dist/query-PKGYE5HR.js +0 -2
  149. package/dist/registry-IFMDJWQ7.js +0 -2
  150. package/dist/scheduler-63D5KFO7.js +0 -2
  151. package/dist/store-5MJOO74U.js +0 -2
  152. package/dist/timers-PCB4ZIBD.js +0 -2
  153. package/dist/types-C7IFH42Z.js +0 -2
  154. package/dist/types-OIFU3KSQ.js +0 -2
  155. package/dist/usage-dashboard-AXPXB2KP.js +0 -803
  156. package/dist/usage-dashboard-AXPXB2KP.js.map +0 -1
  157. package/dist/wiki-UDPYFJBL.js +0 -2
  158. package/dist/workspace-setup-C4VB3QZV.js +0 -2
  159. /package/dist/{agent-4AOMVXRJ.js.map → agent-57MG4LBM.js.map} +0 -0
  160. /package/dist/{chunk-EKTPCSN4.js.map → chunk-4ITQP3XL.js.map} +0 -0
  161. /package/dist/{chunk-FIOB3MEX.js.map → chunk-4YCH6IZV.js.map} +0 -0
  162. /package/dist/{chunk-63UYRJIC.js.map → chunk-IKBHHTIT.js.map} +0 -0
  163. /package/dist/{config-KCYHMKCT.js.map → chunk-VWTBHLMX.js.map} +0 -0
  164. /package/dist/{compaction-X46EQEPS.js.map → compaction-BTUJJ3LJ.js.map} +0 -0
  165. /package/dist/{config-mutator-QP4GLBOE.js.map → config-QXWKEQON.js.map} +0 -0
  166. /package/dist/{debug-3MEUO2P2.js.map → config-mutator-53XGR2NT.js.map} +0 -0
  167. /package/dist/{context-planner-G2J7FNNU.js.map → context-planner-I7ID7XF3.js.map} +0 -0
  168. /package/dist/{heal-JDXUPRET.js.map → debug-N3B5NVJU.js.map} +0 -0
  169. /package/dist/{loader-PTCXLJEX.js.map → doctor-SEOUFHSL.js.map} +0 -0
  170. /package/dist/{editor-chat-R54E65W5.js.map → editor-chat-RVLCKKB7.js.map} +0 -0
  171. /package/dist/{memory-extract-WH4FZ456.js.map → heal-YEQYWX2L.js.map} +0 -0
  172. /package/dist/{program-FFWEILAS.js.map → inbox-BIN2S5XN.js.map} +0 -0
  173. /package/dist/{ingest-whatsapp-NS4OWDOU.js.map → ingest-whatsapp-LZE62INA.js.map} +0 -0
  174. /package/dist/{providers-AKQ4HTB4.js.map → loader-5CA3O5GM.js.map} +0 -0
  175. /package/dist/{query-PKGYE5HR.js.map → loader-6IHUCPVO.js.map} +0 -0
  176. /package/dist/{registry-IFMDJWQ7.js.map → memory-extract-KRCHD3OP.js.map} +0 -0
  177. /package/dist/{scheduler-63D5KFO7.js.map → processes-RJ6RDP32.js.map} +0 -0
  178. /package/dist/{store-5MJOO74U.js.map → program-SASDC2GV.js.map} +0 -0
  179. /package/dist/{task-store-NM7VKNLE.js.map → providers-WVCMIW67.js.map} +0 -0
  180. /package/dist/{timers-PCB4ZIBD.js.map → query-HZYYRCLU.js.map} +0 -0
  181. /package/dist/{types-C7IFH42Z.js.map → recipes-EPLE2SNT.js.map} +0 -0
  182. /package/dist/{types-OIFU3KSQ.js.map → registry-HM4ELSXS.js.map} +0 -0
  183. /package/dist/{wiki-UDPYFJBL.js.map → scheduler-XVFIK4XH.js.map} +0 -0
  184. /package/dist/{slack-PSQLVTGB.js.map → slack-6P7ZJ32Y.js.map} +0 -0
  185. /package/dist/{workspace-setup-C4VB3QZV.js.map → store-BAPDZHXE.js.map} +0 -0
  186. /package/dist/{subagent-2SJHSSJS.js.map → subagent-WV7QKQ3L.js.map} +0 -0
  187. /package/dist/{telegram-W4SLFMNY.js.map → telegram-PIYDRM46.js.map} +0 -0
  188. /package/dist/{whatsapp-DCHRBRVV.js.map → whatsapp-PFRDMUMT.js.map} +0 -0
  189. /package/dist/{whatsapp-state-6D6FHHD2.js.map → whatsapp-state-XMTCSRXU.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -262,7 +262,7 @@ interface UserPreference {
262
262
  confidence: number;
263
263
  source: string;
264
264
  }
265
- interface MemoryStore {
265
+ interface MemoryStore$1 {
266
266
  version: number;
267
267
  entries: MemoryEntry[];
268
268
  patterns: LearnedPattern[];
@@ -293,7 +293,7 @@ declare class Memory {
293
293
  getSimilarTasks(task: string, limit?: number): MemoryEntry[];
294
294
  getPatterns(): LearnedPattern[];
295
295
  getPreferences(): UserPreference[];
296
- getStats(): MemoryStore["stats"];
296
+ getStats(): MemoryStore$1["stats"];
297
297
  buildMemoryContext(task: string): string;
298
298
  private extractPattern;
299
299
  private updateSuccessRate;
@@ -413,6 +413,15 @@ declare const skillFrontmatterSchema: z.ZodObject<{
413
413
  }>, "many">>;
414
414
  /** If true, skill is auto-injected into context when triggers match (per-turn) */
415
415
  autoInject: z.ZodOptional<z.ZodBoolean>;
416
+ /** Reference card ids cited by this skill (e.g. "ksi.gitlab.project.ksi-v2").
417
+ * Audit lint flags FAILING when any id does not resolve. */
418
+ references: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
419
+ /** Skills this one delegates to (e.g. ksi-cx-email → [hotmail]). Audit lint
420
+ * flags FAILING when a delegate has no SKILL.md. */
421
+ delegatesTo: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
422
+ /** Free-form category — used by recipes and audit rules. Common values:
423
+ * deploy, ssh, email, gitlab, ops, content, marketing. */
424
+ category: z.ZodOptional<z.ZodString>;
416
425
  }, "strip", z.ZodTypeAny, {
417
426
  name: string;
418
427
  description: string;
@@ -425,6 +434,9 @@ declare const skillFrontmatterSchema: z.ZodObject<{
425
434
  description?: string | undefined;
426
435
  }[] | undefined;
427
436
  autoInject?: boolean | undefined;
437
+ references?: string[] | undefined;
438
+ delegatesTo?: string[] | undefined;
439
+ category?: string | undefined;
428
440
  }, {
429
441
  name: string;
430
442
  description: string;
@@ -437,6 +449,9 @@ declare const skillFrontmatterSchema: z.ZodObject<{
437
449
  description?: string | undefined;
438
450
  }[] | undefined;
439
451
  autoInject?: boolean | undefined;
452
+ references?: string[] | undefined;
453
+ delegatesTo?: string[] | undefined;
454
+ category?: string | undefined;
440
455
  }>;
441
456
  type SkillFrontmatter = z.infer<typeof skillFrontmatterSchema>;
442
457
  interface Skill {
@@ -758,8 +773,8 @@ declare class MemoryHierarchy {
758
773
  * Get stats from both levels.
759
774
  */
760
775
  getStats(): {
761
- user: MemoryStore["stats"];
762
- project: MemoryStore["stats"];
776
+ user: MemoryStore$1["stats"];
777
+ project: MemoryStore$1["stats"];
763
778
  };
764
779
  /**
765
780
  * Get recent generations from project level.
@@ -833,7 +848,7 @@ declare const debug: {
833
848
  channel(name: string, event: string, detail?: string): void;
834
849
  };
835
850
 
836
- interface Session {
851
+ interface Session$1 {
837
852
  id: string;
838
853
  createdAt: string;
839
854
  updatedAt: string;
@@ -845,25 +860,25 @@ interface Session {
845
860
  /**
846
861
  * Create a new session.
847
862
  */
848
- declare function createSession(cwd: string): Session;
863
+ declare function createSession(cwd: string): Session$1;
849
864
  /**
850
865
  * Save a session to disk.
851
866
  */
852
- declare function saveSession(session: Session): void;
867
+ declare function saveSession(session: Session$1): void;
853
868
  /**
854
869
  * Load a session from disk.
855
870
  */
856
- declare function loadSession(id: string): Session | null;
871
+ declare function loadSession(id: string): Session$1 | null;
857
872
  /**
858
873
  * Load the most recent session.
859
874
  */
860
- declare function loadLatestSession(): Session | null;
875
+ declare function loadLatestSession(): Session$1 | null;
861
876
  /**
862
877
  * List all saved sessions.
863
878
  */
864
- declare function listSessions(): Session[];
879
+ declare function listSessions(): Session$1[];
865
880
 
866
- declare function exportSession(session: Session, usage?: UsageSummary): string;
881
+ declare function exportSession(session: Session$1, usage?: UsageSummary): string;
867
882
 
868
883
  declare const PERMISSION_MODES: readonly ["default", "acceptEdits", "plan", "yolo"];
869
884
  type PermissionMode = (typeof PERMISSION_MODES)[number];
@@ -1151,9 +1166,9 @@ declare class ReplEngine {
1151
1166
  }
1152
1167
 
1153
1168
  interface CommandContext {
1154
- session: Session;
1169
+ session: Session$1;
1155
1170
  cwd: string;
1156
- onSessionChange: (session: Session) => void;
1171
+ onSessionChange: (session: Session$1) => void;
1157
1172
  }
1158
1173
  type SlashCommandHandler = (args: string, ctx: CommandContext) => Promise<boolean>;
1159
1174
  declare function registerCommand(name: string, handler: SlashCommandHandler): void;
@@ -1299,6 +1314,52 @@ declare const agentConfigSchema: z.ZodObject<{
1299
1314
  model: z.ZodOptional<z.ZodString>;
1300
1315
  systemPrompt: z.ZodOptional<z.ZodString>;
1301
1316
  mentions: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1317
+ /** Phase 5 — typed capabilities (drop-condition fallback). Free-form
1318
+ * list of intent strings this agent is allowed to handle. When set,
1319
+ * the org-chart `canHandle(agentId, project, intent)` check rejects
1320
+ * dispatches with intents not in this list. When empty/unset
1321
+ * (the default), the agent is permissive — handles any intent.
1322
+ * Intent matching is exact-string for now; a glob/prefix layer can
1323
+ * come later if it produces real rejections.
1324
+ * Example: ["issue.opened", "issue.commented", "merge_request.opened"]
1325
+ * Example: ["cron.fired", "message.received"] */
1326
+ intents: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1327
+ /** Phase 8 — capability-bounded security. Max distinct upstream
1328
+ * agents in the delegation chain on the same (project, subject)
1329
+ * before a dispatch to THIS agent is refused. The ledger itself
1330
+ * provides the chain — `decideAndCommit` walks recent decisions on
1331
+ * the subject and counts distinct agents. Default 5; set to 0 to
1332
+ * disable for an agent that's always called as the bottom of a
1333
+ * chain. The check prevents cascade loops where A → B → A → B → ...
1334
+ * blows past sane chain depth. */
1335
+ maxDelegationDepth: z.ZodDefault<z.ZodNumber>;
1336
+ /** MCP servers this agent's Claude Code session should load. Synced
1337
+ * to <workspace>/.mcp.json at daemon boot via agent-mcp.ts. Operator
1338
+ * edits to .mcp.json are respected (see SyncResult.skipped-operator-owned). */
1339
+ mcp: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
1340
+ command: z.ZodString;
1341
+ args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1342
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1343
+ }, "strip", z.ZodTypeAny, {
1344
+ command: string;
1345
+ args: string[];
1346
+ env?: Record<string, string> | undefined;
1347
+ }, {
1348
+ command: string;
1349
+ env?: Record<string, string> | undefined;
1350
+ args?: string[] | undefined;
1351
+ }>>>;
1352
+ /** Per-agent override for the global `session.contextStrategy`. Lets
1353
+ * one agent run `planner` (smaller upfront context, more tool-driven
1354
+ * exploration) while siblings stay on `layered`. Used for agents that
1355
+ * consistently bloat their cache via large workspace reads. */
1356
+ contextStrategy: z.ZodOptional<z.ZodEnum<["layered", "planner"]>>;
1357
+ /** When true, the registry resolves references-recipes for this agent's
1358
+ * workspace and renders a deterministic [Verified References] block at
1359
+ * priority 4.7. Off by default — flip on per agent (pm-ksi, devops-agent,
1360
+ * etc.) once a `references/` registry exists in the agent's workspace
1361
+ * or repo root. See src/agents/references/. */
1362
+ contextReferences: z.ZodDefault<z.ZodBoolean>;
1302
1363
  maxConcurrent: z.ZodDefault<z.ZodNumber>;
1303
1364
  /** Hard wall-clock cap on a single Claude Code invocation. Exceeding the
1304
1365
  * cap sends SIGTERM (exit 143). Default 20 min — bump for devops/coder
@@ -1332,6 +1393,9 @@ declare const agentConfigSchema: z.ZodObject<{
1332
1393
  workspace: string;
1333
1394
  tier: "claude-code" | "sdk" | "orchestrator";
1334
1395
  mentions: string[];
1396
+ intents: string[];
1397
+ maxDelegationDepth: number;
1398
+ contextReferences: boolean;
1335
1399
  maxConcurrent: number;
1336
1400
  maxExecutionMinutes: number;
1337
1401
  permissionMode: string;
@@ -1346,6 +1410,12 @@ declare const agentConfigSchema: z.ZodObject<{
1346
1410
  provider?: string | undefined;
1347
1411
  model?: string | undefined;
1348
1412
  systemPrompt?: string | undefined;
1413
+ mcp?: Record<string, {
1414
+ command: string;
1415
+ args: string[];
1416
+ env?: Record<string, string> | undefined;
1417
+ }> | undefined;
1418
+ contextStrategy?: "layered" | "planner" | undefined;
1349
1419
  }, {
1350
1420
  name: string;
1351
1421
  workspace: string;
@@ -1354,6 +1424,15 @@ declare const agentConfigSchema: z.ZodObject<{
1354
1424
  tier?: "claude-code" | "sdk" | "orchestrator" | undefined;
1355
1425
  systemPrompt?: string | undefined;
1356
1426
  mentions?: string[] | undefined;
1427
+ intents?: string[] | undefined;
1428
+ maxDelegationDepth?: number | undefined;
1429
+ mcp?: Record<string, {
1430
+ command: string;
1431
+ env?: Record<string, string> | undefined;
1432
+ args?: string[] | undefined;
1433
+ }> | undefined;
1434
+ contextStrategy?: "layered" | "planner" | undefined;
1435
+ contextReferences?: boolean | undefined;
1357
1436
  maxConcurrent?: number | undefined;
1358
1437
  maxExecutionMinutes?: number | undefined;
1359
1438
  permissionMode?: string | undefined;
@@ -1475,6 +1554,52 @@ declare const daemonConfigSchema: z.ZodObject<{
1475
1554
  model: z.ZodOptional<z.ZodString>;
1476
1555
  systemPrompt: z.ZodOptional<z.ZodString>;
1477
1556
  mentions: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1557
+ /** Phase 5 — typed capabilities (drop-condition fallback). Free-form
1558
+ * list of intent strings this agent is allowed to handle. When set,
1559
+ * the org-chart `canHandle(agentId, project, intent)` check rejects
1560
+ * dispatches with intents not in this list. When empty/unset
1561
+ * (the default), the agent is permissive — handles any intent.
1562
+ * Intent matching is exact-string for now; a glob/prefix layer can
1563
+ * come later if it produces real rejections.
1564
+ * Example: ["issue.opened", "issue.commented", "merge_request.opened"]
1565
+ * Example: ["cron.fired", "message.received"] */
1566
+ intents: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1567
+ /** Phase 8 — capability-bounded security. Max distinct upstream
1568
+ * agents in the delegation chain on the same (project, subject)
1569
+ * before a dispatch to THIS agent is refused. The ledger itself
1570
+ * provides the chain — `decideAndCommit` walks recent decisions on
1571
+ * the subject and counts distinct agents. Default 5; set to 0 to
1572
+ * disable for an agent that's always called as the bottom of a
1573
+ * chain. The check prevents cascade loops where A → B → A → B → ...
1574
+ * blows past sane chain depth. */
1575
+ maxDelegationDepth: z.ZodDefault<z.ZodNumber>;
1576
+ /** MCP servers this agent's Claude Code session should load. Synced
1577
+ * to <workspace>/.mcp.json at daemon boot via agent-mcp.ts. Operator
1578
+ * edits to .mcp.json are respected (see SyncResult.skipped-operator-owned). */
1579
+ mcp: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
1580
+ command: z.ZodString;
1581
+ args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1582
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1583
+ }, "strip", z.ZodTypeAny, {
1584
+ command: string;
1585
+ args: string[];
1586
+ env?: Record<string, string> | undefined;
1587
+ }, {
1588
+ command: string;
1589
+ env?: Record<string, string> | undefined;
1590
+ args?: string[] | undefined;
1591
+ }>>>;
1592
+ /** Per-agent override for the global `session.contextStrategy`. Lets
1593
+ * one agent run `planner` (smaller upfront context, more tool-driven
1594
+ * exploration) while siblings stay on `layered`. Used for agents that
1595
+ * consistently bloat their cache via large workspace reads. */
1596
+ contextStrategy: z.ZodOptional<z.ZodEnum<["layered", "planner"]>>;
1597
+ /** When true, the registry resolves references-recipes for this agent's
1598
+ * workspace and renders a deterministic [Verified References] block at
1599
+ * priority 4.7. Off by default — flip on per agent (pm-ksi, devops-agent,
1600
+ * etc.) once a `references/` registry exists in the agent's workspace
1601
+ * or repo root. See src/agents/references/. */
1602
+ contextReferences: z.ZodDefault<z.ZodBoolean>;
1478
1603
  maxConcurrent: z.ZodDefault<z.ZodNumber>;
1479
1604
  /** Hard wall-clock cap on a single Claude Code invocation. Exceeding the
1480
1605
  * cap sends SIGTERM (exit 143). Default 20 min — bump for devops/coder
@@ -1508,6 +1633,9 @@ declare const daemonConfigSchema: z.ZodObject<{
1508
1633
  workspace: string;
1509
1634
  tier: "claude-code" | "sdk" | "orchestrator";
1510
1635
  mentions: string[];
1636
+ intents: string[];
1637
+ maxDelegationDepth: number;
1638
+ contextReferences: boolean;
1511
1639
  maxConcurrent: number;
1512
1640
  maxExecutionMinutes: number;
1513
1641
  permissionMode: string;
@@ -1522,6 +1650,12 @@ declare const daemonConfigSchema: z.ZodObject<{
1522
1650
  provider?: string | undefined;
1523
1651
  model?: string | undefined;
1524
1652
  systemPrompt?: string | undefined;
1653
+ mcp?: Record<string, {
1654
+ command: string;
1655
+ args: string[];
1656
+ env?: Record<string, string> | undefined;
1657
+ }> | undefined;
1658
+ contextStrategy?: "layered" | "planner" | undefined;
1525
1659
  }, {
1526
1660
  name: string;
1527
1661
  workspace: string;
@@ -1530,6 +1664,15 @@ declare const daemonConfigSchema: z.ZodObject<{
1530
1664
  tier?: "claude-code" | "sdk" | "orchestrator" | undefined;
1531
1665
  systemPrompt?: string | undefined;
1532
1666
  mentions?: string[] | undefined;
1667
+ intents?: string[] | undefined;
1668
+ maxDelegationDepth?: number | undefined;
1669
+ mcp?: Record<string, {
1670
+ command: string;
1671
+ env?: Record<string, string> | undefined;
1672
+ args?: string[] | undefined;
1673
+ }> | undefined;
1674
+ contextStrategy?: "layered" | "planner" | undefined;
1675
+ contextReferences?: boolean | undefined;
1533
1676
  maxConcurrent?: number | undefined;
1534
1677
  maxExecutionMinutes?: number | undefined;
1535
1678
  permissionMode?: string | undefined;
@@ -2705,10 +2848,53 @@ declare const daemonConfigSchema: z.ZodObject<{
2705
2848
  reportsTo?: string | undefined;
2706
2849
  utilizationTarget?: number | undefined;
2707
2850
  }>>>;
2851
+ projects: z.ZodDefault<z.ZodArray<z.ZodObject<{
2852
+ id: z.ZodString;
2853
+ pm: z.ZodOptional<z.ZodString>;
2854
+ client: z.ZodOptional<z.ZodString>;
2855
+ }, "strip", z.ZodTypeAny, {
2856
+ id: string;
2857
+ pm?: string | undefined;
2858
+ client?: string | undefined;
2859
+ }, {
2860
+ id: string;
2861
+ pm?: string | undefined;
2862
+ client?: string | undefined;
2863
+ }>, "many">>;
2864
+ contactMap: z.ZodDefault<z.ZodArray<z.ZodObject<{
2865
+ channel: z.ZodOptional<z.ZodString>;
2866
+ chatId: z.ZodOptional<z.ZodString>;
2867
+ username: z.ZodOptional<z.ZodString>;
2868
+ senderId: z.ZodOptional<z.ZodString>;
2869
+ client: z.ZodString;
2870
+ project: z.ZodOptional<z.ZodString>;
2871
+ displayName: z.ZodOptional<z.ZodString>;
2872
+ }, "strip", z.ZodTypeAny, {
2873
+ client: string;
2874
+ channel?: string | undefined;
2875
+ chatId?: string | undefined;
2876
+ username?: string | undefined;
2877
+ senderId?: string | undefined;
2878
+ project?: string | undefined;
2879
+ displayName?: string | undefined;
2880
+ }, {
2881
+ client: string;
2882
+ channel?: string | undefined;
2883
+ chatId?: string | undefined;
2884
+ username?: string | undefined;
2885
+ senderId?: string | undefined;
2886
+ project?: string | undefined;
2887
+ displayName?: string | undefined;
2888
+ }>, "many">>;
2708
2889
  workTickMinutes: z.ZodDefault<z.ZodNumber>;
2709
2890
  idleQueueThreshold: z.ZodDefault<z.ZodNumber>;
2710
2891
  }, "strip", z.ZodTypeAny, {
2711
2892
  enabled: boolean;
2893
+ projects: {
2894
+ id: string;
2895
+ pm?: string | undefined;
2896
+ client?: string | undefined;
2897
+ }[];
2712
2898
  timezone: string;
2713
2899
  mainChannel: {
2714
2900
  channel: string;
@@ -2746,6 +2932,15 @@ declare const daemonConfigSchema: z.ZodObject<{
2746
2932
  utilizationTarget: number;
2747
2933
  reportsTo?: string | undefined;
2748
2934
  }>;
2935
+ contactMap: {
2936
+ client: string;
2937
+ channel?: string | undefined;
2938
+ chatId?: string | undefined;
2939
+ username?: string | undefined;
2940
+ senderId?: string | undefined;
2941
+ project?: string | undefined;
2942
+ displayName?: string | undefined;
2943
+ }[];
2749
2944
  workTickMinutes: number;
2750
2945
  idleQueueThreshold: number;
2751
2946
  }, {
@@ -2766,6 +2961,11 @@ declare const daemonConfigSchema: z.ZodObject<{
2766
2961
  glob?: string | undefined;
2767
2962
  };
2768
2963
  enabled?: boolean | undefined;
2964
+ projects?: {
2965
+ id: string;
2966
+ pm?: string | undefined;
2967
+ client?: string | undefined;
2968
+ }[] | undefined;
2769
2969
  timezone?: string | undefined;
2770
2970
  roles?: Record<string, {
2771
2971
  title: string;
@@ -2787,6 +2987,15 @@ declare const daemonConfigSchema: z.ZodObject<{
2787
2987
  reportsTo?: string | undefined;
2788
2988
  utilizationTarget?: number | undefined;
2789
2989
  }> | undefined;
2990
+ contactMap?: {
2991
+ client: string;
2992
+ channel?: string | undefined;
2993
+ chatId?: string | undefined;
2994
+ username?: string | undefined;
2995
+ senderId?: string | undefined;
2996
+ project?: string | undefined;
2997
+ displayName?: string | undefined;
2998
+ }[] | undefined;
2790
2999
  workTickMinutes?: number | undefined;
2791
3000
  idleQueueThreshold?: number | undefined;
2792
3001
  }>>;
@@ -2937,7 +3146,6 @@ declare const daemonConfigSchema: z.ZodObject<{
2937
3146
  url: z.ZodString;
2938
3147
  dashboardUrl: z.ZodOptional<z.ZodString>;
2939
3148
  token: z.ZodOptional<z.ZodString>;
2940
- /** Phone numbers or JIDs. Substring match, same semantics as allowFrom. */
2941
3149
  dashboardToken: z.ZodOptional<z.ZodString>;
2942
3150
  }, "strip", z.ZodTypeAny, {
2943
3151
  name: string;
@@ -2952,8 +3160,7 @@ declare const daemonConfigSchema: z.ZodObject<{
2952
3160
  dashboardUrl?: string | undefined;
2953
3161
  dashboardToken?: string | undefined;
2954
3162
  }>, "many">>;
2955
- draftAgent: z.ZodOptional<z.ZodString>; /** Safety rails on live Baileys reads — personal-account accounts
2956
- * can get throttled/banned under burst reads. */
3163
+ draftAgent: z.ZodOptional<z.ZodString>;
2957
3164
  }, "strip", z.ZodTypeAny, {
2958
3165
  enabled: boolean;
2959
3166
  port: number;
@@ -3012,6 +3219,11 @@ declare const daemonConfigSchema: z.ZodObject<{
3012
3219
  * is driven by `autoApproveStructure` alone. Lower it to e.g. 0.7 if you
3013
3220
  * also want high-confidence structural changes auto-approved. */
3014
3221
  autoApproveConfidence: z.ZodDefault<z.ZodNumber>;
3222
+ /** Anthropic model id used for the direct classifier call (Phase 2 of
3223
+ * classifier-retire). Default haiku — classification is metadata, not
3224
+ * work, so we use the cheapest fast model. Override only if Haiku is
3225
+ * rate-limited or you want to A/B test. */
3226
+ classifierModel: z.ZodDefault<z.ZodString>;
3015
3227
  /** Weights for the wiki hybrid retrieval score. Path-ancestry match vs
3016
3228
  * BM25 over article text. Sum need not be 1. */
3017
3229
  retrievalWeights: z.ZodDefault<z.ZodObject<{
@@ -3029,6 +3241,7 @@ declare const daemonConfigSchema: z.ZodObject<{
3029
3241
  baseDir: string;
3030
3242
  autoApproveStructure: "any" | "strict" | "extend-leaves";
3031
3243
  autoApproveConfidence: number;
3244
+ classifierModel: string;
3032
3245
  retrievalWeights: {
3033
3246
  graph: number;
3034
3247
  bm25: number;
@@ -3042,6 +3255,7 @@ declare const daemonConfigSchema: z.ZodObject<{
3042
3255
  reviewAgent?: string | undefined;
3043
3256
  autoApproveStructure?: "any" | "strict" | "extend-leaves" | undefined;
3044
3257
  autoApproveConfidence?: number | undefined;
3258
+ classifierModel?: string | undefined;
3045
3259
  retrievalWeights?: {
3046
3260
  graph?: number | undefined;
3047
3261
  bm25?: number | undefined;
@@ -3078,22 +3292,43 @@ declare const daemonConfigSchema: z.ZodObject<{
3078
3292
  enabled: z.ZodDefault<z.ZodBoolean>;
3079
3293
  /** Route to a mesh peer instead of local execution. */
3080
3294
  node: z.ZodOptional<z.ZodString>;
3295
+ /** Per-event-type workflow routing. Keys are platform event-type
3296
+ * strings — the format the platform's HTTP header uses, optionally
3297
+ * joined with the action. Examples:
3298
+ * GitHub: "issues.opened", "pull_request.synchronize",
3299
+ * "push" (action-less events use the bare type)
3300
+ * GitLab: "Note Hook", "Merge Request Hook"
3301
+ * Values are workflow ids registered via `agentx workflow create`.
3302
+ * When the inbound event-type matches a key, the named workflow is
3303
+ * dispatched; if no key matches, the webhook falls through to
3304
+ * `defaultWorkflow` (or the agent itself). Closes the recurring
3305
+ * GitHub problem of multiple event types collapsing to a single
3306
+ * workflow. */
3307
+ triggers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
3308
+ /** Workflow id used when no `triggers` entry matches the event-type.
3309
+ * Backward-compatible: pre-existing webhooks without `triggers`
3310
+ * always hit this path. */
3311
+ defaultWorkflow: z.ZodOptional<z.ZodString>;
3081
3312
  }, "strip", z.ZodTypeAny, {
3082
3313
  enabled: boolean;
3083
3314
  id: string;
3084
3315
  source: "custom" | "gitlab" | "discord" | "slack" | "github" | "sentry" | "stripe";
3085
3316
  agentId: string;
3086
3317
  description?: string | undefined;
3318
+ triggers?: Record<string, string> | undefined;
3087
3319
  node?: string | undefined;
3088
3320
  secretEnv?: string | undefined;
3321
+ defaultWorkflow?: string | undefined;
3089
3322
  }, {
3090
3323
  id: string;
3091
3324
  source: "custom" | "gitlab" | "discord" | "slack" | "github" | "sentry" | "stripe";
3092
3325
  agentId: string;
3093
3326
  enabled?: boolean | undefined;
3094
3327
  description?: string | undefined;
3328
+ triggers?: Record<string, string> | undefined;
3095
3329
  node?: string | undefined;
3096
3330
  secretEnv?: string | undefined;
3331
+ defaultWorkflow?: string | undefined;
3097
3332
  }>, "many">>;
3098
3333
  /** Session cache-reuse policy. Controls when we drop a Claude `--resume`
3099
3334
  * session and rebuild the prompt from scratch.
@@ -3130,26 +3365,37 @@ declare const daemonConfigSchema: z.ZodObject<{
3130
3365
  maxClaudeCodeDispatchesPerHour: z.ZodDefault<z.ZodNumber>;
3131
3366
  maxClaudeCodeDispatchesPer5h: z.ZodDefault<z.ZodNumber>;
3132
3367
  }, "strip", z.ZodTypeAny, {
3368
+ contextStrategy: "layered" | "planner";
3133
3369
  staleMinutes: number;
3134
3370
  maxTurnsPerSession: number;
3135
3371
  tierTwoThresholdTokens: number;
3136
- contextStrategy: "layered" | "planner";
3137
3372
  maxClaudeCodeDispatchesPerHour: number;
3138
3373
  maxClaudeCodeDispatchesPer5h: number;
3139
3374
  }, {
3375
+ contextStrategy?: "layered" | "planner" | undefined;
3140
3376
  staleMinutes?: number | undefined;
3141
3377
  maxTurnsPerSession?: number | undefined;
3142
3378
  tierTwoThresholdTokens?: number | undefined;
3143
- contextStrategy?: "layered" | "planner" | undefined;
3144
3379
  maxClaudeCodeDispatchesPerHour?: number | undefined;
3145
3380
  maxClaudeCodeDispatchesPer5h?: number | undefined;
3146
3381
  }>>;
3382
+ /** Move B — JS/TS plugins. Each entry is an installed npm package name
3383
+ * (e.g. `agentx-plugin-mattermost` or `@noqta/plugin-mattermost`); the
3384
+ * loader does a dynamic `import(name)` at boot, validates the manifest,
3385
+ * and calls plugin.setup(ctx). Plugins can register channel adapters
3386
+ * via ctx.addChannel() and subscribe to bus events via ctx.on(). Empty
3387
+ * default — installs that don't list plugins are unaffected. Plugin
3388
+ * authoring guide: docs/architecture/plugins.md. */
3389
+ plugins: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
3147
3390
  }, "strip", z.ZodTypeAny, {
3148
3391
  agents: Record<string, {
3149
3392
  name: string;
3150
3393
  workspace: string;
3151
3394
  tier: "claude-code" | "sdk" | "orchestrator";
3152
3395
  mentions: string[];
3396
+ intents: string[];
3397
+ maxDelegationDepth: number;
3398
+ contextReferences: boolean;
3153
3399
  maxConcurrent: number;
3154
3400
  maxExecutionMinutes: number;
3155
3401
  permissionMode: string;
@@ -3164,6 +3410,12 @@ declare const daemonConfigSchema: z.ZodObject<{
3164
3410
  provider?: string | undefined;
3165
3411
  model?: string | undefined;
3166
3412
  systemPrompt?: string | undefined;
3413
+ mcp?: Record<string, {
3414
+ command: string;
3415
+ args: string[];
3416
+ env?: Record<string, string> | undefined;
3417
+ }> | undefined;
3418
+ contextStrategy?: "layered" | "planner" | undefined;
3167
3419
  }>;
3168
3420
  mesh: {
3169
3421
  enabled: boolean;
@@ -3189,6 +3441,7 @@ declare const daemonConfigSchema: z.ZodObject<{
3189
3441
  baseDir: string;
3190
3442
  autoApproveStructure: "any" | "strict" | "extend-leaves";
3191
3443
  autoApproveConfidence: number;
3444
+ classifierModel: string;
3192
3445
  retrievalWeights: {
3193
3446
  graph: number;
3194
3447
  bm25: number;
@@ -3428,19 +3681,27 @@ declare const daemonConfigSchema: z.ZodObject<{
3428
3681
  source: "custom" | "gitlab" | "discord" | "slack" | "github" | "sentry" | "stripe";
3429
3682
  agentId: string;
3430
3683
  description?: string | undefined;
3684
+ triggers?: Record<string, string> | undefined;
3431
3685
  node?: string | undefined;
3432
3686
  secretEnv?: string | undefined;
3687
+ defaultWorkflow?: string | undefined;
3433
3688
  }[];
3434
3689
  session: {
3690
+ contextStrategy: "layered" | "planner";
3435
3691
  staleMinutes: number;
3436
3692
  maxTurnsPerSession: number;
3437
3693
  tierTwoThresholdTokens: number;
3438
- contextStrategy: "layered" | "planner";
3439
3694
  maxClaudeCodeDispatchesPerHour: number;
3440
3695
  maxClaudeCodeDispatchesPer5h: number;
3441
3696
  };
3697
+ plugins: string[];
3442
3698
  business?: {
3443
3699
  enabled: boolean;
3700
+ projects: {
3701
+ id: string;
3702
+ pm?: string | undefined;
3703
+ client?: string | undefined;
3704
+ }[];
3444
3705
  timezone: string;
3445
3706
  mainChannel: {
3446
3707
  channel: string;
@@ -3478,6 +3739,15 @@ declare const daemonConfigSchema: z.ZodObject<{
3478
3739
  utilizationTarget: number;
3479
3740
  reportsTo?: string | undefined;
3480
3741
  }>;
3742
+ contactMap: {
3743
+ client: string;
3744
+ channel?: string | undefined;
3745
+ chatId?: string | undefined;
3746
+ username?: string | undefined;
3747
+ senderId?: string | undefined;
3748
+ project?: string | undefined;
3749
+ displayName?: string | undefined;
3750
+ }[];
3481
3751
  workTickMinutes: number;
3482
3752
  idleQueueThreshold: number;
3483
3753
  } | undefined;
@@ -3496,6 +3766,15 @@ declare const daemonConfigSchema: z.ZodObject<{
3496
3766
  tier?: "claude-code" | "sdk" | "orchestrator" | undefined;
3497
3767
  systemPrompt?: string | undefined;
3498
3768
  mentions?: string[] | undefined;
3769
+ intents?: string[] | undefined;
3770
+ maxDelegationDepth?: number | undefined;
3771
+ mcp?: Record<string, {
3772
+ command: string;
3773
+ env?: Record<string, string> | undefined;
3774
+ args?: string[] | undefined;
3775
+ }> | undefined;
3776
+ contextStrategy?: "layered" | "planner" | undefined;
3777
+ contextReferences?: boolean | undefined;
3499
3778
  maxConcurrent?: number | undefined;
3500
3779
  maxExecutionMinutes?: number | undefined;
3501
3780
  permissionMode?: string | undefined;
@@ -3528,6 +3807,7 @@ declare const daemonConfigSchema: z.ZodObject<{
3528
3807
  reviewAgent?: string | undefined;
3529
3808
  autoApproveStructure?: "any" | "strict" | "extend-leaves" | undefined;
3530
3809
  autoApproveConfidence?: number | undefined;
3810
+ classifierModel?: string | undefined;
3531
3811
  retrievalWeights?: {
3532
3812
  graph?: number | undefined;
3533
3813
  bm25?: number | undefined;
@@ -3725,6 +4005,11 @@ declare const daemonConfigSchema: z.ZodObject<{
3725
4005
  glob?: string | undefined;
3726
4006
  };
3727
4007
  enabled?: boolean | undefined;
4008
+ projects?: {
4009
+ id: string;
4010
+ pm?: string | undefined;
4011
+ client?: string | undefined;
4012
+ }[] | undefined;
3728
4013
  timezone?: string | undefined;
3729
4014
  roles?: Record<string, {
3730
4015
  title: string;
@@ -3746,6 +4031,15 @@ declare const daemonConfigSchema: z.ZodObject<{
3746
4031
  reportsTo?: string | undefined;
3747
4032
  utilizationTarget?: number | undefined;
3748
4033
  }> | undefined;
4034
+ contactMap?: {
4035
+ client: string;
4036
+ channel?: string | undefined;
4037
+ chatId?: string | undefined;
4038
+ username?: string | undefined;
4039
+ senderId?: string | undefined;
4040
+ project?: string | undefined;
4041
+ displayName?: string | undefined;
4042
+ }[] | undefined;
3749
4043
  workTickMinutes?: number | undefined;
3750
4044
  idleQueueThreshold?: number | undefined;
3751
4045
  } | undefined;
@@ -3807,17 +4101,20 @@ declare const daemonConfigSchema: z.ZodObject<{
3807
4101
  agentId: string;
3808
4102
  enabled?: boolean | undefined;
3809
4103
  description?: string | undefined;
4104
+ triggers?: Record<string, string> | undefined;
3810
4105
  node?: string | undefined;
3811
4106
  secretEnv?: string | undefined;
4107
+ defaultWorkflow?: string | undefined;
3812
4108
  }[] | undefined;
3813
4109
  session?: {
4110
+ contextStrategy?: "layered" | "planner" | undefined;
3814
4111
  staleMinutes?: number | undefined;
3815
4112
  maxTurnsPerSession?: number | undefined;
3816
4113
  tierTwoThresholdTokens?: number | undefined;
3817
- contextStrategy?: "layered" | "planner" | undefined;
3818
4114
  maxClaudeCodeDispatchesPerHour?: number | undefined;
3819
4115
  maxClaudeCodeDispatchesPer5h?: number | undefined;
3820
4116
  } | undefined;
4117
+ plugins?: string[] | undefined;
3821
4118
  }>;
3822
4119
  type DaemonConfig = z.infer<typeof daemonConfigSchema>;
3823
4120
  type AgentDef = z.infer<typeof agentConfigSchema>;
@@ -3851,6 +4148,14 @@ declare class A2AMesh {
3851
4148
  private healthTimer?;
3852
4149
  private config;
3853
4150
  private log;
4151
+ /** Optional callback fired on peer state transitions (recovered /
4152
+ * lost / skills changed). Daemon wires this to the event bus for
4153
+ * live operator visibility. */
4154
+ private peerChangeCallback?;
4155
+ /** Register a listener for peer state transitions. Only one listener
4156
+ * is kept — repeat calls overwrite. Used by the daemon to bridge
4157
+ * into the EventBus without introducing a circular dependency. */
4158
+ onPeerChange(cb: typeof A2AMesh.prototype.peerChangeCallback): void;
3854
4159
  constructor(config: DaemonConfig, log?: (...args: unknown[]) => void);
3855
4160
  /**
3856
4161
  * Start the mesh: discover peers and begin health checks.
@@ -3867,6 +4172,28 @@ declare class A2AMesh {
3867
4172
  removed: string[];
3868
4173
  updated: string[];
3869
4174
  }>;
4175
+ /** Number of peers currently registered (regardless of health). */
4176
+ peerCount(): number;
4177
+ /**
4178
+ * Re-probe a single peer immediately. Use case: an operator just added
4179
+ * an agent on the remote daemon and doesn't want to wait up to a full
4180
+ * health-check interval (default 60s) before mentioning the new agent
4181
+ * resolves. The probe pulls a fresh agent card and updates `state.agents`
4182
+ * so `directory()` reflects the new roster on the very next route lookup.
4183
+ *
4184
+ * Returns true on success, false when the peer is unknown or the probe
4185
+ * failed. Does NOT throw — callers can blindly fan-out across peers.
4186
+ */
4187
+ refreshPeer(name: string): Promise<boolean>;
4188
+ /**
4189
+ * Re-probe every peer in parallel. Cheap when peers are healthy
4190
+ * (single GET /a2a/agent-card per peer). Used by `agentx mesh refresh`
4191
+ * and after agent-roster changes to invalidate the cached directory.
4192
+ */
4193
+ refreshAll(): Promise<{
4194
+ name: string;
4195
+ healthy: boolean;
4196
+ }[]>;
3870
4197
  /**
3871
4198
  * Discover agent cards from all peers.
3872
4199
  */
@@ -3879,6 +4206,21 @@ declare class A2AMesh {
3879
4206
  */
3880
4207
  sendTask(peerName: string, text: string, agentId?: string, opts?: {
3881
4208
  timeoutMs?: number;
4209
+ /** Identity of the agent on whose behalf this call is made. Forwarded
4210
+ * in the request body so the receiving daemon can record it in
4211
+ * route_traces and (in a future protocol revision) validate that the
4212
+ * caller is allowed to act for this agent. Optional during the
4213
+ * log-warn rollout; missing values produce a server-side warning. */
4214
+ senderAgentId?: string;
4215
+ /** Origin context — channel, chatId, sender, channelMeta, etc. Forwarded
4216
+ * to the receiving daemon's /task handler verbatim so the receiver's
4217
+ * registry.execute() keys the session by the SAME (channel, chatId)
4218
+ * the sender used, instead of falling back to api/default. Without
4219
+ * this, a GitLab webhook routed across the mesh lands in the
4220
+ * recipient's api:default bucket with no project, no issue id, no
4221
+ * channelMeta — i.e., the mtgl/hasanah confusion incident on
4222
+ * 2026-04-29 issue #709. Shape matches AgentTask.context. */
4223
+ context?: Record<string, unknown>;
3882
4224
  }): Promise<string>;
3883
4225
  /**
3884
4226
  * Forward a WebRTC signaling message (SDP / ICE / hangup) to a remote peer's
@@ -3919,6 +4261,99 @@ declare class A2AMesh {
3919
4261
  }>;
3920
4262
  }
3921
4263
 
4264
+ type EventKind = "run" | "task" | "signal" | "mesh" | "channel" | "status";
4265
+ interface BaseEvent {
4266
+ kind: EventKind;
4267
+ /** Monotonic-ish identifier; just for debug/replay. */
4268
+ id: string;
4269
+ /** ISO-8601 emit time. */
4270
+ at: string;
4271
+ }
4272
+ interface RunEvent extends BaseEvent {
4273
+ kind: "run";
4274
+ runId: string;
4275
+ workflowId: string;
4276
+ /** Node that just transitioned. Optional for run-created events. */
4277
+ nodeId?: string;
4278
+ /** "created" | "ok" | "failed" | "paused" | "resumed" | "skipped" | "completed" | "timeout". */
4279
+ phase: string;
4280
+ /** Current run status after the transition. */
4281
+ status?: string;
4282
+ homeNode?: string;
4283
+ note?: string;
4284
+ }
4285
+ interface TaskEvent extends BaseEvent {
4286
+ kind: "task";
4287
+ taskId: string;
4288
+ workflowId: string;
4289
+ runId: string;
4290
+ phase: "created" | "submitted" | "canceled";
4291
+ assignedTo?: string[];
4292
+ title?: string;
4293
+ submittedBy?: string;
4294
+ }
4295
+ interface SignalEvent extends BaseEvent {
4296
+ kind: "signal";
4297
+ name: string;
4298
+ scope: "workflow" | "global";
4299
+ workflowId?: string;
4300
+ payload?: Record<string, unknown>;
4301
+ }
4302
+ interface MeshEvent extends BaseEvent {
4303
+ kind: "mesh";
4304
+ peer: string;
4305
+ healthy: boolean;
4306
+ skills?: string[];
4307
+ delta: "recovered" | "lost" | "skills-changed" | "added" | "removed";
4308
+ }
4309
+ interface ChannelEvent extends BaseEvent {
4310
+ kind: "channel";
4311
+ channel: string;
4312
+ direction: "in" | "out";
4313
+ chatId?: string;
4314
+ sender?: string;
4315
+ agentId?: string;
4316
+ textPreview?: string;
4317
+ messageId?: string;
4318
+ }
4319
+ interface StatusEvent extends BaseEvent {
4320
+ kind: "status";
4321
+ message: string;
4322
+ meta?: Record<string, unknown>;
4323
+ }
4324
+ type DaemonEvent = RunEvent | TaskEvent | SignalEvent | MeshEvent | ChannelEvent | StatusEvent;
4325
+ interface SubscriptionFilter {
4326
+ /** Match only these kinds. Empty / omitted = all kinds. */
4327
+ kinds?: EventKind[];
4328
+ /** Workflow id filter (applies to run/task/signal events). */
4329
+ workflowId?: string;
4330
+ /** Actor id filter (task.assignedTo includes this, or task.submittedBy equals). */
4331
+ actor?: string;
4332
+ /** Channel filter (for channel events). */
4333
+ channel?: string;
4334
+ /** Run id filter (run events for a specific run). */
4335
+ runId?: string;
4336
+ }
4337
+ type Listener = (e: DaemonEvent) => void;
4338
+ /** Simple in-memory publish/subscribe. No ordering guarantees beyond
4339
+ * "subscribers see events in the order they were published". No
4340
+ * durability. Listener callbacks are invoked synchronously; if a
4341
+ * listener throws, the error is swallowed so a single bad subscriber
4342
+ * can't break the fanout. */
4343
+ declare class EventBus {
4344
+ private listeners;
4345
+ subscribe(filter: SubscriptionFilter, fn: Listener): () => void;
4346
+ /** Publish an event. The `id` and `at` fields are filled in if absent.
4347
+ * We deliberately accept a loose input shape — callers construct the
4348
+ * per-kind literal and we trust them; runtime validation happens at
4349
+ * the SSE serialisation layer. */
4350
+ publish(event: {
4351
+ kind: EventKind;
4352
+ } & Record<string, unknown>): void;
4353
+ /** Active subscriber count — useful for health endpoints. */
4354
+ get size(): number;
4355
+ }
4356
+
3922
4357
  declare class AgentXDaemon {
3923
4358
  private config;
3924
4359
  private registry;
@@ -3937,12 +4372,11 @@ declare class AgentXDaemon {
3937
4372
  private workflowDispatcher?;
3938
4373
  private workflowStore?;
3939
4374
  private workflowRuns?;
3940
- /** Structured per-agent memory (Claude-Code-style user / feedback /
3941
- * project / reference). Deliberately owned by the daemon (not the
3942
- * registry) so HTTP callers — including an agent curling from its
3943
- * own Claude Code session — can write without going through the
3944
- * dispatcher. Inlined into agent system prompts happens elsewhere. */
4375
+ private db;
4376
+ private loadedPlugins;
3945
4377
  private readonly agentMemory;
4378
+ private contacts;
4379
+ readonly events: EventBus;
3946
4380
  private log;
3947
4381
  private sseClients;
3948
4382
  private configPath?;
@@ -4018,12 +4452,24 @@ declare class AgentXDaemon {
4018
4452
  */
4019
4453
  private handleOpenAICompat;
4020
4454
  private json;
4455
+ /** Pick today's usage rollup according to AGENTX_USAGE_READ:
4456
+ * - "sqlite": SQLite only (empty if db null / no rows)
4457
+ * - "json": JSON only (legacy behaviour)
4458
+ * - "sqlite-then-json" (default): try SQLite, fall back to JSON when
4459
+ * the rollup is empty (no agents seen today). Transparent for
4460
+ * operators on first deploy where SQLite is empty until the first
4461
+ * task completes. */
4462
+ private resolveTodayUsage;
4021
4463
  /** Boot-time: install the `remember` skill into every agent workspace
4022
4464
  * that doesn't already have it, and sync each agent's existing memory
4023
4465
  * into <workspace>/CLAUDE.md + .agentx-memory.md. Idempotent — safe to
4024
4466
  * run on every daemon start. Write-if-absent for the skill, sentinel-
4025
4467
  * replace for CLAUDE.md, so operator edits survive. */
4026
4468
  private installAgentMemorySurface;
4469
+ /** Boot-time: sync each agent's `mcp` config block to
4470
+ * <workspace>/.mcp.json. Mirrors installAgentMemorySurface — same
4471
+ * ownership semantics, marker-based to preserve operator edits. */
4472
+ private installAgentMcpConfig;
4027
4473
  /** Look up an agent's workspace from the live registry. Returns null
4028
4474
  * for agents the daemon doesn't know about (e.g., a stale memory
4029
4475
  * entry for a since-removed agent). */
@@ -4269,6 +4715,19 @@ interface AgentTask {
4269
4715
  * supports it. Workflow `agent` nodes pass this through from their
4270
4716
  * config.timeoutMinutes. */
4271
4717
  timeoutMinutes?: number;
4718
+ /** Phase 1 / 6 — when set, identifies the intent-ledger decision row
4719
+ * this task corresponds to. The registry records a resolution row
4720
+ * on this decision when the task completes (success / error / mesh-
4721
+ * fallback). Active-task safety in `decideAndCommit` reads
4722
+ * intent_resolutions to clear in-flight slots; without resolution
4723
+ * writes, every dispatched decision sits in-flight forever and
4724
+ * Inv-ActiveTaskSafety becomes vacuously over-aggressive. Channel
4725
+ * adapters (gitlab, router) set this when their record*Dispatch
4726
+ * helper returns a dispatched decision. */
4727
+ intentRef?: {
4728
+ eventId: string;
4729
+ decidedBy: string;
4730
+ };
4272
4731
  context?: {
4273
4732
  channel?: string;
4274
4733
  sender?: string;
@@ -4359,6 +4818,464 @@ declare function executeTask(agent: AgentDef, task: AgentTask, providers: Record
4359
4818
  apiKey?: string;
4360
4819
  }>, onDelta?: StreamCallback, historyContext?: string, resumeSessionId?: string, onEvent?: (event: any) => void): Promise<AgentResponse>;
4361
4820
 
4821
+ interface DriftReport {
4822
+ /** 0-1 score: 0 = no drift, 1 = complete drift */
4823
+ overallScore: number;
4824
+ /** Ghost lexicon decay: percentage of domain words that disappeared */
4825
+ lexiconDecay: number;
4826
+ /** Tool-call Jaccard distance: 0 = identical patterns, 1 = completely different */
4827
+ toolShift: number;
4828
+ /** Keyword overlap decline: percentage of shared keywords lost */
4829
+ semanticDrift: number;
4830
+ /** Domain words that disappeared */
4831
+ lostWords: string[];
4832
+ /** New tool calls that weren't in the baseline */
4833
+ newTools: string[];
4834
+ /** Missing tool calls that were in the baseline */
4835
+ missingTools: string[];
4836
+ }
4837
+
4838
+ interface MemoryFact {
4839
+ id: string;
4840
+ agentId: string;
4841
+ category: "fact" | "secret" | "preference" | "commitment" | "task-state";
4842
+ content: string;
4843
+ keywords: string[];
4844
+ source: {
4845
+ channel: string;
4846
+ chatId: string;
4847
+ sender: string;
4848
+ date: string;
4849
+ };
4850
+ createdAt: string;
4851
+ expiresAt?: string;
4852
+ accessCount?: number;
4853
+ lastAccessed?: string;
4854
+ nextReview?: string;
4855
+ /** Review interval in days — doubles on each successful recall */
4856
+ intervalDays?: number;
4857
+ }
4858
+ declare class MemoryStore {
4859
+ private memoryDir;
4860
+ constructor(baseDir?: string);
4861
+ private filePath;
4862
+ addMemory(agentId: string, fact: Omit<MemoryFact, "id" | "createdAt">): void;
4863
+ getAll(agentId: string): MemoryFact[];
4864
+ findRelevant(message: string, agentId: string, limit?: number): MemoryFact[];
4865
+ buildContext(memories: MemoryFact[]): string;
4866
+ /**
4867
+ * Record that memories were accessed (for spaced repetition tracking).
4868
+ */
4869
+ recordAccess(agentId: string, memoryIds: string[]): void;
4870
+ /**
4871
+ * Get memories due for review (spaced repetition).
4872
+ * Returns facts whose nextReview date has passed or that have never been reviewed.
4873
+ */
4874
+ getDueForReview(agentId: string, limit?: number): MemoryFact[];
4875
+ /**
4876
+ * Build a recall prompt for memories due for review.
4877
+ * Injected into heartbeat context so the agent proactively recalls facts.
4878
+ */
4879
+ buildRecallContext(agentId: string): string;
4880
+ /**
4881
+ * Check if a substantially similar memory already exists.
4882
+ */
4883
+ hasSimilar(agentId: string, content: string): boolean;
4884
+ /**
4885
+ * Prune old/expired memories. Cap at MAX_MEMORIES per agent.
4886
+ */
4887
+ prune(agentId: string): void;
4888
+ }
4889
+
4890
+ /**
4891
+ * Verified channel context — facts the channel adapter knows for certain.
4892
+ * Prevents agents from hallucinating about their environment.
4893
+ */
4894
+ interface ChannelMeta {
4895
+ /** Channel name */
4896
+ channel: string;
4897
+ /** Verified agents/bots present in this chat/group/project */
4898
+ agents?: Array<{
4899
+ id: string;
4900
+ name: string;
4901
+ handle?: string;
4902
+ }>;
4903
+ /** Project path (GitLab) or group topic */
4904
+ project?: string;
4905
+ /** Issue/MR context (GitLab) */
4906
+ issue?: {
4907
+ type: string;
4908
+ iid: string;
4909
+ title: string;
4910
+ };
4911
+ /** Channel-specific facts (e.g., pipeline status, group description) */
4912
+ facts?: string[];
4913
+ }
4914
+ interface IncomingMessage {
4915
+ id: string;
4916
+ channel: string;
4917
+ accountId: string;
4918
+ sender: {
4919
+ id: string;
4920
+ name: string;
4921
+ username?: string;
4922
+ /** True when the origin is another bot account (Telegram `from.is_bot`).
4923
+ * Used by the router to apply strict @-mention-only routing — prevents
4924
+ * cross-daemon cascades from bare-word matches in bot replies. */
4925
+ isBot?: boolean;
4926
+ };
4927
+ group?: {
4928
+ id: string;
4929
+ name: string;
4930
+ };
4931
+ text: string;
4932
+ replyTo?: string;
4933
+ replyToText?: string;
4934
+ timestamp: Date;
4935
+ media?: {
4936
+ path: string;
4937
+ type: string;
4938
+ fileName?: string;
4939
+ };
4940
+ raw?: unknown;
4941
+ resolvedAgent?: string;
4942
+ preferNode?: string;
4943
+ channelMeta?: ChannelMeta;
4944
+ /** Correlator threaded by the workflow engine. When a workflow dispatches
4945
+ * an agent, this carries the run id through the pipeline so post:response
4946
+ * can re-enter the engine with `kind: agentResult` transitions. Opaque
4947
+ * everywhere outside src/workflows/. */
4948
+ workflowRunId?: string;
4949
+ /** Phase 1 / 6 — when set, identifies the intent-ledger decision row
4950
+ * this message corresponds to. The agent registry calls
4951
+ * `ledger.recordResolution(...)` when the dispatched task completes,
4952
+ * so Inv-ActiveTaskSafety's "decision in flight" check can clear.
4953
+ * Set by the channel adapter (gitlab, router) right after
4954
+ * recordGitLabTargetDispatch / recordRouterDispatch returns the
4955
+ * decision row. Undefined when the dispatch was deduped/halted by
4956
+ * the ledger (no resolution to write) or when the source is in
4957
+ * mode=off. */
4958
+ intentRef?: {
4959
+ eventId: string;
4960
+ decidedBy: string;
4961
+ };
4962
+ }
4963
+ interface OutgoingMessage {
4964
+ channel: string;
4965
+ chatId: string;
4966
+ text: string;
4967
+ replyTo?: string;
4968
+ parseMode?: "markdown" | "html" | "plain";
4969
+ agentId?: string;
4970
+ poll?: {
4971
+ name: string;
4972
+ values: string[];
4973
+ selectableCount?: number;
4974
+ };
4975
+ media?: {
4976
+ type: "image" | "document" | "audio" | "video";
4977
+ url: string;
4978
+ caption?: string;
4979
+ mimetype?: string;
4980
+ fileName?: string;
4981
+ };
4982
+ }
4983
+ interface ChannelAdapter {
4984
+ readonly name: string;
4985
+ /** Start polling or webhook listener */
4986
+ start(): Promise<void>;
4987
+ /** Stop the adapter gracefully */
4988
+ stop(): Promise<void>;
4989
+ /** Send a message back to a chat */
4990
+ send(msg: OutgoingMessage): Promise<string | void>;
4991
+ /** Edit an existing message (returns false if not supported) */
4992
+ editMessage?(chatId: string, messageId: string, text: string, parseMode?: string): Promise<boolean>;
4993
+ /** Send typing/action indicator */
4994
+ sendTyping?(chatId: string): Promise<void>;
4995
+ /** React to a message with an emoji (e.g., 👀 for seen) */
4996
+ react?(chatId: string, messageId: string, emoji?: string): Promise<void>;
4997
+ /** Register handler for incoming messages */
4998
+ onMessage(handler: (msg: IncomingMessage) => Promise<void>): void;
4999
+ /** Get verified context for a chat (optional — channels implement what they can) */
5000
+ getChannelMeta?(chatId: string): Promise<ChannelMeta | undefined>;
5001
+ /** Fetch the most recent messages from the live channel for cold-start
5002
+ * session seeding. Called once per (agent, channel, chatId, day) when a
5003
+ * fresh session is created — never on warm cache hits. Bounded by
5004
+ * maxMessages and maxChars (enforced by the caller). Channels return their
5005
+ * own externalId so SessionStore can dedup against re-seeds. */
5006
+ seedHistory?(chatId: string, opts: {
5007
+ sinceISO?: string;
5008
+ maxMessages: number;
5009
+ maxChars: number;
5010
+ }): Promise<Array<SeededMessage>>;
5011
+ }
5012
+ /** A message returned by seedHistory — flat, channel-agnostic. */
5013
+ interface SeededMessage {
5014
+ role: "user" | "agent";
5015
+ name: string;
5016
+ content: string;
5017
+ timestamp: string;
5018
+ externalId?: string;
5019
+ /** Optional channel-side account/bot identity that handled this message
5020
+ * (e.g., Telegram accountId "noqta_cx_bot"). Captured by adapters that
5021
+ * shadow-log outbound, so seeded history preserves the audit trail of
5022
+ * which bot identity actually sent each line. Renderers may ignore it. */
5023
+ accountId?: string;
5024
+ }
5025
+
5026
+ interface SessionMessage {
5027
+ role: "user" | "agent";
5028
+ name?: string;
5029
+ content: string;
5030
+ timestamp: string;
5031
+ /** True when this message was injected by SessionStore.seedFromAdapter()
5032
+ * reading the live channel on cold session create — never via the inbound
5033
+ * router pipeline. Marked so observers can distinguish seeded turns from
5034
+ * live ones; the model sees them identically in buildHistoryContext. */
5035
+ seeded?: boolean;
5036
+ /** Channel-side message id (Telegram update_id, GitLab note id, WhatsApp
5037
+ * key.id). Used to dedup re-seeds — if a message with this externalId is
5038
+ * already in the session, appendSeededMessages skips it. */
5039
+ externalId?: string;
5040
+ }
5041
+ interface Session {
5042
+ id: string;
5043
+ agentId: string;
5044
+ channel: string;
5045
+ chatId: string;
5046
+ day: string;
5047
+ claudeSessionId?: string;
5048
+ messages: SessionMessage[];
5049
+ createdAt: string;
5050
+ updatedAt: string;
5051
+ /** Number of completed turns on the current claudeSessionId. Resets to 0
5052
+ * when the session is rotated (cleared). Used to bound --resume growth:
5053
+ * Claude CLI replays the entire prior session on every turn, so long
5054
+ * sessions pay a linearly growing cache-read tax. */
5055
+ turnCount?: number;
5056
+ /** Total billable input of the LAST turn on this claudeSessionId
5057
+ * (inputTokens + cacheReadTokens + cacheCreateTokens). Used to detect
5058
+ * tier-2 hits (>200K) from the prior turn so we can rotate before the
5059
+ * next turn pays the 1.5× multiplier again. */
5060
+ lastTurnInputTokens?: number;
5061
+ }
5062
+ declare class SessionStore {
5063
+ private sessionsDir;
5064
+ private cache;
5065
+ private staleMinutes;
5066
+ private maxTurnsPerSession;
5067
+ private tierTwoThresholdTokens;
5068
+ /** Resolves a channel name to its adapter — installed by the daemon after
5069
+ * channels are registered (see daemon/index.ts after router.register). The
5070
+ * cold-create branch consults it to call adapter.seedHistory(). Optional;
5071
+ * when unset, seeding is a no-op (back-compat for tests, CLI tools, and
5072
+ * any caller that constructs SessionStore standalone). */
5073
+ private adapterResolver?;
5074
+ /** In-flight seed promises keyed by sessionKey. Coalesces concurrent
5075
+ * cold-creates against the same (agent, channel, chatId, day) so we hit
5076
+ * the channel API exactly once per fresh session. */
5077
+ private seedingPromises;
5078
+ constructor(baseDir?: string, opts?: {
5079
+ staleMinutes?: number;
5080
+ maxTurnsPerSession?: number;
5081
+ tierTwoThresholdTokens?: number;
5082
+ });
5083
+ /** Install the channel-adapter resolver. Called once at daemon startup
5084
+ * after MessageRouter has registered every adapter. Hot-reload of channel
5085
+ * adapters re-uses the same router, so the resolver stays valid across
5086
+ * /reload cycles without re-installation. */
5087
+ setAdapterResolver(fn: (channel: string) => ChannelAdapter | undefined): void;
5088
+ /** Seed a fresh session from the live channel before any user/agent
5089
+ * messages get appended. No-op when:
5090
+ * - the session already has messages (warm cache or partially loaded)
5091
+ * - no adapter resolver is installed
5092
+ * - the channel adapter has no seedHistory method
5093
+ * Concurrent calls against the same key share one in-flight promise so
5094
+ * the channel API is hit exactly once per cold create. Errors are
5095
+ * swallowed — a seeding failure should never block a turn. */
5096
+ seedIfEmpty(agentId: string, channel: string, chatId: string): Promise<void>;
5097
+ /** Append seeded messages to a session in chronological order, deduping
5098
+ * by externalId against anything already present. Marks each entry with
5099
+ * `seeded: true` so observers can distinguish them; the model's prompt
5100
+ * (buildHistoryContext) renders them identically to live turns. */
5101
+ private appendSeededMessages;
5102
+ /**
5103
+ * Build a deterministic session key.
5104
+ */
5105
+ private sessionKey;
5106
+ private sessionFile;
5107
+ /**
5108
+ * Get or create a session for this agent+channel+chat+day.
5109
+ */
5110
+ getSession(agentId: string, channel: string, chatId: string): Session;
5111
+ /**
5112
+ * Add a user message to the session. Consecutive duplicates from the same
5113
+ * sender are collapsed — when a user re-sends the exact same text (retry,
5114
+ * accidental double-tap, telegram glitches), storing every copy bloats the
5115
+ * replayed history and re-burns tokens on every subsequent turn.
5116
+ */
5117
+ addUserMessage(agentId: string, channel: string, chatId: string, senderName: string, content: string): void;
5118
+ /**
5119
+ * Add an agent response to the session. Same dedup rule as user messages —
5120
+ * retries and duplicate responses shouldn't be replayed on every turn.
5121
+ */
5122
+ addAgentMessage(agentId: string, channel: string, chatId: string, content: string): void;
5123
+ /**
5124
+ * Get the Claude Code session ID for this conversation (for --resume).
5125
+ * Returns undefined if no session yet (first message of the day).
5126
+ */
5127
+ getClaudeSessionId(agentId: string, channel: string, chatId: string): string | undefined;
5128
+ /**
5129
+ * Store the Claude Code session ID after first invocation.
5130
+ */
5131
+ setClaudeSessionId(agentId: string, channel: string, chatId: string, claudeSessionId: string): void;
5132
+ /**
5133
+ * Build conversation history string to prepend to the prompt.
5134
+ * Returns empty string if no history.
5135
+ * Used for non-claude-code tiers that don't have native sessions.
5136
+ */
5137
+ buildHistoryContext(agentId: string, channel: string, chatId: string): string;
5138
+ /**
5139
+ * Recall conversation turns across multiple stored sessions for an agent.
5140
+ *
5141
+ * Used by the `/recall` HTTP endpoint and the [Conversation Recall] skill —
5142
+ * when an agent receives a message that references prior context (anaphora,
5143
+ * "as discussed", "correct me if I'm wrong"), it can call this to fetch
5144
+ * the actual prior turns rather than guessing or running cold-start tool
5145
+ * calls. Read-only; no side effects.
5146
+ *
5147
+ * Pagination: cursor by timestamp, descending (newest first). Pass the
5148
+ * previous response's `oldestTs` as `before` to walk further back.
5149
+ *
5150
+ * Scoping: required `agentId`. `channel`/`chatId` narrow to a specific
5151
+ * thread; omit them to recall across all of this agent's conversations.
5152
+ * The store is per-agent on disk so we never leak another agent's chats.
5153
+ */
5154
+ recallTurns(opts: {
5155
+ agentId: string;
5156
+ channel?: string;
5157
+ chatId?: string;
5158
+ before?: string;
5159
+ after?: string;
5160
+ /** Convenience override for `after`: number of days back from now. */
5161
+ lookbackDays?: number;
5162
+ limit?: number;
5163
+ query?: string;
5164
+ participants?: string[];
5165
+ }): {
5166
+ turns: Array<{
5167
+ ts: string;
5168
+ role: "user" | "agent";
5169
+ senderName: string;
5170
+ content: string;
5171
+ channel: string;
5172
+ chatId: string;
5173
+ day: string;
5174
+ sessionFile: string;
5175
+ }>;
5176
+ oldestTs: string | null;
5177
+ hasMore: boolean;
5178
+ totalScanned: number;
5179
+ };
5180
+ /** Cross-agent view of a chat. Aggregates session messages from EVERY
5181
+ * agent that has a session for `(channel, chatId)` in the requested
5182
+ * window, sorts oldest-first, and dedups exact (timestamp, role, name,
5183
+ * content) collisions (which happen when two agents in the same group
5184
+ * both record the same inbound).
5185
+ *
5186
+ * Differs from recallTurns in two ways:
5187
+ * 1. Not scoped to one agentId — answers "what's in this chat across
5188
+ * all agents", which is the question the cx→devops→marketing thread
5189
+ * on 2026-04-29 needed and didn't have.
5190
+ * 2. Returns oldest-first so the caller reads it like a transcript;
5191
+ * recallTurns returns newest-first because it paginates.
5192
+ *
5193
+ * Bounded by the same MAX_MESSAGES default as buildHistoryContext so
5194
+ * callers don't accidentally pull a 5000-turn group into one prompt. */
5195
+ recentByChatId(opts: {
5196
+ channel: string;
5197
+ chatId: string;
5198
+ sinceISO?: string;
5199
+ limit?: number;
5200
+ }): Array<{
5201
+ ts: string;
5202
+ role: "user" | "agent";
5203
+ senderName: string;
5204
+ content: string;
5205
+ agentId: string;
5206
+ sessionFile: string;
5207
+ }>;
5208
+ /**
5209
+ * Check if a Claude session is stale (idle too long for --resume to be useful).
5210
+ * When stale, the resumed context will be too far behind — better to start fresh.
5211
+ */
5212
+ isSessionStale(agentId: string, channel: string, chatId: string): boolean;
5213
+ /**
5214
+ * Build a summary of recent messages from OTHER sessions for the same agent today.
5215
+ * This bridges the cross-chat amnesia gap — if someone shared info in a DM,
5216
+ * the group session gets a hint about it.
5217
+ *
5218
+ * Gated by `message`: cross-chat hints are expensive (up to ~1.5K tokens of
5219
+ * unrelated conversation) AND cache-breaking (the content changes as other
5220
+ * chats get traffic, invalidating the prompt cache every turn). We only
5221
+ * return hints when the current message actually references another
5222
+ * conversation or a peer agent. Pass `message = ""` to force-include
5223
+ * (legacy behavior) — useful for testing.
5224
+ */
5225
+ getCrossSessionSummary(agentId: string, channel: string, chatId: string, message?: string): string;
5226
+ /**
5227
+ * Check if session history needs compaction and compact if so.
5228
+ * Call this after adding messages. Returns true if compaction was performed.
5229
+ */
5230
+ compactIfNeeded(agentId: string, channel: string, chatId: string, memoryStore?: MemoryStore): Promise<{
5231
+ compacted: boolean;
5232
+ qualityScore?: number;
5233
+ lostEntities?: string[];
5234
+ drift?: DriftReport;
5235
+ }>;
5236
+ /**
5237
+ * Check if current session already has a compacted summary.
5238
+ */
5239
+ hasCompaction(agentId: string, channel: string, chatId: string): boolean;
5240
+ /**
5241
+ * Clear the stored Claude session ID so next invocation starts fresh.
5242
+ * Also resets the per-session turn counter and last-turn input size —
5243
+ * those are only meaningful relative to the current claudeSessionId.
5244
+ */
5245
+ clearClaudeSessionId(agentId: string, channel: string, chatId: string): void;
5246
+ /**
5247
+ * Check whether this session has hit the max-turns cap. Rotate when true
5248
+ * to stop --resume replay from growing unbounded across a long chat.
5249
+ */
5250
+ shouldRotateByTurns(agentId: string, channel: string, chatId: string): boolean;
5251
+ /**
5252
+ * Check whether the LAST turn on this session pushed total input past
5253
+ * the tier-2 threshold. If yes, rotate so we don't pay the 1.5×
5254
+ * multiplier again on the next turn.
5255
+ */
5256
+ shouldRotateByTierTwo(agentId: string, channel: string, chatId: string): boolean;
5257
+ /**
5258
+ * Record a completed turn's token usage and bump the turn counter.
5259
+ * Called after a successful Claude response returns with usage info.
5260
+ */
5261
+ recordTurnUsage(agentId: string, channel: string, chatId: string, usage: {
5262
+ inputTokens: number;
5263
+ outputTokens: number;
5264
+ cacheReadTokens: number;
5265
+ cacheCreateTokens: number;
5266
+ }): void;
5267
+ /** Diagnostic getters — used by registry logging. */
5268
+ getTurnCount(agentId: string, channel: string, chatId: string): number;
5269
+ getLastTurnInputTokens(agentId: string, channel: string, chatId: string): number;
5270
+ getMaxTurnsPerSession(): number;
5271
+ getTierTwoThresholdTokens(): number;
5272
+ /**
5273
+ * Trim session to stay within limits.
5274
+ */
5275
+ private trim;
5276
+ private save;
5277
+ }
5278
+
4362
5279
  type WikiAccess = "private" | "shared" | "public";
4363
5280
  /**
4364
5281
  * Article type — the organizational spine. Matches Farzapedia's
@@ -5143,11 +6060,29 @@ declare const indexFileSchema: z.ZodObject<{
5143
6060
  type IndexFile = z.infer<typeof indexFileSchema>;
5144
6061
 
5145
6062
  /**
5146
- * Ships with the install. When .agentx/graph/schema.json is missing, the
5147
- * store seeds this so a fresh daemon has something to classify against.
6063
+ * Ships with the install. When .agentx/graph/schema.json is missing,
6064
+ * the store seeds this so a fresh daemon has something to classify
6065
+ * against.
6066
+ *
6067
+ * v2 — Phase 1 of the classifier-retire plan: verb-level intent
6068
+ * taxonomy. The classifier now answers ONLY "what kind of work is
6069
+ * this" — it does not embed client/project/agent in the leaf because
6070
+ * those already live on the event metadata (project, subject,
6071
+ * agentId). One copy of "review.merge-request" instead of one per
6072
+ * client.
5148
6073
  *
5149
- * Five levels, three primaries at the leaf (who / what / where) — matches
5150
- * the "primary colors per level" design from the plan.
6074
+ * Two levels:
6075
+ * category — broad work area (code/ops/support/admin/knowledge/social/system)
6076
+ * verb — specific intent (review.merge-request, deploy.staging, etc.)
6077
+ *
6078
+ * The category is closed-set; the verb is open-set so the operator
6079
+ * can add new ones via `agentx graph review` over time. Most paths
6080
+ * will reuse the seeded verbs below.
6081
+ *
6082
+ * Why so few levels: every level is information the classifier
6083
+ * actually has to decide. The previous v1 schema (scope > location >
6084
+ * org > unit > activity) re-encoded data already on the event —
6085
+ * forcing a 5-LLM-question prompt to recover what we already knew.
5151
6086
  */
5152
6087
  declare const STARTER_SCHEMA: GraphSchema;
5153
6088
 
@@ -5163,7 +6098,13 @@ declare class GraphStore {
5163
6098
  nodesPath(): string;
5164
6099
  indexPath(): string;
5165
6100
  classificationsPath(): string;
5166
- /** Load the graph schema, seeding STARTER_SCHEMA if the file is missing. */
6101
+ /** Load the graph schema, seeding STARTER_SCHEMA if the file is missing.
6102
+ * Phase 1 of the classifier-retire plan ships a v2 verb-level schema;
6103
+ * installs with the v1 hierarchical schema (scope > org > unit >
6104
+ * activity) get auto-migrated on next load: the v1 file is renamed
6105
+ * to schema.v1.bak.json, the v2 starter is written, and the
6106
+ * per-event nodes.json + classifications.jsonl are left alone for
6107
+ * historical reading. New events classify under v2 from then on. */
5167
6108
  loadSchema(): GraphSchema;
5168
6109
  saveSchema(schema: GraphSchema): void;
5169
6110
  loadNodes(): NodesFile;
@@ -5239,6 +6180,65 @@ declare class GraphStore {
5239
6180
  rejectClassification(c: Classification): void;
5240
6181
  }
5241
6182
 
6183
+ type MemoryType = "user" | "feedback" | "project" | "reference";
6184
+ interface MemoryRecord {
6185
+ /** Slug-safe name, unique within an agent. */
6186
+ name: string;
6187
+ type: MemoryType;
6188
+ /** One-line hook — used as the MEMORY.md index entry. */
6189
+ description: string;
6190
+ /** The body, excluding frontmatter. */
6191
+ body: string;
6192
+ createdAt: string;
6193
+ updatedAt: string;
6194
+ }
6195
+ interface AgentMemoryOptions {
6196
+ baseDir?: string;
6197
+ }
6198
+ declare class AgentMemory {
6199
+ readonly baseDir: string;
6200
+ constructor(opts?: AgentMemoryOptions);
6201
+ private dirFor;
6202
+ private fileFor;
6203
+ private indexPath;
6204
+ /** Save (create or update) a memory. Keeps createdAt stable across
6205
+ * updates; bumps updatedAt. Always rewrites MEMORY.md. */
6206
+ save(args: {
6207
+ agentId: string;
6208
+ type: MemoryType;
6209
+ name: string;
6210
+ description: string;
6211
+ body: string;
6212
+ }): MemoryRecord;
6213
+ get(agentId: string, name: string): MemoryRecord | null;
6214
+ /** Every memory for an agent. Sorted by type then name for stable
6215
+ * index rendering. */
6216
+ list(agentId: string): MemoryRecord[];
6217
+ /** Remove a memory by name. Returns true on success, false if none found. */
6218
+ remove(agentId: string, name: string): boolean;
6219
+ /** The content of MEMORY.md — used at prompt-build time to inline into
6220
+ * the agent's system prompt. Returns "" when the agent has no
6221
+ * memories (so the prompt builder can no-op). */
6222
+ indexMarkdown(agentId: string): string;
6223
+ /** Push the agent's memory into its workspace so Claude Code sessions
6224
+ * pick it up automatically. Does two things:
6225
+ *
6226
+ * 1. Writes `<workspace>/.agentx-memory.md` — full MEMORY.md content,
6227
+ * explicit file the skill can `Read` at session start.
6228
+ * 2. Merges that same content into `<workspace>/CLAUDE.md` between
6229
+ * sentinel comments so Claude Code auto-loads it into the cached
6230
+ * system context on every session. Idempotent: subsequent syncs
6231
+ * replace the sentinel block.
6232
+ *
6233
+ * Never touches content outside the sentinel block — if the file
6234
+ * doesn't exist, creates it with just the sentinels. Safe to call
6235
+ * on any save / delete. */
6236
+ syncToWorkspace(agentId: string, workspacePath: string): void;
6237
+ /** Regenerate MEMORY.md from the on-disk files. Called automatically
6238
+ * after every save / remove; safe to call manually. */
6239
+ rewriteIndex(agentId: string): void;
6240
+ }
6241
+
5242
6242
  interface MeshPeerInfo {
5243
6243
  peer: string;
5244
6244
  healthy: boolean;
@@ -5331,6 +6331,12 @@ declare class AgentRegistry {
5331
6331
  private sessions;
5332
6332
  private wikiHub;
5333
6333
  private memoryStore;
6334
+ /** Structured per-agent memory (Claude-Code-style: user / feedback /
6335
+ * project / reference). Separate from the BM25 fact store above —
6336
+ * that's for short-lived facts extracted from conversations; this is
6337
+ * for long-lived behavioural memory that inlines into the system
6338
+ * prompt on every task. */
6339
+ readonly agentMemory: AgentMemory;
5334
6340
  private patternStore;
5335
6341
  private rateLimiter;
5336
6342
  private tokenTracker;
@@ -5353,6 +6359,11 @@ declare class AgentRegistry {
5353
6359
  private lastSummaries;
5354
6360
  /** 24-hour sparkline cache per agent — recomputed from disk at most once a minute. */
5355
6361
  private sparklineCache;
6362
+ /** Per-workspace references registry cache. Loaded lazily on first turn for
6363
+ * agents with `contextReferences: true`; reused for the daemon's lifetime
6364
+ * (operator-edited registries take effect on next daemon restart — same
6365
+ * policy as agentx.json). */
6366
+ private referencesCache;
5356
6367
  private log;
5357
6368
  constructor(config: DaemonConfig, log?: (...args: unknown[]) => void);
5358
6369
  /**
@@ -5406,6 +6417,21 @@ declare class AgentRegistry {
5406
6417
  /** Wiki hub accessor. */
5407
6418
  getWikiHub(): WikiHub;
5408
6419
  getGraphStore(): GraphStore | undefined;
6420
+ /** Session-store accessor — used by the /recall HTTP endpoint to expose
6421
+ * conversation history to agents that need to rebuild context. */
6422
+ getSessionStore(): SessionStore;
6423
+ /** Fire-and-forget pre-rotation memo capture. Spawns a one-shot Haiku
6424
+ * call against the about-to-be-dropped Claude session asking for the
6425
+ * facts/decisions worth carrying forward, persists the result into
6426
+ * MemoryStore. Runs asynchronously so the calling rotation path
6427
+ * doesn't pay the extraction latency — the next user turn dispatches
6428
+ * immediately on the fresh session, and the memo lands in time for
6429
+ * whichever turn arrives ~30s later (which is when atlas's bloated-
6430
+ * session WhatsApp conversations actually need it).
6431
+ *
6432
+ * Errors are swallowed by design — memory continuity is best-effort,
6433
+ * it must never block or break the rotation it's hooked into. */
6434
+ private captureRotationMemoAsync;
5409
6435
  /**
5410
6436
  * Build peer list for context engine.
5411
6437
  */
@@ -5416,11 +6442,27 @@ declare class AgentRegistry {
5416
6442
  private getChannelHandle;
5417
6443
  /**
5418
6444
  * Execute a task on an agent. Respects maxConcurrent limit.
6445
+ *
6446
+ * Wraps `executeInternal` to record an intent-ledger resolution
6447
+ * after completion when `task.intentRef` is set. The resolution
6448
+ * write clears the dispatched-but-unresolved slot in
6449
+ * `intent_decisions` so Inv-ActiveTaskSafety lookups stop blocking
6450
+ * subsequent dispatches to the same (project, subject). Without
6451
+ * this, every dispatched decision sits in-flight forever and the
6452
+ * active-task check becomes vacuously over-aggressive.
5419
6453
  */
5420
6454
  execute(task: AgentTask, onDelta?: StreamCallback): Promise<AgentResponse>;
6455
+ /**
6456
+ * Internal dispatcher — the real body. See `execute` for the public
6457
+ * wrapper that adds intent-ledger resolution recording.
6458
+ */
6459
+ private executeInternal;
5421
6460
  /**
5422
6461
  * List all agents and their status.
5423
6462
  */
6463
+ /** Total active task count across all agents — used by the daemon's
6464
+ * graceful shutdown to drain in-flight runs before exit. */
6465
+ getActiveTaskCount(): number;
5424
6466
  list(): Array<{
5425
6467
  id: string;
5426
6468
  name: string;
@@ -5525,94 +6567,6 @@ declare class AgentRegistry {
5525
6567
  getTokenTracker(): TokenTracker;
5526
6568
  }
5527
6569
 
5528
- /**
5529
- * Verified channel context — facts the channel adapter knows for certain.
5530
- * Prevents agents from hallucinating about their environment.
5531
- */
5532
- interface ChannelMeta {
5533
- /** Channel name */
5534
- channel: string;
5535
- /** Verified agents/bots present in this chat/group/project */
5536
- agents?: Array<{
5537
- id: string;
5538
- name: string;
5539
- handle?: string;
5540
- }>;
5541
- /** Project path (GitLab) or group topic */
5542
- project?: string;
5543
- /** Issue/MR context (GitLab) */
5544
- issue?: {
5545
- type: string;
5546
- iid: string;
5547
- title: string;
5548
- };
5549
- /** Channel-specific facts (e.g., pipeline status, group description) */
5550
- facts?: string[];
5551
- }
5552
- interface IncomingMessage {
5553
- id: string;
5554
- channel: string;
5555
- accountId: string;
5556
- sender: {
5557
- id: string;
5558
- name: string;
5559
- username?: string;
5560
- /** True when the origin is another bot account (Telegram `from.is_bot`).
5561
- * Used by the router to apply strict @-mention-only routing — prevents
5562
- * cross-daemon cascades from bare-word matches in bot replies. */
5563
- isBot?: boolean;
5564
- };
5565
- group?: {
5566
- id: string;
5567
- name: string;
5568
- };
5569
- text: string;
5570
- replyTo?: string;
5571
- replyToText?: string;
5572
- timestamp: Date;
5573
- media?: {
5574
- path: string;
5575
- type: string;
5576
- fileName?: string;
5577
- };
5578
- raw?: unknown;
5579
- resolvedAgent?: string;
5580
- preferNode?: string;
5581
- channelMeta?: ChannelMeta;
5582
- /** Correlator threaded by the workflow engine. When a workflow dispatches
5583
- * an agent, this carries the run id through the pipeline so post:response
5584
- * can re-enter the engine with `kind: agentResult` transitions. Opaque
5585
- * everywhere outside src/workflows/. */
5586
- workflowRunId?: string;
5587
- }
5588
- interface OutgoingMessage {
5589
- channel: string;
5590
- chatId: string;
5591
- text: string;
5592
- replyTo?: string;
5593
- parseMode?: "markdown" | "html" | "plain";
5594
- agentId?: string;
5595
- }
5596
- interface ChannelAdapter {
5597
- readonly name: string;
5598
- /** Start polling or webhook listener */
5599
- start(): Promise<void>;
5600
- /** Stop the adapter gracefully */
5601
- stop(): Promise<void>;
5602
- /** Send a message back to a chat */
5603
- send(msg: OutgoingMessage): Promise<string | void>;
5604
- /** Edit an existing message (returns false if not supported) */
5605
- editMessage?(chatId: string, messageId: string, text: string, parseMode?: string): Promise<boolean>;
5606
- /** Send typing/action indicator */
5607
- sendTyping?(chatId: string): Promise<void>;
5608
- /** React to a message with an emoji (e.g., 👀 for seen) */
5609
- react?(chatId: string, messageId: string, emoji?: string): Promise<void>;
5610
- /** Register handler for incoming messages */
5611
- onMessage(handler: (msg: IncomingMessage) => Promise<void>): void;
5612
- /** Get verified context for a chat (optional — channels implement what they can) */
5613
- getChannelMeta?(chatId: string): Promise<ChannelMeta | undefined>;
5614
- }
5615
-
5616
6570
  interface HandoverOverride {
5617
6571
  channel: string;
5618
6572
  chatId: string;
@@ -5935,12 +6889,76 @@ declare const businessConfigSchema: z.ZodObject<{
5935
6889
  reportsTo?: string | undefined;
5936
6890
  utilizationTarget?: number | undefined;
5937
6891
  }>>>;
6892
+ /** Per-project metadata. Phase 3 — defaults to empty array, so
6893
+ * existing agentx.json files validate without modification. */
6894
+ projects: z.ZodDefault<z.ZodArray<z.ZodObject<{
6895
+ /** Project identifier. For GitLab/GitHub: "owner/repo". For
6896
+ * noqta-internal projects: a stable string. */
6897
+ id: z.ZodString;
6898
+ /** AgentId of the PM for this project. Looked up by
6899
+ * `Organization.pmFor(project)` at dispatch time. */
6900
+ pm: z.ZodOptional<z.ZodString>;
6901
+ /** Optional client this project belongs to. Used by the activity
6902
+ * graph to attribute non-projected events (Telegram chats, free-
6903
+ * text WhatsApp, cron jobs) to the right client. Falls back to
6904
+ * the leading segment of `id` (split on "/") when unset. */
6905
+ client: z.ZodOptional<z.ZodString>;
6906
+ }, "strip", z.ZodTypeAny, {
6907
+ id: string;
6908
+ pm?: string | undefined;
6909
+ client?: string | undefined;
6910
+ }, {
6911
+ id: string;
6912
+ pm?: string | undefined;
6913
+ client?: string | undefined;
6914
+ }>, "many">>;
6915
+ /** Maps free-text chat senders to a client/project so the activity
6916
+ * graph can attribute Telegram/WhatsApp/etc. to the right client
6917
+ * instead of the catch-all "internal" bucket. */
6918
+ contactMap: z.ZodDefault<z.ZodArray<z.ZodObject<{
6919
+ /** Channel kind, e.g. "telegram", "whatsapp", "slack", "discord". */
6920
+ channel: z.ZodOptional<z.ZodString>;
6921
+ /** Native chat id ("-100..." for tg groups, JID for WhatsApp). */
6922
+ chatId: z.ZodOptional<z.ZodString>;
6923
+ /** Sender username/handle as exposed by the channel adapter. */
6924
+ username: z.ZodOptional<z.ZodString>;
6925
+ /** Numeric sender id when username is unstable. */
6926
+ senderId: z.ZodOptional<z.ZodString>;
6927
+ /** Client this contact belongs to. Required. */
6928
+ client: z.ZodString;
6929
+ /** Project this contact's traffic should attribute to. Defaults to
6930
+ * `${client}/_chat`. */
6931
+ project: z.ZodOptional<z.ZodString>;
6932
+ /** Display name override for the initiator pill. */
6933
+ displayName: z.ZodOptional<z.ZodString>;
6934
+ }, "strip", z.ZodTypeAny, {
6935
+ client: string;
6936
+ channel?: string | undefined;
6937
+ chatId?: string | undefined;
6938
+ username?: string | undefined;
6939
+ senderId?: string | undefined;
6940
+ project?: string | undefined;
6941
+ displayName?: string | undefined;
6942
+ }, {
6943
+ client: string;
6944
+ channel?: string | undefined;
6945
+ chatId?: string | undefined;
6946
+ username?: string | undefined;
6947
+ senderId?: string | undefined;
6948
+ project?: string | undefined;
6949
+ displayName?: string | undefined;
6950
+ }>, "many">>;
5938
6951
  /** Work-tick cadence in minutes during business hours. Default 15. */
5939
6952
  workTickMinutes: z.ZodDefault<z.ZodNumber>;
5940
6953
  /** Max queue depth for an idle agent before skipping the work tick (avoids piling up). */
5941
6954
  idleQueueThreshold: z.ZodDefault<z.ZodNumber>;
5942
6955
  }, "strip", z.ZodTypeAny, {
5943
6956
  enabled: boolean;
6957
+ projects: {
6958
+ id: string;
6959
+ pm?: string | undefined;
6960
+ client?: string | undefined;
6961
+ }[];
5944
6962
  timezone: string;
5945
6963
  mainChannel: {
5946
6964
  channel: string;
@@ -5978,6 +6996,15 @@ declare const businessConfigSchema: z.ZodObject<{
5978
6996
  utilizationTarget: number;
5979
6997
  reportsTo?: string | undefined;
5980
6998
  }>;
6999
+ contactMap: {
7000
+ client: string;
7001
+ channel?: string | undefined;
7002
+ chatId?: string | undefined;
7003
+ username?: string | undefined;
7004
+ senderId?: string | undefined;
7005
+ project?: string | undefined;
7006
+ displayName?: string | undefined;
7007
+ }[];
5981
7008
  workTickMinutes: number;
5982
7009
  idleQueueThreshold: number;
5983
7010
  }, {
@@ -5998,6 +7025,11 @@ declare const businessConfigSchema: z.ZodObject<{
5998
7025
  glob?: string | undefined;
5999
7026
  };
6000
7027
  enabled?: boolean | undefined;
7028
+ projects?: {
7029
+ id: string;
7030
+ pm?: string | undefined;
7031
+ client?: string | undefined;
7032
+ }[] | undefined;
6001
7033
  timezone?: string | undefined;
6002
7034
  roles?: Record<string, {
6003
7035
  title: string;
@@ -6019,6 +7051,15 @@ declare const businessConfigSchema: z.ZodObject<{
6019
7051
  reportsTo?: string | undefined;
6020
7052
  utilizationTarget?: number | undefined;
6021
7053
  }> | undefined;
7054
+ contactMap?: {
7055
+ client: string;
7056
+ channel?: string | undefined;
7057
+ chatId?: string | undefined;
7058
+ username?: string | undefined;
7059
+ senderId?: string | undefined;
7060
+ project?: string | undefined;
7061
+ displayName?: string | undefined;
7062
+ }[] | undefined;
6022
7063
  workTickMinutes?: number | undefined;
6023
7064
  idleQueueThreshold?: number | undefined;
6024
7065
  }>;
@@ -6036,6 +7077,7 @@ interface EmployeeProfile {
6036
7077
  }
6037
7078
  declare class Organization {
6038
7079
  private employees;
7080
+ private projects;
6039
7081
  constructor(config: BusinessConfig);
6040
7082
  get(agentId: string): EmployeeProfile | undefined;
6041
7083
  all(): EmployeeProfile[];
@@ -6043,6 +7085,43 @@ declare class Organization {
6043
7085
  directReports(agentId: string): string[];
6044
7086
  /** Walk up the org tree to the root. First element is `agentId` itself. */
6045
7087
  chainOfCommand(agentId: string): string[];
7088
+ /**
7089
+ * Phase 3 — PM lookup. Returns the agentId of the PM responsible
7090
+ * for `project`, or `undefined` when no PM is configured. The
7091
+ * dispatcher's PM gate (in a future commit) calls this before
7092
+ * dispatching to make sure project-scoped events flow through the
7093
+ * PM first. When undefined, dispatches proceed without a PM gate
7094
+ * (the legacy direct-routing behavior).
7095
+ */
7096
+ pmFor(project: string | null | undefined): string | undefined;
7097
+ /**
7098
+ * Phase 3 — escalation chain. Returns agents to escalate to in
7099
+ * upward order, EXCLUDING the agent itself. `chainOfCommand`
7100
+ * includes self at index 0; escalationChain skips that.
7101
+ *
7102
+ * Used when an agent fails / declines / times out — the dispatcher
7103
+ * walks up the chain looking for someone to take over.
7104
+ */
7105
+ escalationChain(agentId: string): string[];
7106
+ /**
7107
+ * Phase 3 — capability check (scaffold). Returns true when:
7108
+ * - The org chart is empty (`employees.size === 0`) — this is the
7109
+ * permissive default for partially-configured `business` blocks
7110
+ * that populate `projects[].pm` for the PM gate but haven't
7111
+ * filled in `orgChart`. Without this fallback, enabling business
7112
+ * with an empty orgChart would block every dispatch.
7113
+ * - OR the agent is registered in the org chart.
7114
+ *
7115
+ * Per-project / per-intent restrictions need typed capabilities
7116
+ * (Phase 5); until then this is a permissive-when-unconfigured
7117
+ * default that matches the legacy any-registered-agent-can-handle-
7118
+ * anything behavior.
7119
+ *
7120
+ * The `decideAndCommit` PM gate will call this *after* the PM
7121
+ * approves — the PM provides the project-scoped check, this
7122
+ * provides the agent-existence check.
7123
+ */
7124
+ canHandle(agentId: string, _project: string | null | undefined, _intent: string | null | undefined): boolean;
6046
7125
  }
6047
7126
 
6048
7127
  declare class Schedule {
@@ -6065,8 +7144,11 @@ interface WorkItem {
6065
7144
  estimatedSeconds?: number;
6066
7145
  url?: string;
6067
7146
  priority?: number;
6068
- /** Board stage derived from labels (kanban column id). */
6069
- stage?: "triage" | "todo" | "doing" | "onhold" | "review" | "done";
7147
+ /** Board stage / kanban column id. Was a closed enum back when boards
7148
+ * had a fixed schema; widened to `string` because per-project boards
7149
+ * can declare arbitrary column ids. The well-known names below remain
7150
+ * the standard set most boards use. */
7151
+ stage?: string;
6070
7152
  /** Raw labels from the source (GitLab). Empty array if source doesn't support labels. */
6071
7153
  labels?: string[];
6072
7154
  /** Label name+color when the source returns colored labels (GitLab with_labels_details). */
@@ -6289,6 +7371,13 @@ declare class MessageRouter {
6289
7371
  private dedupSaveTimer?;
6290
7372
  /** Crash-safe inflight log (see InflightLog class above). */
6291
7373
  private inflight;
7374
+ /** In-flight mesh forwards (this node is awaiting a peer's response).
7375
+ * Counted so the daemon's shutdown drain can wait for these in addition
7376
+ * to local agent tasks — otherwise a clawd restart mid-forward kills the
7377
+ * awaiter, the peer's response lands on a dead connection, and the
7378
+ * inflight-replay re-runs the task on the peer. */
7379
+ private activeMeshForwards;
7380
+ getActiveMeshForwardCount(): number;
6292
7381
  constructor(registry: AgentRegistry, config: DaemonConfig, hooks?: HookRegistry, log?: (...args: unknown[]) => void);
6293
7382
  private loadDedupFromDisk;
6294
7383
  private scheduleDedupSave;
@@ -6335,6 +7424,23 @@ declare class MessageRouter {
6335
7424
  * Stamps the key when false. Size-bounded GC avoids unbounded growth.
6336
7425
  */
6337
7426
  private isDuplicateMessage;
7427
+ /**
7428
+ * Phase 1 commit 6.b — record one router decision in the intent ledger
7429
+ * when the source is enabled (mode != "off"). Covers all router
7430
+ * channels (telegram, slack, whatsapp, discord). Each channel has its
7431
+ * own per-source mode flag so they can be promoted independently in 1c.
7432
+ * Wrapped in try/catch so a ledger failure can never break message
7433
+ * routing — legacy is still authoritative until the 1c per-source
7434
+ * promotion.
7435
+ *
7436
+ * Returns the recorded decision when ledger fired (and outcome was
7437
+ * "dispatched"), so the caller can tag the IncomingMessage with
7438
+ * `intentRef` for resolution-on-completion. Returns undefined when
7439
+ * the source is off, the channel isn't supported, ledger threw, or
7440
+ * the ledger's own decision was non-dispatched (deduped/halted —
7441
+ * no resolution to write).
7442
+ */
7443
+ private recordRouterDecisionInLedger;
6338
7444
  private handleMessage;
6339
7445
  /** The actual processing body — split out so handleMessage can wrap it in
6340
7446
  * the inflight try/finally without drowning the happy path in indentation. */
@@ -6352,10 +7458,21 @@ declare class MessageRouter {
6352
7458
  private adapterEdit;
6353
7459
  private adapterReact;
6354
7460
  private startTypingLoop;
7461
+ private traceRoute;
7462
+ private runRoutingPipeline;
6355
7463
  /**
6356
7464
  * Handle a message by routing to a mesh peer's agent.
6357
7465
  * Searches peer agent cards for mention matches.
6358
7466
  */
7467
+ /** Build the context payload that mesh.sendTask forwards to the receiving
7468
+ * daemon's /task handler. Without this, the receiver runs registry.execute
7469
+ * with default channel="api"/chatId="default" — losing the channel,
7470
+ * project, issue id, sender, and channelMeta the original adapter built
7471
+ * from the inbound webhook. Shape matches what processResolvedMessage
7472
+ * already passes to registry.execute on the local path, so a mesh-routed
7473
+ * task and a locally-routed task produce the same session keying and
7474
+ * the same prompt context. */
7475
+ private buildMeshContext;
6359
7476
  private handleViaMesh;
6360
7477
  /**
6361
7478
  * Route to a mesh peer by resolved agentId (not text matching).
@@ -6368,6 +7485,10 @@ declare class MessageRouter {
6368
7485
  */
6369
7486
  private handleViaMeshByPeer;
6370
7487
  private getAccountForAgent;
7488
+ /** @deprecated Phase 2 — resolveAgent now delegates to the pipeline.
7489
+ * Kept as a thin wrapper for callers that only need the agentId; new
7490
+ * code should call runRoutingPipeline() to get the full PipelineResult
7491
+ * (deciding stage, drop reason, per-stage trace). */
6371
7492
  private resolveAgent;
6372
7493
  }
6373
7494
 
@@ -6381,7 +7502,7 @@ interface TelegramAccountConfig {
6381
7502
  declare class TelegramAdapter implements ChannelAdapter {
6382
7503
  readonly name = "telegram";
6383
7504
  private accounts;
6384
- private offsetStore;
7505
+ private cursors;
6385
7506
  private handler?;
6386
7507
  private polling;
6387
7508
  /** Per-account polling gate — flipped to false when an account is removed
@@ -6449,6 +7570,12 @@ declare class TelegramAdapter implements ChannelAdapter {
6449
7570
  private chatAccountMap;
6450
7571
  private botInfo;
6451
7572
  private groupStore;
7573
+ /** Account IDs of bots currently active (member/administrator) in a group.
7574
+ * Used by the router to pick the correct bot when an agent has multiple
7575
+ * Telegram accounts bound to it (e.g. pm-ksi → both @noqta_ksi_bot and
7576
+ * @noqta_pm_ksi_bot) — the in-group account should win, otherwise messages
7577
+ * to the absent bot get silently dropped by multi-account-dedup. */
7578
+ getGroupBotAccounts(groupId: string): string[];
6452
7579
  /**
6453
7580
  * Send a message. Returns the sent message ID.
6454
7581
  * Pass accountId to send from a specific bot account.
@@ -6456,6 +7583,12 @@ declare class TelegramAdapter implements ChannelAdapter {
6456
7583
  send(msg: OutgoingMessage & {
6457
7584
  accountId?: string;
6458
7585
  }): Promise<string>;
7586
+ /** Best-effort outbound shadow log. Captures every successful send into
7587
+ * the same per-chat shadow file the inbound writer uses, so seedHistory
7588
+ * + agent introspection see a complete picture (which bot identity sent
7589
+ * what, at which time). Failures are swallowed — the message already
7590
+ * went out on the wire; logging is observability, not correctness. */
7591
+ private recordOutboundShadow;
6459
7592
  /**
6460
7593
  * Send a message with an inline keyboard. Used by the workflow user-task
6461
7594
  * renderer so approve/reject-style tasks get one-tap URL buttons in
@@ -6527,6 +7660,26 @@ declare class TelegramAdapter implements ChannelAdapter {
6527
7660
  * Called once per group on first encounter, then maintained via my_chat_member events.
6528
7661
  */
6529
7662
  private seedGroupMembership;
7663
+ /** Append one entry to the shadow log for `chatId`. The shadow log is a
7664
+ * daily file at `.agentx/sessions/_telegram_raw:{chatId}:{day}.json` that
7665
+ * captures every allowed inbound (and adapter-side outbound) message
7666
+ * regardless of how the router resolved it — including periods when no
7667
+ * agent was bound or the daemon was offline (the next inbound triggers
7668
+ * a write). seedHistory reads it back on cold session create so a fresh
7669
+ * session mirrors the live chat instead of starting blank. */
7670
+ private appendShadowLog;
7671
+ private shadowLogPath;
7672
+ /** ChannelAdapter.seedHistory: returns the most recent shadow-logged
7673
+ * messages for `chatId`, walking back day-by-day until we hit
7674
+ * `maxMessages` or `maxChars`. Telegram's Bot API has no "fetch chat
7675
+ * history" endpoint, so the shadow log is our only source — meaning the
7676
+ * first deployment sees an empty seed for any pre-existing chat, and
7677
+ * context grows as the bot observes new traffic. */
7678
+ seedHistory(chatId: string, opts: {
7679
+ sinceISO?: string;
7680
+ maxMessages: number;
7681
+ maxChars: number;
7682
+ }): Promise<SeededMessage[]>;
6530
7683
  private apiCall;
6531
7684
  }
6532
7685
 
@@ -6705,6 +7858,16 @@ declare class WhatsAppAdapter implements ChannelAdapter {
6705
7858
  limit?: number;
6706
7859
  before?: string;
6707
7860
  }): Promise<HistoryMessage[]>;
7861
+ /** ChannelAdapter.seedHistory: thin wrapper over getHistory() that maps
7862
+ * Baileys' HistoryMessage shape to the channel-agnostic SeededMessage
7863
+ * shape consumed by SessionStore on cold session create. Bounded by the
7864
+ * caller's maxMessages/maxChars; fromMe → role:agent. The chatId is the
7865
+ * Baileys jid (e.g., "21694xxx@s.whatsapp.net" for DMs). */
7866
+ seedHistory(chatId: string, opts: {
7867
+ sinceISO?: string;
7868
+ maxMessages: number;
7869
+ maxChars: number;
7870
+ }): Promise<SeededMessage[]>;
6708
7871
  /** Token-bucket gate for live Baileys reads. Enforces
6709
7872
  * `throttleMinMs` between calls and caps the per-minute call count.
6710
7873
  * Returns a promise that resolves once it's safe to fire. */
@@ -6771,6 +7934,13 @@ declare class CronScheduler {
6771
7934
  stop(): Promise<void>;
6772
7935
  private scheduleNext;
6773
7936
  private scheduleRetry;
7937
+ /**
7938
+ * Phase 1 commit 6.d — record one cron-fire decision in the ledger
7939
+ * when the source is enabled. Wrapped in try/catch so a ledger
7940
+ * failure can never break cron dispatch — legacy stays authoritative
7941
+ * until the 1c per-source promotion lands.
7942
+ */
7943
+ private recordCronDecisionInLedger;
6774
7944
  private executeJob;
6775
7945
  /**
6776
7946
  * Detect cron jobs that should have fired while the daemon was down.
@@ -6869,4 +8039,4 @@ declare function handleError(error: unknown): void;
6869
8039
  */
6870
8040
  declare function getPackageInfo(): PackageJson;
6871
8041
 
6872
- export { A2AClient, A2AMesh, A2AServer, A2AServerConfig, ALL_TOOL_NAMES, AgentCard, AgentConfig, AgentContext, AgentDef, AgentProvider, AgentRegistry, AgentResponse, AgentTask, AgentXDaemon, AgentXRuntime, AnthropicMessage, AuthConfig, AxisDef, AxisType, BLOCKING_EVENTS, ChannelAdapter, Classification, ClassificationSource, ClassificationStatus, ClaudeCodeProvider, ClaudeProvider, ContentBlock, ContextBuilder, CronJobDef, CronJobState, CronRunResult, CronScheduler, DaemonConfig, EnhanceConfig, EnhanceEngine, EnhanceResult, FingerprintEntry, GenerateOptions, GenerateResult, GenerateStreamEvent, GeneratedFile, GenerationMessage, GenerationResult, GitCommitResult, GitDiffFile, GitLogEntry, GitManager, GitStatus, GraphNode, GraphSchema, GraphStore, GraphStoreOptions, HOOK_EVENTS, HealConfig, HealEngine, HealResult, HookContext, HookDefinition, HookEvent, HookHandler, HookRegistry, HookResult, IncomingMessage, IndexFile, LevelDef, Memory, MemoryEntry, MemoryHierarchy, MemoryStore, MeshPeer, MessageRouter, MiddlewareFn, ModelUsage, NodesFile, OUTPUT_CONFIGS, OUTPUT_TYPES, OutgoingMessage, OutputConfig, OutputType, PERMISSION_MODES, PROVIDER_CAPABILITIES, PermissionAction, PermissionConfig, PermissionManager, PermissionMode, PermissionRule, Pipeline, PipelineRequest, PipelineResponse, ProjectSchemas, ProviderCapabilities, ProviderName, ProviderOptions, RawGenerationResult, ReplEngine, ReplOptions, RuntimeConfig, STARTER_SCHEMA, Session, StepUsage, StreamEvent, Task, TaskArtifact, TaskMessage, TaskState, TaskStatusUpdate, TechStack, TelegramAdapter, ToolCallInput, ToolExecutor, ToolExecutorOptions, ToolResult, UsageSummary, UsageTracker, WhatsAppAdapter, WikiAccess, WikiArticle, WikiArticleMeta, WikiEntry, WikiIndex, WikiStore, agentConfigSchema$1 as agentConfigSchema, checkCapabilities, createAgentContext, createProvider, createSession, daemonConfigSchema, debug, detectSchemas, detectTechStack, ensureCredentials, executeClaudeCode, executeOrchestrator, executeSdk, executeTask, exportSession, formatSchemas, formatTechStack, formatToolsForSystemPrompt, gatherContext7Docs, generate, generateSkill, generateSkillMd, generateStream, getAnthropicTools, getCommand, getLegacyTools, getPackageInfo, globalHooks, globalPermissions, globalTracker, handleError, installSkillPackage, isCommand, isDebug, listInstalledSkills, listSessions, loadAuthConfig, loadDaemonConfig, loadHooks, loadLatestSession, loadLocalSkills, loadProjectInstructions, loadSession, logger, matchSkillsToTask, outputTypeDescriptions, parseCommand, parseSkillContent, parseSkillFile, permissionConfigSchema, permissionModeSchema, registerCommand, resolveAtImports, resolveOutputType, resolveToken, runModelSetup, saveAuthConfig, saveSession, setDebug, startMcpServer, validateWorkspaces };
8042
+ export { A2AClient, A2AMesh, A2AServer, A2AServerConfig, ALL_TOOL_NAMES, AgentCard, AgentConfig, AgentContext, AgentDef, AgentProvider, AgentRegistry, AgentResponse, AgentTask, AgentXDaemon, AgentXRuntime, AnthropicMessage, AuthConfig, AxisDef, AxisType, BLOCKING_EVENTS, ChannelAdapter, Classification, ClassificationSource, ClassificationStatus, ClaudeCodeProvider, ClaudeProvider, ContentBlock, ContextBuilder, CronJobDef, CronJobState, CronRunResult, CronScheduler, DaemonConfig, EnhanceConfig, EnhanceEngine, EnhanceResult, FingerprintEntry, GenerateOptions, GenerateResult, GenerateStreamEvent, GeneratedFile, GenerationMessage, GenerationResult, GitCommitResult, GitDiffFile, GitLogEntry, GitManager, GitStatus, GraphNode, GraphSchema, GraphStore, GraphStoreOptions, HOOK_EVENTS, HealConfig, HealEngine, HealResult, HookContext, HookDefinition, HookEvent, HookHandler, HookRegistry, HookResult, IncomingMessage, IndexFile, LevelDef, Memory, MemoryEntry, MemoryHierarchy, MemoryStore$1 as MemoryStore, MeshPeer, MessageRouter, MiddlewareFn, ModelUsage, NodesFile, OUTPUT_CONFIGS, OUTPUT_TYPES, OutgoingMessage, OutputConfig, OutputType, PERMISSION_MODES, PROVIDER_CAPABILITIES, PermissionAction, PermissionConfig, PermissionManager, PermissionMode, PermissionRule, Pipeline, PipelineRequest, PipelineResponse, ProjectSchemas, ProviderCapabilities, ProviderName, ProviderOptions, RawGenerationResult, ReplEngine, ReplOptions, RuntimeConfig, STARTER_SCHEMA, Session$1 as Session, StepUsage, StreamEvent, Task, TaskArtifact, TaskMessage, TaskState, TaskStatusUpdate, TechStack, TelegramAdapter, ToolCallInput, ToolExecutor, ToolExecutorOptions, ToolResult, UsageSummary, UsageTracker, WhatsAppAdapter, WikiAccess, WikiArticle, WikiArticleMeta, WikiEntry, WikiIndex, WikiStore, agentConfigSchema$1 as agentConfigSchema, checkCapabilities, createAgentContext, createProvider, createSession, daemonConfigSchema, debug, detectSchemas, detectTechStack, ensureCredentials, executeClaudeCode, executeOrchestrator, executeSdk, executeTask, exportSession, formatSchemas, formatTechStack, formatToolsForSystemPrompt, gatherContext7Docs, generate, generateSkill, generateSkillMd, generateStream, getAnthropicTools, getCommand, getLegacyTools, getPackageInfo, globalHooks, globalPermissions, globalTracker, handleError, installSkillPackage, isCommand, isDebug, listInstalledSkills, listSessions, loadAuthConfig, loadDaemonConfig, loadHooks, loadLatestSession, loadLocalSkills, loadProjectInstructions, loadSession, logger, matchSkillsToTask, outputTypeDescriptions, parseCommand, parseSkillContent, parseSkillFile, permissionConfigSchema, permissionModeSchema, registerCommand, resolveAtImports, resolveOutputType, resolveToken, runModelSetup, saveAuthConfig, saveSession, setDebug, startMcpServer, validateWorkspaces };