@monoes/monomindcli 1.9.16 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.claude/commands/mastermind/_repeat.md +182 -39
  2. package/.claude/commands/mastermind/architect.md +17 -11
  3. package/.claude/commands/mastermind/brain.md +4 -0
  4. package/.claude/commands/mastermind/build.md +4 -0
  5. package/.claude/commands/mastermind/content.md +4 -0
  6. package/.claude/commands/mastermind/createorg.md +5 -3
  7. package/.claude/commands/mastermind/finance.md +4 -0
  8. package/.claude/commands/mastermind/idea.md +4 -0
  9. package/.claude/commands/mastermind/marketing.md +4 -0
  10. package/.claude/commands/mastermind/master.md +100 -46
  11. package/.claude/commands/mastermind/ops.md +4 -0
  12. package/.claude/commands/mastermind/release.md +4 -0
  13. package/.claude/commands/mastermind/research.md +4 -0
  14. package/.claude/commands/mastermind/review.md +4 -0
  15. package/.claude/commands/mastermind/runorg.md +5 -3
  16. package/.claude/commands/mastermind/sales.md +4 -0
  17. package/.claude/commands/mastermind/techport.md +9 -0
  18. package/.claude/commands/monomind/do.md +5 -1
  19. package/.claude/commands/monomind/idea.md +5 -1
  20. package/.claude/commands/monomind/improve.md +5 -1
  21. package/.claude/commands/monomind/repeat.md +85 -29
  22. package/.claude/commands/monomind/review.md +6 -2
  23. package/.claude/commands/monomind/understand.md +10 -8
  24. package/.claude/helpers/extras-registry.json +235 -235
  25. package/.claude/helpers/graphify-freshen.cjs +13 -1
  26. package/.claude/helpers/hook-handler.cjs +1 -1
  27. package/.claude/helpers/router.cjs +4 -1
  28. package/.claude/skills/mastermind/_protocol.md +37 -21
  29. package/.claude/skills/mastermind/access.md +236 -0
  30. package/.claude/skills/mastermind/activity.md +191 -0
  31. package/.claude/skills/mastermind/adapter-manager.md +259 -0
  32. package/.claude/skills/mastermind/adapters.md +204 -0
  33. package/.claude/skills/mastermind/agent-detail.md +242 -0
  34. package/.claude/skills/mastermind/agents.md +178 -0
  35. package/.claude/skills/mastermind/approval-detail.md +259 -0
  36. package/.claude/skills/mastermind/approve.md +181 -0
  37. package/.claude/skills/mastermind/architect.md +24 -8
  38. package/.claude/skills/mastermind/backup.md +197 -0
  39. package/.claude/skills/mastermind/bootstrap.md +190 -0
  40. package/.claude/skills/mastermind/budgets.md +237 -0
  41. package/.claude/skills/mastermind/companies.md +256 -0
  42. package/.claude/skills/mastermind/costs.md +151 -0
  43. package/.claude/skills/mastermind/createorg.md +23 -5
  44. package/.claude/skills/mastermind/diagnose.md +249 -0
  45. package/.claude/skills/mastermind/env.md +198 -0
  46. package/.claude/skills/mastermind/environments.md +250 -0
  47. package/.claude/skills/mastermind/export.md +324 -0
  48. package/.claude/skills/mastermind/goal-detail.md +255 -0
  49. package/.claude/skills/mastermind/goals.md +149 -0
  50. package/.claude/skills/mastermind/heartbeat.md +164 -0
  51. package/.claude/skills/mastermind/idea.md +318 -186
  52. package/.claude/skills/mastermind/import.md +281 -0
  53. package/.claude/skills/mastermind/inbox.md +214 -0
  54. package/.claude/skills/mastermind/instance-settings.md +315 -0
  55. package/.claude/skills/mastermind/instance.md +231 -0
  56. package/.claude/skills/mastermind/invite-landing.md +227 -0
  57. package/.claude/skills/mastermind/invites.md +254 -0
  58. package/.claude/skills/mastermind/issue-detail.md +291 -0
  59. package/.claude/skills/mastermind/issues.md +235 -0
  60. package/.claude/skills/mastermind/join-queue.md +170 -0
  61. package/.claude/skills/mastermind/liveness.md +392 -0
  62. package/.claude/skills/mastermind/memory.md +321 -0
  63. package/.claude/skills/mastermind/my-issues.md +146 -0
  64. package/.claude/skills/mastermind/new-agent.md +241 -0
  65. package/.claude/skills/mastermind/org-chart.md +207 -0
  66. package/.claude/skills/mastermind/org-settings.md +217 -0
  67. package/.claude/skills/mastermind/plan-to-tasks.md +136 -0
  68. package/.claude/skills/mastermind/plugin-manager.md +241 -0
  69. package/.claude/skills/mastermind/plugin-settings.md +273 -0
  70. package/.claude/skills/mastermind/plugins.md +190 -0
  71. package/.claude/skills/mastermind/profile.md +187 -0
  72. package/.claude/skills/mastermind/project-detail.md +249 -0
  73. package/.claude/skills/mastermind/project-workspace.md +244 -0
  74. package/.claude/skills/mastermind/projects.md +164 -0
  75. package/.claude/skills/mastermind/routine-detail.md +253 -0
  76. package/.claude/skills/mastermind/routines.md +202 -0
  77. package/.claude/skills/mastermind/runorg.md +74 -9
  78. package/.claude/skills/mastermind/search.md +186 -0
  79. package/.claude/skills/mastermind/secrets.md +199 -0
  80. package/.claude/skills/mastermind/skills.md +156 -0
  81. package/.claude/skills/mastermind/tasks.md +149 -0
  82. package/.claude/skills/mastermind/techport.md +5 -5
  83. package/.claude/skills/mastermind/threads.md +259 -0
  84. package/.claude/skills/mastermind/tree-control.md +250 -0
  85. package/.claude/skills/mastermind/wiki.md +314 -0
  86. package/.claude/skills/mastermind/workspace-detail.md +317 -0
  87. package/.claude/skills/mastermind/workspaces.md +261 -0
  88. package/.claude/skills/mastermind/worktree.md +187 -0
  89. package/dist/src/init/executor.js +8 -8
  90. package/dist/src/init/executor.js.map +1 -1
  91. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  92. package/dist/src/init/statusline-generator.js +12 -0
  93. package/dist/src/init/statusline-generator.js.map +1 -1
  94. package/dist/src/ui/.monomind/data/ranked-context.json +1 -1
  95. package/dist/src/ui/.monomind/loops/mastermind-review-1778664132789.json +16 -0
  96. package/dist/src/ui/.monomind/sessions/current.json +5 -5
  97. package/dist/src/ui/.monomind/sessions/session-1776778451399.json +15 -0
  98. package/dist/src/ui/dashboard.html +3030 -181
  99. package/dist/src/ui/data/mastermind-events.jsonl +8 -0
  100. package/dist/src/ui/data/mastermind-sessions.json +1 -0
  101. package/dist/src/ui/server.mjs +738 -0
  102. package/dist/tsconfig.tsbuildinfo +1 -1
  103. package/package.json +1 -1
  104. package/.claude/skills/.monomind/data/ranked-context.json +0 -5
  105. package/.claude/skills/.monomind/sessions/current.json +0 -13
  106. package/.claude/skills/.monomind/sessions/session-1777829336455.json +0 -15
  107. package/.claude/skills/.monomind/sessions/session-1777831614725.json +0 -15
  108. package/.claude/skills/.monomind/sessions/session-1777832095857.json +0 -15
  109. package/.claude/skills/.monomind/sessions/session-1777839814183.json +0 -15
  110. package/.claude/skills/.monomind/sessions/session-1777841847131.json +0 -15
  111. package/.claude/skills/.monomind/sessions/session-1777843309463.json +0 -15
  112. package/.claude/skills/.monomind/sessions/session-1777880867159.json +0 -15
  113. package/.claude/skills/.monomind/sessions/session-1777881884593.json +0 -15
  114. package/.claude/skills/.monomind/sessions/session-1777884090471.json +0 -15
  115. package/.claude/skills/.monomind/sessions/session-1777884808221.json +0 -15
  116. package/.claude/skills/.monomind/sessions/session-1777885672155.json +0 -15
  117. package/.claude/skills/.monomind/sessions/session-1777886852818.json +0 -15
  118. package/.claude/skills/.monomind/sessions/session-1777896532690.json +0 -15
@@ -0,0 +1,250 @@
1
+ ---
2
+ name: mastermind-environments
3
+ description: Mastermind environments — manage execution environments (local, SSH, sandbox) for an org. Controls where agent workloads run, SSH connection details, and which environment is the default.
4
+ type: domain-skill
5
+ default_mode: confirm
6
+ ---
7
+
8
+ # Mastermind Environments
9
+
10
+ This skill is invoked by `mastermind:environments` or directly via `/mastermind:environments`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
17
+ - `org_name`: org to manage environments for (required)
18
+ - `action`: list | create | edit | delete | probe | set-default
19
+ - `env_id`: environment id (required for edit/delete/probe/set-default)
20
+ - `kind`: local | ssh | sandbox (required for create)
21
+ - `name`: display name (required for create)
22
+ - `host`: SSH hostname or IP (required for ssh kind)
23
+ - `port`: SSH port (default 22)
24
+ - `user`: SSH username (required for ssh kind)
25
+ - `secret_ref`: secret name holding the SSH private key (see mastermind:secrets — NEVER pass raw key values)
26
+ - `work_dir`: remote working directory (default: /tmp/monomind)
27
+ - `caller`: command | master
28
+
29
+ ---
30
+
31
+ ## Security Constraints
32
+
33
+ - NEVER print SSH private key values
34
+ - NEVER store key material in environment JSON files — store only the secret_ref name
35
+ - SSH keys must be stored via `mastermind:secrets` and referenced by name only
36
+ - Probe connection is read-only (runs `echo ok` over SSH)
37
+
38
+ ---
39
+
40
+ ## Step 0 — Brain Load (standalone only)
41
+
42
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
43
+
44
+ ---
45
+
46
+ ## Step 1 — Load Environments File
47
+
48
+ ```bash
49
+ orgFile=".monomind/orgs/${org_name}.json"
50
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
51
+
52
+ envFile=".monomind/orgs/${org_name}-environments.json"
53
+ [ ! -f "$envFile" ] && cat > "$envFile" <<'EOF'
54
+ {"environments":[],"default_env":null}
55
+ EOF
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Step 2 — Execute Action
61
+
62
+ ### list (default)
63
+
64
+ ```bash
65
+ echo "ENVIRONMENTS — org: $org_name"
66
+ echo "────────────────────────────────────────────────────────"
67
+ printf "%-20s %-10s %-28s %-8s %s\n" "ID" "KIND" "HOST / PATH" "DEFAULT" "SECRET REF"
68
+ echo "────────────────────────────────────────────────────────"
69
+
70
+ defaultEnv=$(jq -r '.default_env // "none"' "$envFile")
71
+ count=$(jq '.environments | length' "$envFile")
72
+
73
+ if [ "$count" -eq 0 ]; then
74
+ echo " No environments. Use --action create to add one."
75
+ else
76
+ jq -r --arg def "$defaultEnv" '.environments[] |
77
+ [
78
+ .id,
79
+ (.kind // "local"),
80
+ (if .kind == "ssh" then ((.user // "?") + "@" + (.host // "?") + ":" + ((.port // 22) | tostring)) else (.work_dir // "(local)") end),
81
+ (if .id == $def then "yes" else "-" end),
82
+ (.secret_ref // "-")
83
+ ] | @tsv' "$envFile" | while IFS=$'\t' read -r id kind loc def sref; do
84
+ printf "%-20s %-10s %-28s %-8s %s\n" "$id" "$kind" "$loc" "$def" "$sref"
85
+ done
86
+ fi
87
+
88
+ echo ""
89
+ echo "Total: $count environment(s) | Default: $defaultEnv"
90
+ ```
91
+
92
+ ### create
93
+
94
+ ```bash
95
+ [ -z "$kind" ] && { echo "ERROR: --kind required (local|ssh|sandbox)."; exit 1; }
96
+ [ -z "$name" ] && { echo "ERROR: --name required."; exit 1; }
97
+ case "$kind" in local|ssh|sandbox) : ;; *)
98
+ echo "ERROR: --kind must be local, ssh, or sandbox"; exit 1 ;;
99
+ esac
100
+ if [ "$kind" = "ssh" ]; then
101
+ [ -z "$host" ] && { echo "ERROR: --host required for ssh kind."; exit 1; }
102
+ [ -z "$user" ] && { echo "ERROR: --user required for ssh kind."; exit 1; }
103
+ [ -z "$secret_ref" ] && { echo "WARNING: No --secret-ref supplied. SSH key must be pre-configured on the agent."; }
104
+ fi
105
+
106
+ envId=$(echo "${name}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//;s/-$//')
107
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
108
+
109
+ tmp="${envFile}.tmp"
110
+ jq --arg id "$envId" \
111
+ --arg n "$name" \
112
+ --arg kind "$kind" \
113
+ --arg host "${host:-}" \
114
+ --argjson port "${port:-22}" \
115
+ --arg user "${user:-}" \
116
+ --arg sref "${secret_ref:-}" \
117
+ --arg wdir "${work_dir:-/tmp/monomind}" \
118
+ --arg ts "$ts" \
119
+ '.environments = [.environments[] | select(.id != $id)] +
120
+ [{"id":$id,"name":$n,"kind":$kind,
121
+ "host":(if $host != "" then $host else null end),
122
+ "port":(if $host != "" then $port else null end),
123
+ "user":(if $user != "" then $user else null end),
124
+ "secret_ref":(if $sref != "" then $sref else null end),
125
+ "work_dir":$wdir,
126
+ "createdAt":$ts,"lastProbe":null,"probeStatus":null}]' \
127
+ "$envFile" > "$tmp" && mv "$tmp" "$envFile"
128
+
129
+ echo "Created environment: $envId (kind: $kind)"
130
+ [ "$kind" = "ssh" ] && echo " SSH: ${user}@${host}:${port:-22} key ref: ${secret_ref:-(none)}"
131
+ echo "Run --action probe --env-id $envId to verify connectivity."
132
+ ```
133
+
134
+ ### edit
135
+
136
+ ```bash
137
+ [ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
138
+ exists=$(jq --arg id "$env_id" '[.environments[] | select(.id == $id)] | length' "$envFile")
139
+ [ "$exists" -eq 0 ] && { echo "ERROR: Environment '$env_id' not found."; exit 1; }
140
+
141
+ tmp="${envFile}.tmp"
142
+ jq --arg id "$env_id" \
143
+ --arg host "${host:-}" \
144
+ --argjson port "${port:-0}" \
145
+ --arg user "${user:-}" \
146
+ --arg sref "${secret_ref:-}" \
147
+ --arg wdir "${work_dir:-}" \
148
+ '.environments = [.environments[] | if .id == $id then
149
+ . *
150
+ (if $host != "" then {"host":$host} else {} end) *
151
+ (if $port > 0 then {"port":$port} else {} end) *
152
+ (if $user != "" then {"user":$user} else {} end) *
153
+ (if $sref != "" then {"secret_ref":$sref} else {} end) *
154
+ (if $wdir != "" then {"work_dir":$wdir} else {} end)
155
+ else . end]' \
156
+ "$envFile" > "$tmp" && mv "$tmp" "$envFile"
157
+
158
+ echo "Updated environment: $env_id"
159
+ ```
160
+
161
+ ### delete
162
+
163
+ ```bash
164
+ [ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
165
+ tmp="${envFile}.tmp"
166
+ jq --arg id "$env_id" \
167
+ '.environments = [.environments[] | select(.id != $id)] |
168
+ if .default_env == $id then .default_env = null else . end' \
169
+ "$envFile" > "$tmp" && mv "$tmp" "$envFile"
170
+ echo "Deleted environment: $env_id"
171
+ ```
172
+
173
+ ### probe
174
+
175
+ ```bash
176
+ [ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
177
+ envData=$(jq -r --arg id "$env_id" '.environments[] | select(.id == $id)' "$envFile")
178
+ [ -z "$envData" ] && { echo "ERROR: Environment '$env_id' not found."; exit 1; }
179
+
180
+ kind=$(echo "$envData" | jq -r '.kind')
181
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
182
+
183
+ case "$kind" in
184
+ local)
185
+ if [ -d "$(echo "$envData" | jq -r '.work_dir // "/tmp/monomind"')" ]; then
186
+ status="ok"
187
+ else
188
+ status="unreachable"
189
+ fi
190
+ ;;
191
+ ssh)
192
+ sshHost=$(echo "$envData" | jq -r '.host')
193
+ sshUser=$(echo "$envData" | jq -r '.user')
194
+ sshPort=$(echo "$envData" | jq -r '.port // 22')
195
+ sref=$(echo "$envData" | jq -r '.secret_ref // ""')
196
+ keyPath=""
197
+ [ -n "$sref" ] && keyPath=$(cat ".monomind/orgs/.secrets/${org_name}/${sref}" 2>/dev/null | jq -r '.path // ""' 2>/dev/null || echo "")
198
+
199
+ if [ -n "$keyPath" ] && [ -f "$keyPath" ]; then
200
+ result=$(ssh -i "$keyPath" -p "$sshPort" -o ConnectTimeout=5 -o StrictHostKeyChecking=no \
201
+ "${sshUser}@${sshHost}" "echo ok" 2>&1)
202
+ else
203
+ result=$(ssh -p "$sshPort" -o ConnectTimeout=5 -o StrictHostKeyChecking=no \
204
+ "${sshUser}@${sshHost}" "echo ok" 2>&1)
205
+ fi
206
+ [ "$result" = "ok" ] && status="ok" || status="unreachable"
207
+ ;;
208
+ sandbox)
209
+ status="unknown"
210
+ ;;
211
+ esac
212
+
213
+ tmp="${envFile}.tmp"
214
+ jq --arg id "$env_id" --arg st "$status" --arg ts "$ts" \
215
+ '.environments = [.environments[] | if .id == $id then .probeStatus = $st | .lastProbe = $ts else . end]' \
216
+ "$envFile" > "$tmp" && mv "$tmp" "$envFile"
217
+
218
+ echo "Probe [$env_id]: $status (checked at $ts)"
219
+ ```
220
+
221
+ ### set-default
222
+
223
+ ```bash
224
+ [ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
225
+ exists=$(jq --arg id "$env_id" '[.environments[] | select(.id == $id)] | length' "$envFile")
226
+ [ "$exists" -eq 0 ] && { echo "ERROR: Environment '$env_id' not found."; exit 1; }
227
+
228
+ tmp="${envFile}.tmp"
229
+ jq --arg id "$env_id" '.default_env = $id' "$envFile" > "$tmp" && mv "$tmp" "$envFile"
230
+ echo "Default environment → $env_id"
231
+ ```
232
+
233
+ ---
234
+
235
+ ## Step 3 — Return Output
236
+
237
+ ```yaml
238
+ domain: ops
239
+ status: complete
240
+ action: <action>
241
+ org: <org_name>
242
+ environments_count: <N>
243
+ default_env: <id or null>
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Step 4 — Brain Write (standalone only)
249
+
250
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
@@ -0,0 +1,324 @@
1
+ ---
2
+ name: mastermind-export
3
+ description: Mastermind export — full org portability. Export an org to a compressed archive (tar.gz or zip) with file tree selection, and import from an archive with collision strategy and adapter override. Mirrors Paperclip's CompanyExport/CompanyImport pages.
4
+ type: domain-skill
5
+ default_mode: confirm
6
+ ---
7
+
8
+ # Mastermind Export
9
+
10
+ This skill is invoked by `mastermind:export` or directly via `/mastermind:export`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
17
+ - `org_name`: org to export/import (required)
18
+ - `action`: export | import | preview | list-archives
19
+ - `output_path`: destination path for exported archive (optional, default: `.monomind/exports/<org>-<ts>.tar.gz`)
20
+ - `input_path`: path to archive file to import (required for import)
21
+ - `collision_strategy`: merge | overwrite | skip (default: merge — for import)
22
+ - `adapter_override`: adapter type to substitute during import (optional: claude-local | gemini-local | codex-local)
23
+ - `include`: comma-separated sections to include (config,goals,routines,projects,members,adapters,secrets-refs,activity — default: all except secrets-refs)
24
+ - `dry_run`: true | false — for import, preview changes without writing (default false)
25
+ - `caller`: command | master
26
+
27
+ ---
28
+
29
+ ## Sections Available for Export
30
+
31
+ | Section | Files Included | Default |
32
+ |---------|---------------|---------|
33
+ | `config` | `<org>.json` | ✓ |
34
+ | `goals` | `<org>-goals.json` | ✓ |
35
+ | `routines` | `<org>-routines.json` | ✓ |
36
+ | `projects` | `<org>-projects.json` | ✓ |
37
+ | `members` | `<org>-members.json` | ✓ |
38
+ | `adapters` | `<org>-adapters.json` | ✓ |
39
+ | `environments` | `<org>-environments.json` | ✓ |
40
+ | `workspaces` | `<org>-workspaces.json` | ✓ |
41
+ | `activity` | `<org>-activity.jsonl` (last 500 events) | ✓ |
42
+ | `secrets-refs` | secret reference names only (NO values) | opt-in |
43
+
44
+ **SECURITY:** Secret *values* are NEVER exported. Only masked reference names may be included if `secrets-refs` is explicitly listed in `include`.
45
+
46
+ ## Collision Strategies (import)
47
+
48
+ | Strategy | Behavior |
49
+ |----------|----------|
50
+ | `merge` | New records added; existing records with same ID kept as-is |
51
+ | `overwrite` | New records replace existing ones with same ID |
52
+ | `skip` | Skip entire section if any file already exists in org |
53
+
54
+ ---
55
+
56
+ ## Step 0 — Brain Load (standalone only)
57
+
58
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
59
+
60
+ ---
61
+
62
+ ## Step 1 — Validate Org
63
+
64
+ ```bash
65
+ orgFile=".monomind/orgs/${org_name}.json"
66
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
67
+
68
+ exportsDir=".monomind/exports"
69
+ mkdir -p "$exportsDir"
70
+ ts=$(date -u +%Y%m%dT%H%M%SZ)
71
+ defaultOutput="${exportsDir}/${org_name}-${ts}.tar.gz"
72
+ outputPath="${output_path:-$defaultOutput}"
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Step 2 — Execute Action
78
+
79
+ ### preview
80
+
81
+ Show what would be included in an export without writing anything:
82
+
83
+ ```bash
84
+ echo "EXPORT PREVIEW — org: $org_name"
85
+ echo "────────────────────────────────────────────────────────"
86
+
87
+ allSections="config goals routines projects members adapters environments workspaces activity"
88
+ includeSections="${include:-$allSections}"
89
+
90
+ for section in $allSections; do
91
+ echo "$includeSections" | grep -qw "$section" || continue
92
+ case "$section" in
93
+ config) srcFile=".monomind/orgs/${org_name}.json" ;;
94
+ goals) srcFile=".monomind/orgs/${org_name}-goals.json" ;;
95
+ routines) srcFile=".monomind/orgs/${org_name}-routines.json" ;;
96
+ projects) srcFile=".monomind/orgs/${org_name}-projects.json" ;;
97
+ members) srcFile=".monomind/orgs/${org_name}-members.json" ;;
98
+ adapters) srcFile=".monomind/orgs/${org_name}-adapters.json" ;;
99
+ environments) srcFile=".monomind/orgs/${org_name}-environments.json" ;;
100
+ workspaces) srcFile=".monomind/orgs/${org_name}-workspaces.json" ;;
101
+ activity) srcFile=".monomind/orgs/${org_name}-activity.jsonl" ;;
102
+ secrets-refs) srcFile=".monomind/orgs/.secrets/${org_name}/" ;;
103
+ esac
104
+ if [ -f "$srcFile" ] || [ -d "$srcFile" ]; then
105
+ size=$(du -sh "$srcFile" 2>/dev/null | cut -f1 || echo "?")
106
+ echo " ✓ $section ($srcFile) [$size]"
107
+ else
108
+ echo " - $section ($srcFile) [not found — will be skipped]"
109
+ fi
110
+ done
111
+
112
+ echo ""
113
+ echo "Output would be: $outputPath"
114
+ echo "Run with --action export to proceed."
115
+ ```
116
+
117
+ ### export
118
+
119
+ ```bash
120
+ echo "Exporting org '$org_name'…"
121
+
122
+ allSections="config goals routines projects members adapters environments workspaces activity"
123
+ includeSections="${include:-$allSections}"
124
+
125
+ # Build list of files to include
126
+ tmpDir=$(mktemp -d)
127
+ orgExportDir="${tmpDir}/${org_name}"
128
+ mkdir -p "$orgExportDir"
129
+
130
+ fileCount=0
131
+ for section in $allSections; do
132
+ echo "$includeSections" | grep -qw "$section" || continue
133
+ case "$section" in
134
+ config) srcFile=".monomind/orgs/${org_name}.json" ; dstName="${org_name}.json" ;;
135
+ goals) srcFile=".monomind/orgs/${org_name}-goals.json" ; dstName="${org_name}-goals.json" ;;
136
+ routines) srcFile=".monomind/orgs/${org_name}-routines.json" ; dstName="${org_name}-routines.json" ;;
137
+ projects) srcFile=".monomind/orgs/${org_name}-projects.json" ; dstName="${org_name}-projects.json" ;;
138
+ members) srcFile=".monomind/orgs/${org_name}-members.json" ; dstName="${org_name}-members.json" ;;
139
+ adapters) srcFile=".monomind/orgs/${org_name}-adapters.json" ; dstName="${org_name}-adapters.json" ;;
140
+ environments) srcFile=".monomind/orgs/${org_name}-environments.json" ; dstName="${org_name}-environments.json" ;;
141
+ workspaces) srcFile=".monomind/orgs/${org_name}-workspaces.json" ; dstName="${org_name}-workspaces.json" ;;
142
+ activity) srcFile=".monomind/orgs/${org_name}-activity.jsonl" ; dstName="${org_name}-activity.jsonl" ;;
143
+ secrets-refs)
144
+ # Export ONLY secret reference names — NO values
145
+ secretsDir=".monomind/orgs/.secrets/${org_name}"
146
+ if [ -d "$secretsDir" ]; then
147
+ refsList=$(ls "$secretsDir" 2>/dev/null | jq -Rsc 'split("\n") | map(select(. != ""))')
148
+ echo "{\"secret_refs\":$refsList,\"note\":\"values_not_exported\"}" > "${orgExportDir}/${org_name}-secret-refs.json"
149
+ echo " ✓ secrets-refs (reference names only)"
150
+ fileCount=$((fileCount + 1))
151
+ fi
152
+ continue ;;
153
+ esac
154
+ if [ -f "$srcFile" ]; then
155
+ # For environments: strip key material before including
156
+ if [ "$section" = "environments" ]; then
157
+ jq '.environments = [.environments[] | del(.key_material,.private_key,.ssh_key,.password)]' \
158
+ "$srcFile" > "${orgExportDir}/${dstName}"
159
+ elif [ "$section" = "activity" ]; then
160
+ # Only last 500 events
161
+ tail -500 "$srcFile" > "${orgExportDir}/${dstName}"
162
+ else
163
+ cp "$srcFile" "${orgExportDir}/${dstName}"
164
+ fi
165
+ echo " ✓ $section"
166
+ fileCount=$((fileCount + 1))
167
+ else
168
+ echo " - $section (skipped — file not found)"
169
+ fi
170
+ done
171
+
172
+ # Write manifest
173
+ jq -cn \
174
+ --arg org "$org_name" \
175
+ --arg ts "$ts" \
176
+ --arg sections "$includeSections" \
177
+ --argjson files "$fileCount" \
178
+ '{"org":$org,"exported_at":$ts,"sections":($sections|split(" ")),"file_count":$files,"version":"1.0"}' \
179
+ > "${orgExportDir}/manifest.json"
180
+
181
+ # Create archive
182
+ tar -czf "$outputPath" -C "$tmpDir" "$org_name" 2>/dev/null
183
+ rm -rf "$tmpDir"
184
+
185
+ echo ""
186
+ echo "Export complete: $outputPath"
187
+ echo " Files: $fileCount | Sections: $includeSections"
188
+ echo " Size: $(du -sh "$outputPath" 2>/dev/null | cut -f1)"
189
+ ```
190
+
191
+ ### import
192
+
193
+ ```bash
194
+ [ -z "$input_path" ] && { echo "ERROR: --input-path required."; exit 1; }
195
+ [ ! -f "$input_path" ] && { echo "ERROR: Archive not found: $input_path"; exit 1; }
196
+
197
+ collision="${collision_strategy:-merge}"
198
+ case "$collision" in merge|overwrite|skip) : ;; *)
199
+ echo "ERROR: --collision-strategy must be merge, overwrite, or skip"; exit 1 ;;
200
+ esac
201
+
202
+ dryRun="${dry_run:-false}"
203
+ [ "$dryRun" = "true" ] && echo "DRY RUN — no changes will be written."
204
+
205
+ echo "IMPORT — org: $org_name"
206
+ echo "Collision strategy: $collision"
207
+ [ -n "$adapter_override" ] && echo "Adapter override: $adapter_override"
208
+ echo "────────────────────────────────────────────────────────"
209
+
210
+ # Extract archive to temp dir
211
+ tmpDir=$(mktemp -d)
212
+ tar -xzf "$input_path" -C "$tmpDir" 2>/dev/null || { echo "ERROR: Failed to extract archive."; rm -rf "$tmpDir"; exit 1; }
213
+
214
+ # Find org dir in archive
215
+ archiveOrgDir=$(find "$tmpDir" -name "manifest.json" -maxdepth 3 | head -1 | xargs dirname 2>/dev/null)
216
+ [ -z "$archiveOrgDir" ] && { echo "ERROR: No manifest.json found in archive. Invalid export?"; rm -rf "$tmpDir"; exit 1; }
217
+
218
+ archiveOrg=$(jq -r '.org // ""' "${archiveOrgDir}/manifest.json")
219
+ echo "Archive org: $archiveOrg → importing as: $org_name"
220
+ echo ""
221
+
222
+ imported=0
223
+ skipped=0
224
+ for srcFile in "${archiveOrgDir}"/*.json "${archiveOrgDir}"/*.jsonl; do
225
+ [ -f "$srcFile" ] || continue
226
+ # Rewrite filename for target org name
227
+ dstName=$(basename "$srcFile" | sed "s/^${archiveOrg}/${org_name}/")
228
+ dstPath=".monomind/orgs/${dstName}"
229
+
230
+ # Skip manifest
231
+ [[ "$dstName" == "manifest.json" ]] && continue
232
+
233
+ # Skip secret refs — never auto-import
234
+ [[ "$dstName" == *secret-refs* ]] && echo " SKIP: secret refs (never auto-imported)" && continue
235
+
236
+ # Apply adapter override
237
+ if [ -n "$adapter_override" ] && [[ "$dstName" == *-adapters.json ]]; then
238
+ echo " OVERRIDE: applying adapter_override=$adapter_override to adapters file"
239
+ fi
240
+
241
+ if [ -f "$dstPath" ]; then
242
+ case "$collision" in
243
+ skip)
244
+ echo " SKIP: $dstName (exists, strategy=skip)"
245
+ skipped=$((skipped + 1))
246
+ continue ;;
247
+ merge)
248
+ echo " MERGE: $dstName"
249
+ if [ "$dryRun" = "false" ]; then
250
+ # JSON files: merge arrays; jsonl files: append deduplicated
251
+ if [[ "$dstPath" == *.jsonl ]]; then
252
+ cat "$srcFile" >> "$dstPath"
253
+ else
254
+ # Merge: combine top-level arrays from both files
255
+ python3 -c "
256
+ import json, sys
257
+ with open('$dstPath') as f: existing = json.load(f)
258
+ with open('$srcFile') as f: incoming = json.load(f)
259
+ for k, v in incoming.items():
260
+ if isinstance(v, list) and isinstance(existing.get(k), list):
261
+ existIds = {i.get('id') for i in existing[k] if isinstance(i,dict)}
262
+ existing[k] += [i for i in v if isinstance(i,dict) and i.get('id') not in existIds]
263
+ elif k not in existing:
264
+ existing[k] = v
265
+ with open('$dstPath', 'w') as f: json.dump(existing, f, indent=2)
266
+ " 2>/dev/null || cp "$srcFile" "$dstPath"
267
+ fi
268
+ fi ;;
269
+ overwrite)
270
+ echo " OVERWRITE: $dstName"
271
+ [ "$dryRun" = "false" ] && cp "$srcFile" "$dstPath" ;;
272
+ esac
273
+ else
274
+ echo " CREATE: $dstName (new)"
275
+ [ "$dryRun" = "false" ] && cp "$srcFile" "$dstPath"
276
+ fi
277
+ imported=$((imported + 1))
278
+ done
279
+
280
+ rm -rf "$tmpDir"
281
+ echo ""
282
+ [ "$dryRun" = "true" ] && echo "DRY RUN complete — $imported file(s) would be imported, $skipped skipped." \
283
+ || echo "Import complete — $imported file(s) imported, $skipped skipped."
284
+ ```
285
+
286
+ ### list-archives
287
+
288
+ ```bash
289
+ echo "EXPORT ARCHIVES — org: $org_name"
290
+ echo "────────────────────────────────────────────────────────"
291
+
292
+ found=0
293
+ for f in ".monomind/exports/${org_name}-"*.tar.gz ".monomind/exports/${org_name}-"*.zip; do
294
+ [ -f "$f" ] || continue
295
+ size=$(du -sh "$f" 2>/dev/null | cut -f1 || echo "?")
296
+ ts=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$f" 2>/dev/null || stat -c "%y" "$f" 2>/dev/null | cut -c1-16 || echo "?")
297
+ printf " %-50s %8s %s\n" "$(basename "$f")" "$size" "$ts"
298
+ found=$((found + 1))
299
+ done
300
+
301
+ [ "$found" -eq 0 ] && echo " No archives found. Run --action export to create one."
302
+ echo ""
303
+ echo "Total: $found archive(s) in .monomind/exports/"
304
+ ```
305
+
306
+ ---
307
+
308
+ ## Step 3 — Return Output
309
+
310
+ ```yaml
311
+ domain: ops
312
+ status: complete
313
+ action: <action>
314
+ org: <org_name>
315
+ output_path: <path if export>
316
+ files_processed: <N>
317
+ collision_strategy: <strategy if import>
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Step 4 — Brain Write (standalone only)
323
+
324
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.