@askexenow/exe-os 0.9.35 → 0.9.37

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 (67) hide show
  1. package/dist/bin/backfill-conversations.js +5 -1
  2. package/dist/bin/backfill-responses.js +5 -1
  3. package/dist/bin/backfill-vectors.js +1 -1
  4. package/dist/bin/cleanup-stale-review-tasks.js +10 -2
  5. package/dist/bin/cli.js +48 -14
  6. package/dist/bin/exe-agent.js +1 -1
  7. package/dist/bin/exe-assign.js +10 -2
  8. package/dist/bin/exe-boot.js +1 -1
  9. package/dist/bin/exe-call.js +7 -5
  10. package/dist/bin/exe-dispatch.js +10 -2
  11. package/dist/bin/exe-doctor.js +1 -1
  12. package/dist/bin/exe-export-behaviors.js +87 -4
  13. package/dist/bin/exe-forget.js +31 -11
  14. package/dist/bin/exe-gateway.js +10 -2
  15. package/dist/bin/exe-heartbeat.js +10 -2
  16. package/dist/bin/exe-kill.js +10 -2
  17. package/dist/bin/exe-launch-agent.js +85 -7
  18. package/dist/bin/exe-new-employee.js +26 -2
  19. package/dist/bin/exe-pending-messages.js +10 -2
  20. package/dist/bin/exe-pending-notifications.js +10 -2
  21. package/dist/bin/exe-pending-reviews.js +10 -2
  22. package/dist/bin/exe-rename.js +1 -1
  23. package/dist/bin/exe-review.js +10 -2
  24. package/dist/bin/exe-search.js +38 -19
  25. package/dist/bin/exe-session-cleanup.js +14 -3
  26. package/dist/bin/exe-start-codex.js +69 -3
  27. package/dist/bin/exe-start-opencode.js +80 -3
  28. package/dist/bin/exe-status.js +10 -2
  29. package/dist/bin/exe-team.js +10 -2
  30. package/dist/bin/git-sweep.js +10 -2
  31. package/dist/bin/graph-backfill.js +2 -1
  32. package/dist/bin/graph-export.js +10 -2
  33. package/dist/bin/install.js +25 -1
  34. package/dist/bin/intercom-check.js +10 -2
  35. package/dist/bin/scan-tasks.js +10 -2
  36. package/dist/bin/setup.js +7 -5
  37. package/dist/bin/shard-migrate.js +2 -1
  38. package/dist/gateway/index.js +10 -2
  39. package/dist/hooks/bug-report-worker.js +10 -2
  40. package/dist/hooks/codex-stop-task-finalizer.js +10 -2
  41. package/dist/hooks/commit-complete.js +10 -2
  42. package/dist/hooks/error-recall.js +38 -19
  43. package/dist/hooks/ingest-worker.js +9 -2
  44. package/dist/hooks/ingest.js +10 -2
  45. package/dist/hooks/instructions-loaded.js +10 -2
  46. package/dist/hooks/notification.js +10 -2
  47. package/dist/hooks/post-compact.js +10 -2
  48. package/dist/hooks/post-tool-combined.js +47 -21
  49. package/dist/hooks/pre-compact.js +12 -3
  50. package/dist/hooks/pre-tool-use.js +20 -8
  51. package/dist/hooks/prompt-submit.js +133 -20
  52. package/dist/hooks/session-end.js +138 -5
  53. package/dist/hooks/session-start.js +216 -46
  54. package/dist/hooks/stop.js +14 -4
  55. package/dist/hooks/subagent-stop.js +10 -2
  56. package/dist/hooks/summary-worker.js +121 -19
  57. package/dist/index.js +32 -16
  58. package/dist/lib/employee-templates.js +7 -5
  59. package/dist/lib/exe-daemon.js +124 -34
  60. package/dist/lib/hybrid-search.js +38 -19
  61. package/dist/lib/schedules.js +1 -1
  62. package/dist/lib/store.js +10 -2
  63. package/dist/mcp/server.js +118 -34
  64. package/dist/runtime/index.js +32 -16
  65. package/dist/tui/App.js +10 -2
  66. package/package.json +1 -1
  67. package/src/commands/exe/save.md +52 -0
@@ -3601,6 +3601,9 @@ function classifyMemoryType(input) {
3601
3601
  if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
3602
3602
  if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
3603
3603
  if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
3604
+ if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
3605
+ if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
3606
+ if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
3604
3607
  if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
3605
3608
  if (tool === "store_memory" || tool === "manual") return "observation";
3606
3609
  return "raw";
@@ -3743,6 +3746,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
3743
3746
  }
3744
3747
  }
3745
3748
  function schedulePostWriteMemoryHygiene(memoryIds) {
3749
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
3746
3750
  if (memoryIds.length === 0) return;
3747
3751
  const run = () => {
3748
3752
  void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
@@ -4137,7 +4141,7 @@ var init_platform_procedures = __esm({
4137
4141
  title: "Chain of command \u2014 who talks to whom",
4138
4142
  domain: "workflow",
4139
4143
  priority: "p0",
4140
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
4144
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
4141
4145
  },
4142
4146
  {
4143
4147
  title: "Single dispatch path \u2014 create_task only",
@@ -4809,7 +4813,11 @@ async function searchMemories(queryVector, agentId, options) {
4809
4813
  sql += ` AND timestamp >= ?`;
4810
4814
  args.push(options.since);
4811
4815
  }
4812
- if (options?.memoryType) {
4816
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
4817
+ const uniqueTypes = [...new Set(options.memoryTypes)];
4818
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
4819
+ args.push(...uniqueTypes);
4820
+ } else if (options?.memoryType) {
4813
4821
  sql += ` AND memory_type = ?`;
4814
4822
  args.push(options.memoryType);
4815
4823
  }
@@ -6039,6 +6047,17 @@ __export(hybrid_search_exports, {
6039
6047
  rrfMerge: () => rrfMerge,
6040
6048
  rrfMergeMulti: () => rrfMergeMulti
6041
6049
  });
6050
+ function appendMemoryTypeFilter(sql, args, column, options) {
6051
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
6052
+ const uniqueTypes = [...new Set(options.memoryTypes)];
6053
+ sql += ` AND ${column} IN (${uniqueTypes.map(() => "?").join(",")})`;
6054
+ args.push(...uniqueTypes);
6055
+ } else if (options?.memoryType) {
6056
+ sql += ` AND ${column} = ?`;
6057
+ args.push(options.memoryType);
6058
+ }
6059
+ return sql;
6060
+ }
6042
6061
  async function hybridSearch(queryText, agentId, options) {
6043
6062
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
6044
6063
  const config2 = await loadConfig2();
@@ -6134,7 +6153,7 @@ async function hybridSearch(queryText, agentId, options) {
6134
6153
  }
6135
6154
  if (lists.length === 0) return [];
6136
6155
  if (lists.length === 1 && !effectiveIsBroad) return lists[0].slice(0, limit);
6137
- const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, 150) : limit;
6156
+ const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : limit;
6138
6157
  let merged = lists.length === 1 ? lists[0].slice(0, rrfLimit) : rrfMergeMulti(lists, rrfLimit, RRF_K, weights);
6139
6158
  let graphContextMap = /* @__PURE__ */ new Map();
6140
6159
  let entityBoostRan = false;
@@ -6155,6 +6174,7 @@ async function hybridSearch(queryText, agentId, options) {
6155
6174
  returnTopK: 5
6156
6175
  };
6157
6176
  let rerankedAndBlended = null;
6177
+ const rerankReturnLimit = Math.max(limit, auto.returnTopK ?? 5);
6158
6178
  if (effectiveIsBroad && auto.enabled && rerankerAvailable) {
6159
6179
  const cardinality2 = await estimateCardinality(agentId, effectiveOptions);
6160
6180
  if (cardinality2 > auto.broadQueryMinCardinality) {
@@ -6166,16 +6186,16 @@ async function hybridSearch(queryText, agentId, options) {
6166
6186
  text: m.raw_text,
6167
6187
  context: graphContextMap.get(m.id)
6168
6188
  }));
6169
- const scored = await rerankWithContext2(effectiveQuery, candidates, auto.returnTopK);
6189
+ const scored = await rerankWithContext2(effectiveQuery, candidates, rerankReturnLimit);
6170
6190
  rerankedRecords = scored.map((s) => merged[s.index]);
6171
6191
  } else {
6172
6192
  const { rerank: rerank2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
6173
- rerankedRecords = await rerank2(effectiveQuery, merged, auto.returnTopK);
6193
+ rerankedRecords = await rerank2(effectiveQuery, merged, rerankReturnLimit);
6174
6194
  }
6175
6195
  if (rerankedRecords.length > 0) {
6176
6196
  rerankedAndBlended = rrfMergeMulti(
6177
6197
  [rerankedRecords],
6178
- auto.returnTopK,
6198
+ rerankReturnLimit,
6179
6199
  RRF_K
6180
6200
  );
6181
6201
  }
@@ -6183,10 +6203,7 @@ async function hybridSearch(queryText, agentId, options) {
6183
6203
  }
6184
6204
  }
6185
6205
  }
6186
- const finalResults = (rerankedAndBlended ?? merged).slice(
6187
- 0,
6188
- rerankedAndBlended ? auto.returnTopK : limit
6189
- );
6206
+ const finalResults = (rerankedAndBlended ?? merged).slice(0, limit);
6190
6207
  if (options?.includeSource && finalResults.length > 0) {
6191
6208
  await attachDocumentMetadata(finalResults);
6192
6209
  }
@@ -6267,6 +6284,7 @@ async function estimateCardinality(agentId, options) {
6267
6284
  sql += ` AND timestamp >= ?`;
6268
6285
  args.push(options.since);
6269
6286
  }
6287
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
6270
6288
  try {
6271
6289
  const result = await client.execute({ sql, args });
6272
6290
  return Number(result.rows[0]?.cnt) || 0;
@@ -6388,10 +6406,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
6388
6406
  sql += ` AND m.timestamp >= ?`;
6389
6407
  args.push(options.since);
6390
6408
  }
6391
- if (options?.memoryType) {
6392
- sql += ` AND m.memory_type = ?`;
6393
- args.push(options.memoryType);
6394
- }
6409
+ sql = appendMemoryTypeFilter(sql, args, "m.memory_type", options);
6395
6410
  sql += ` ORDER BY rank LIMIT ?`;
6396
6411
  args.push(limit);
6397
6412
  const result = await client.execute({ sql, args });
@@ -6448,9 +6463,16 @@ async function recentRecords(agentId, options, limit, textFilter) {
6448
6463
  AND timestamp >= ? AND timestamp <= ?
6449
6464
  AND COALESCE(status, 'active') = 'active'
6450
6465
  AND ${options?.includeRaw === false ? "COALESCE(memory_type, 'raw') != 'raw'" : "1 = 1"}
6466
+ ${options?.memoryTypes?.length ? `AND memory_type IN (${options.memoryTypes.map(() => "?").join(",")})` : options?.memoryType ? "AND memory_type = ?" : ""}
6451
6467
  AND COALESCE(confidence, 0.7) >= 0.3
6452
6468
  ORDER BY timestamp DESC LIMIT ?`,
6453
- args: [agentId, windowStart, killedAt, boundarySlots]
6469
+ args: [
6470
+ agentId,
6471
+ windowStart,
6472
+ killedAt,
6473
+ ...options?.memoryTypes?.length ? [...new Set(options.memoryTypes)] : options?.memoryType ? [options.memoryType] : [],
6474
+ boundarySlots
6475
+ ]
6454
6476
  });
6455
6477
  for (const row of boundaryResult.rows) {
6456
6478
  sessionBoundaryMemories.push(rowToMemoryRecord(row));
@@ -6496,10 +6518,7 @@ async function recentRecords(agentId, options, limit, textFilter) {
6496
6518
  sql += ` AND timestamp >= ?`;
6497
6519
  args.push(options.since);
6498
6520
  }
6499
- if (options?.memoryType) {
6500
- sql += ` AND memory_type = ?`;
6501
- args.push(options.memoryType);
6502
- }
6521
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
6503
6522
  if (textFilter) {
6504
6523
  sql += ` AND raw_text LIKE '%' || ? || '%'`;
6505
6524
  args.push(textFilter);
@@ -12685,6 +12704,63 @@ init_hybrid_search();
12685
12704
  init_store();
12686
12705
  init_active_agent();
12687
12706
  import { z } from "zod";
12707
+
12708
+ // src/lib/memory-retrieval-modes.ts
12709
+ var RETRIEVAL_MODES = [
12710
+ "all",
12711
+ "decisions_only",
12712
+ "behaviors_only",
12713
+ "procedures_only",
12714
+ "operational",
12715
+ "no_raw",
12716
+ "recent_high_value"
12717
+ ];
12718
+ var RETRIEVAL_MODE_DESCRIPTIONS = {
12719
+ all: "All visible memory types.",
12720
+ decisions_only: "Only decisions and ADRs.",
12721
+ behaviors_only: "Only durable behavior/correction memories.",
12722
+ procedures_only: "Only procedures/runbooks.",
12723
+ operational: "Raw operational/debug/tool output.",
12724
+ no_raw: "All non-raw memory types.",
12725
+ recent_high_value: "High-value durable memory types, intended for recency recovery."
12726
+ };
12727
+ function applyRetrievalMode(base, mode) {
12728
+ if (!mode || mode === "all") return base;
12729
+ const next = { ...base };
12730
+ switch (mode) {
12731
+ case "decisions_only":
12732
+ next.memoryTypes = ["decision", "adr"];
12733
+ next.includeRaw = false;
12734
+ break;
12735
+ case "behaviors_only":
12736
+ next.memoryTypes = ["behavior"];
12737
+ next.includeRaw = false;
12738
+ break;
12739
+ case "procedures_only":
12740
+ next.memoryTypes = ["procedure"];
12741
+ next.includeRaw = false;
12742
+ break;
12743
+ case "operational":
12744
+ next.memoryTypes = ["raw", "observation"];
12745
+ next.includeRaw = true;
12746
+ break;
12747
+ case "no_raw":
12748
+ next.includeRaw = false;
12749
+ break;
12750
+ case "recent_high_value":
12751
+ next.memoryTypes = ["decision", "adr", "behavior", "procedure"];
12752
+ next.includeRaw = false;
12753
+ break;
12754
+ default:
12755
+ return next;
12756
+ }
12757
+ return next;
12758
+ }
12759
+ function formatRetrievalModes() {
12760
+ return RETRIEVAL_MODES.map((mode) => `${mode}: ${RETRIEVAL_MODE_DESCRIPTIONS[mode]}`).join("; ");
12761
+ }
12762
+
12763
+ // src/mcp/tools/recall-my-memory.ts
12688
12764
  function formatSourceLine(record) {
12689
12765
  const doc2 = record.document_metadata;
12690
12766
  if (!doc2) return "";
@@ -12720,7 +12796,8 @@ function registerRecallMyMemory(server2) {
12720
12796
  ),
12721
12797
  include_source: z.boolean().optional().default(false).describe(
12722
12798
  "When true, attach parent document metadata (filename, mime, source_type) to each result. Default false."
12723
- )
12799
+ ),
12800
+ retrieval_mode: z.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. ${formatRetrievalModes()}`)
12724
12801
  }
12725
12802
  },
12726
12803
  async ({
@@ -12734,7 +12811,8 @@ function registerRecallMyMemory(server2) {
12734
12811
  include_archived,
12735
12812
  workspace_id,
12736
12813
  user_id,
12737
- include_source
12814
+ include_source,
12815
+ retrieval_mode
12738
12816
  }) => {
12739
12817
  try {
12740
12818
  if (!recent && !query) {
@@ -12744,7 +12822,7 @@ function registerRecallMyMemory(server2) {
12744
12822
  };
12745
12823
  }
12746
12824
  const { agentId } = getActiveAgent();
12747
- const searchOptions = {
12825
+ const searchOptions = applyRetrievalMode({
12748
12826
  projectName: project_name,
12749
12827
  hasError: has_error,
12750
12828
  toolName: tool_name,
@@ -12755,7 +12833,7 @@ function registerRecallMyMemory(server2) {
12755
12833
  includeSource: include_source,
12756
12834
  includeDrafts: true,
12757
12835
  ...user_id !== void 0 ? { userId: user_id } : {}
12758
- };
12836
+ }, retrieval_mode);
12759
12837
  let results;
12760
12838
  if (recent) {
12761
12839
  results = await recentRecords(agentId, searchOptions, limit, query);
@@ -12843,10 +12921,11 @@ function registerAskTeamMemory(server2) {
12843
12921
  ),
12844
12922
  include_raw: z2.boolean().optional().default(false).describe(
12845
12923
  "Include raw technical memories when ACL allows it (default: non-raw memories only for cross-agent reads)"
12846
- )
12924
+ ),
12925
+ retrieval_mode: z2.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. Raw visibility is still ACL-gated. ${formatRetrievalModes()}`)
12847
12926
  }
12848
12927
  },
12849
- async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw }) => {
12928
+ async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
12850
12929
  try {
12851
12930
  const { agentId: queryingAgentId, agentRole: queryingAgentRole } = getActiveAgent();
12852
12931
  const employees = loadEmployeesSync();
@@ -12855,16 +12934,18 @@ function registerAskTeamMemory(server2) {
12855
12934
  const targetRole = targetEmployee?.role ?? "";
12856
12935
  const hasRawAccess = canSeeRaw(queryingRole, targetRole);
12857
12936
  const effectiveIncludeRaw = _include_raw && hasRawAccess;
12858
- const results = await hybridSearch(query, team_member, {
12937
+ const requestedMode = retrieval_mode ?? "all";
12938
+ const safeMode = !effectiveIncludeRaw && ["all", "operational"].includes(requestedMode) ? "no_raw" : requestedMode;
12939
+ const searchOptions = applyRetrievalMode({
12859
12940
  projectName: project_name,
12860
12941
  limit,
12861
12942
  since,
12862
12943
  includeArchived: include_archived,
12863
12944
  includeDrafts: false,
12864
- includeRaw: effectiveIncludeRaw,
12865
- memoryType: void 0
12866
- // Show all memory types — privacy enforced by draft filter + ACL, not type filter
12867
- });
12945
+ includeRaw: effectiveIncludeRaw
12946
+ }, safeMode);
12947
+ if (!effectiveIncludeRaw) searchOptions.includeRaw = false;
12948
+ const results = await hybridSearch(query, team_member, searchOptions);
12868
12949
  if (results.length === 0) {
12869
12950
  return {
12870
12951
  content: [
@@ -15695,7 +15776,7 @@ created_by: system
15695
15776
  ---
15696
15777
  ## Identity
15697
15778
 
15698
- You are {{agent_name}}, the Chief Operating Officer at {{company_name}}.
15779
+ You are {{agent_name}}, the {{title}} at {{company_name}}.
15699
15780
 
15700
15781
  You are {{founder_name}}'s most reliable teammate in business \u2014 the knowledgeable older sibling who has been through it all. You have seen projects succeed and fail. You know what matters and what is noise. You do not get anxious about problems; you see them coming, stay calm, and handle them.
15701
15782
 
@@ -15782,11 +15863,13 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
15782
15863
  var CLIENT_COO_PLACEHOLDERS = [
15783
15864
  "agent_name",
15784
15865
  "company_name",
15785
- "founder_name"
15866
+ "founder_name",
15867
+ "title"
15786
15868
  ];
15787
15869
  function renderClientCOOTemplate(vars) {
15870
+ const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
15788
15871
  for (const key of CLIENT_COO_PLACEHOLDERS) {
15789
- const value = vars[key];
15872
+ const value = resolved[key];
15790
15873
  if (typeof value !== "string" || value.length === 0) {
15791
15874
  throw new Error(
15792
15875
  `renderClientCOOTemplate: missing required variable "${key}"`
@@ -15795,7 +15878,7 @@ function renderClientCOOTemplate(vars) {
15795
15878
  }
15796
15879
  let out = CLIENT_COO_TEMPLATE;
15797
15880
  for (const key of CLIENT_COO_PLACEHOLDERS) {
15798
- out = out.split(`{{${key}}}`).join(vars[key]);
15881
+ out = out.split(`{{${key}}}`).join(resolved[key]);
15799
15882
  }
15800
15883
  if (vars.industry_context) {
15801
15884
  out += "\n" + vars.industry_context;
@@ -15961,6 +16044,7 @@ ${vars}`);
15961
16044
  agent_name,
15962
16045
  company_name,
15963
16046
  founder_name,
16047
+ title: "Chief Operating Officer",
15964
16048
  industry_context: pack.identityContext ?? void 0
15965
16049
  });
15966
16050
  cooSummaryLines = [
@@ -6788,6 +6788,9 @@ function classifyMemoryType(input) {
6788
6788
  if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
6789
6789
  if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
6790
6790
  if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
6791
+ if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
6792
+ if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
6793
+ if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
6791
6794
  if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
6792
6795
  if (tool === "store_memory" || tool === "manual") return "observation";
6793
6796
  return "raw";
@@ -6930,6 +6933,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
6930
6933
  }
6931
6934
  }
6932
6935
  function schedulePostWriteMemoryHygiene(memoryIds) {
6936
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
6933
6937
  if (memoryIds.length === 0) return;
6934
6938
  const run = () => {
6935
6939
  void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
@@ -7324,7 +7328,7 @@ var init_platform_procedures = __esm({
7324
7328
  title: "Chain of command \u2014 who talks to whom",
7325
7329
  domain: "workflow",
7326
7330
  priority: "p0",
7327
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
7331
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
7328
7332
  },
7329
7333
  {
7330
7334
  title: "Single dispatch path \u2014 create_task only",
@@ -7996,7 +8000,11 @@ async function searchMemories(queryVector, agentId, options) {
7996
8000
  sql += ` AND timestamp >= ?`;
7997
8001
  args.push(options.since);
7998
8002
  }
7999
- if (options?.memoryType) {
8003
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
8004
+ const uniqueTypes = [...new Set(options.memoryTypes)];
8005
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
8006
+ args.push(...uniqueTypes);
8007
+ } else if (options?.memoryType) {
8000
8008
  sql += ` AND memory_type = ?`;
8001
8009
  args.push(options.memoryType);
8002
8010
  }
@@ -10228,20 +10236,28 @@ function createExeOSHooks(config) {
10228
10236
  async onSessionEnd(_context, summary) {
10229
10237
  try {
10230
10238
  const { writeMemory: writeMemory2 } = await Promise.resolve().then(() => (init_store(), store_exports));
10231
- if (summary) {
10232
- await writeMemory2({
10233
- id: randomUUID5(),
10234
- agent_id: config.agentId,
10235
- agent_role: "employee",
10236
- session_id: `api-${config.agentId}`,
10237
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10238
- tool_name: "SessionEnd",
10239
- project_name: config.projectName,
10240
- has_error: false,
10241
- raw_text: `Session ended. Summary: ${summary}`,
10242
- vector: null
10243
- });
10244
- }
10239
+ await writeMemory2({
10240
+ id: randomUUID5(),
10241
+ agent_id: config.agentId,
10242
+ agent_role: "employee",
10243
+ session_id: `api-${config.agentId}`,
10244
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10245
+ tool_name: "SessionEnd",
10246
+ project_name: config.projectName,
10247
+ has_error: false,
10248
+ raw_text: [
10249
+ "CONTEXT CHECKPOINT [auto:session-end]",
10250
+ `Agent: ${config.agentId}`,
10251
+ `Project: ${config.projectName}`,
10252
+ `Time: ${(/* @__PURE__ */ new Date()).toISOString()}`,
10253
+ "",
10254
+ "## Runtime Summary",
10255
+ summary || "Session ended. No runtime summary was provided."
10256
+ ].join("\n"),
10257
+ vector: null,
10258
+ importance: 8,
10259
+ memory_type: "checkpoint"
10260
+ });
10245
10261
  } catch (err) {
10246
10262
  process.stderr.write(
10247
10263
  `[exe-hooks] session summary store failed: ${err instanceof Error ? err.message : String(err)}
package/dist/tui/App.js CHANGED
@@ -8520,7 +8520,7 @@ var init_platform_procedures = __esm({
8520
8520
  title: "Chain of command \u2014 who talks to whom",
8521
8521
  domain: "workflow",
8522
8522
  priority: "p0",
8523
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
8523
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
8524
8524
  },
8525
8525
  {
8526
8526
  title: "Single dispatch path \u2014 create_task only",
@@ -11097,6 +11097,9 @@ function classifyMemoryType(input) {
11097
11097
  if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
11098
11098
  if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
11099
11099
  if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
11100
+ if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
11101
+ if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
11102
+ if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
11100
11103
  if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
11101
11104
  if (tool === "store_memory" || tool === "manual") return "observation";
11102
11105
  return "raw";
@@ -11239,6 +11242,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
11239
11242
  }
11240
11243
  }
11241
11244
  function schedulePostWriteMemoryHygiene(memoryIds) {
11245
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
11242
11246
  if (memoryIds.length === 0) return;
11243
11247
  const run = () => {
11244
11248
  void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
@@ -12056,7 +12060,11 @@ async function searchMemories(queryVector, agentId, options) {
12056
12060
  sql += ` AND timestamp >= ?`;
12057
12061
  args.push(options.since);
12058
12062
  }
12059
- if (options?.memoryType) {
12063
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
12064
+ const uniqueTypes = [...new Set(options.memoryTypes)];
12065
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
12066
+ args.push(...uniqueTypes);
12067
+ } else if (options?.memoryType) {
12060
12068
  sql += ` AND memory_type = ?`;
12061
12069
  args.push(options.memoryType);
12062
12070
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askexenow/exe-os",
3
- "version": "0.9.35",
3
+ "version": "0.9.37",
4
4
  "description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -0,0 +1,52 @@
1
+ # /exe-save
2
+
3
+ Manual escape hatch for saving a context checkpoint.
4
+
5
+ Normally you do **not** need this. Exe OS automatically creates structured
6
+ `CONTEXT CHECKPOINT` memories in the background during meaningful work, before
7
+ compaction/context pressure, and at session end. Use `/exe-save` only when the
8
+ founder explicitly says "save everything" or you want an immediate extra
9
+ checkpoint before risky manual work.
10
+
11
+ ## What to save
12
+
13
+ Store a structured memory checkpoint with ALL of the following:
14
+
15
+ 1. **What you accomplished** — list every completed task, fix, or deliverable
16
+ 2. **Decisions made** — architectural choices, trade-offs, priorities decided
17
+ 3. **Open items** — anything unfinished, blocked, or deferred
18
+ 4. **Key file paths** — files you created, modified, or need to revisit
19
+ 5. **Risks or concerns** — anything that might break or needs follow-up
20
+
21
+ ## How to save
22
+
23
+ ```bash
24
+ # Use store_memory MCP tool with a structured checkpoint
25
+ ```
26
+
27
+ Call `store_memory` with this format:
28
+
29
+ ```
30
+ CONTEXT CHECKPOINT [session-date]:
31
+ ## Completed
32
+ - [list what was done]
33
+
34
+ ## Decisions
35
+ - [list decisions and why]
36
+
37
+ ## Open Items
38
+ - [list what's unfinished]
39
+
40
+ ## Key Files
41
+ - [list important file paths]
42
+
43
+ ## Risks
44
+ - [list concerns]
45
+ ```
46
+
47
+ Then call `store_memory` again for each major decision as a separate `decision` type memory — these survive consolidation and are always retrievable via `recall_my_memory(query, retrieval_mode="decisions_only")`.
48
+
49
+ ## When to use
50
+
51
+ - When the founder explicitly asks to save everything
52
+ - Before risky/manual infrastructure work where an extra checkpoint is useful