@askexenow/exe-os 0.9.93 → 0.9.94

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 (88) hide show
  1. package/deploy/compose/docker-compose.yml +1 -0
  2. package/dist/bin/agentic-ontology-backfill.js +65 -8
  3. package/dist/bin/agentic-reflection-backfill.js +54 -3
  4. package/dist/bin/agentic-semantic-label.js +54 -3
  5. package/dist/bin/backfill-conversations.js +69 -9
  6. package/dist/bin/backfill-responses.js +69 -9
  7. package/dist/bin/backfill-vectors.js +54 -3
  8. package/dist/bin/bulk-sync-postgres.js +66 -8
  9. package/dist/bin/cleanup-stale-review-tasks.js +118 -13
  10. package/dist/bin/cli.js +1558 -466
  11. package/dist/bin/customer-readiness.js +51 -0
  12. package/dist/bin/exe-agent.js +17 -3
  13. package/dist/bin/exe-assign.js +75 -9
  14. package/dist/bin/exe-boot.js +111 -12
  15. package/dist/bin/exe-call.js +17 -3
  16. package/dist/bin/exe-cloud.js +76 -10
  17. package/dist/bin/exe-dispatch.js +133 -18
  18. package/dist/bin/exe-doctor.js +75 -9
  19. package/dist/bin/exe-export-behaviors.js +75 -9
  20. package/dist/bin/exe-forget.js +94 -9
  21. package/dist/bin/exe-gateway.js +132 -18
  22. package/dist/bin/exe-heartbeat.js +118 -13
  23. package/dist/bin/exe-kill.js +75 -9
  24. package/dist/bin/exe-launch-agent.js +75 -9
  25. package/dist/bin/exe-new-employee.js +18 -4
  26. package/dist/bin/exe-pending-messages.js +118 -13
  27. package/dist/bin/exe-pending-notifications.js +118 -13
  28. package/dist/bin/exe-pending-reviews.js +118 -13
  29. package/dist/bin/exe-rename.js +75 -9
  30. package/dist/bin/exe-review.js +75 -9
  31. package/dist/bin/exe-search.js +100 -9
  32. package/dist/bin/exe-session-cleanup.js +133 -18
  33. package/dist/bin/exe-settings.js +1 -0
  34. package/dist/bin/exe-start-codex.js +65 -8
  35. package/dist/bin/exe-start-opencode.js +65 -8
  36. package/dist/bin/exe-status.js +118 -13
  37. package/dist/bin/exe-support.js +1 -0
  38. package/dist/bin/exe-team.js +75 -9
  39. package/dist/bin/git-sweep.js +133 -18
  40. package/dist/bin/graph-backfill.js +65 -8
  41. package/dist/bin/graph-export.js +75 -9
  42. package/dist/bin/intercom-check.js +133 -18
  43. package/dist/bin/scan-tasks.js +133 -18
  44. package/dist/bin/setup.js +55 -4
  45. package/dist/bin/shard-migrate.js +65 -8
  46. package/dist/bin/stack-update.js +5 -6
  47. package/dist/bin/update.js +1 -1
  48. package/dist/gateway/index.js +133 -18
  49. package/dist/hooks/bug-report-worker.js +133 -18
  50. package/dist/hooks/codex-stop-task-finalizer.js +123 -14
  51. package/dist/hooks/commit-complete.js +133 -18
  52. package/dist/hooks/error-recall.js +100 -9
  53. package/dist/hooks/ingest.js +75 -9
  54. package/dist/hooks/instructions-loaded.js +75 -9
  55. package/dist/hooks/notification.js +75 -9
  56. package/dist/hooks/post-compact.js +310 -50
  57. package/dist/hooks/post-tool-combined.js +433 -13
  58. package/dist/hooks/pre-compact.js +133 -18
  59. package/dist/hooks/pre-tool-use.js +118 -13
  60. package/dist/hooks/prompt-submit.js +191 -19
  61. package/dist/hooks/session-end.js +133 -18
  62. package/dist/hooks/session-start.js +143 -13
  63. package/dist/hooks/stop.js +118 -13
  64. package/dist/hooks/subagent-stop.js +118 -13
  65. package/dist/hooks/summary-worker.js +96 -7
  66. package/dist/index.js +133 -18
  67. package/dist/lib/cloud-sync.js +38 -0
  68. package/dist/lib/consolidation.js +3 -1
  69. package/dist/lib/database.js +37 -0
  70. package/dist/lib/db.js +37 -0
  71. package/dist/lib/device-registry.js +37 -0
  72. package/dist/lib/employee-templates.js +17 -3
  73. package/dist/lib/exe-daemon.js +913 -42
  74. package/dist/lib/hybrid-search.js +100 -9
  75. package/dist/lib/license.js +1 -1
  76. package/dist/lib/messaging.js +40 -4
  77. package/dist/lib/schedules.js +54 -3
  78. package/dist/lib/store.js +75 -9
  79. package/dist/lib/tasks.js +58 -9
  80. package/dist/lib/tmux-routing.js +58 -9
  81. package/dist/mcp/server.js +875 -42
  82. package/dist/mcp/tools/create-task.js +67 -12
  83. package/dist/mcp/tools/list-tasks.js +46 -5
  84. package/dist/mcp/tools/send-message.js +40 -4
  85. package/dist/mcp/tools/update-task.js +58 -9
  86. package/dist/runtime/index.js +133 -18
  87. package/dist/tui/App.js +132 -18
  88. package/package.json +1 -1
@@ -195,6 +195,57 @@ test("CLI/MCP parity \u2014 customer ops wrappers are registered", () => {
195
195
  }
196
196
  return true;
197
197
  });
198
+ test("Platform procedures \u2014 all MCP tool actions documented", () => {
199
+ const procs = readSrc("src/lib/platform-procedures.ts");
200
+ const requiredActions = {
201
+ memory: ["recall", "ask_team", "store", "commit", "search", "session_context", "consolidate", "cardinality", "supersede"],
202
+ task: ["create", "list", "get", "update", "close", "checkpoint", "resume"],
203
+ graph: ["query_relationships", "entity_neighbors", "hot_entities", "stats", "export", "merge_entities", "similar_trajectories"],
204
+ identity: ["get", "update"],
205
+ behavior: ["store", "list", "deactivate"],
206
+ support: ["create_bug", "create_feature", "health", "triage_bug"],
207
+ message: ["send", "acknowledge"],
208
+ reminder: ["create", "list", "complete"],
209
+ session: ["events", "last_response"],
210
+ wiki: ["list", "get"],
211
+ document: ["ingest", "list", "purge", "set_importance", "rerank"],
212
+ diagnostics: ["healthcheck", "doctor", "status_brief", "check_update", "cloud_status", "tool_search", "drift"],
213
+ config: ["list_employees", "agent_spend", "daemon_health", "license_status", "cloud_sync", "memory_audit", "run_consolidation", "company_procedure", "global_procedure", "create_trigger", "list_triggers", "export_orchestration", "import_orchestration"]
214
+ };
215
+ const requiredParams = [
216
+ "as_of",
217
+ // bi-temporal recall
218
+ "kind",
219
+ // memory type filter
220
+ "procedure_for",
221
+ // procedure domain tag
222
+ "spawn_runtime",
223
+ // per-task runtime override
224
+ "spawn_model",
225
+ // per-task model override
226
+ "tool_search",
227
+ // capability vector search
228
+ "drift"
229
+ // identity drift detection
230
+ ];
231
+ const missing = [];
232
+ for (const [domain, actions] of Object.entries(requiredActions)) {
233
+ for (const action of actions) {
234
+ if (!procs.includes(action)) {
235
+ missing.push(`${domain}.${action}`);
236
+ }
237
+ }
238
+ }
239
+ for (const param of requiredParams) {
240
+ if (!procs.includes(param)) {
241
+ missing.push(`param:${param}`);
242
+ }
243
+ }
244
+ if (missing.length > 0) {
245
+ return `${missing.length} undocumented in procedures: ${missing.slice(0, 5).join(", ")}${missing.length > 5 ? ` (+${missing.length - 5} more)` : ""}`;
246
+ }
247
+ return true;
248
+ });
198
249
  console.log(`
199
250
  \x1B[1m${pass + fail} tests: ${pass} passed, ${fail} failed\x1B[0m
200
251
  `);
@@ -1409,6 +1409,20 @@ var PLATFORM_PROCEDURES = [
1409
1409
  priority: "p1",
1410
1410
  content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
1411
1411
  },
1412
+ // --- Tool guidance ---
1413
+ {
1414
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
1415
+ domain: "tools",
1416
+ priority: "p2",
1417
+ content: "The company_actions tool executes business actions through gateway connectors (e.g. send WhatsApp, trigger workflows, update CRM). It routes through the exe-gateway on the VPS. Actions are defined by the customer's gateway configuration \u2014 each connector (WhatsApp, Shopify, email, etc.) exposes specific actions. Use query_company_brain to find available data first, then company_actions to act on it. Requires gateway auth token. Read-only founders should NOT use this \u2014 it mutates external state."
1418
+ },
1419
+ // --- Release awareness ---
1420
+ {
1421
+ title: "What's New check \u2014 surface new features after update",
1422
+ domain: "support",
1423
+ priority: "p1",
1424
+ content: "Once per session (COO boot only, never repeat), check if the installed exe-os version is newer than the last session. If it is, read the bundled release-notes.json (at the package root) and surface a brief summary to the founder: 'Updated to exe-os vX.Y.Z \u2014 N new features, M fixes.' List the top 3 features by name. This helps the founder know what they got from the update. If release-notes.json doesn't exist or the version hasn't changed, skip silently. Never repeat this check in the same session."
1425
+ },
1412
1426
  // --- Platform vs Customer ownership ---
1413
1427
  {
1414
1428
  title: "What the platform provides vs what you customize",
@@ -1497,13 +1511,13 @@ var PLATFORM_PROCEDURES = [
1497
1511
  title: "MCP tools \u2014 memory, decision, and search",
1498
1512
  domain: "tool-use",
1499
1513
  priority: "p1",
1500
- content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
1514
+ content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). Supports as_of param for bi-temporal queries (what did I know at time X?), kind param to filter by memory type (decision, procedure, observation, raw, conversation, behavior). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. Supports kind param and procedure_for domain tag for procedure-type memories. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="supersede") / supersede: replace an old memory with a new version (old_id + new text). decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
1501
1515
  },
1502
1516
  {
1503
1517
  title: "MCP tools \u2014 task orchestration",
1504
1518
  domain: "tool-use",
1505
1519
  priority: "p1",
1506
- content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.'
1520
+ content: `task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Supports spawn_runtime and spawn_model params to override the agent's default runtime/model for a specific task. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.`
1507
1521
  },
1508
1522
  {
1509
1523
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -1533,7 +1547,7 @@ var PLATFORM_PROCEDURES = [
1533
1547
  title: "MCP tools \u2014 admin, config, and operations",
1534
1548
  domain: "tool-use",
1535
1549
  priority: "p1",
1536
- content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. mcp_ping(): daemon health + license status + tool usage stats.'
1550
+ content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. Returns top-K tools ranked by relevance. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role identity. Returns drift score + recommendations. mcp_ping(): daemon health + license status + tool usage stats.'
1537
1551
  }
1538
1552
  ];
1539
1553
  var PLATFORM_PROCEDURE_TITLES = new Set(
@@ -2700,6 +2700,20 @@ async function ensureSchema() {
2700
2700
  });
2701
2701
  } catch {
2702
2702
  }
2703
+ try {
2704
+ await client.execute({
2705
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2706
+ args: []
2707
+ });
2708
+ } catch {
2709
+ }
2710
+ try {
2711
+ await client.execute({
2712
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2713
+ args: []
2714
+ });
2715
+ } catch {
2716
+ }
2703
2717
  await client.executeMultiple(`
2704
2718
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
2705
2719
  content_text,
@@ -2951,6 +2965,22 @@ async function ensureSchema() {
2951
2965
  );
2952
2966
  } catch {
2953
2967
  }
2968
+ for (const col of [
2969
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
2970
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
2971
+ ]) {
2972
+ try {
2973
+ await client.execute(col);
2974
+ } catch {
2975
+ }
2976
+ }
2977
+ try {
2978
+ await client.execute({
2979
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
2980
+ args: []
2981
+ });
2982
+ } catch {
2983
+ }
2954
2984
  try {
2955
2985
  await client.execute({
2956
2986
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -2993,6 +3023,13 @@ async function ensureSchema() {
2993
3023
  } catch {
2994
3024
  }
2995
3025
  }
3026
+ try {
3027
+ await client.execute({
3028
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3029
+ args: []
3030
+ });
3031
+ } catch {
3032
+ }
2996
3033
  try {
2997
3034
  await client.execute({
2998
3035
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -3574,6 +3611,20 @@ var init_platform_procedures = __esm({
3574
3611
  priority: "p1",
3575
3612
  content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3576
3613
  },
3614
+ // --- Tool guidance ---
3615
+ {
3616
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
3617
+ domain: "tools",
3618
+ priority: "p2",
3619
+ content: "The company_actions tool executes business actions through gateway connectors (e.g. send WhatsApp, trigger workflows, update CRM). It routes through the exe-gateway on the VPS. Actions are defined by the customer's gateway configuration \u2014 each connector (WhatsApp, Shopify, email, etc.) exposes specific actions. Use query_company_brain to find available data first, then company_actions to act on it. Requires gateway auth token. Read-only founders should NOT use this \u2014 it mutates external state."
3620
+ },
3621
+ // --- Release awareness ---
3622
+ {
3623
+ title: "What's New check \u2014 surface new features after update",
3624
+ domain: "support",
3625
+ priority: "p1",
3626
+ content: "Once per session (COO boot only, never repeat), check if the installed exe-os version is newer than the last session. If it is, read the bundled release-notes.json (at the package root) and surface a brief summary to the founder: 'Updated to exe-os vX.Y.Z \u2014 N new features, M fixes.' List the top 3 features by name. This helps the founder know what they got from the update. If release-notes.json doesn't exist or the version hasn't changed, skip silently. Never repeat this check in the same session."
3627
+ },
3577
3628
  // --- Platform vs Customer ownership ---
3578
3629
  {
3579
3630
  title: "What the platform provides vs what you customize",
@@ -3662,13 +3713,13 @@ var init_platform_procedures = __esm({
3662
3713
  title: "MCP tools \u2014 memory, decision, and search",
3663
3714
  domain: "tool-use",
3664
3715
  priority: "p1",
3665
- content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
3716
+ content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). Supports as_of param for bi-temporal queries (what did I know at time X?), kind param to filter by memory type (decision, procedure, observation, raw, conversation, behavior). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. Supports kind param and procedure_for domain tag for procedure-type memories. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="supersede") / supersede: replace an old memory with a new version (old_id + new text). decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
3666
3717
  },
3667
3718
  {
3668
3719
  title: "MCP tools \u2014 task orchestration",
3669
3720
  domain: "tool-use",
3670
3721
  priority: "p1",
3671
- content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.'
3722
+ content: `task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Supports spawn_runtime and spawn_model params to override the agent's default runtime/model for a specific task. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.`
3672
3723
  },
3673
3724
  {
3674
3725
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -3698,7 +3749,7 @@ var init_platform_procedures = __esm({
3698
3749
  title: "MCP tools \u2014 admin, config, and operations",
3699
3750
  domain: "tool-use",
3700
3751
  priority: "p1",
3701
- content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. mcp_ping(): daemon health + license status + tool usage stats.'
3752
+ content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. Returns top-K tools ranked by relevance. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role identity. Returns drift score + recommendations. mcp_ping(): daemon health + license status + tool usage stats.'
3702
3753
  }
3703
3754
  ];
3704
3755
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -5065,6 +5116,8 @@ async function writeMemory(record) {
5065
5116
  source_type: record.source_type ?? null,
5066
5117
  tier: record.tier ?? classifyTier(record),
5067
5118
  supersedes_id: record.supersedes_id ?? null,
5119
+ valid_from: record.valid_from ?? record.timestamp,
5120
+ invalid_at: record.invalid_at ?? null,
5068
5121
  draft: record.draft ? 1 : 0,
5069
5122
  memory_type: memoryType,
5070
5123
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
@@ -5083,7 +5136,8 @@ async function writeMemory(record) {
5083
5136
  token_cost: record.token_cost ?? null,
5084
5137
  audience: record.audience ?? null,
5085
5138
  language_type: record.language_type ?? inferLanguageType(record),
5086
- parent_memory_id: record.parent_memory_id ?? null
5139
+ parent_memory_id: record.parent_memory_id ?? null,
5140
+ procedure_for: record.procedure_for ?? null
5087
5141
  };
5088
5142
  _pendingRecords.push(dbRow);
5089
5143
  orgBus.emit({
@@ -5138,6 +5192,8 @@ async function flushBatch() {
5138
5192
  const sourceType = row.source_type ?? null;
5139
5193
  const tier = row.tier ?? 3;
5140
5194
  const supersedesId = row.supersedes_id ?? null;
5195
+ const validFrom = row.valid_from ?? row.timestamp;
5196
+ const invalidAt = row.invalid_at ?? null;
5141
5197
  const draft = row.draft ? 1 : 0;
5142
5198
  const memoryType = row.memory_type ?? "raw";
5143
5199
  const trajectory = row.trajectory ?? null;
@@ -5157,15 +5213,16 @@ async function flushBatch() {
5157
5213
  const audience = row.audience ?? null;
5158
5214
  const languageType = row.language_type ?? null;
5159
5215
  const parentMemoryId = row.parent_memory_id ?? null;
5216
+ const procedureFor = row.procedure_for ?? null;
5160
5217
  const cols = `id, agent_id, agent_role, session_id, timestamp,
5161
5218
  tool_name, project_name,
5162
5219
  has_error, raw_text, vector, version, task_id, importance, status,
5163
5220
  confidence, last_accessed,
5164
5221
  workspace_id, document_id, user_id, char_offset, page_number,
5165
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
5222
+ source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
5166
5223
  intent, outcome, domain, referenced_entities, retrieval_count,
5167
5224
  chain_position, review_status, context_window_pct, file_paths, commit_hash,
5168
- duration_ms, token_cost, audience, language_type, parent_memory_id`;
5225
+ duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
5169
5226
  const metaArgs = [
5170
5227
  intent,
5171
5228
  outcome,
@@ -5181,7 +5238,8 @@ async function flushBatch() {
5181
5238
  tokenCost,
5182
5239
  audience,
5183
5240
  languageType,
5184
- parentMemoryId
5241
+ parentMemoryId,
5242
+ procedureFor
5185
5243
  ];
5186
5244
  const baseArgs = [
5187
5245
  row.id,
@@ -5210,6 +5268,8 @@ async function flushBatch() {
5210
5268
  sourceType,
5211
5269
  tier,
5212
5270
  supersedesId,
5271
+ validFrom,
5272
+ invalidAt,
5213
5273
  draft,
5214
5274
  memoryType,
5215
5275
  trajectory,
@@ -5217,8 +5277,8 @@ async function flushBatch() {
5217
5277
  ];
5218
5278
  return {
5219
5279
  sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
5220
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
5221
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5280
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
5281
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5222
5282
  args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
5223
5283
  };
5224
5284
  };
@@ -5334,6 +5394,12 @@ async function searchMemories(queryVector, agentId, options) {
5334
5394
  AND vector IS NOT NULL${statusFilter}${draftFilter}
5335
5395
  AND COALESCE(confidence, 0.7) >= 0.3`;
5336
5396
  const args = [agentId];
5397
+ if (options?.asOf) {
5398
+ sql += ` AND (valid_from IS NULL OR valid_from <= ?) AND (invalid_at IS NULL OR invalid_at > ?)`;
5399
+ args.push(options.asOf, options.asOf);
5400
+ } else {
5401
+ sql += ` AND invalid_at IS NULL`;
5402
+ }
5337
5403
  const scope = buildWikiScopeFilter(options, "");
5338
5404
  sql += scope.clause;
5339
5405
  args.push(...scope.args);
@@ -2852,6 +2852,20 @@ async function ensureSchema() {
2852
2852
  });
2853
2853
  } catch {
2854
2854
  }
2855
+ try {
2856
+ await client.execute({
2857
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2858
+ args: []
2859
+ });
2860
+ } catch {
2861
+ }
2862
+ try {
2863
+ await client.execute({
2864
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2865
+ args: []
2866
+ });
2867
+ } catch {
2868
+ }
2855
2869
  await client.executeMultiple(`
2856
2870
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
2857
2871
  content_text,
@@ -3103,6 +3117,22 @@ async function ensureSchema() {
3103
3117
  );
3104
3118
  } catch {
3105
3119
  }
3120
+ for (const col of [
3121
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
3122
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
3123
+ ]) {
3124
+ try {
3125
+ await client.execute(col);
3126
+ } catch {
3127
+ }
3128
+ }
3129
+ try {
3130
+ await client.execute({
3131
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3132
+ args: []
3133
+ });
3134
+ } catch {
3135
+ }
3106
3136
  try {
3107
3137
  await client.execute({
3108
3138
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -3145,6 +3175,13 @@ async function ensureSchema() {
3145
3175
  } catch {
3146
3176
  }
3147
3177
  }
3178
+ try {
3179
+ await client.execute({
3180
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3181
+ args: []
3182
+ });
3183
+ } catch {
3184
+ }
3148
3185
  try {
3149
3186
  await client.execute({
3150
3187
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -3311,6 +3348,20 @@ var init_platform_procedures = __esm({
3311
3348
  priority: "p1",
3312
3349
  content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3313
3350
  },
3351
+ // --- Tool guidance ---
3352
+ {
3353
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
3354
+ domain: "tools",
3355
+ priority: "p2",
3356
+ content: "The company_actions tool executes business actions through gateway connectors (e.g. send WhatsApp, trigger workflows, update CRM). It routes through the exe-gateway on the VPS. Actions are defined by the customer's gateway configuration \u2014 each connector (WhatsApp, Shopify, email, etc.) exposes specific actions. Use query_company_brain to find available data first, then company_actions to act on it. Requires gateway auth token. Read-only founders should NOT use this \u2014 it mutates external state."
3357
+ },
3358
+ // --- Release awareness ---
3359
+ {
3360
+ title: "What's New check \u2014 surface new features after update",
3361
+ domain: "support",
3362
+ priority: "p1",
3363
+ content: "Once per session (COO boot only, never repeat), check if the installed exe-os version is newer than the last session. If it is, read the bundled release-notes.json (at the package root) and surface a brief summary to the founder: 'Updated to exe-os vX.Y.Z \u2014 N new features, M fixes.' List the top 3 features by name. This helps the founder know what they got from the update. If release-notes.json doesn't exist or the version hasn't changed, skip silently. Never repeat this check in the same session."
3364
+ },
3314
3365
  // --- Platform vs Customer ownership ---
3315
3366
  {
3316
3367
  title: "What the platform provides vs what you customize",
@@ -3399,13 +3450,13 @@ var init_platform_procedures = __esm({
3399
3450
  title: "MCP tools \u2014 memory, decision, and search",
3400
3451
  domain: "tool-use",
3401
3452
  priority: "p1",
3402
- content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
3453
+ content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). Supports as_of param for bi-temporal queries (what did I know at time X?), kind param to filter by memory type (decision, procedure, observation, raw, conversation, behavior). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. Supports kind param and procedure_for domain tag for procedure-type memories. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="supersede") / supersede: replace an old memory with a new version (old_id + new text). decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
3403
3454
  },
3404
3455
  {
3405
3456
  title: "MCP tools \u2014 task orchestration",
3406
3457
  domain: "tool-use",
3407
3458
  priority: "p1",
3408
- content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.'
3459
+ content: `task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Supports spawn_runtime and spawn_model params to override the agent's default runtime/model for a specific task. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.`
3409
3460
  },
3410
3461
  {
3411
3462
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -3435,7 +3486,7 @@ var init_platform_procedures = __esm({
3435
3486
  title: "MCP tools \u2014 admin, config, and operations",
3436
3487
  domain: "tool-use",
3437
3488
  priority: "p1",
3438
- content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. mcp_ping(): daemon health + license status + tool usage stats.'
3489
+ content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. Returns top-K tools ranked by relevance. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role identity. Returns drift score + recommendations. mcp_ping(): daemon health + license status + tool usage stats.'
3439
3490
  }
3440
3491
  ];
3441
3492
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -5521,7 +5572,7 @@ var init_license = __esm({
5521
5572
  LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
5522
5573
  CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
5523
5574
  DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
5524
- API_BASE = "https://askexe.com/cloud";
5575
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
5525
5576
  RETRY_DELAY_MS = 500;
5526
5577
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
5527
5578
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
@@ -6310,8 +6361,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
6310
6361
  const complexity = input.complexity ?? "standard";
6311
6362
  const sessionScope = earlySessionScope;
6312
6363
  await client.execute({
6313
- sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
6314
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6364
+ sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, spawn_runtime, spawn_model, created_at, updated_at)
6365
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
6315
6366
  args: [
6316
6367
  id,
6317
6368
  input.title,
@@ -6331,6 +6382,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
6331
6382
  0,
6332
6383
  null,
6333
6384
  sessionScope,
6385
+ input.spawnRuntime ?? null,
6386
+ input.spawnModel ?? null,
6334
6387
  now,
6335
6388
  now
6336
6389
  ]
@@ -6387,7 +6440,9 @@ ${input.context}
6387
6440
  budgetTokens: input.budgetTokens ?? null,
6388
6441
  budgetFallbackModel: input.budgetFallbackModel ?? null,
6389
6442
  tokensUsed: 0,
6390
- tokensWarnedAt: null
6443
+ tokensWarnedAt: null,
6444
+ spawnRuntime: input.spawnRuntime ?? null,
6445
+ spawnModel: input.spawnModel ?? null
6391
6446
  };
6392
6447
  }
6393
6448
  async function listTasks(input) {
@@ -6437,7 +6492,9 @@ async function listTasks(input) {
6437
6492
  budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
6438
6493
  budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
6439
6494
  tokensUsed: Number(r.tokens_used ?? 0),
6440
- tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
6495
+ tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
6496
+ spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
6497
+ spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
6441
6498
  }));
6442
6499
  }
6443
6500
  function isTmuxSessionAlive(identifier) {
@@ -7734,6 +7791,8 @@ async function updateTask(input) {
7734
7791
  budgetFallbackModel: row.budget_fallback_model !== void 0 && row.budget_fallback_model !== null ? String(row.budget_fallback_model) : null,
7735
7792
  tokensUsed: Number(row.tokens_used ?? 0),
7736
7793
  tokensWarnedAt: row.tokens_warned_at !== void 0 && row.tokens_warned_at !== null ? Number(row.tokens_warned_at) : null,
7794
+ spawnRuntime: row.spawn_runtime !== void 0 && row.spawn_runtime !== null ? String(row.spawn_runtime) : null,
7795
+ spawnModel: row.spawn_model !== void 0 && row.spawn_model !== null ? String(row.spawn_model) : null,
7737
7796
  nextTask
7738
7797
  };
7739
7798
  }
@@ -8229,6 +8288,7 @@ function resolveExeSession() {
8229
8288
  const mySession = getMySession();
8230
8289
  if (!mySession) return null;
8231
8290
  const fromSessionName = extractRootExe(mySession);
8291
+ let candidate = null;
8232
8292
  try {
8233
8293
  const key = getSessionKey();
8234
8294
  const parentExe = getParentExe(key);
@@ -8239,13 +8299,47 @@ function resolveExeSession() {
8239
8299
  `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
8240
8300
  `
8241
8301
  );
8242
- return fromSessionName;
8302
+ candidate = fromSessionName;
8303
+ } else {
8304
+ candidate = fromCache;
8243
8305
  }
8244
- return fromCache;
8245
8306
  }
8246
8307
  } catch {
8247
8308
  }
8248
- return fromSessionName ?? mySession;
8309
+ if (!candidate) {
8310
+ candidate = fromSessionName ?? mySession;
8311
+ }
8312
+ if (candidate && isRootSession(candidate)) {
8313
+ try {
8314
+ const transport = getTransport();
8315
+ const liveSessions = transport.listSessions();
8316
+ if (!liveSessions.includes(candidate)) {
8317
+ const liveRoots = liveSessions.filter((s) => isRootSession(s));
8318
+ if (liveRoots.length === 1) {
8319
+ process.stderr.write(
8320
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
8321
+ `
8322
+ );
8323
+ return liveRoots[0];
8324
+ } else if (liveRoots.length > 1) {
8325
+ const base = candidate.replace(/\d+$/, "");
8326
+ const match = liveRoots.find((s) => s.startsWith(base));
8327
+ const chosen = match ?? liveRoots[0];
8328
+ process.stderr.write(
8329
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
8330
+ `
8331
+ );
8332
+ return chosen;
8333
+ }
8334
+ process.stderr.write(
8335
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
8336
+ `
8337
+ );
8338
+ }
8339
+ } catch {
8340
+ }
8341
+ }
8342
+ return candidate;
8249
8343
  }
8250
8344
  function isEmployeeAlive(sessionName) {
8251
8345
  return getTransport().isAlive(sessionName);
@@ -8647,7 +8741,12 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
8647
8741
  }
8648
8742
  const spawnCwd = opts?.cwd ?? projectDir;
8649
8743
  const useExeAgent = !!(opts?.model && opts?.provider);
8650
- const agentRtConfig = getAgentRuntime(employeeName);
8744
+ const baseRtConfig = getAgentRuntime(employeeName);
8745
+ const agentRtConfig = {
8746
+ ...baseRtConfig,
8747
+ ...opts?.runtimeOverride ? { runtime: opts.runtimeOverride } : {},
8748
+ ...opts?.modelOverride ? { model: opts.modelOverride } : {}
8749
+ };
8651
8750
  const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
8652
8751
  const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
8653
8752
  const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
@@ -347,6 +347,20 @@ var init_platform_procedures = __esm({
347
347
  priority: "p1",
348
348
  content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
349
349
  },
350
+ // --- Tool guidance ---
351
+ {
352
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
353
+ domain: "tools",
354
+ priority: "p2",
355
+ content: "The company_actions tool executes business actions through gateway connectors (e.g. send WhatsApp, trigger workflows, update CRM). It routes through the exe-gateway on the VPS. Actions are defined by the customer's gateway configuration \u2014 each connector (WhatsApp, Shopify, email, etc.) exposes specific actions. Use query_company_brain to find available data first, then company_actions to act on it. Requires gateway auth token. Read-only founders should NOT use this \u2014 it mutates external state."
356
+ },
357
+ // --- Release awareness ---
358
+ {
359
+ title: "What's New check \u2014 surface new features after update",
360
+ domain: "support",
361
+ priority: "p1",
362
+ content: "Once per session (COO boot only, never repeat), check if the installed exe-os version is newer than the last session. If it is, read the bundled release-notes.json (at the package root) and surface a brief summary to the founder: 'Updated to exe-os vX.Y.Z \u2014 N new features, M fixes.' List the top 3 features by name. This helps the founder know what they got from the update. If release-notes.json doesn't exist or the version hasn't changed, skip silently. Never repeat this check in the same session."
363
+ },
350
364
  // --- Platform vs Customer ownership ---
351
365
  {
352
366
  title: "What the platform provides vs what you customize",
@@ -435,13 +449,13 @@ var init_platform_procedures = __esm({
435
449
  title: "MCP tools \u2014 memory, decision, and search",
436
450
  domain: "tool-use",
437
451
  priority: "p1",
438
- content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
452
+ content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). Supports as_of param for bi-temporal queries (what did I know at time X?), kind param to filter by memory type (decision, procedure, observation, raw, conversation, behavior). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. Supports kind param and procedure_for domain tag for procedure-type memories. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="supersede") / supersede: replace an old memory with a new version (old_id + new text). decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
439
453
  },
440
454
  {
441
455
  title: "MCP tools \u2014 task orchestration",
442
456
  domain: "tool-use",
443
457
  priority: "p1",
444
- content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.'
458
+ content: `task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Supports spawn_runtime and spawn_model params to override the agent's default runtime/model for a specific task. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.`
445
459
  },
446
460
  {
447
461
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -471,7 +485,7 @@ var init_platform_procedures = __esm({
471
485
  title: "MCP tools \u2014 admin, config, and operations",
472
486
  domain: "tool-use",
473
487
  priority: "p1",
474
- content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. mcp_ping(): daemon health + license status + tool usage stats.'
488
+ content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. Returns top-K tools ranked by relevance. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role identity. Returns drift score + recommendations. mcp_ping(): daemon health + license status + tool usage stats.'
475
489
  }
476
490
  ];
477
491
  PLATFORM_PROCEDURE_TITLES = new Set(