@askexenow/exe-os 0.9.104 → 0.9.106

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 (89) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +24 -10
  2. package/dist/bin/agentic-reflection-backfill.js +24 -10
  3. package/dist/bin/agentic-semantic-label.js +24 -10
  4. package/dist/bin/backfill-conversations.js +24 -10
  5. package/dist/bin/backfill-responses.js +24 -10
  6. package/dist/bin/backfill-vectors.js +24 -10
  7. package/dist/bin/bulk-sync-postgres.js +24 -10
  8. package/dist/bin/cleanup-stale-review-tasks.js +24 -10
  9. package/dist/bin/cli.js +24 -10
  10. package/dist/bin/exe-agent.js +15 -9
  11. package/dist/bin/exe-assign.js +24 -10
  12. package/dist/bin/exe-boot.js +24 -10
  13. package/dist/bin/exe-call.js +15 -9
  14. package/dist/bin/exe-cloud.js +24 -10
  15. package/dist/bin/exe-dispatch.js +24 -10
  16. package/dist/bin/exe-doctor.js +24 -10
  17. package/dist/bin/exe-export-behaviors.js +24 -10
  18. package/dist/bin/exe-forget.js +50 -11
  19. package/dist/bin/exe-gateway.js +24 -10
  20. package/dist/bin/exe-heartbeat.js +24 -10
  21. package/dist/bin/exe-kill.js +24 -10
  22. package/dist/bin/exe-launch-agent.js +24 -10
  23. package/dist/bin/exe-new-employee.js +24 -10
  24. package/dist/bin/exe-pending-messages.js +24 -10
  25. package/dist/bin/exe-pending-notifications.js +24 -10
  26. package/dist/bin/exe-pending-reviews.js +24 -10
  27. package/dist/bin/exe-rename.js +24 -10
  28. package/dist/bin/exe-review.js +24 -10
  29. package/dist/bin/exe-search.js +50 -11
  30. package/dist/bin/exe-session-cleanup.js +24 -10
  31. package/dist/bin/exe-start-codex.js +24 -10
  32. package/dist/bin/exe-start-opencode.js +24 -10
  33. package/dist/bin/exe-status.js +24 -10
  34. package/dist/bin/exe-team.js +24 -10
  35. package/dist/bin/git-sweep.js +24 -10
  36. package/dist/bin/graph-backfill.js +24 -10
  37. package/dist/bin/graph-export.js +24 -10
  38. package/dist/bin/intercom-check.js +24 -10
  39. package/dist/bin/pre-publish.js +15 -9
  40. package/dist/bin/scan-tasks.js +24 -10
  41. package/dist/bin/setup.js +24 -10
  42. package/dist/bin/shard-migrate.js +24 -10
  43. package/dist/gateway/index.js +24 -10
  44. package/dist/hooks/bug-report-worker.js +24 -10
  45. package/dist/hooks/codex-stop-task-finalizer.js +24 -10
  46. package/dist/hooks/commit-complete.js +24 -10
  47. package/dist/hooks/error-recall.js +50 -11
  48. package/dist/hooks/ingest.js +24 -10
  49. package/dist/hooks/instructions-loaded.js +24 -10
  50. package/dist/hooks/notification.js +24 -10
  51. package/dist/hooks/post-compact.js +24 -10
  52. package/dist/hooks/post-tool-combined.js +50 -11
  53. package/dist/hooks/pre-compact.js +24 -10
  54. package/dist/hooks/pre-tool-use.js +24 -10
  55. package/dist/hooks/prompt-submit.js +50 -11
  56. package/dist/hooks/session-end.js +24 -10
  57. package/dist/hooks/session-start.js +50 -11
  58. package/dist/hooks/stop.js +24 -10
  59. package/dist/hooks/subagent-stop.js +24 -10
  60. package/dist/hooks/summary-worker.js +24 -10
  61. package/dist/index.js +24 -10
  62. package/dist/lib/cloud-sync.js +9 -1
  63. package/dist/lib/database.js +9 -1
  64. package/dist/lib/db.js +9 -1
  65. package/dist/lib/device-registry.js +9 -1
  66. package/dist/lib/employee-templates.js +15 -9
  67. package/dist/lib/exe-daemon.js +50 -11
  68. package/dist/lib/hybrid-search.js +50 -11
  69. package/dist/lib/identity.js +9 -1
  70. package/dist/lib/messaging.js +9 -1
  71. package/dist/lib/reminders.js +9 -1
  72. package/dist/lib/schedules.js +24 -10
  73. package/dist/lib/skill-learning.js +9 -1
  74. package/dist/lib/store.js +24 -10
  75. package/dist/lib/tasks.js +9 -1
  76. package/dist/lib/tmux-routing.js +9 -1
  77. package/dist/lib/token-spend.js +9 -1
  78. package/dist/mcp/server.js +50 -11
  79. package/dist/mcp/tools/complete-reminder.js +9 -1
  80. package/dist/mcp/tools/create-reminder.js +9 -1
  81. package/dist/mcp/tools/create-task.js +9 -1
  82. package/dist/mcp/tools/deactivate-behavior.js +9 -1
  83. package/dist/mcp/tools/list-reminders.js +9 -1
  84. package/dist/mcp/tools/list-tasks.js +9 -1
  85. package/dist/mcp/tools/send-message.js +9 -1
  86. package/dist/mcp/tools/update-task.js +9 -1
  87. package/dist/runtime/index.js +24 -10
  88. package/dist/tui/App.js +24 -10
  89. package/package.json +1 -1
@@ -1606,7 +1606,15 @@ function getClient() {
1606
1606
  if (!_resilientClient) {
1607
1607
  return _adapterClient;
1608
1608
  }
1609
- return _resilientClient;
1609
+ if (process.env.EXE_DB_READONLY === "1") {
1610
+ return _resilientClient;
1611
+ }
1612
+ process.stderr.write(
1613
+ "[database] ERROR: Daemon is not running \u2014 refusing direct SQLite write access.\n[database] Direct writes bypass the single-writer gate and corrupt FTS5 indexes.\n[database] Restart the daemon: kill $(cat ~/.exe-os/exed.pid) && exe-os update\n[database] Or set EXE_DB_READONLY=1 if you only need read access.\n"
1614
+ );
1615
+ throw new Error(
1616
+ "Daemon not running. Direct SQLite writes are blocked to prevent FTS5 corruption. Restart daemon or set EXE_DB_READONLY=1 for read-only access."
1617
+ );
1610
1618
  }
1611
1619
  async function initDaemonClient() {
1612
1620
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
@@ -3627,7 +3635,7 @@ var init_platform_procedures = __esm({
3627
3635
  title: "Bug report status check \u2014 surface available fixes on boot",
3628
3636
  domain: "support",
3629
3637
  priority: "p1",
3630
- content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \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 reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3638
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_bugs') to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'closed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. You can also file new bugs with support(action='create_bug') and check status anytime with support(action='list_my_bugs'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3631
3639
  },
3632
3640
  {
3633
3641
  title: "Feature request triage \u2014 upstream feature vs local customization",
@@ -3639,7 +3647,7 @@ var init_platform_procedures = __esm({
3639
3647
  title: "Feature request status check \u2014 surface shipped features on boot",
3640
3648
  domain: "support",
3641
3649
  priority: "p1",
3642
- 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."
3650
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_features') 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'. You can also file new requests with support(action='create_feature') and check status anytime with support(action='list_my_features'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3643
3651
  },
3644
3652
  // --- Tool guidance ---
3645
3653
  {
@@ -3675,6 +3683,18 @@ var init_platform_procedures = __esm({
3675
3683
  priority: "p0",
3676
3684
  content: "exe-os has TWO version numbers that move independently. This is normal \u2014 do not treat a mismatch as an error. (1) CLI version (e.g. 0.9.89, 0.9.90) \u2014 the npm package installed locally. Updates frequently: bug fixes, new MCP tools, platform procedures, search improvements, client-side changes. Update with `npm install -g @askexenow/exe-os@latest`. (2) Stack version (e.g. 0.9.7, 0.9.8) \u2014 the Docker images on the VPS. Updates less frequently: only when server-side daemon, gateway, wiki, or CRM images need rebuilding. Update with `exe-os stack-update --target <version> --yes`. The CLI version will almost always be higher than the stack version. A CLI at 0.9.90 with a stack at 0.9.8 is perfectly normal \u2014 it means the CLI got 12 patches since the last Docker image rebuild. Only update the stack when: (a) the boot brief surfaces a fix that mentions 'stack update required', (b) a new stack manifest version is bundled in the CLI (`exe-os stack-update --check` shows pending changes), or (c) AskExe support explicitly tells you to. Do NOT attempt to make the numbers match \u2014 they are separate tracks."
3677
3685
  },
3686
+ {
3687
+ title: "Update lifecycle \u2014 what each command does and what picks up new code",
3688
+ domain: "operations",
3689
+ priority: "p0",
3690
+ content: "Three update paths exist \u2014 know which does what. (1) `npm install -g @askexenow/exe-os@latest` \u2014 customer update. Replaces all dist/ files. postinstall copies slash commands AND restarts the daemon automatically. MCP server picks up new code on next `/mcp` reconnect or new Claude Code session. Hooks pick up new code on next session (they spawn fresh processes). (2) `exe-os update` \u2014 interactive update command. Runs `npm install -g` then `install --global` which restarts daemon, regenerates session wrappers, normalizes roster, registers Codex hooks. This is the recommended customer path. (3) `npm run deploy` \u2014 dev-only (COO/CTO on main branch). Builds, installs globally, runs `install --global`, restarts daemon. Never run from a worktree. NEVER confuse `exe-os setup` (first-time setup wizard for new installs) with `exe-os update` (update existing install). Setup creates encryption keys, configures cloud, runs first sync. Update just replaces code and restarts services. They are completely different commands."
3691
+ },
3692
+ {
3693
+ title: "First install \u2014 setup wizard and license activation",
3694
+ domain: "operations",
3695
+ priority: "p1",
3696
+ content: "Fresh install: `npm install -g @askexenow/exe-os` then run `exe` to start the setup wizard. The wizard prompts for: encryption passphrase (creates master key), license key (exe_sk_* from AskExe team), COO name, and optional team members. No license key = free tier (1 employee, 5K memories). After setup: hooks install automatically, MCP server registers in ~/.claude.json, daemon starts. Verify health: run `exe-os healthcheck` or use mcp_ping() tool."
3697
+ },
3678
3698
  // --- Operations ---
3679
3699
  {
3680
3700
  title: "Managers must supervise deployed workers",
@@ -3725,12 +3745,6 @@ var init_platform_procedures = __esm({
3725
3745
  priority: "p0",
3726
3746
  content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
3727
3747
  },
3728
- {
3729
- title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3730
- domain: "workflow",
3731
- priority: "p0",
3732
- content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
3733
- },
3734
3748
  {
3735
3749
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3736
3750
  domain: "architecture",
@@ -3786,7 +3800,7 @@ var init_platform_procedures = __esm({
3786
3800
  title: "MCP tools \u2014 identity, behavior, and support",
3787
3801
  domain: "tool-use",
3788
3802
  priority: "p1",
3789
- content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug") / create_bug_report: file a bug report to AskExe (title, description, severity). support(action="create_feature") / create_feature_request: file a feature request. support(action="health") / support_health: check support server readiness. support(action="triage_bug"): triage a bug (id, triage_notes). AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3803
+ content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug"): file a bug report (title, description, severity p0-p3). Auto-delivers to AskExe. support(action="create_feature"): file a feature request (title, description, use_case). support(action="list_my_bugs"): check status of YOUR filed bug reports \u2014 see which are open, triaged, or fixed with version number. support(action="list_my_features"): check status of YOUR filed feature requests \u2014 see which are planned, shipped, or closed. support(action="health"): verify support server is reachable. When a bug you filed shows status='fixed' with a fixed_version, update exe-os to that version to get the fix. support(action="triage_bug"): AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3790
3804
  },
3791
3805
  {
3792
3806
  title: "MCP tools \u2014 communication and messaging",
@@ -1606,7 +1606,15 @@ function getClient() {
1606
1606
  if (!_resilientClient) {
1607
1607
  return _adapterClient;
1608
1608
  }
1609
- return _resilientClient;
1609
+ if (process.env.EXE_DB_READONLY === "1") {
1610
+ return _resilientClient;
1611
+ }
1612
+ process.stderr.write(
1613
+ "[database] ERROR: Daemon is not running \u2014 refusing direct SQLite write access.\n[database] Direct writes bypass the single-writer gate and corrupt FTS5 indexes.\n[database] Restart the daemon: kill $(cat ~/.exe-os/exed.pid) && exe-os update\n[database] Or set EXE_DB_READONLY=1 if you only need read access.\n"
1614
+ );
1615
+ throw new Error(
1616
+ "Daemon not running. Direct SQLite writes are blocked to prevent FTS5 corruption. Restart daemon or set EXE_DB_READONLY=1 for read-only access."
1617
+ );
1610
1618
  }
1611
1619
  async function initDaemonClient() {
1612
1620
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
@@ -3627,7 +3635,7 @@ var init_platform_procedures = __esm({
3627
3635
  title: "Bug report status check \u2014 surface available fixes on boot",
3628
3636
  domain: "support",
3629
3637
  priority: "p1",
3630
- content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \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 reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3638
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_bugs') to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'closed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. You can also file new bugs with support(action='create_bug') and check status anytime with support(action='list_my_bugs'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3631
3639
  },
3632
3640
  {
3633
3641
  title: "Feature request triage \u2014 upstream feature vs local customization",
@@ -3639,7 +3647,7 @@ var init_platform_procedures = __esm({
3639
3647
  title: "Feature request status check \u2014 surface shipped features on boot",
3640
3648
  domain: "support",
3641
3649
  priority: "p1",
3642
- 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."
3650
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_features') 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'. You can also file new requests with support(action='create_feature') and check status anytime with support(action='list_my_features'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3643
3651
  },
3644
3652
  // --- Tool guidance ---
3645
3653
  {
@@ -3675,6 +3683,18 @@ var init_platform_procedures = __esm({
3675
3683
  priority: "p0",
3676
3684
  content: "exe-os has TWO version numbers that move independently. This is normal \u2014 do not treat a mismatch as an error. (1) CLI version (e.g. 0.9.89, 0.9.90) \u2014 the npm package installed locally. Updates frequently: bug fixes, new MCP tools, platform procedures, search improvements, client-side changes. Update with `npm install -g @askexenow/exe-os@latest`. (2) Stack version (e.g. 0.9.7, 0.9.8) \u2014 the Docker images on the VPS. Updates less frequently: only when server-side daemon, gateway, wiki, or CRM images need rebuilding. Update with `exe-os stack-update --target <version> --yes`. The CLI version will almost always be higher than the stack version. A CLI at 0.9.90 with a stack at 0.9.8 is perfectly normal \u2014 it means the CLI got 12 patches since the last Docker image rebuild. Only update the stack when: (a) the boot brief surfaces a fix that mentions 'stack update required', (b) a new stack manifest version is bundled in the CLI (`exe-os stack-update --check` shows pending changes), or (c) AskExe support explicitly tells you to. Do NOT attempt to make the numbers match \u2014 they are separate tracks."
3677
3685
  },
3686
+ {
3687
+ title: "Update lifecycle \u2014 what each command does and what picks up new code",
3688
+ domain: "operations",
3689
+ priority: "p0",
3690
+ content: "Three update paths exist \u2014 know which does what. (1) `npm install -g @askexenow/exe-os@latest` \u2014 customer update. Replaces all dist/ files. postinstall copies slash commands AND restarts the daemon automatically. MCP server picks up new code on next `/mcp` reconnect or new Claude Code session. Hooks pick up new code on next session (they spawn fresh processes). (2) `exe-os update` \u2014 interactive update command. Runs `npm install -g` then `install --global` which restarts daemon, regenerates session wrappers, normalizes roster, registers Codex hooks. This is the recommended customer path. (3) `npm run deploy` \u2014 dev-only (COO/CTO on main branch). Builds, installs globally, runs `install --global`, restarts daemon. Never run from a worktree. NEVER confuse `exe-os setup` (first-time setup wizard for new installs) with `exe-os update` (update existing install). Setup creates encryption keys, configures cloud, runs first sync. Update just replaces code and restarts services. They are completely different commands."
3691
+ },
3692
+ {
3693
+ title: "First install \u2014 setup wizard and license activation",
3694
+ domain: "operations",
3695
+ priority: "p1",
3696
+ content: "Fresh install: `npm install -g @askexenow/exe-os` then run `exe` to start the setup wizard. The wizard prompts for: encryption passphrase (creates master key), license key (exe_sk_* from AskExe team), COO name, and optional team members. No license key = free tier (1 employee, 5K memories). After setup: hooks install automatically, MCP server registers in ~/.claude.json, daemon starts. Verify health: run `exe-os healthcheck` or use mcp_ping() tool."
3697
+ },
3678
3698
  // --- Operations ---
3679
3699
  {
3680
3700
  title: "Managers must supervise deployed workers",
@@ -3725,12 +3745,6 @@ var init_platform_procedures = __esm({
3725
3745
  priority: "p0",
3726
3746
  content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
3727
3747
  },
3728
- {
3729
- title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3730
- domain: "workflow",
3731
- priority: "p0",
3732
- content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
3733
- },
3734
3748
  {
3735
3749
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3736
3750
  domain: "architecture",
@@ -3786,7 +3800,7 @@ var init_platform_procedures = __esm({
3786
3800
  title: "MCP tools \u2014 identity, behavior, and support",
3787
3801
  domain: "tool-use",
3788
3802
  priority: "p1",
3789
- content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug") / create_bug_report: file a bug report to AskExe (title, description, severity). support(action="create_feature") / create_feature_request: file a feature request. support(action="health") / support_health: check support server readiness. support(action="triage_bug"): triage a bug (id, triage_notes). AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3803
+ content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug"): file a bug report (title, description, severity p0-p3). Auto-delivers to AskExe. support(action="create_feature"): file a feature request (title, description, use_case). support(action="list_my_bugs"): check status of YOUR filed bug reports \u2014 see which are open, triaged, or fixed with version number. support(action="list_my_features"): check status of YOUR filed feature requests \u2014 see which are planned, shipped, or closed. support(action="health"): verify support server is reachable. When a bug you filed shows status='fixed' with a fixed_version, update exe-os to that version to get the fix. support(action="triage_bug"): AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3790
3804
  },
3791
3805
  {
3792
3806
  title: "MCP tools \u2014 communication and messaging",
@@ -1606,7 +1606,15 @@ function getClient() {
1606
1606
  if (!_resilientClient) {
1607
1607
  return _adapterClient;
1608
1608
  }
1609
- return _resilientClient;
1609
+ if (process.env.EXE_DB_READONLY === "1") {
1610
+ return _resilientClient;
1611
+ }
1612
+ process.stderr.write(
1613
+ "[database] ERROR: Daemon is not running \u2014 refusing direct SQLite write access.\n[database] Direct writes bypass the single-writer gate and corrupt FTS5 indexes.\n[database] Restart the daemon: kill $(cat ~/.exe-os/exed.pid) && exe-os update\n[database] Or set EXE_DB_READONLY=1 if you only need read access.\n"
1614
+ );
1615
+ throw new Error(
1616
+ "Daemon not running. Direct SQLite writes are blocked to prevent FTS5 corruption. Restart daemon or set EXE_DB_READONLY=1 for read-only access."
1617
+ );
1610
1618
  }
1611
1619
  async function initDaemonClient() {
1612
1620
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
@@ -3627,7 +3635,7 @@ var init_platform_procedures = __esm({
3627
3635
  title: "Bug report status check \u2014 surface available fixes on boot",
3628
3636
  domain: "support",
3629
3637
  priority: "p1",
3630
- content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \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 reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3638
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_bugs') to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'closed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. You can also file new bugs with support(action='create_bug') and check status anytime with support(action='list_my_bugs'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3631
3639
  },
3632
3640
  {
3633
3641
  title: "Feature request triage \u2014 upstream feature vs local customization",
@@ -3639,7 +3647,7 @@ var init_platform_procedures = __esm({
3639
3647
  title: "Feature request status check \u2014 surface shipped features on boot",
3640
3648
  domain: "support",
3641
3649
  priority: "p1",
3642
- 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."
3650
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_features') 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'. You can also file new requests with support(action='create_feature') and check status anytime with support(action='list_my_features'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3643
3651
  },
3644
3652
  // --- Tool guidance ---
3645
3653
  {
@@ -3675,6 +3683,18 @@ var init_platform_procedures = __esm({
3675
3683
  priority: "p0",
3676
3684
  content: "exe-os has TWO version numbers that move independently. This is normal \u2014 do not treat a mismatch as an error. (1) CLI version (e.g. 0.9.89, 0.9.90) \u2014 the npm package installed locally. Updates frequently: bug fixes, new MCP tools, platform procedures, search improvements, client-side changes. Update with `npm install -g @askexenow/exe-os@latest`. (2) Stack version (e.g. 0.9.7, 0.9.8) \u2014 the Docker images on the VPS. Updates less frequently: only when server-side daemon, gateway, wiki, or CRM images need rebuilding. Update with `exe-os stack-update --target <version> --yes`. The CLI version will almost always be higher than the stack version. A CLI at 0.9.90 with a stack at 0.9.8 is perfectly normal \u2014 it means the CLI got 12 patches since the last Docker image rebuild. Only update the stack when: (a) the boot brief surfaces a fix that mentions 'stack update required', (b) a new stack manifest version is bundled in the CLI (`exe-os stack-update --check` shows pending changes), or (c) AskExe support explicitly tells you to. Do NOT attempt to make the numbers match \u2014 they are separate tracks."
3677
3685
  },
3686
+ {
3687
+ title: "Update lifecycle \u2014 what each command does and what picks up new code",
3688
+ domain: "operations",
3689
+ priority: "p0",
3690
+ content: "Three update paths exist \u2014 know which does what. (1) `npm install -g @askexenow/exe-os@latest` \u2014 customer update. Replaces all dist/ files. postinstall copies slash commands AND restarts the daemon automatically. MCP server picks up new code on next `/mcp` reconnect or new Claude Code session. Hooks pick up new code on next session (they spawn fresh processes). (2) `exe-os update` \u2014 interactive update command. Runs `npm install -g` then `install --global` which restarts daemon, regenerates session wrappers, normalizes roster, registers Codex hooks. This is the recommended customer path. (3) `npm run deploy` \u2014 dev-only (COO/CTO on main branch). Builds, installs globally, runs `install --global`, restarts daemon. Never run from a worktree. NEVER confuse `exe-os setup` (first-time setup wizard for new installs) with `exe-os update` (update existing install). Setup creates encryption keys, configures cloud, runs first sync. Update just replaces code and restarts services. They are completely different commands."
3691
+ },
3692
+ {
3693
+ title: "First install \u2014 setup wizard and license activation",
3694
+ domain: "operations",
3695
+ priority: "p1",
3696
+ content: "Fresh install: `npm install -g @askexenow/exe-os` then run `exe` to start the setup wizard. The wizard prompts for: encryption passphrase (creates master key), license key (exe_sk_* from AskExe team), COO name, and optional team members. No license key = free tier (1 employee, 5K memories). After setup: hooks install automatically, MCP server registers in ~/.claude.json, daemon starts. Verify health: run `exe-os healthcheck` or use mcp_ping() tool."
3697
+ },
3678
3698
  // --- Operations ---
3679
3699
  {
3680
3700
  title: "Managers must supervise deployed workers",
@@ -3725,12 +3745,6 @@ var init_platform_procedures = __esm({
3725
3745
  priority: "p0",
3726
3746
  content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
3727
3747
  },
3728
- {
3729
- title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3730
- domain: "workflow",
3731
- priority: "p0",
3732
- content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
3733
- },
3734
3748
  {
3735
3749
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3736
3750
  domain: "architecture",
@@ -3786,7 +3800,7 @@ var init_platform_procedures = __esm({
3786
3800
  title: "MCP tools \u2014 identity, behavior, and support",
3787
3801
  domain: "tool-use",
3788
3802
  priority: "p1",
3789
- content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug") / create_bug_report: file a bug report to AskExe (title, description, severity). support(action="create_feature") / create_feature_request: file a feature request. support(action="health") / support_health: check support server readiness. support(action="triage_bug"): triage a bug (id, triage_notes). AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3803
+ content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug"): file a bug report (title, description, severity p0-p3). Auto-delivers to AskExe. support(action="create_feature"): file a feature request (title, description, use_case). support(action="list_my_bugs"): check status of YOUR filed bug reports \u2014 see which are open, triaged, or fixed with version number. support(action="list_my_features"): check status of YOUR filed feature requests \u2014 see which are planned, shipped, or closed. support(action="health"): verify support server is reachable. When a bug you filed shows status='fixed' with a fixed_version, update exe-os to that version to get the fix. support(action="triage_bug"): AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3790
3804
  },
3791
3805
  {
3792
3806
  title: "MCP tools \u2014 communication and messaging",
@@ -1746,7 +1746,15 @@ function getClient() {
1746
1746
  if (!_resilientClient) {
1747
1747
  return _adapterClient;
1748
1748
  }
1749
- return _resilientClient;
1749
+ if (process.env.EXE_DB_READONLY === "1") {
1750
+ return _resilientClient;
1751
+ }
1752
+ process.stderr.write(
1753
+ "[database] ERROR: Daemon is not running \u2014 refusing direct SQLite write access.\n[database] Direct writes bypass the single-writer gate and corrupt FTS5 indexes.\n[database] Restart the daemon: kill $(cat ~/.exe-os/exed.pid) && exe-os update\n[database] Or set EXE_DB_READONLY=1 if you only need read access.\n"
1754
+ );
1755
+ throw new Error(
1756
+ "Daemon not running. Direct SQLite writes are blocked to prevent FTS5 corruption. Restart daemon or set EXE_DB_READONLY=1 for read-only access."
1757
+ );
1750
1758
  }
1751
1759
  async function initDaemonClient() {
1752
1760
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
@@ -3767,7 +3775,7 @@ var init_platform_procedures = __esm({
3767
3775
  title: "Bug report status check \u2014 surface available fixes on boot",
3768
3776
  domain: "support",
3769
3777
  priority: "p1",
3770
- content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \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 reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3778
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_bugs') to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'closed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. You can also file new bugs with support(action='create_bug') and check status anytime with support(action='list_my_bugs'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3771
3779
  },
3772
3780
  {
3773
3781
  title: "Feature request triage \u2014 upstream feature vs local customization",
@@ -3779,7 +3787,7 @@ var init_platform_procedures = __esm({
3779
3787
  title: "Feature request status check \u2014 surface shipped features on boot",
3780
3788
  domain: "support",
3781
3789
  priority: "p1",
3782
- 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."
3790
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_features') 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'. You can also file new requests with support(action='create_feature') and check status anytime with support(action='list_my_features'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3783
3791
  },
3784
3792
  // --- Tool guidance ---
3785
3793
  {
@@ -3815,6 +3823,18 @@ var init_platform_procedures = __esm({
3815
3823
  priority: "p0",
3816
3824
  content: "exe-os has TWO version numbers that move independently. This is normal \u2014 do not treat a mismatch as an error. (1) CLI version (e.g. 0.9.89, 0.9.90) \u2014 the npm package installed locally. Updates frequently: bug fixes, new MCP tools, platform procedures, search improvements, client-side changes. Update with `npm install -g @askexenow/exe-os@latest`. (2) Stack version (e.g. 0.9.7, 0.9.8) \u2014 the Docker images on the VPS. Updates less frequently: only when server-side daemon, gateway, wiki, or CRM images need rebuilding. Update with `exe-os stack-update --target <version> --yes`. The CLI version will almost always be higher than the stack version. A CLI at 0.9.90 with a stack at 0.9.8 is perfectly normal \u2014 it means the CLI got 12 patches since the last Docker image rebuild. Only update the stack when: (a) the boot brief surfaces a fix that mentions 'stack update required', (b) a new stack manifest version is bundled in the CLI (`exe-os stack-update --check` shows pending changes), or (c) AskExe support explicitly tells you to. Do NOT attempt to make the numbers match \u2014 they are separate tracks."
3817
3825
  },
3826
+ {
3827
+ title: "Update lifecycle \u2014 what each command does and what picks up new code",
3828
+ domain: "operations",
3829
+ priority: "p0",
3830
+ content: "Three update paths exist \u2014 know which does what. (1) `npm install -g @askexenow/exe-os@latest` \u2014 customer update. Replaces all dist/ files. postinstall copies slash commands AND restarts the daemon automatically. MCP server picks up new code on next `/mcp` reconnect or new Claude Code session. Hooks pick up new code on next session (they spawn fresh processes). (2) `exe-os update` \u2014 interactive update command. Runs `npm install -g` then `install --global` which restarts daemon, regenerates session wrappers, normalizes roster, registers Codex hooks. This is the recommended customer path. (3) `npm run deploy` \u2014 dev-only (COO/CTO on main branch). Builds, installs globally, runs `install --global`, restarts daemon. Never run from a worktree. NEVER confuse `exe-os setup` (first-time setup wizard for new installs) with `exe-os update` (update existing install). Setup creates encryption keys, configures cloud, runs first sync. Update just replaces code and restarts services. They are completely different commands."
3831
+ },
3832
+ {
3833
+ title: "First install \u2014 setup wizard and license activation",
3834
+ domain: "operations",
3835
+ priority: "p1",
3836
+ content: "Fresh install: `npm install -g @askexenow/exe-os` then run `exe` to start the setup wizard. The wizard prompts for: encryption passphrase (creates master key), license key (exe_sk_* from AskExe team), COO name, and optional team members. No license key = free tier (1 employee, 5K memories). After setup: hooks install automatically, MCP server registers in ~/.claude.json, daemon starts. Verify health: run `exe-os healthcheck` or use mcp_ping() tool."
3837
+ },
3818
3838
  // --- Operations ---
3819
3839
  {
3820
3840
  title: "Managers must supervise deployed workers",
@@ -3865,12 +3885,6 @@ var init_platform_procedures = __esm({
3865
3885
  priority: "p0",
3866
3886
  content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
3867
3887
  },
3868
- {
3869
- title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3870
- domain: "workflow",
3871
- priority: "p0",
3872
- content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
3873
- },
3874
3888
  {
3875
3889
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3876
3890
  domain: "architecture",
@@ -3926,7 +3940,7 @@ var init_platform_procedures = __esm({
3926
3940
  title: "MCP tools \u2014 identity, behavior, and support",
3927
3941
  domain: "tool-use",
3928
3942
  priority: "p1",
3929
- content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug") / create_bug_report: file a bug report to AskExe (title, description, severity). support(action="create_feature") / create_feature_request: file a feature request. support(action="health") / support_health: check support server readiness. support(action="triage_bug"): triage a bug (id, triage_notes). AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3943
+ content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug"): file a bug report (title, description, severity p0-p3). Auto-delivers to AskExe. support(action="create_feature"): file a feature request (title, description, use_case). support(action="list_my_bugs"): check status of YOUR filed bug reports \u2014 see which are open, triaged, or fixed with version number. support(action="list_my_features"): check status of YOUR filed feature requests \u2014 see which are planned, shipped, or closed. support(action="health"): verify support server is reachable. When a bug you filed shows status='fixed' with a fixed_version, update exe-os to that version to get the fix. support(action="triage_bug"): AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3930
3944
  },
3931
3945
  {
3932
3946
  title: "MCP tools \u2014 communication and messaging",
@@ -1746,7 +1746,15 @@ function getClient() {
1746
1746
  if (!_resilientClient) {
1747
1747
  return _adapterClient;
1748
1748
  }
1749
- return _resilientClient;
1749
+ if (process.env.EXE_DB_READONLY === "1") {
1750
+ return _resilientClient;
1751
+ }
1752
+ process.stderr.write(
1753
+ "[database] ERROR: Daemon is not running \u2014 refusing direct SQLite write access.\n[database] Direct writes bypass the single-writer gate and corrupt FTS5 indexes.\n[database] Restart the daemon: kill $(cat ~/.exe-os/exed.pid) && exe-os update\n[database] Or set EXE_DB_READONLY=1 if you only need read access.\n"
1754
+ );
1755
+ throw new Error(
1756
+ "Daemon not running. Direct SQLite writes are blocked to prevent FTS5 corruption. Restart daemon or set EXE_DB_READONLY=1 for read-only access."
1757
+ );
1750
1758
  }
1751
1759
  async function initDaemonClient() {
1752
1760
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
@@ -3767,7 +3775,7 @@ var init_platform_procedures = __esm({
3767
3775
  title: "Bug report status check \u2014 surface available fixes on boot",
3768
3776
  domain: "support",
3769
3777
  priority: "p1",
3770
- content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \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 reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3778
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_bugs') to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'closed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. You can also file new bugs with support(action='create_bug') and check status anytime with support(action='list_my_bugs'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3771
3779
  },
3772
3780
  {
3773
3781
  title: "Feature request triage \u2014 upstream feature vs local customization",
@@ -3779,7 +3787,7 @@ var init_platform_procedures = __esm({
3779
3787
  title: "Feature request status check \u2014 surface shipped features on boot",
3780
3788
  domain: "support",
3781
3789
  priority: "p1",
3782
- 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."
3790
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_features') 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'. You can also file new requests with support(action='create_feature') and check status anytime with support(action='list_my_features'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3783
3791
  },
3784
3792
  // --- Tool guidance ---
3785
3793
  {
@@ -3815,6 +3823,18 @@ var init_platform_procedures = __esm({
3815
3823
  priority: "p0",
3816
3824
  content: "exe-os has TWO version numbers that move independently. This is normal \u2014 do not treat a mismatch as an error. (1) CLI version (e.g. 0.9.89, 0.9.90) \u2014 the npm package installed locally. Updates frequently: bug fixes, new MCP tools, platform procedures, search improvements, client-side changes. Update with `npm install -g @askexenow/exe-os@latest`. (2) Stack version (e.g. 0.9.7, 0.9.8) \u2014 the Docker images on the VPS. Updates less frequently: only when server-side daemon, gateway, wiki, or CRM images need rebuilding. Update with `exe-os stack-update --target <version> --yes`. The CLI version will almost always be higher than the stack version. A CLI at 0.9.90 with a stack at 0.9.8 is perfectly normal \u2014 it means the CLI got 12 patches since the last Docker image rebuild. Only update the stack when: (a) the boot brief surfaces a fix that mentions 'stack update required', (b) a new stack manifest version is bundled in the CLI (`exe-os stack-update --check` shows pending changes), or (c) AskExe support explicitly tells you to. Do NOT attempt to make the numbers match \u2014 they are separate tracks."
3817
3825
  },
3826
+ {
3827
+ title: "Update lifecycle \u2014 what each command does and what picks up new code",
3828
+ domain: "operations",
3829
+ priority: "p0",
3830
+ content: "Three update paths exist \u2014 know which does what. (1) `npm install -g @askexenow/exe-os@latest` \u2014 customer update. Replaces all dist/ files. postinstall copies slash commands AND restarts the daemon automatically. MCP server picks up new code on next `/mcp` reconnect or new Claude Code session. Hooks pick up new code on next session (they spawn fresh processes). (2) `exe-os update` \u2014 interactive update command. Runs `npm install -g` then `install --global` which restarts daemon, regenerates session wrappers, normalizes roster, registers Codex hooks. This is the recommended customer path. (3) `npm run deploy` \u2014 dev-only (COO/CTO on main branch). Builds, installs globally, runs `install --global`, restarts daemon. Never run from a worktree. NEVER confuse `exe-os setup` (first-time setup wizard for new installs) with `exe-os update` (update existing install). Setup creates encryption keys, configures cloud, runs first sync. Update just replaces code and restarts services. They are completely different commands."
3831
+ },
3832
+ {
3833
+ title: "First install \u2014 setup wizard and license activation",
3834
+ domain: "operations",
3835
+ priority: "p1",
3836
+ content: "Fresh install: `npm install -g @askexenow/exe-os` then run `exe` to start the setup wizard. The wizard prompts for: encryption passphrase (creates master key), license key (exe_sk_* from AskExe team), COO name, and optional team members. No license key = free tier (1 employee, 5K memories). After setup: hooks install automatically, MCP server registers in ~/.claude.json, daemon starts. Verify health: run `exe-os healthcheck` or use mcp_ping() tool."
3837
+ },
3818
3838
  // --- Operations ---
3819
3839
  {
3820
3840
  title: "Managers must supervise deployed workers",
@@ -3865,12 +3885,6 @@ var init_platform_procedures = __esm({
3865
3885
  priority: "p0",
3866
3886
  content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
3867
3887
  },
3868
- {
3869
- title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3870
- domain: "workflow",
3871
- priority: "p0",
3872
- content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
3873
- },
3874
3888
  {
3875
3889
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3876
3890
  domain: "architecture",
@@ -3926,7 +3940,7 @@ var init_platform_procedures = __esm({
3926
3940
  title: "MCP tools \u2014 identity, behavior, and support",
3927
3941
  domain: "tool-use",
3928
3942
  priority: "p1",
3929
- content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug") / create_bug_report: file a bug report to AskExe (title, description, severity). support(action="create_feature") / create_feature_request: file a feature request. support(action="health") / support_health: check support server readiness. support(action="triage_bug"): triage a bug (id, triage_notes). AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3943
+ content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug"): file a bug report (title, description, severity p0-p3). Auto-delivers to AskExe. support(action="create_feature"): file a feature request (title, description, use_case). support(action="list_my_bugs"): check status of YOUR filed bug reports \u2014 see which are open, triaged, or fixed with version number. support(action="list_my_features"): check status of YOUR filed feature requests \u2014 see which are planned, shipped, or closed. support(action="health"): verify support server is reachable. When a bug you filed shows status='fixed' with a fixed_version, update exe-os to that version to get the fix. support(action="triage_bug"): AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3930
3944
  },
3931
3945
  {
3932
3946
  title: "MCP tools \u2014 communication and messaging",
@@ -1742,7 +1742,15 @@ function getClient() {
1742
1742
  if (!_resilientClient) {
1743
1743
  return _adapterClient;
1744
1744
  }
1745
- return _resilientClient;
1745
+ if (process.env.EXE_DB_READONLY === "1") {
1746
+ return _resilientClient;
1747
+ }
1748
+ process.stderr.write(
1749
+ "[database] ERROR: Daemon is not running \u2014 refusing direct SQLite write access.\n[database] Direct writes bypass the single-writer gate and corrupt FTS5 indexes.\n[database] Restart the daemon: kill $(cat ~/.exe-os/exed.pid) && exe-os update\n[database] Or set EXE_DB_READONLY=1 if you only need read access.\n"
1750
+ );
1751
+ throw new Error(
1752
+ "Daemon not running. Direct SQLite writes are blocked to prevent FTS5 corruption. Restart daemon or set EXE_DB_READONLY=1 for read-only access."
1753
+ );
1746
1754
  }
1747
1755
  async function initDaemonClient() {
1748
1756
  if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
@@ -3763,7 +3771,7 @@ var init_platform_procedures = __esm({
3763
3771
  title: "Bug report status check \u2014 surface available fixes on boot",
3764
3772
  domain: "support",
3765
3773
  priority: "p1",
3766
- content: "Once per session (COO boot only, never repeat), call list_my_bug_reports to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'fixed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \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 reports exist or none are fixed, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
3774
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_bugs') to check if any previously filed bug reports have been fixed by AskExe. If any report has status 'closed' with a fixed_version, surface it to the founder immediately: '\u{1F527} N bug fix(es) available \u2014 run exe-os update to get version X.Y.Z'. You can also file new bugs with support(action='create_bug') and check status anytime with support(action='list_my_bugs'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3767
3775
  },
3768
3776
  {
3769
3777
  title: "Feature request triage \u2014 upstream feature vs local customization",
@@ -3775,7 +3783,7 @@ var init_platform_procedures = __esm({
3775
3783
  title: "Feature request status check \u2014 surface shipped features on boot",
3776
3784
  domain: "support",
3777
3785
  priority: "p1",
3778
- 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."
3786
+ content: "Once per session (COO boot only, never repeat), call support(action='list_my_features') 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'. You can also file new requests with support(action='create_feature') and check status anytime with support(action='list_my_features'). This boot check is one-time, not a recurring poll. If the tool is unavailable, skip silently."
3779
3787
  },
3780
3788
  // --- Tool guidance ---
3781
3789
  {
@@ -3811,6 +3819,18 @@ var init_platform_procedures = __esm({
3811
3819
  priority: "p0",
3812
3820
  content: "exe-os has TWO version numbers that move independently. This is normal \u2014 do not treat a mismatch as an error. (1) CLI version (e.g. 0.9.89, 0.9.90) \u2014 the npm package installed locally. Updates frequently: bug fixes, new MCP tools, platform procedures, search improvements, client-side changes. Update with `npm install -g @askexenow/exe-os@latest`. (2) Stack version (e.g. 0.9.7, 0.9.8) \u2014 the Docker images on the VPS. Updates less frequently: only when server-side daemon, gateway, wiki, or CRM images need rebuilding. Update with `exe-os stack-update --target <version> --yes`. The CLI version will almost always be higher than the stack version. A CLI at 0.9.90 with a stack at 0.9.8 is perfectly normal \u2014 it means the CLI got 12 patches since the last Docker image rebuild. Only update the stack when: (a) the boot brief surfaces a fix that mentions 'stack update required', (b) a new stack manifest version is bundled in the CLI (`exe-os stack-update --check` shows pending changes), or (c) AskExe support explicitly tells you to. Do NOT attempt to make the numbers match \u2014 they are separate tracks."
3813
3821
  },
3822
+ {
3823
+ title: "Update lifecycle \u2014 what each command does and what picks up new code",
3824
+ domain: "operations",
3825
+ priority: "p0",
3826
+ content: "Three update paths exist \u2014 know which does what. (1) `npm install -g @askexenow/exe-os@latest` \u2014 customer update. Replaces all dist/ files. postinstall copies slash commands AND restarts the daemon automatically. MCP server picks up new code on next `/mcp` reconnect or new Claude Code session. Hooks pick up new code on next session (they spawn fresh processes). (2) `exe-os update` \u2014 interactive update command. Runs `npm install -g` then `install --global` which restarts daemon, regenerates session wrappers, normalizes roster, registers Codex hooks. This is the recommended customer path. (3) `npm run deploy` \u2014 dev-only (COO/CTO on main branch). Builds, installs globally, runs `install --global`, restarts daemon. Never run from a worktree. NEVER confuse `exe-os setup` (first-time setup wizard for new installs) with `exe-os update` (update existing install). Setup creates encryption keys, configures cloud, runs first sync. Update just replaces code and restarts services. They are completely different commands."
3827
+ },
3828
+ {
3829
+ title: "First install \u2014 setup wizard and license activation",
3830
+ domain: "operations",
3831
+ priority: "p1",
3832
+ content: "Fresh install: `npm install -g @askexenow/exe-os` then run `exe` to start the setup wizard. The wizard prompts for: encryption passphrase (creates master key), license key (exe_sk_* from AskExe team), COO name, and optional team members. No license key = free tier (1 employee, 5K memories). After setup: hooks install automatically, MCP server registers in ~/.claude.json, daemon starts. Verify health: run `exe-os healthcheck` or use mcp_ping() tool."
3833
+ },
3814
3834
  // --- Operations ---
3815
3835
  {
3816
3836
  title: "Managers must supervise deployed workers",
@@ -3861,12 +3881,6 @@ var init_platform_procedures = __esm({
3861
3881
  priority: "p0",
3862
3882
  content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
3863
3883
  },
3864
- {
3865
- title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
3866
- domain: "workflow",
3867
- priority: "p0",
3868
- content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
3869
- },
3870
3884
  {
3871
3885
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
3872
3886
  domain: "architecture",
@@ -3922,7 +3936,7 @@ var init_platform_procedures = __esm({
3922
3936
  title: "MCP tools \u2014 identity, behavior, and support",
3923
3937
  domain: "tool-use",
3924
3938
  priority: "p1",
3925
- content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug") / create_bug_report: file a bug report to AskExe (title, description, severity). support(action="create_feature") / create_feature_request: file a feature request. support(action="health") / support_health: check support server readiness. support(action="triage_bug"): triage a bug (id, triage_notes). AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3939
+ content: `identity(action="get") / get_identity: read an agent's exe.md (Layer 1 identity). identity(action="update") / update_identity: write an agent's exe.md. Identity > behavior. behavior(action="store") / store_behavior: record a correction or pattern (Layer 2 expertise). behavior(action="list") / list_behaviors: view active behaviors. behavior(action="deactivate") / deactivate_behavior: soft-delete a stale behavior. support(action="create_bug"): file a bug report (title, description, severity p0-p3). Auto-delivers to AskExe. support(action="create_feature"): file a feature request (title, description, use_case). support(action="list_my_bugs"): check status of YOUR filed bug reports \u2014 see which are open, triaged, or fixed with version number. support(action="list_my_features"): check status of YOUR filed feature requests \u2014 see which are planned, shipped, or closed. support(action="health"): verify support server is reachable. When a bug you filed shows status='fixed' with a fixed_version, update exe-os to that version to get the fix. support(action="triage_bug"): AskExe-internal only. CRITICAL: triage uses triage_notes NOT notes.`
3926
3940
  },
3927
3941
  {
3928
3942
  title: "MCP tools \u2014 communication and messaging",