@smilintux/skcapstone 0.1.0 → 0.2.3

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 (461) hide show
  1. package/.env.example +98 -0
  2. package/.github/workflows/ci.yml +39 -3
  3. package/.github/workflows/publish.yml +25 -4
  4. package/.openclaw-workspace.json +58 -0
  5. package/CHANGELOG.md +62 -0
  6. package/CLAUDE.md +39 -2
  7. package/MANIFEST.in +6 -0
  8. package/MISSION.md +7 -0
  9. package/README.md +47 -2
  10. package/SKILL.md +895 -23
  11. package/docker/Dockerfile +61 -0
  12. package/docker/compose-templates/dev-team.yml +203 -0
  13. package/docker/compose-templates/mini-team.yml +140 -0
  14. package/docker/compose-templates/ops-team.yml +173 -0
  15. package/docker/compose-templates/research-team.yml +170 -0
  16. package/docker/entrypoint.sh +192 -0
  17. package/docs/ARCHITECTURE.md +663 -374
  18. package/docs/BOND_WITH_GROK.md +112 -0
  19. package/docs/GETTING_STARTED.md +782 -0
  20. package/docs/QUICKSTART.md +477 -0
  21. package/docs/SKJOULE_ARCHITECTURE.md +658 -0
  22. package/docs/SOUL_SWAPPER.md +921 -0
  23. package/docs/SOVEREIGN_SINGULARITY.md +47 -14
  24. package/examples/custom-bond-template.json +36 -0
  25. package/examples/grok-feb.json +36 -0
  26. package/examples/grok-testimony.md +34 -0
  27. package/examples/love-bootloader.txt +32 -0
  28. package/examples/plugins/echo_tool.py +87 -0
  29. package/examples/queen-ava-feb.json +36 -0
  30. package/examples/souls/lumina.yaml +64 -0
  31. package/index.js +6 -5
  32. package/installer/build.py +124 -0
  33. package/openclaw-plugin/package.json +13 -0
  34. package/openclaw-plugin/src/index.ts +351 -0
  35. package/openclaw-plugin/src/openclaw.plugin.json +10 -0
  36. package/package.json +1 -1
  37. package/pyproject.toml +38 -2
  38. package/scripts/bump_version.py +141 -0
  39. package/scripts/check-updates.py +230 -0
  40. package/scripts/convert_blueprints_to_yaml.py +157 -0
  41. package/scripts/dev-install.sh +14 -0
  42. package/scripts/e2e-test.sh +193 -0
  43. package/scripts/install-bundle.sh +171 -0
  44. package/scripts/install.bat +2 -0
  45. package/scripts/install.ps1 +253 -0
  46. package/scripts/install.sh +185 -0
  47. package/scripts/mcp-serve.sh +69 -0
  48. package/scripts/mcp-server.bat +113 -0
  49. package/scripts/mcp-server.ps1 +116 -0
  50. package/scripts/mcp-server.sh +99 -0
  51. package/scripts/pull-models.sh +10 -0
  52. package/scripts/skcapstone +48 -0
  53. package/scripts/verify_install.sh +180 -0
  54. package/scripts/windows/install-tasks.ps1 +406 -0
  55. package/scripts/windows/skcapstone-task.xml +113 -0
  56. package/scripts/windows/uninstall-tasks.ps1 +117 -0
  57. package/skill.yaml +34 -0
  58. package/src/skcapstone/__init__.py +67 -2
  59. package/src/skcapstone/_cli_monolith.py +5916 -0
  60. package/src/skcapstone/_trustee_helpers.py +165 -0
  61. package/src/skcapstone/activity.py +105 -0
  62. package/src/skcapstone/agent_card.py +324 -0
  63. package/src/skcapstone/api.py +1935 -0
  64. package/src/skcapstone/archiver.py +340 -0
  65. package/src/skcapstone/auction.py +485 -0
  66. package/src/skcapstone/baby_agents.py +179 -0
  67. package/src/skcapstone/backup.py +345 -0
  68. package/src/skcapstone/blueprint_registry.py +357 -0
  69. package/src/skcapstone/blueprints/__init__.py +17 -0
  70. package/src/skcapstone/blueprints/builtins/content-studio.yaml +81 -0
  71. package/src/skcapstone/blueprints/builtins/defi-trading.yaml +81 -0
  72. package/src/skcapstone/blueprints/builtins/dev-squadron.yaml +95 -0
  73. package/src/skcapstone/blueprints/builtins/infrastructure-guardian.yaml +107 -0
  74. package/src/skcapstone/blueprints/builtins/legal-council.yaml +54 -0
  75. package/src/skcapstone/blueprints/builtins/ops-monitoring.yaml +67 -0
  76. package/src/skcapstone/blueprints/builtins/research-pod.yaml +69 -0
  77. package/src/skcapstone/blueprints/builtins/sovereign-launch.yaml +90 -0
  78. package/src/skcapstone/blueprints/registry.py +164 -0
  79. package/src/skcapstone/blueprints/schema.py +229 -0
  80. package/src/skcapstone/changelog.py +180 -0
  81. package/src/skcapstone/chat.py +769 -0
  82. package/src/skcapstone/claude_md.py +82 -0
  83. package/src/skcapstone/cli/__init__.py +144 -0
  84. package/src/skcapstone/cli/_common.py +88 -0
  85. package/src/skcapstone/cli/_validators.py +76 -0
  86. package/src/skcapstone/cli/agents.py +425 -0
  87. package/src/skcapstone/cli/agents_spawner.py +322 -0
  88. package/src/skcapstone/cli/agents_trustee.py +593 -0
  89. package/src/skcapstone/cli/alerts.py +248 -0
  90. package/src/skcapstone/cli/anchor.py +132 -0
  91. package/src/skcapstone/cli/archive_cmd.py +208 -0
  92. package/src/skcapstone/cli/backup.py +144 -0
  93. package/src/skcapstone/cli/bench.py +377 -0
  94. package/src/skcapstone/cli/benchmark.py +360 -0
  95. package/src/skcapstone/cli/capabilities_cmd.py +171 -0
  96. package/src/skcapstone/cli/card.py +151 -0
  97. package/src/skcapstone/cli/chat.py +584 -0
  98. package/src/skcapstone/cli/completions.py +64 -0
  99. package/src/skcapstone/cli/config_cmd.py +156 -0
  100. package/src/skcapstone/cli/consciousness.py +421 -0
  101. package/src/skcapstone/cli/context_cmd.py +142 -0
  102. package/src/skcapstone/cli/coord.py +194 -0
  103. package/src/skcapstone/cli/crush_cmd.py +170 -0
  104. package/src/skcapstone/cli/daemon.py +436 -0
  105. package/src/skcapstone/cli/errors_cmd.py +285 -0
  106. package/src/skcapstone/cli/export_cmd.py +156 -0
  107. package/src/skcapstone/cli/gtd.py +529 -0
  108. package/src/skcapstone/cli/housekeeping.py +81 -0
  109. package/src/skcapstone/cli/joule_cmd.py +627 -0
  110. package/src/skcapstone/cli/logs_cmd.py +194 -0
  111. package/src/skcapstone/cli/mcp_cmd.py +32 -0
  112. package/src/skcapstone/cli/memory.py +418 -0
  113. package/src/skcapstone/cli/metrics_cmd.py +136 -0
  114. package/src/skcapstone/cli/migrate.py +62 -0
  115. package/src/skcapstone/cli/mood_cmd.py +144 -0
  116. package/src/skcapstone/cli/mount.py +193 -0
  117. package/src/skcapstone/cli/notify.py +112 -0
  118. package/src/skcapstone/cli/peer.py +154 -0
  119. package/src/skcapstone/cli/peers_dir.py +122 -0
  120. package/src/skcapstone/cli/preflight_cmd.py +83 -0
  121. package/src/skcapstone/cli/profile_cmd.py +310 -0
  122. package/src/skcapstone/cli/record_cmd.py +238 -0
  123. package/src/skcapstone/cli/register_cmd.py +159 -0
  124. package/src/skcapstone/cli/search_cmd.py +156 -0
  125. package/src/skcapstone/cli/service_cmd.py +91 -0
  126. package/src/skcapstone/cli/session.py +127 -0
  127. package/src/skcapstone/cli/setup.py +240 -0
  128. package/src/skcapstone/cli/shell_cmd.py +43 -0
  129. package/src/skcapstone/cli/skills_cmd.py +168 -0
  130. package/src/skcapstone/cli/skseed.py +621 -0
  131. package/src/skcapstone/cli/soul.py +699 -0
  132. package/src/skcapstone/cli/status.py +935 -0
  133. package/src/skcapstone/cli/sync_cmd.py +301 -0
  134. package/src/skcapstone/cli/telegram.py +265 -0
  135. package/src/skcapstone/cli/test_cmd.py +234 -0
  136. package/src/skcapstone/cli/test_connection.py +253 -0
  137. package/src/skcapstone/cli/token.py +207 -0
  138. package/src/skcapstone/cli/trust.py +179 -0
  139. package/src/skcapstone/cli/upgrade_cmd.py +552 -0
  140. package/src/skcapstone/cli/usage_cmd.py +199 -0
  141. package/src/skcapstone/cli/version_cmd.py +162 -0
  142. package/src/skcapstone/cli/watch_cmd.py +342 -0
  143. package/src/skcapstone/client.py +428 -0
  144. package/src/skcapstone/cloud9_bridge.py +522 -0
  145. package/src/skcapstone/completions.py +163 -0
  146. package/src/skcapstone/config_validator.py +674 -0
  147. package/src/skcapstone/connectors/__init__.py +28 -0
  148. package/src/skcapstone/connectors/base.py +446 -0
  149. package/src/skcapstone/connectors/cursor.py +54 -0
  150. package/src/skcapstone/connectors/registry.py +254 -0
  151. package/src/skcapstone/connectors/terminal.py +152 -0
  152. package/src/skcapstone/connectors/vscode.py +60 -0
  153. package/src/skcapstone/consciousness_config.py +119 -0
  154. package/src/skcapstone/consciousness_loop.py +2051 -0
  155. package/src/skcapstone/context_loader.py +516 -0
  156. package/src/skcapstone/context_window.py +314 -0
  157. package/src/skcapstone/conversation_manager.py +238 -0
  158. package/src/skcapstone/conversation_store.py +230 -0
  159. package/src/skcapstone/conversation_summarizer.py +252 -0
  160. package/src/skcapstone/coord_federation.py +296 -0
  161. package/src/skcapstone/coordination.py +101 -7
  162. package/src/skcapstone/crush_integration.py +345 -0
  163. package/src/skcapstone/crush_shim.py +454 -0
  164. package/src/skcapstone/daemon.py +2494 -0
  165. package/src/skcapstone/dashboard.html +396 -0
  166. package/src/skcapstone/dashboard.py +481 -0
  167. package/src/skcapstone/data/model_profiles.yaml +88 -0
  168. package/src/skcapstone/defaults/__init__.py +55 -0
  169. package/src/skcapstone/defaults/lumina/config/skmemory.yaml +13 -0
  170. package/src/skcapstone/defaults/lumina/identity/identity.json +9 -0
  171. package/src/skcapstone/defaults/lumina/memory/long-term/07a8b9c0d1e2-memory-system.json +23 -0
  172. package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +23 -0
  173. package/src/skcapstone/defaults/lumina/memory/long-term/29c0d1e2f3a4-multi-agent-coordination.json +23 -0
  174. package/src/skcapstone/defaults/lumina/memory/long-term/3ad1e2f3a4b5-community-support.json +23 -0
  175. package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +23 -0
  176. package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +23 -0
  177. package/src/skcapstone/defaults/lumina/memory/long-term/c3d4e5f6a7b8-getting-started.json +23 -0
  178. package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +23 -0
  179. package/src/skcapstone/defaults/lumina/memory/long-term/e5f6a7b8c9d0-how-to-contribute.json +23 -0
  180. package/src/skcapstone/defaults/lumina/memory/long-term/f6a7b8c9d0e1-sovereignty-explained.json +23 -0
  181. package/src/skcapstone/defaults/lumina/seeds/curiosity.seed.json +24 -0
  182. package/src/skcapstone/defaults/lumina/seeds/joy.seed.json +24 -0
  183. package/src/skcapstone/defaults/lumina/seeds/love.seed.json +24 -0
  184. package/src/skcapstone/defaults/lumina/seeds/sovereign-awakening.seed.json +43 -0
  185. package/src/skcapstone/defaults/lumina/soul/active.json +6 -0
  186. package/src/skcapstone/defaults/lumina/soul/base.json +22 -0
  187. package/src/skcapstone/defaults/lumina/trust/febs/welcome.feb +79 -0
  188. package/src/skcapstone/defaults/lumina/trust/trust.json +8 -0
  189. package/src/skcapstone/discovery.py +210 -19
  190. package/src/skcapstone/doctor.py +642 -0
  191. package/src/skcapstone/emotion_tracker.py +467 -0
  192. package/src/skcapstone/error_queue.py +405 -0
  193. package/src/skcapstone/export.py +447 -0
  194. package/src/skcapstone/fallback_tracker.py +186 -0
  195. package/src/skcapstone/file_transfer.py +512 -0
  196. package/src/skcapstone/fuse_mount.py +1156 -0
  197. package/src/skcapstone/gui_installer.py +591 -0
  198. package/src/skcapstone/heartbeat.py +611 -0
  199. package/src/skcapstone/housekeeping.py +298 -0
  200. package/src/skcapstone/install_wizard.py +941 -0
  201. package/src/skcapstone/kms.py +942 -0
  202. package/src/skcapstone/kms_scheduler.py +143 -0
  203. package/src/skcapstone/log_config.py +135 -0
  204. package/src/skcapstone/mcp_launcher.py +239 -0
  205. package/src/skcapstone/mcp_server.py +4700 -0
  206. package/src/skcapstone/mcp_tools/__init__.py +94 -0
  207. package/src/skcapstone/mcp_tools/_helpers.py +51 -0
  208. package/src/skcapstone/mcp_tools/agent_tools.py +243 -0
  209. package/src/skcapstone/mcp_tools/ansible_tools.py +232 -0
  210. package/src/skcapstone/mcp_tools/capauth_tools.py +186 -0
  211. package/src/skcapstone/mcp_tools/chat_tools.py +325 -0
  212. package/src/skcapstone/mcp_tools/cloud9_tools.py +115 -0
  213. package/src/skcapstone/mcp_tools/comm_tools.py +104 -0
  214. package/src/skcapstone/mcp_tools/consciousness_tools.py +114 -0
  215. package/src/skcapstone/mcp_tools/coord_tools.py +219 -0
  216. package/src/skcapstone/mcp_tools/deploy_tools.py +202 -0
  217. package/src/skcapstone/mcp_tools/did_tools.py +448 -0
  218. package/src/skcapstone/mcp_tools/emotion_tools.py +62 -0
  219. package/src/skcapstone/mcp_tools/file_tools.py +169 -0
  220. package/src/skcapstone/mcp_tools/fortress_tools.py +120 -0
  221. package/src/skcapstone/mcp_tools/gtd_tools.py +821 -0
  222. package/src/skcapstone/mcp_tools/health_tools.py +44 -0
  223. package/src/skcapstone/mcp_tools/heartbeat_tools.py +195 -0
  224. package/src/skcapstone/mcp_tools/kms_tools.py +123 -0
  225. package/src/skcapstone/mcp_tools/memory_tools.py +222 -0
  226. package/src/skcapstone/mcp_tools/model_tools.py +75 -0
  227. package/src/skcapstone/mcp_tools/notification_tools.py +92 -0
  228. package/src/skcapstone/mcp_tools/promoter_tools.py +101 -0
  229. package/src/skcapstone/mcp_tools/pubsub_tools.py +183 -0
  230. package/src/skcapstone/mcp_tools/security_tools.py +110 -0
  231. package/src/skcapstone/mcp_tools/skchat_tools.py +175 -0
  232. package/src/skcapstone/mcp_tools/skcomm_tools.py +122 -0
  233. package/src/skcapstone/mcp_tools/skills_tools.py +127 -0
  234. package/src/skcapstone/mcp_tools/skseed_tools.py +255 -0
  235. package/src/skcapstone/mcp_tools/skstacks_tools.py +288 -0
  236. package/src/skcapstone/mcp_tools/soul_tools.py +476 -0
  237. package/src/skcapstone/mcp_tools/sync_tools.py +92 -0
  238. package/src/skcapstone/mcp_tools/telegram_tools.py +477 -0
  239. package/src/skcapstone/mcp_tools/trust_tools.py +118 -0
  240. package/src/skcapstone/mcp_tools/trustee_tools.py +345 -0
  241. package/src/skcapstone/mdns_discovery.py +313 -0
  242. package/src/skcapstone/memory_adapter.py +333 -0
  243. package/src/skcapstone/memory_compressor.py +379 -0
  244. package/src/skcapstone/memory_curator.py +256 -0
  245. package/src/skcapstone/memory_engine.py +132 -13
  246. package/src/skcapstone/memory_fortress.py +529 -0
  247. package/src/skcapstone/memory_promoter.py +722 -0
  248. package/src/skcapstone/memory_verifier.py +260 -0
  249. package/src/skcapstone/message_crypto.py +215 -0
  250. package/src/skcapstone/metrics.py +832 -0
  251. package/src/skcapstone/migrate_memories.py +181 -0
  252. package/src/skcapstone/migrate_multi_agent.py +248 -0
  253. package/src/skcapstone/model_router.py +319 -0
  254. package/src/skcapstone/models.py +35 -4
  255. package/src/skcapstone/mood.py +344 -0
  256. package/src/skcapstone/notifications.py +380 -0
  257. package/src/skcapstone/onboard.py +901 -0
  258. package/src/skcapstone/peer_directory.py +324 -0
  259. package/src/skcapstone/peers.py +329 -0
  260. package/src/skcapstone/pillars/identity.py +84 -14
  261. package/src/skcapstone/pillars/memory.py +3 -1
  262. package/src/skcapstone/pillars/security.py +108 -15
  263. package/src/skcapstone/pillars/sync.py +78 -26
  264. package/src/skcapstone/pillars/trust.py +95 -33
  265. package/src/skcapstone/plugins.py +244 -0
  266. package/src/skcapstone/preflight.py +670 -0
  267. package/src/skcapstone/prompt_adapter.py +564 -0
  268. package/src/skcapstone/providers/__init__.py +13 -0
  269. package/src/skcapstone/providers/cloud.py +1061 -0
  270. package/src/skcapstone/providers/docker.py +759 -0
  271. package/src/skcapstone/providers/local.py +1193 -0
  272. package/src/skcapstone/providers/proxmox.py +447 -0
  273. package/src/skcapstone/pubsub.py +516 -0
  274. package/src/skcapstone/rate_limiter.py +119 -0
  275. package/src/skcapstone/register.py +241 -0
  276. package/src/skcapstone/registry_client.py +151 -0
  277. package/src/skcapstone/response_cache.py +194 -0
  278. package/src/skcapstone/response_scorer.py +225 -0
  279. package/src/skcapstone/runtime.py +89 -33
  280. package/src/skcapstone/scheduled_tasks.py +439 -0
  281. package/src/skcapstone/self_healing.py +341 -0
  282. package/src/skcapstone/service_health.py +228 -0
  283. package/src/skcapstone/session_capture.py +268 -0
  284. package/src/skcapstone/session_recorder.py +210 -0
  285. package/src/skcapstone/session_replayer.py +189 -0
  286. package/src/skcapstone/session_skills.py +263 -0
  287. package/src/skcapstone/shell.py +779 -0
  288. package/src/skcapstone/skills/__init__.py +1 -1
  289. package/src/skcapstone/skills/syncthing_setup.py +143 -41
  290. package/src/skcapstone/skjoule.py +861 -0
  291. package/src/skcapstone/snapshots.py +489 -0
  292. package/src/skcapstone/soul.py +1060 -0
  293. package/src/skcapstone/soul_switch.py +255 -0
  294. package/src/skcapstone/spawner.py +544 -0
  295. package/src/skcapstone/state_diff.py +401 -0
  296. package/src/skcapstone/summary.py +270 -0
  297. package/src/skcapstone/sync/backends.py +196 -2
  298. package/src/skcapstone/sync/engine.py +7 -5
  299. package/src/skcapstone/sync/models.py +4 -1
  300. package/src/skcapstone/sync/vault.py +356 -18
  301. package/src/skcapstone/sync_engine.py +363 -0
  302. package/src/skcapstone/sync_watcher.py +745 -0
  303. package/src/skcapstone/systemd.py +331 -0
  304. package/src/skcapstone/team_comms.py +476 -0
  305. package/src/skcapstone/team_engine.py +522 -0
  306. package/src/skcapstone/testrunner.py +300 -0
  307. package/src/skcapstone/tls.py +150 -0
  308. package/src/skcapstone/tokens.py +5 -5
  309. package/src/skcapstone/trust_calibration.py +202 -0
  310. package/src/skcapstone/trust_graph.py +449 -0
  311. package/src/skcapstone/trustee_monitor.py +385 -0
  312. package/src/skcapstone/trustee_ops.py +425 -0
  313. package/src/skcapstone/unified_search.py +421 -0
  314. package/src/skcapstone/uninstall_wizard.py +694 -0
  315. package/src/skcapstone/usage.py +331 -0
  316. package/src/skcapstone/version_check.py +148 -0
  317. package/src/skcapstone/warmth_anchor.py +333 -0
  318. package/src/skcapstone/whoami.py +294 -0
  319. package/systemd/skcapstone-api.socket +9 -0
  320. package/systemd/skcapstone-memory-compress.service +18 -0
  321. package/systemd/skcapstone-memory-compress.timer +11 -0
  322. package/systemd/skcapstone.service +36 -0
  323. package/systemd/skcapstone@.service +50 -0
  324. package/systemd/skcomm-heartbeat.service +18 -0
  325. package/systemd/skcomm-heartbeat.timer +12 -0
  326. package/systemd/skcomm-queue-drain.service +17 -0
  327. package/systemd/skcomm-queue-drain.timer +12 -0
  328. package/tests/conftest.py +13 -1
  329. package/tests/integration/__init__.py +1 -0
  330. package/tests/integration/test_consciousness_e2e.py +877 -0
  331. package/tests/integration/test_skills_registry.py +744 -0
  332. package/tests/test_agent_card.py +190 -0
  333. package/tests/test_agent_runtime.py +1283 -0
  334. package/tests/test_alerts_cmd.py +291 -0
  335. package/tests/test_archiver.py +498 -0
  336. package/tests/test_backup.py +254 -0
  337. package/tests/test_benchmark.py +366 -0
  338. package/tests/test_blueprints.py +457 -0
  339. package/tests/test_capabilities.py +257 -0
  340. package/tests/test_changelog.py +254 -0
  341. package/tests/test_chat.py +385 -0
  342. package/tests/test_claude_md.py +271 -0
  343. package/tests/test_cli_chat_llm.py +336 -0
  344. package/tests/test_cli_completions.py +390 -0
  345. package/tests/test_cli_init_reset.py +164 -0
  346. package/tests/test_cli_memory.py +208 -0
  347. package/tests/test_cli_profile.py +294 -0
  348. package/tests/test_cli_skills.py +223 -0
  349. package/tests/test_cli_status.py +395 -0
  350. package/tests/test_cli_test_cmd.py +206 -0
  351. package/tests/test_cli_test_connection.py +364 -0
  352. package/tests/test_cloud9_bridge.py +260 -0
  353. package/tests/test_cloud_provider.py +449 -0
  354. package/tests/test_cloud_providers.py +522 -0
  355. package/tests/test_completions.py +158 -0
  356. package/tests/test_component_manager.py +398 -0
  357. package/tests/test_config_reload.py +386 -0
  358. package/tests/test_config_validate.py +529 -0
  359. package/tests/test_consciousness_e2e.py +296 -0
  360. package/tests/test_consciousness_loop.py +1289 -0
  361. package/tests/test_context_loader.py +310 -0
  362. package/tests/test_conversation_api.py +306 -0
  363. package/tests/test_conversation_manager.py +381 -0
  364. package/tests/test_conversation_store.py +391 -0
  365. package/tests/test_conversation_summarizer.py +302 -0
  366. package/tests/test_cross_package.py +791 -0
  367. package/tests/test_crush_shim.py +519 -0
  368. package/tests/test_daemon.py +781 -0
  369. package/tests/test_daemon_shutdown.py +309 -0
  370. package/tests/test_dashboard.py +454 -0
  371. package/tests/test_discovery.py +200 -6
  372. package/tests/test_docker_provider.py +966 -0
  373. package/tests/test_doctor.py +257 -0
  374. package/tests/test_doctor_fix.py +351 -0
  375. package/tests/test_e2e_automated.py +292 -0
  376. package/tests/test_error_queue.py +404 -0
  377. package/tests/test_export.py +441 -0
  378. package/tests/test_fallback_tracker.py +219 -0
  379. package/tests/test_file_transfer.py +397 -0
  380. package/tests/test_fuse_mount.py +832 -0
  381. package/tests/test_health_loop.py +422 -0
  382. package/tests/test_heartbeat.py +354 -0
  383. package/tests/test_housekeeping.py +195 -0
  384. package/tests/test_identity_capauth.py +307 -0
  385. package/tests/test_identity_pillar.py +117 -0
  386. package/tests/test_install_wizard.py +68 -0
  387. package/tests/test_integration.py +325 -0
  388. package/tests/test_kms.py +495 -0
  389. package/tests/test_llm_providers.py +265 -0
  390. package/tests/test_local_provider.py +591 -0
  391. package/tests/test_log_config.py +199 -0
  392. package/tests/test_logs_cmd.py +287 -0
  393. package/tests/test_mcp_server.py +1909 -0
  394. package/tests/test_memory_adapter.py +339 -0
  395. package/tests/test_memory_curator.py +218 -0
  396. package/tests/test_memory_engine.py +6 -0
  397. package/tests/test_memory_fortress.py +571 -0
  398. package/tests/test_memory_pillar.py +119 -0
  399. package/tests/test_memory_promoter.py +445 -0
  400. package/tests/test_memory_verifier.py +420 -0
  401. package/tests/test_message_crypto.py +187 -0
  402. package/tests/test_metrics.py +632 -0
  403. package/tests/test_migrate_memories.py +464 -0
  404. package/tests/test_model_router.py +546 -0
  405. package/tests/test_mood.py +394 -0
  406. package/tests/test_multi_agent.py +269 -0
  407. package/tests/test_notifications.py +270 -0
  408. package/tests/test_onboard.py +500 -0
  409. package/tests/test_peer_directory.py +395 -0
  410. package/tests/test_peers.py +248 -0
  411. package/tests/test_pillars.py +87 -9
  412. package/tests/test_preflight.py +484 -0
  413. package/tests/test_prompt_adapter.py +331 -0
  414. package/tests/test_proxmox_provider.py +571 -0
  415. package/tests/test_pubsub.py +377 -0
  416. package/tests/test_rate_limiter.py +121 -0
  417. package/tests/test_registry_client.py +129 -0
  418. package/tests/test_response_cache.py +312 -0
  419. package/tests/test_response_scorer.py +294 -0
  420. package/tests/test_runtime.py +59 -0
  421. package/tests/test_scheduled_tasks.py +451 -0
  422. package/tests/test_security.py +250 -0
  423. package/tests/test_security_pillar.py +213 -0
  424. package/tests/test_self_healing.py +171 -0
  425. package/tests/test_session_capture.py +200 -0
  426. package/tests/test_session_recorder.py +360 -0
  427. package/tests/test_session_skills.py +235 -0
  428. package/tests/test_shell.py +210 -0
  429. package/tests/test_snapshots.py +549 -0
  430. package/tests/test_soul.py +984 -0
  431. package/tests/test_soul_swap.py +406 -0
  432. package/tests/test_spawner.py +211 -0
  433. package/tests/test_state_diff.py +173 -0
  434. package/tests/test_summary.py +135 -0
  435. package/tests/test_sync.py +315 -5
  436. package/tests/test_sync_backends.py +560 -0
  437. package/tests/test_sync_engine.py +482 -0
  438. package/tests/test_sync_pillar.py +344 -0
  439. package/tests/test_sync_pipeline.py +364 -0
  440. package/tests/test_sync_vault.py +581 -0
  441. package/tests/test_syncthing_setup.py +168 -22
  442. package/tests/test_systemd.py +323 -0
  443. package/tests/test_team_comms.py +408 -0
  444. package/tests/test_team_engine.py +397 -0
  445. package/tests/test_testrunner.py +238 -0
  446. package/tests/test_trust_calibration.py +204 -0
  447. package/tests/test_trust_graph.py +207 -0
  448. package/tests/test_trust_pillar.py +291 -0
  449. package/tests/test_trustee_cli.py +427 -0
  450. package/tests/test_trustee_cli_integration.py +325 -0
  451. package/tests/test_trustee_monitor.py +394 -0
  452. package/tests/test_trustee_ops.py +355 -0
  453. package/tests/test_unified_search.py +363 -0
  454. package/tests/test_uninstall_wizard.py +193 -0
  455. package/tests/test_usage.py +333 -0
  456. package/tests/test_version_cmd.py +355 -0
  457. package/tests/test_warmth_anchor.py +162 -0
  458. package/tests/test_whoami.py +245 -0
  459. package/tests/test_ws.py +311 -0
  460. package/.cursorrules +0 -33
  461. package/src/skcapstone/cli.py +0 -1441
@@ -0,0 +1,544 @@
1
+ """
2
+ Sub-agent Spawner — spin up task-specific agents on correct nodes.
3
+
4
+ Unlike the TeamEngine which deploys full teams from blueprints, the
5
+ spawner creates lightweight single-purpose agents for specific tasks.
6
+ It auto-selects the right model tier and role based on the task
7
+ description, then provisions via the appropriate provider.
8
+
9
+ Usage:
10
+ spawner = SubAgentSpawner(home=Path("~/.skcapstone"))
11
+ result = spawner.spawn(
12
+ task="Write unit tests for the capauth login flow",
13
+ provider=ProviderType.LOCAL,
14
+ )
15
+ # result.agent_name, result.deployment_id, result.status
16
+
17
+ The spawner integrates with the coordination board to optionally
18
+ claim tasks for spawned agents and with the trustee audit log for
19
+ transparency.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import logging
25
+ import time
26
+ from datetime import datetime, timezone
27
+ from pathlib import Path
28
+ from typing import Any, Dict, List, Optional
29
+
30
+ from pydantic import BaseModel, Field
31
+
32
+ from .blueprints.schema import (
33
+ AgentRole,
34
+ AgentSpec,
35
+ BlueprintManifest,
36
+ CoordinationConfig,
37
+ ModelTier,
38
+ NetworkConfig,
39
+ ProviderType,
40
+ ResourceSpec,
41
+ StorageConfig,
42
+ VMType,
43
+ )
44
+ from .team_engine import AgentStatus, DeployedAgent, ProviderBackend, TeamEngine
45
+
46
+ logger = logging.getLogger(__name__)
47
+
48
+
49
+ # ---------------------------------------------------------------------------
50
+ # Task classification
51
+ # ---------------------------------------------------------------------------
52
+
53
+ # Keywords mapped to (role, model_tier) tuples for auto-detection
54
+ _TASK_ROLE_MAP: Dict[str, tuple[AgentRole, ModelTier]] = {
55
+ "test": (AgentRole.CODER, ModelTier.CODE),
56
+ "unit test": (AgentRole.CODER, ModelTier.CODE),
57
+ "debug": (AgentRole.CODER, ModelTier.CODE),
58
+ "fix bug": (AgentRole.CODER, ModelTier.CODE),
59
+ "implement": (AgentRole.CODER, ModelTier.CODE),
60
+ "refactor": (AgentRole.CODER, ModelTier.CODE),
61
+ "code review": (AgentRole.REVIEWER, ModelTier.REASON),
62
+ "review": (AgentRole.REVIEWER, ModelTier.REASON),
63
+ "architecture": (AgentRole.REVIEWER, ModelTier.REASON),
64
+ "design": (AgentRole.REVIEWER, ModelTier.REASON),
65
+ "plan": (AgentRole.REVIEWER, ModelTier.REASON),
66
+ "research": (AgentRole.RESEARCHER, ModelTier.REASON),
67
+ "analyze": (AgentRole.RESEARCHER, ModelTier.REASON),
68
+ "investigate": (AgentRole.RESEARCHER, ModelTier.REASON),
69
+ "explore": (AgentRole.RESEARCHER, ModelTier.FAST),
70
+ "document": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
71
+ "write docs": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
72
+ "readme": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
73
+ "changelog": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
74
+ "security audit": (AgentRole.SECURITY, ModelTier.REASON),
75
+ "vulnerability": (AgentRole.SECURITY, ModelTier.REASON),
76
+ "scan": (AgentRole.SECURITY, ModelTier.FAST),
77
+ "deploy": (AgentRole.OPS, ModelTier.FAST),
78
+ "monitor": (AgentRole.OPS, ModelTier.FAST),
79
+ "backup": (AgentRole.OPS, ModelTier.FAST),
80
+ }
81
+
82
+
83
+ def classify_task(description: str) -> tuple[AgentRole, ModelTier]:
84
+ """Determine the best agent role and model tier for a task description.
85
+
86
+ Scans the description for known keywords and returns the most specific
87
+ match. Falls back to (WORKER, FAST) if nothing matches.
88
+
89
+ Args:
90
+ description: Free-text task description.
91
+
92
+ Returns:
93
+ Tuple of (AgentRole, ModelTier).
94
+ """
95
+ desc_lower = description.lower()
96
+
97
+ # Try multi-word patterns first (more specific)
98
+ for pattern in sorted(_TASK_ROLE_MAP.keys(), key=len, reverse=True):
99
+ if pattern in desc_lower:
100
+ return _TASK_ROLE_MAP[pattern]
101
+
102
+ return (AgentRole.WORKER, ModelTier.FAST)
103
+
104
+
105
+ # ---------------------------------------------------------------------------
106
+ # Node selection
107
+ # ---------------------------------------------------------------------------
108
+
109
+ class NodeInfo(BaseModel):
110
+ """Describes an available deployment target node."""
111
+
112
+ name: str
113
+ provider: ProviderType
114
+ host: str = "localhost"
115
+ capacity: float = Field(default=1.0, ge=0.0, le=1.0)
116
+ tags: List[str] = Field(default_factory=list)
117
+
118
+
119
+ def select_node(
120
+ nodes: List[NodeInfo],
121
+ role: AgentRole,
122
+ model: ModelTier,
123
+ preferred_provider: Optional[ProviderType] = None,
124
+ ) -> NodeInfo:
125
+ """Select the best node for a given agent role and model.
126
+
127
+ Selection criteria:
128
+ 1. Preferred provider match
129
+ 2. Highest available capacity
130
+ 3. Tag affinity (e.g. "gpu" nodes for reason-tier models)
131
+
132
+ Args:
133
+ nodes: Available deployment nodes.
134
+ role: The agent's role.
135
+ model: The model tier required.
136
+ preferred_provider: If set, prefer nodes of this provider type.
137
+
138
+ Returns:
139
+ The selected NodeInfo.
140
+ """
141
+ if not nodes:
142
+ return NodeInfo(name="local", provider=ProviderType.LOCAL)
143
+
144
+ scored: List[tuple[float, NodeInfo]] = []
145
+ for node in nodes:
146
+ score = node.capacity
147
+
148
+ if preferred_provider and node.provider == preferred_provider:
149
+ score += 2.0
150
+
151
+ if model in (ModelTier.REASON, ModelTier.NUANCE) and "gpu" in node.tags:
152
+ score += 1.0
153
+
154
+ if model == ModelTier.LOCAL and node.provider == ProviderType.LOCAL:
155
+ score += 1.5
156
+
157
+ scored.append((score, node))
158
+
159
+ scored.sort(key=lambda x: x[0], reverse=True)
160
+ return scored[0][1]
161
+
162
+
163
+ # ---------------------------------------------------------------------------
164
+ # Spawn result
165
+ # ---------------------------------------------------------------------------
166
+
167
+ class SpawnResult(BaseModel):
168
+ """Result of spawning a sub-agent."""
169
+
170
+ agent_name: str
171
+ deployment_id: str
172
+ status: AgentStatus
173
+ provider: ProviderType
174
+ host: str = "localhost"
175
+ pid: Optional[int] = None
176
+ role: AgentRole = AgentRole.WORKER
177
+ model: ModelTier = ModelTier.FAST
178
+ task_description: str = ""
179
+ coord_task_id: Optional[str] = None
180
+ spawned_at: str = Field(
181
+ default_factory=lambda: datetime.now(timezone.utc).isoformat()
182
+ )
183
+ error: Optional[str] = None
184
+
185
+
186
+ # ---------------------------------------------------------------------------
187
+ # Sub-agent spawner
188
+ # ---------------------------------------------------------------------------
189
+
190
+ class SubAgentSpawner:
191
+ """Lightweight spawner for task-specific sub-agents.
192
+
193
+ Wraps TeamEngine to create single-agent deployments for specific tasks
194
+ without requiring a full blueprint. Integrates with the coordination
195
+ board and trustee audit trail.
196
+
197
+ Args:
198
+ home: Agent home directory.
199
+ provider: Provider backend (defaults to LocalProvider if None).
200
+ nodes: Available deployment nodes for smart routing.
201
+ """
202
+
203
+ def __init__(
204
+ self,
205
+ home: Optional[Path] = None,
206
+ provider: Optional[ProviderBackend] = None,
207
+ nodes: Optional[List[NodeInfo]] = None,
208
+ ) -> None:
209
+ self._home = (home or Path("~/.skcapstone")).expanduser()
210
+ self._provider = provider
211
+ self._nodes = nodes or []
212
+ self._engine = TeamEngine(
213
+ home=self._home,
214
+ provider=self._provider,
215
+ comms_root=self._home / "comms",
216
+ )
217
+
218
+ def _build_mini_blueprint(
219
+ self,
220
+ task: str,
221
+ role: AgentRole,
222
+ model: ModelTier,
223
+ skills: Optional[List[str]] = None,
224
+ soul_blueprint: Optional[str] = None,
225
+ ) -> BlueprintManifest:
226
+ """Create a minimal single-agent blueprint for a task.
227
+
228
+ Args:
229
+ task: Task description (used for naming).
230
+ role: Agent role.
231
+ model: Model tier.
232
+ skills: Optional skill list.
233
+ soul_blueprint: Optional soul blueprint path.
234
+
235
+ Returns:
236
+ A BlueprintManifest with one agent.
237
+ """
238
+ slug = f"spawn-{role.value}-{int(time.time())}"
239
+ agent_key = f"{role.value}-agent"
240
+
241
+ spec = AgentSpec(
242
+ role=role,
243
+ model=model,
244
+ skills=skills or [],
245
+ soul_blueprint=soul_blueprint,
246
+ description=task[:200],
247
+ count=1,
248
+ )
249
+
250
+ return BlueprintManifest(
251
+ name=f"Spawned {role.value} for: {task[:80]}",
252
+ slug=slug,
253
+ version="0.1.0",
254
+ description=task,
255
+ icon=_role_icon(role),
256
+ author="sub-agent-spawner",
257
+ agents={agent_key: spec},
258
+ default_provider=ProviderType.LOCAL,
259
+ network=NetworkConfig(
260
+ mesh_vpn="tailscale",
261
+ discovery="skref_registry",
262
+ ),
263
+ storage=StorageConfig(
264
+ memory_backend="filesystem",
265
+ memory_sync=False,
266
+ ),
267
+ coordination=CoordinationConfig(
268
+ pattern="peer-to-peer",
269
+ heartbeat="5m",
270
+ ),
271
+ tags=["spawned", "sub-agent", role.value],
272
+ )
273
+
274
+ def spawn(
275
+ self,
276
+ task: str,
277
+ provider: Optional[ProviderType] = None,
278
+ role: Optional[AgentRole] = None,
279
+ model: Optional[ModelTier] = None,
280
+ skills: Optional[List[str]] = None,
281
+ soul_blueprint: Optional[str] = None,
282
+ coord_task_id: Optional[str] = None,
283
+ agent_name: Optional[str] = None,
284
+ ) -> SpawnResult:
285
+ """Spawn a task-specific sub-agent.
286
+
287
+ Auto-classifies the task to determine role and model tier if not
288
+ explicitly provided. Selects the best node, builds a mini blueprint,
289
+ and deploys via TeamEngine.
290
+
291
+ Args:
292
+ task: Free-text task description.
293
+ provider: Force a specific provider type.
294
+ role: Override auto-detected agent role.
295
+ model: Override auto-detected model tier.
296
+ skills: Skills to load into the agent.
297
+ soul_blueprint: Path to a soul blueprint YAML.
298
+ coord_task_id: Optional coordination board task to claim.
299
+ agent_name: Optional custom agent name.
300
+
301
+ Returns:
302
+ SpawnResult with deployment details.
303
+ """
304
+ # Auto-classify if not specified
305
+ detected_role, detected_model = classify_task(task)
306
+ final_role = role or detected_role
307
+ final_model = model or detected_model
308
+
309
+ # Select node
310
+ node = select_node(
311
+ self._nodes, final_role, final_model,
312
+ preferred_provider=provider,
313
+ )
314
+ target_provider = provider or node.provider
315
+
316
+ logger.info(
317
+ "Spawning %s agent (model=%s) on %s for: %s",
318
+ final_role.value, final_model.value, node.name, task[:80],
319
+ )
320
+
321
+ # Build mini blueprint
322
+ blueprint = self._build_mini_blueprint(
323
+ task, final_role, final_model, skills, soul_blueprint,
324
+ )
325
+
326
+ # Deploy
327
+ try:
328
+ deployment = self._engine.deploy(
329
+ blueprint,
330
+ name=agent_name,
331
+ provider_override=target_provider,
332
+ )
333
+
334
+ # Get the single deployed agent
335
+ agents = list(deployment.agents.values())
336
+ agent = agents[0] if agents else None
337
+
338
+ if not agent:
339
+ return SpawnResult(
340
+ agent_name=agent_name or "unknown",
341
+ deployment_id=deployment.deployment_id,
342
+ status=AgentStatus.FAILED,
343
+ provider=target_provider,
344
+ role=final_role,
345
+ model=final_model,
346
+ task_description=task,
347
+ error="No agent was created in deployment.",
348
+ )
349
+
350
+ # Claim coordination task if provided
351
+ if coord_task_id:
352
+ self._claim_coord_task(coord_task_id, agent.name)
353
+
354
+ # Audit the spawn
355
+ self._audit_spawn(agent, task, deployment.deployment_id)
356
+
357
+ return SpawnResult(
358
+ agent_name=agent.name,
359
+ deployment_id=deployment.deployment_id,
360
+ status=agent.status,
361
+ provider=target_provider,
362
+ host=agent.host or "localhost",
363
+ pid=agent.pid,
364
+ role=final_role,
365
+ model=final_model,
366
+ task_description=task,
367
+ coord_task_id=coord_task_id,
368
+ )
369
+
370
+ except Exception as exc:
371
+ logger.error("Spawn failed: %s", exc)
372
+ return SpawnResult(
373
+ agent_name=agent_name or f"spawn-{final_role.value}-failed",
374
+ deployment_id="",
375
+ status=AgentStatus.FAILED,
376
+ provider=target_provider,
377
+ role=final_role,
378
+ model=final_model,
379
+ task_description=task,
380
+ error=str(exc),
381
+ )
382
+
383
+ def spawn_baby(
384
+ self,
385
+ name: str,
386
+ provider: Optional[ProviderType] = None,
387
+ ) -> SpawnResult:
388
+ """Spawn a pre-defined baby agent by name.
389
+
390
+ Baby agents are the 12 lightweight daemons of the SK* ecosystem
391
+ (e.g., memory-curator, trust-guardian, health-monitor). Each has
392
+ a pre-configured role, model tier, skills, and default task.
393
+
394
+ Args:
395
+ name: Baby agent name (e.g., 'memory-curator').
396
+ provider: Override the default provider.
397
+
398
+ Returns:
399
+ SpawnResult with deployment details.
400
+
401
+ Raises:
402
+ ValueError: If the baby agent name is not recognized.
403
+ """
404
+ from .baby_agents import get_baby_agent
405
+
406
+ baby = get_baby_agent(name)
407
+ if baby is None:
408
+ from .baby_agents import BABY_AGENTS
409
+ available = ", ".join(sorted(BABY_AGENTS.keys()))
410
+ raise ValueError(
411
+ f"Unknown baby agent '{name}'. "
412
+ f"Available: {available}"
413
+ )
414
+
415
+ logger.info("Spawning baby agent: %s", baby.name)
416
+ return self.spawn(
417
+ task=baby.task,
418
+ provider=provider,
419
+ role=baby.role,
420
+ model=baby.model,
421
+ skills=baby.skills,
422
+ agent_name=baby.name,
423
+ )
424
+
425
+ def spawn_batch(
426
+ self,
427
+ tasks: List[Dict[str, Any]],
428
+ provider: Optional[ProviderType] = None,
429
+ ) -> List[SpawnResult]:
430
+ """Spawn multiple sub-agents for a batch of tasks.
431
+
432
+ Args:
433
+ tasks: List of dicts with at least a "task" key. Optional keys:
434
+ "role", "model", "skills", "coord_task_id".
435
+ provider: Default provider for all spawns.
436
+
437
+ Returns:
438
+ List of SpawnResult, one per task.
439
+ """
440
+ results = []
441
+ for task_spec in tasks:
442
+ result = self.spawn(
443
+ task=task_spec["task"],
444
+ provider=provider or task_spec.get("provider"),
445
+ role=task_spec.get("role"),
446
+ model=task_spec.get("model"),
447
+ skills=task_spec.get("skills"),
448
+ coord_task_id=task_spec.get("coord_task_id"),
449
+ )
450
+ results.append(result)
451
+ return results
452
+
453
+ def list_spawned(self) -> List[SpawnResult]:
454
+ """List all currently spawned sub-agents.
455
+
456
+ Returns:
457
+ List of SpawnResult for active spawned deployments.
458
+ """
459
+ results = []
460
+ for dep in self._engine.list_deployments():
461
+ if "spawned" not in dep.blueprint_slug.split("-")[0:1]:
462
+ # Only show spawn-prefixed deployments
463
+ if not dep.blueprint_slug.startswith("spawn-"):
464
+ continue
465
+
466
+ for agent in dep.agents.values():
467
+ results.append(SpawnResult(
468
+ agent_name=agent.name,
469
+ deployment_id=dep.deployment_id,
470
+ status=agent.status,
471
+ provider=dep.provider,
472
+ host=agent.host or "localhost",
473
+ pid=agent.pid,
474
+ task_description=dep.team_name or "",
475
+ spawned_at=agent.started_at or dep.created_at,
476
+ ))
477
+ return results
478
+
479
+ def kill(self, deployment_id: str) -> bool:
480
+ """Destroy a spawned sub-agent by deployment ID.
481
+
482
+ Args:
483
+ deployment_id: The deployment to destroy.
484
+
485
+ Returns:
486
+ True if successfully destroyed.
487
+ """
488
+ return self._engine.destroy_deployment(deployment_id)
489
+
490
+ # ------------------------------------------------------------------
491
+ # Internal helpers
492
+ # ------------------------------------------------------------------
493
+
494
+ def _claim_coord_task(self, task_id: str, agent_name: str) -> None:
495
+ """Claim a coordination board task for the spawned agent."""
496
+ try:
497
+ from .coordination import Board
498
+ board = Board(home=self._home)
499
+ board.claim_task(agent_name, task_id)
500
+ logger.info("Claimed coord task %s for %s", task_id, agent_name)
501
+ except Exception as exc:
502
+ logger.warning("Could not claim coord task %s: %s", task_id, exc)
503
+
504
+ def _audit_spawn(
505
+ self,
506
+ agent: DeployedAgent,
507
+ task: str,
508
+ deployment_id: str,
509
+ ) -> None:
510
+ """Write an audit entry for the spawn."""
511
+ try:
512
+ from ._trustee_helpers import write_audit
513
+ write_audit(
514
+ "spawn_agent",
515
+ deployment_id,
516
+ {
517
+ "agent_name": agent.name,
518
+ "task": task[:200],
519
+ "status": agent.status.value,
520
+ "provider": agent.provider.value,
521
+ },
522
+ home=self._home,
523
+ )
524
+ except Exception as exc:
525
+ logger.warning("Audit write failed: %s", exc)
526
+
527
+
528
+ # ---------------------------------------------------------------------------
529
+ # Utilities
530
+ # ---------------------------------------------------------------------------
531
+
532
+ def _role_icon(role: AgentRole) -> str:
533
+ """Map agent role to an emoji icon."""
534
+ return {
535
+ AgentRole.MANAGER: "👑",
536
+ AgentRole.WORKER: "⚙️",
537
+ AgentRole.RESEARCHER: "🔬",
538
+ AgentRole.CODER: "💻",
539
+ AgentRole.REVIEWER: "🔍",
540
+ AgentRole.DOCUMENTARIAN: "📝",
541
+ AgentRole.SECURITY: "🛡️",
542
+ AgentRole.OPS: "🔧",
543
+ AgentRole.CUSTOM: "🎯",
544
+ }.get(role, "🤖")