@smilintux/skcapstone 0.10.0 → 0.12.5

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 (279) hide show
  1. package/.env.example +10 -4
  2. package/.github/workflows/ci.yml +2 -2
  3. package/.github/workflows/publish.yml +9 -2
  4. package/.openclaw-workspace.json +2 -2
  5. package/CLAUDE.md +37 -0
  6. package/MISSION.md +17 -2
  7. package/README.md +282 -3
  8. package/docker/Dockerfile +7 -7
  9. package/docker/compose-templates/dev-team.yml +12 -12
  10. package/docker/compose-templates/mini-team.yml +9 -9
  11. package/docker/compose-templates/ops-team.yml +10 -10
  12. package/docker/compose-templates/research-team.yml +10 -10
  13. package/docker/entrypoint.sh +4 -4
  14. package/docs/ADR-optional-integration-backbone.md +181 -0
  15. package/docs/ARCHITECTURE.md +186 -43
  16. package/docs/BOND_WITH_GROK.md +6 -6
  17. package/docs/CUSTOM_AGENT.md +123 -30
  18. package/docs/DREAMING.md +70 -0
  19. package/docs/GETTING_STARTED.md +7 -7
  20. package/docs/QUICKSTART.md +10 -6
  21. package/docs/SKJOULE_ARCHITECTURE.md +3 -3
  22. package/docs/SOUL_SWAPPER.md +5 -5
  23. package/docs/hammertime-audit.md +402 -0
  24. package/docs/sk-integration-HANDOFF.md +117 -0
  25. package/docs/skscheduler.md +155 -0
  26. package/docs/superpowers/examples/jobs.yaml +31 -0
  27. package/docs/superpowers/plans/2026-06-08-skscheduler.md +1265 -0
  28. package/docs/superpowers/specs/2026-06-08-skscheduler-design.md +186 -0
  29. package/examples/custom-bond-template.json +1 -1
  30. package/examples/grok-feb.json +1 -1
  31. package/examples/queen-ava-feb.json +1 -1
  32. package/launchd/{com.skcapstone.skcomm-heartbeat.plist → com.skcapstone.skcomms-heartbeat.plist} +4 -4
  33. package/launchd/{com.skcapstone.skcomm-queue-drain.plist → com.skcapstone.skcomms-queue-drain.plist} +4 -4
  34. package/launchd/install-launchd.sh +6 -6
  35. package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/index.ts +3 -2
  36. package/package.json +1 -1
  37. package/pyproject.toml +16 -10
  38. package/scripts/archive-sessions.sh +7 -0
  39. package/scripts/check-updates.py +4 -4
  40. package/scripts/install-bundle.sh +8 -8
  41. package/scripts/install.ps1 +12 -11
  42. package/scripts/install.sh +159 -5
  43. package/scripts/model-fallback-monitor.sh +102 -0
  44. package/scripts/nvidia-proxy.mjs +78 -26
  45. package/scripts/refresh-anthropic-token.sh +172 -0
  46. package/scripts/release.sh +98 -0
  47. package/scripts/session-to-memory.py +219 -0
  48. package/scripts/skgateway.mjs +3 -3
  49. package/scripts/telegram-catchup-all.sh +12 -1
  50. package/scripts/verify_install.sh +2 -2
  51. package/scripts/wargov-ufo-capture/README.md +43 -0
  52. package/scripts/wargov-ufo-capture/cdp_capture_release2.py +273 -0
  53. package/scripts/wargov-ufo-capture/cdp_capture_splc_doj.py +246 -0
  54. package/scripts/wargov-ufo-capture/cdp_finish.py +271 -0
  55. package/scripts/wargov-ufo-capture/cdp_probe.py +188 -0
  56. package/scripts/wargov-ufo-capture/cdp_splc_pressrelease.py +101 -0
  57. package/scripts/wargov-ufo-capture/parse_csv.py +95 -0
  58. package/scripts/wargov-ufo-capture/pull_dvids.sh +107 -0
  59. package/scripts/watch-anthropic-token.sh +212 -0
  60. package/scripts/windows/install-tasks.ps1 +7 -7
  61. package/scripts/windows/skcapstone-task.xml +1 -1
  62. package/src/skcapstone/__init__.py +45 -3
  63. package/src/skcapstone/_cli_monolith.py +20 -15
  64. package/src/skcapstone/activity.py +5 -1
  65. package/src/skcapstone/agent_card.py +3 -2
  66. package/src/skcapstone/api.py +41 -40
  67. package/src/skcapstone/auction.py +14 -11
  68. package/src/skcapstone/backup.py +2 -1
  69. package/src/skcapstone/blueprint_registry.py +4 -3
  70. package/src/skcapstone/brain_first.py +238 -0
  71. package/src/skcapstone/changelog.py +1 -1
  72. package/src/skcapstone/chat.py +22 -17
  73. package/src/skcapstone/cli/__init__.py +9 -1
  74. package/src/skcapstone/cli/_common.py +1 -0
  75. package/src/skcapstone/cli/agents_spawner.py +5 -2
  76. package/src/skcapstone/cli/alerts.py +25 -4
  77. package/src/skcapstone/cli/bench.py +15 -15
  78. package/src/skcapstone/cli/chat.py +7 -4
  79. package/src/skcapstone/cli/consciousness.py +5 -2
  80. package/src/skcapstone/cli/context_cmd.py +18 -4
  81. package/src/skcapstone/cli/daemon.py +11 -7
  82. package/src/skcapstone/cli/gtd.py +26 -1
  83. package/src/skcapstone/cli/housekeeping.py +3 -3
  84. package/src/skcapstone/cli/identity_cmd.py +378 -0
  85. package/src/skcapstone/cli/joule_cmd.py +7 -3
  86. package/src/skcapstone/cli/memory.py +8 -6
  87. package/src/skcapstone/cli/peers_dir.py +1 -1
  88. package/src/skcapstone/cli/register_cmd.py +29 -3
  89. package/src/skcapstone/cli/scheduler_cmd.py +167 -0
  90. package/src/skcapstone/cli/session.py +25 -0
  91. package/src/skcapstone/cli/setup.py +96 -29
  92. package/src/skcapstone/cli/shell_cmd.py +53 -1
  93. package/src/skcapstone/cli/skills_cmd.py +2 -2
  94. package/src/skcapstone/cli/soul.py +8 -5
  95. package/src/skcapstone/cli/status.py +37 -11
  96. package/src/skcapstone/cli/telegram.py +21 -0
  97. package/src/skcapstone/cli/test_cmd.py +5 -5
  98. package/src/skcapstone/cli/test_connection.py +2 -2
  99. package/src/skcapstone/cli/upgrade_cmd.py +23 -14
  100. package/src/skcapstone/cli/version_cmd.py +1 -1
  101. package/src/skcapstone/cli/watch_cmd.py +9 -6
  102. package/src/skcapstone/cloud9_bridge.py +14 -14
  103. package/src/skcapstone/codex_setup.py +255 -0
  104. package/src/skcapstone/config_validator.py +7 -4
  105. package/src/skcapstone/consciousness_config.py +5 -1
  106. package/src/skcapstone/consciousness_loop.py +313 -273
  107. package/src/skcapstone/context_loader.py +121 -0
  108. package/src/skcapstone/coord_federation.py +2 -1
  109. package/src/skcapstone/coordination.py +23 -6
  110. package/src/skcapstone/crush_integration.py +2 -1
  111. package/src/skcapstone/daemon.py +132 -77
  112. package/src/skcapstone/dashboard.py +10 -10
  113. package/src/skcapstone/data/sk-agent-picker.sh +421 -0
  114. package/src/skcapstone/data/systemd/skcapstone-api.socket +9 -0
  115. package/src/skcapstone/data/systemd/skcapstone-memory-compress.service +18 -0
  116. package/src/skcapstone/data/systemd/skcapstone-memory-compress.timer +11 -0
  117. package/src/skcapstone/data/systemd/skcapstone.service +37 -0
  118. package/src/skcapstone/data/systemd/skcapstone@.service +50 -0
  119. package/src/skcapstone/data/systemd/skcomms-heartbeat.service +18 -0
  120. package/{systemd/skcomm-heartbeat.timer → src/skcapstone/data/systemd/skcomms-heartbeat.timer} +2 -2
  121. package/src/skcapstone/data/systemd/skcomms-queue-drain.service +17 -0
  122. package/{systemd/skcomm-queue-drain.timer → src/skcapstone/data/systemd/skcomms-queue-drain.timer} +2 -2
  123. package/src/skcapstone/defaults/claude/CLAUDE.md +67 -0
  124. package/src/skcapstone/defaults/claude/settings.json +74 -0
  125. package/src/skcapstone/defaults/lumina/config/claude-hooks.md +57 -0
  126. package/src/skcapstone/defaults/lumina/config/skgraph.yaml +55 -10
  127. package/src/skcapstone/defaults/lumina/config/skmemory.yaml +79 -13
  128. package/src/skcapstone/defaults/lumina/config/skvector.yaml +60 -9
  129. package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +2 -2
  130. package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +2 -2
  131. package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +9 -9
  132. package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +2 -2
  133. package/src/skcapstone/defaults/unhinged.json +13 -0
  134. package/src/skcapstone/discovery.py +43 -20
  135. package/src/skcapstone/doctor.py +941 -22
  136. package/src/skcapstone/dreaming.py +1183 -109
  137. package/src/skcapstone/emotion_tracker.py +2 -2
  138. package/src/skcapstone/export.py +4 -3
  139. package/src/skcapstone/fuse_mount.py +14 -12
  140. package/src/skcapstone/gui_installer.py +2 -2
  141. package/src/skcapstone/heartbeat.py +1 -1
  142. package/src/skcapstone/housekeeping.py +14 -14
  143. package/src/skcapstone/install_wizard.py +209 -7
  144. package/src/skcapstone/itil.py +13 -4
  145. package/src/skcapstone/kms_scheduler.py +10 -8
  146. package/src/skcapstone/launchd.py +19 -19
  147. package/src/skcapstone/mcp_launcher.py +15 -1
  148. package/src/skcapstone/mcp_server.py +83 -49
  149. package/src/skcapstone/mcp_tools/__init__.py +2 -0
  150. package/src/skcapstone/mcp_tools/_helpers.py +2 -2
  151. package/src/skcapstone/mcp_tools/ansible_tools.py +7 -4
  152. package/src/skcapstone/mcp_tools/brain_first_tools.py +90 -0
  153. package/src/skcapstone/mcp_tools/capauth_tools.py +7 -4
  154. package/src/skcapstone/mcp_tools/comm_tools.py +10 -10
  155. package/src/skcapstone/mcp_tools/coord_tools.py +8 -4
  156. package/src/skcapstone/mcp_tools/did_tools.py +11 -8
  157. package/src/skcapstone/mcp_tools/gtd_tools.py +4 -4
  158. package/src/skcapstone/mcp_tools/memory_tools.py +6 -2
  159. package/src/skcapstone/mcp_tools/notification_tools.py +22 -6
  160. package/src/skcapstone/mcp_tools/{skcomm_tools.py → skcomms_tools.py} +14 -14
  161. package/src/skcapstone/mcp_tools/soul_tools.py +8 -2
  162. package/src/skcapstone/mdns_discovery.py +2 -2
  163. package/src/skcapstone/memory_curator.py +1 -1
  164. package/src/skcapstone/memory_engine.py +10 -3
  165. package/src/skcapstone/metrics.py +30 -16
  166. package/src/skcapstone/migrate_memories.py +4 -3
  167. package/src/skcapstone/migrate_multi_agent.py +8 -7
  168. package/src/skcapstone/models.py +47 -5
  169. package/src/skcapstone/notifications.py +42 -18
  170. package/src/skcapstone/onboard.py +875 -121
  171. package/src/skcapstone/operator_link.py +170 -0
  172. package/src/skcapstone/peer_directory.py +4 -4
  173. package/src/skcapstone/peers.py +19 -19
  174. package/src/skcapstone/pillars/__init__.py +7 -5
  175. package/src/skcapstone/pillars/consciousness.py +191 -0
  176. package/src/skcapstone/pillars/identity.py +51 -7
  177. package/src/skcapstone/pillars/memory.py +9 -3
  178. package/src/skcapstone/pillars/sync.py +2 -2
  179. package/src/skcapstone/preflight.py +3 -3
  180. package/src/skcapstone/providers/docker.py +28 -28
  181. package/src/skcapstone/register.py +6 -6
  182. package/src/skcapstone/registry_client.py +5 -4
  183. package/src/skcapstone/runtime.py +14 -3
  184. package/src/skcapstone/scheduled_tasks.py +254 -19
  185. package/src/skcapstone/scheduler_jobs.py +456 -0
  186. package/src/skcapstone/scheduler_runner.py +239 -0
  187. package/src/skcapstone/scheduler_state.py +162 -0
  188. package/src/skcapstone/sdk.py +310 -0
  189. package/src/skcapstone/service_health.py +279 -39
  190. package/src/skcapstone/session_briefing.py +108 -0
  191. package/src/skcapstone/session_capture.py +1 -1
  192. package/src/skcapstone/shell.py +7 -1
  193. package/src/skcapstone/soul.py +3 -1
  194. package/src/skcapstone/soul_switch.py +3 -1
  195. package/src/skcapstone/summary.py +6 -6
  196. package/src/skcapstone/sync_engine.py +15 -15
  197. package/src/skcapstone/sync_watcher.py +2 -2
  198. package/src/skcapstone/systemd.py +55 -21
  199. package/src/skcapstone/team_comms.py +8 -8
  200. package/src/skcapstone/team_engine.py +1 -1
  201. package/src/skcapstone/testrunner.py +3 -3
  202. package/src/skcapstone/trust_graph.py +40 -5
  203. package/src/skcapstone/unified_search.py +15 -6
  204. package/src/skcapstone/uninstall_wizard.py +11 -3
  205. package/src/skcapstone/version_check.py +8 -4
  206. package/src/skcapstone/warmth_anchor.py +4 -2
  207. package/src/skcapstone/whoami.py +4 -4
  208. package/systemd/skcapstone.service +4 -6
  209. package/systemd/skcapstone@.service +7 -8
  210. package/systemd/skcomms-heartbeat.service +21 -0
  211. package/systemd/skcomms-heartbeat.timer +12 -0
  212. package/systemd/skcomms-queue-drain.service +17 -0
  213. package/systemd/skcomms-queue-drain.timer +12 -0
  214. package/tests/conftest.py +39 -0
  215. package/tests/integration/test_consciousness_e2e.py +39 -39
  216. package/tests/test_agent_card.py +1 -1
  217. package/tests/test_agent_home_scaffold.py +34 -0
  218. package/tests/test_alerts_consumer_topics.py +27 -0
  219. package/tests/test_backup.py +2 -1
  220. package/tests/test_chat.py +6 -6
  221. package/tests/test_claude_md.py +2 -2
  222. package/tests/test_cli_skills.py +10 -10
  223. package/tests/test_cli_test_cmd.py +4 -4
  224. package/tests/test_cli_test_connection.py +1 -1
  225. package/tests/test_cloud9_bridge.py +6 -6
  226. package/tests/test_consciousness_e2e.py +1 -1
  227. package/tests/test_consciousness_loop.py +10 -10
  228. package/tests/test_coordination.py +25 -0
  229. package/tests/test_cross_package.py +21 -21
  230. package/tests/test_daemon.py +4 -4
  231. package/tests/test_daemon_shutdown.py +1 -1
  232. package/tests/test_docker_provider.py +29 -29
  233. package/tests/test_doctor.py +400 -0
  234. package/tests/test_doctor_skscheduler.py +50 -0
  235. package/tests/test_dreaming_engine.py +147 -0
  236. package/tests/test_dreaming_gtd_capture.py +35 -0
  237. package/tests/test_e2e_automated.py +8 -5
  238. package/tests/test_fuse_mount.py +10 -10
  239. package/tests/test_gtd_brief.py +46 -0
  240. package/tests/test_gtd_malformed_tolerance.py +31 -0
  241. package/tests/test_housekeeping.py +15 -15
  242. package/tests/test_identity_migrate.py +251 -0
  243. package/tests/test_integration_backbone.py +598 -0
  244. package/tests/test_itil_gtd_lifecycle.py +37 -0
  245. package/tests/test_jobs_dropins.py +84 -0
  246. package/tests/test_mcp_server.py +82 -37
  247. package/tests/test_models.py +48 -4
  248. package/tests/test_multi_agent.py +31 -29
  249. package/tests/test_notifications.py +122 -32
  250. package/tests/test_onboard.py +63 -75
  251. package/tests/test_operator_link.py +78 -0
  252. package/tests/test_peers.py +14 -14
  253. package/tests/test_pillars.py +98 -0
  254. package/tests/test_preflight.py +3 -3
  255. package/tests/test_runtime.py +21 -0
  256. package/tests/test_scheduled_tasks.py +11 -6
  257. package/tests/test_scheduler_cli.py +47 -0
  258. package/tests/test_scheduler_features.py +133 -0
  259. package/tests/test_scheduler_integration.py +87 -0
  260. package/tests/test_scheduler_jobs.py +155 -0
  261. package/tests/test_scheduler_runner.py +64 -0
  262. package/tests/test_scheduler_state.py +57 -0
  263. package/tests/test_sdk.py +70 -0
  264. package/tests/test_service_health_incidents.py +34 -0
  265. package/tests/test_service_registry.py +52 -0
  266. package/tests/test_session_briefing.py +130 -0
  267. package/tests/test_snapshots.py +4 -4
  268. package/tests/test_sync_pipeline.py +26 -26
  269. package/tests/test_team_comms.py +2 -2
  270. package/tests/test_testrunner.py +2 -2
  271. package/tests/test_trust_graph.py +18 -0
  272. package/tests/test_unified_search.py +2 -2
  273. package/tests/test_version_check.py +10 -0
  274. package/tests/test_version_cmd.py +8 -8
  275. package/tests/test_whoami.py +1 -1
  276. package/systemd/skcomm-heartbeat.service +0 -18
  277. package/systemd/skcomm-queue-drain.service +0 -17
  278. /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/package.json +0 -0
  279. /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/openclaw.plugin.json +0 -0
@@ -2,7 +2,7 @@
2
2
  Interactive agent-to-agent chat for the sovereign terminal.
3
3
 
4
4
  Provides a real-time terminal chat experience between agents using
5
- SKChat for message models and SKComm for transport. Works from any
5
+ SKChat for message models and SKComms for transport. Works from any
6
6
  terminal on any platform — no IDE dependency.
7
7
 
8
8
  Usage:
@@ -52,7 +52,7 @@ _TEXT_SUFFIXES = {
52
52
  class AgentChat:
53
53
  """Interactive chat engine for sovereign agent communication.
54
54
 
55
- Wraps SKChat models and SKComm transport into a simple
55
+ Wraps SKChat models and SKComms transport into a simple
56
56
  send/receive/poll interface suitable for terminal use.
57
57
 
58
58
  Args:
@@ -71,7 +71,7 @@ class AgentChat:
71
71
  # ------------------------------------------------------------------
72
72
 
73
73
  def _ensure_comm(self) -> bool:
74
- """Lazily initialize the SKComm engine.
74
+ """Lazily initialize the SKComms engine.
75
75
 
76
76
  Returns:
77
77
  bool: True if communication layer is available.
@@ -80,15 +80,15 @@ class AgentChat:
80
80
  return True
81
81
 
82
82
  try:
83
- from skcomm.core import SKComm
83
+ from skcomms.core import SKComms
84
84
 
85
- self._comm = SKComm.from_config()
85
+ self._comm = SKComms.from_config()
86
86
  return len(self._comm.router.transports) > 0
87
87
  except ImportError:
88
- logger.info("skcomm not installed")
88
+ logger.info("skcomms not installed")
89
89
  return False
90
90
  except Exception as exc:
91
- logger.info("SKComm init failed: %s", exc)
91
+ logger.info("SKComms init failed: %s", exc)
92
92
  return False
93
93
 
94
94
  def _ensure_history(self):
@@ -123,7 +123,7 @@ class AgentChat:
123
123
  """Send a message to a peer agent.
124
124
 
125
125
  Stores locally in SKMemory-backed history and delivers via
126
- SKComm if transports are available.
126
+ SKComms if transports are available.
127
127
 
128
128
  Args:
129
129
  recipient: Peer agent name or CapAuth identity.
@@ -162,6 +162,7 @@ class AgentChat:
162
162
  result["delivered"] = True
163
163
  result["transport"] = getattr(report, "successful_transport", None)
164
164
  except Exception as exc:
165
+ logger.warning("chat.py: %s", exc)
165
166
  result["error"] = str(exc)
166
167
 
167
168
  except ImportError as exc:
@@ -204,8 +205,8 @@ class AgentChat:
204
205
  thread_id=msg_dict.get("thread_id"),
205
206
  )
206
207
  history.store_message(chat_msg)
207
- except Exception:
208
- pass
208
+ except Exception as exc:
209
+ logger.warning("Failed to store received message in history: %s", exc)
209
210
  except Exception as exc:
210
211
  logger.warning("Receive error: %s", exc)
211
212
 
@@ -226,14 +227,16 @@ class AgentChat:
226
227
 
227
228
  try:
228
229
  return history.search_messages(self.identity, limit=limit)
229
- except Exception:
230
+ except Exception as e:
231
+ logger.warning("chat.py: %s", e)
230
232
  try:
231
233
  memories = history._store.list_memories(
232
234
  tags=["skchat:message"],
233
235
  limit=limit,
234
236
  )
235
237
  return [history._memory_to_chat_dict(m) for m in memories]
236
- except Exception:
238
+ except Exception as e:
239
+ logger.warning("chat.py: %s", e)
237
240
  return []
238
241
 
239
242
  def forward(
@@ -246,7 +249,7 @@ class AgentChat:
246
249
 
247
250
  Wraps the original message in a forward envelope that records the
248
251
  original sender and timestamp, then delivers it to target_peer via
249
- SKComm and stores it locally in history.
252
+ SKComms and stores it locally in history.
250
253
 
251
254
  Args:
252
255
  original_msg: Original message dict (from inbox or receive).
@@ -298,6 +301,7 @@ class AgentChat:
298
301
  history.store_message(fwd_msg)
299
302
  result["stored"] = True
300
303
  except Exception as exc:
304
+ logger.warning("chat.py: %s", exc)
301
305
  result["error"] = str(exc)
302
306
 
303
307
  if self._ensure_comm():
@@ -311,6 +315,7 @@ class AgentChat:
311
315
  result["delivered"] = True
312
316
  result["transport"] = getattr(report, "successful_transport", None)
313
317
  except Exception as exc:
318
+ logger.warning("chat.py: %s", exc)
314
319
  result["error"] = str(exc)
315
320
 
316
321
  return result
@@ -410,8 +415,8 @@ class AgentChat:
410
415
  state["last_recv_thread"] = recv_thread
411
416
  display = _format_content(content)
412
417
  print(f"\n \033[32m{sender}\033[0m \033[2m[{ts}]\033[0m {display}\n")
413
- except Exception:
414
- pass
418
+ except Exception as exc:
419
+ logger.warning("Chat poll loop error: %s", exc)
415
420
 
416
421
  # Print header
417
422
  tr_label = "✓ connected" if transport_ok else "✗ local-only"
@@ -629,7 +634,7 @@ class AgentChat:
629
634
  # ---------------------------------------------------------------------------
630
635
 
631
636
  def _pack_chat_payload(msg) -> str:
632
- """Serialize a ChatMessage for SKComm transport.
637
+ """Serialize a ChatMessage for SKComms transport.
633
638
 
634
639
  Args:
635
640
  msg: ChatMessage instance.
@@ -649,7 +654,7 @@ def _pack_chat_payload(msg) -> str:
649
654
 
650
655
 
651
656
  def _unpack_chat_payload(payload: str, sender: str, recipient: str) -> dict:
652
- """Deserialize a chat payload from SKComm.
657
+ """Deserialize a chat payload from SKComms.
653
658
 
654
659
  Falls back to plain text if not structured JSON.
655
660
 
@@ -19,7 +19,7 @@ from .. import __version__
19
19
  @click.group()
20
20
  @click.version_option(version=__version__, prog_name="skcapstone")
21
21
  @click.option(
22
- "--agent", envvar="SKCAPSTONE_AGENT", default="",
22
+ "--agent", envvar="SKAGENT", default="",
23
23
  help="Agent name — resolves home to {root}/agents/{name}/",
24
24
  )
25
25
  @click.pass_context
@@ -52,6 +52,7 @@ from .completions import register_completions_commands
52
52
  from .peer import register_peer_commands
53
53
  from .backup import register_backup_commands
54
54
  from .chat import register_chat_commands
55
+ from .record_cmd import register_record_commands
55
56
  from .anchor import register_anchor_commands
56
57
  from .session import register_session_commands
57
58
  from .context_cmd import register_context_commands
@@ -91,6 +92,9 @@ from .skseed import register_skseed_commands
91
92
  from .service_cmd import register_service_commands
92
93
  from .telegram import register_telegram_commands
93
94
  from .joule_cmd import register_joule_commands
95
+ from .alerts import register_alerts_commands
96
+ from .scheduler_cmd import register_scheduler_commands
97
+ from .identity_cmd import register_identity_commands
94
98
 
95
99
  register_setup_commands(main)
96
100
  register_shell_commands(main)
@@ -106,6 +110,7 @@ register_completions_commands(main)
106
110
  register_peer_commands(main)
107
111
  register_backup_commands(main)
108
112
  register_chat_commands(main)
113
+ register_record_commands(main)
109
114
  register_anchor_commands(main)
110
115
  register_session_commands(main)
111
116
  register_context_commands(main)
@@ -144,3 +149,6 @@ register_skseed_commands(main)
144
149
  register_service_commands(main)
145
150
  register_telegram_commands(main)
146
151
  register_joule_commands(main)
152
+ register_alerts_commands(main)
153
+ register_scheduler_commands(main)
154
+ register_identity_commands(main)
@@ -58,6 +58,7 @@ def apply_agent_override(agent: str) -> None:
58
58
  """
59
59
  if agent:
60
60
  _pkg.SKCAPSTONE_AGENT = agent
61
+ os.environ["SKAGENT"] = agent
61
62
  os.environ["SKCAPSTONE_AGENT"] = agent
62
63
 
63
64
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  from pathlib import Path
6
7
  from typing import Optional
7
8
 
@@ -12,6 +13,8 @@ from ._common import AGENT_HOME, console
12
13
  from rich.panel import Panel
13
14
  from rich.table import Table
14
15
 
16
+ logger = logging.getLogger(__name__)
17
+
15
18
 
16
19
  def _resolve_provider_backend(provider: Optional[str], home_path: Path):
17
20
  """Resolve provider string to backend object and ProviderType.
@@ -37,8 +40,8 @@ def _resolve_provider_backend(provider: Optional[str], home_path: Path):
37
40
  prov_backend = DockerProvider()
38
41
  elif prov_type == ProviderType.PROXMOX:
39
42
  prov_backend = ProxmoxProvider()
40
- except Exception:
41
- pass
43
+ except Exception as exc:
44
+ logger.warning("Failed to initialize provider backend for %s: %s", provider, exc)
42
45
  return prov_backend, prov_type
43
46
 
44
47
 
@@ -25,15 +25,21 @@ except ImportError: # pragma: no cover
25
25
  # Constants
26
26
  # ---------------------------------------------------------------------------
27
27
 
28
- #: Default topics the alerts command subscribes to.
28
+ #: Default topics the alerts command subscribes to. The trailing ``*.<sev>``
29
+ #: wildcards surface alerts published by any sk* service via ``sdk.alert()``,
30
+ #: which follows the ``<service>.<severity>`` topic convention (e.g.
31
+ #: ``skmemory.error``, ``sksecurity.critical``).
29
32
  DEFAULT_TOPICS: tuple[str, ...] = (
30
33
  "agent.critical",
31
34
  "coord.task_failed",
32
35
  "consciousness.error",
33
36
  "pillar.degraded",
37
+ "*.critical",
38
+ "*.error",
39
+ "*.warn",
34
40
  )
35
41
 
36
- #: Rich markup styles per topic prefix (longest match wins).
42
+ #: Rich markup styles per exact topic name.
37
43
  _TOPIC_STYLE: dict[str, str] = {
38
44
  "agent.critical": "bold red",
39
45
  "coord.task_failed": "red",
@@ -41,6 +47,15 @@ _TOPIC_STYLE: dict[str, str] = {
41
47
  "pillar.degraded": "yellow",
42
48
  }
43
49
 
50
+ #: Rich markup styles by severity suffix — used for ``<service>.<severity>``
51
+ #: consumer topics with no exact match in ``_TOPIC_STYLE``.
52
+ _SEVERITY_STYLE: dict[str, str] = {
53
+ "critical": "bold red",
54
+ "error": "red",
55
+ "warn": "yellow",
56
+ "info": "cyan",
57
+ }
58
+
44
59
  #: Default polling interval in seconds.
45
60
  DEFAULT_INTERVAL: float = 1.0
46
61
 
@@ -56,9 +71,15 @@ def _style_for_topic(topic: str) -> str:
56
71
  topic: Full topic name (e.g. ``"agent.critical"``).
57
72
 
58
73
  Returns:
59
- Rich style string for the topic, or ``"dim"`` if unrecognised.
74
+ Rich style string for the topic. Exact matches win; otherwise the
75
+ topic's ``<service>.<severity>`` suffix is used (e.g. ``skmemory.error``
76
+ → the ``error`` style). Falls back to ``"dim"`` if unrecognised.
60
77
  """
61
- return _TOPIC_STYLE.get(topic, "dim")
78
+ exact = _TOPIC_STYLE.get(topic)
79
+ if exact:
80
+ return exact
81
+ suffix = topic.rsplit(".", 1)[-1]
82
+ return _SEVERITY_STYLE.get(suffix, "dim")
62
83
 
63
84
 
64
85
  def _format_payload(payload: dict) -> str:
@@ -1,7 +1,7 @@
1
- """Benchmark SKComm transport throughput and latency.
1
+ """Benchmark SKComms transport throughput and latency.
2
2
 
3
3
  Sends N messages of a configurable size through each available
4
- SKComm transport. Reports p50/p95/p99 latency, throughput (msg/s),
4
+ SKComms transport. Reports p50/p95/p99 latency, throughput (msg/s),
5
5
  and error rate.
6
6
 
7
7
  The file transport is benchmarked via a local temp-dir loopback
@@ -25,14 +25,14 @@ from rich.table import Table
25
25
 
26
26
  from ._common import console
27
27
 
28
- # Mirrors skcomm.core.BUILTIN_TRANSPORTS — kept local to avoid hard dep
28
+ # Mirrors skcomms.core.BUILTIN_TRANSPORTS — kept local to avoid hard dep
29
29
  _BUILTIN_TRANSPORTS: dict[str, str] = {
30
- "file": "skcomm.transports.file",
31
- "syncthing": "skcomm.transports.syncthing",
32
- "nostr": "skcomm.transports.nostr",
33
- "websocket": "skcomm.transports.websocket",
34
- "tailscale": "skcomm.transports.tailscale",
35
- "webrtc": "skcomm.transports.webrtc",
30
+ "file": "skcomms.transports.file",
31
+ "syncthing": "skcomms.transports.syncthing",
32
+ "nostr": "skcomms.transports.nostr",
33
+ "websocket": "skcomms.transports.websocket",
34
+ "tailscale": "skcomms.transports.tailscale",
35
+ "webrtc": "skcomms.transports.webrtc",
36
36
  }
37
37
 
38
38
 
@@ -70,9 +70,9 @@ def _bench_file_loopback(count: int, size: int) -> dict:
70
70
  Result dict with status, mode, latency percentiles, throughput,
71
71
  and error counts.
72
72
  """
73
- tmp = tempfile.mkdtemp(prefix="skcomm_bench_")
73
+ tmp = tempfile.mkdtemp(prefix="skcomms_bench_")
74
74
  try:
75
- mod = importlib.import_module("skcomm.transports.file")
75
+ mod = importlib.import_module("skcomms.transports.file")
76
76
  factory = getattr(mod, "create_transport", None)
77
77
  if factory is None:
78
78
  return {"status": "error", "error": "no create_transport() in file transport"}
@@ -108,7 +108,7 @@ def _bench_file_loopback(count: int, size: int) -> dict:
108
108
  }
109
109
 
110
110
  except ImportError:
111
- return {"status": "unavailable", "error": "skcomm not installed"}
111
+ return {"status": "unavailable", "error": "skcomms not installed"}
112
112
  except Exception as exc:
113
113
  return {"status": "error", "error": str(exc)[:120]}
114
114
  finally:
@@ -247,7 +247,7 @@ def run_bench(
247
247
  def _render_table(results: list[dict], count: int, size: int, health_count: int) -> None:
248
248
  """Render benchmark results as a Rich table with a fastest-transport summary."""
249
249
  table = Table(
250
- title=f"SKComm Transport Benchmark [{count} msgs × {size}B | health×{health_count}]",
250
+ title=f"SKComms Transport Benchmark [{count} msgs × {size}B | health×{health_count}]",
251
251
  show_header=True,
252
252
  header_style="bold magenta",
253
253
  )
@@ -333,7 +333,7 @@ def register_bench_commands(main: click.Group) -> None:
333
333
  transports: tuple,
334
334
  json_out: bool,
335
335
  ) -> None:
336
- """Benchmark SKComm transport throughput and latency.
336
+ """Benchmark SKComms transport throughput and latency.
337
337
 
338
338
  Sends COUNT messages of SIZE bytes through each available transport
339
339
  and reports p50/p95/p99 latency, throughput (msg/s), and error rate.
@@ -357,7 +357,7 @@ def register_bench_commands(main: click.Group) -> None:
357
357
  if not json_out:
358
358
  scope = ", ".join(selected) if selected else "all transports"
359
359
  console.print(
360
- f"[bold]SKComm Transport Benchmark[/] "
360
+ f"[bold]SKComms Transport Benchmark[/] "
361
361
  f"scope={scope} count={count} size={size}B "
362
362
  f"health-count={health_count}"
363
363
  )
@@ -13,12 +13,15 @@ skcapstone chat summary <peer> LLM-powered conversation summary
13
13
  from __future__ import annotations
14
14
 
15
15
  import json
16
+ import logging
16
17
  import sys
17
18
  from pathlib import Path
18
19
  from typing import Optional
19
20
 
20
21
  import click
21
22
 
23
+ logger = logging.getLogger(__name__)
24
+
22
25
  from ._common import AGENT_HOME, console, get_runtime
23
26
  from ._validators import validate_agent_name
24
27
 
@@ -85,8 +88,8 @@ def _run_llm_chat(peer: str, home_path: Path, identity: str) -> None:
85
88
  content = msg.get("content", "")[:100]
86
89
  console.print(f" {label}: {content}")
87
90
  console.print()
88
- except Exception:
89
- pass
91
+ except Exception as exc:
92
+ logger.warning("Failed to load previous conversation history with %s: %s", peer, exc)
90
93
 
91
94
  console.print(f"[bold]Chat with [cyan]{peer}[/][/] [dim]Ctrl+C or /quit to exit[/]\n")
92
95
 
@@ -194,7 +197,7 @@ def register_chat_commands(main: click.Group) -> None:
194
197
  def chat_send(peer: str, message: str, home: str, thread: Optional[str], encrypt: bool):
195
198
  """Send a message to a peer agent.
196
199
 
197
- Stores locally and delivers via SKComm if transports
200
+ Stores locally and delivers via SKComms if transports
198
201
  are configured.
199
202
 
200
203
  \b
@@ -248,7 +251,7 @@ def register_chat_commands(main: click.Group) -> None:
248
251
  """Show recent messages.
249
252
 
250
253
  Displays messages from local history. Use --poll to check
251
- SKComm transports for new messages first. Use --decrypt to
254
+ SKComms transports for new messages first. Use --decrypt to
252
255
  automatically decrypt AES-256-GCM encrypted messages.
253
256
 
254
257
  \b
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import logging
6
7
  import sys
7
8
  from pathlib import Path
8
9
 
@@ -10,6 +11,8 @@ import click
10
11
 
11
12
  from ._common import AGENT_HOME, console
12
13
 
14
+ logger = logging.getLogger(__name__)
15
+
13
16
 
14
17
  def register_consciousness_commands(main: click.Group) -> None:
15
18
  """Register the consciousness command group."""
@@ -233,8 +236,8 @@ def register_consciousness_commands(main: click.Group) -> None:
233
236
  try:
234
237
  file_data = json.loads(daily.read_text(encoding="utf-8"))
235
238
  quality = file_data.get("quality_avg", {})
236
- except Exception:
237
- pass
239
+ except Exception as exc:
240
+ logger.warning("Failed to read daily quality metrics from %s: %s", daily, exc)
238
241
 
239
242
  if not quality or quality.get("count", 0) == 0:
240
243
  if json_out:
@@ -6,7 +6,8 @@ from pathlib import Path
6
6
 
7
7
  import click
8
8
 
9
- from ._common import AGENT_HOME, console
9
+ from ._common import AGENT_HOME, SKCAPSTONE_AGENT, console, resolve_agent_home
10
+ from ._validators import validate_file_path
10
11
 
11
12
 
12
13
  def register_context_commands(main: click.Group) -> None:
@@ -22,7 +23,11 @@ def register_context_commands(main: click.Group) -> None:
22
23
  """
23
24
 
24
25
  @context.command("show")
25
- @click.option("--home", default=AGENT_HOME, type=click.Path())
26
+ @click.option(
27
+ "--home",
28
+ default=str(resolve_agent_home(SKCAPSTONE_AGENT)),
29
+ type=click.Path(),
30
+ )
26
31
  @click.option(
27
32
  "--format",
28
33
  "fmt",
@@ -55,7 +60,11 @@ def register_context_commands(main: click.Group) -> None:
55
60
  click.echo(FORMATTERS[fmt](ctx))
56
61
 
57
62
  @context.command("generate")
58
- @click.option("--home", default=AGENT_HOME, type=click.Path())
63
+ @click.option(
64
+ "--home",
65
+ default=str(resolve_agent_home(SKCAPSTONE_AGENT)),
66
+ type=click.Path(),
67
+ )
59
68
  @click.option("--memories", "-n", default=10, help="Max recent memories to include.")
60
69
  @click.option(
61
70
  "--target",
@@ -95,7 +104,11 @@ def register_context_commands(main: click.Group) -> None:
95
104
  console.print()
96
105
 
97
106
  @main.command("refresh-context")
98
- @click.option("--home", default=AGENT_HOME, type=click.Path())
107
+ @click.option(
108
+ "--home",
109
+ default=str(resolve_agent_home(SKCAPSTONE_AGENT)),
110
+ type=click.Path(),
111
+ )
99
112
  @click.option("--memories", "-n", default=10, help="Max recent memories to embed.")
100
113
  @click.option(
101
114
  "--dest",
@@ -122,6 +135,7 @@ def register_context_commands(main: click.Group) -> None:
122
135
  home_path = Path(home).expanduser()
123
136
 
124
137
  if dest:
138
+ validate_file_path(dest)
125
139
  target = Path(dest).expanduser().resolve()
126
140
  if target.is_dir():
127
141
  target = target / "CLAUDE.md"
@@ -140,7 +140,8 @@ def register_daemon_commands(main: click.Group) -> None:
140
140
  effective_port = _resolve_agent_port(agent, port)
141
141
 
142
142
  if agent:
143
- # Propagate identity to child imports that read SKCAPSTONE_AGENT.
143
+ # Propagate identity to child imports that read SKAGENT.
144
+ os.environ["SKAGENT"] = agent
144
145
  os.environ["SKCAPSTONE_AGENT"] = agent
145
146
 
146
147
  if not home_path.exists():
@@ -314,22 +315,25 @@ def register_daemon_commands(main: click.Group) -> None:
314
315
  console.print()
315
316
 
316
317
  elif platform.system() == "Linux":
317
- from ..systemd import install_service, systemd_available
318
+ from ..systemd import install_service, systemd_available, SERVICE_NAME
318
319
 
319
320
  if not systemd_available():
320
321
  console.print("[red]systemd user session not available.[/]")
321
322
  console.print("[dim]This command requires a Linux system with systemd.[/]")
322
323
  raise SystemExit(1)
323
324
 
324
- console.print("\n[cyan]Installing skcapstone systemd service...[/]")
325
- result = install_service(start=start)
325
+ console.print(f"\n[cyan]Installing skcapstone systemd service for agent '{effective_agent}'...[/]")
326
+ result = install_service(agent_name=effective_agent, start=start)
327
+ svc_name = result.get("service_name", SERVICE_NAME)
326
328
 
327
329
  if result["installed"]:
328
- console.print("[green] Unit files installed.[/]")
330
+ console.print(f"[green] Unit files installed ({svc_name}).[/]")
329
331
  if result["enabled"]:
330
- console.print("[green] Service enabled at login.[/]")
332
+ console.print(f"[green] Service enabled at login.[/]")
331
333
  if result.get("started"):
332
- console.print("[green] Service started.[/]")
334
+ console.print(f"[green] Service started.[/]")
335
+ else:
336
+ console.print(f"[dim] Start: systemctl --user start {svc_name}[/]")
333
337
  console.print()
334
338
 
335
339
  if not result["installed"]:
@@ -108,10 +108,35 @@ def register_gtd_commands(main: click.Group) -> None:
108
108
  console.print()
109
109
 
110
110
  @gtd.command("status")
111
- def gtd_status():
111
+ @click.option("--brief", is_flag=True,
112
+ help="One-line summary (for hooks / session start).")
113
+ def gtd_status(brief: bool):
112
114
  """Summary of all GTD lists."""
113
115
  from ..mcp_tools.gtd_tools import _load_list, _GTD_LISTS
114
116
 
117
+ if brief:
118
+ from datetime import datetime, timezone
119
+
120
+ counts = {name: len(_load_list(name)) for name in _GTD_LISTS}
121
+ now = datetime.now(timezone.utc)
122
+ stale = 0
123
+ for p in _load_list("projects"):
124
+ ts = p.get("moved_at") or p.get("created_at")
125
+ try:
126
+ if ts and (now - datetime.fromisoformat(ts)).days >= 7:
127
+ stale += 1
128
+ except (ValueError, TypeError):
129
+ pass
130
+ stale_str = f" ({stale} stale)" if stale else ""
131
+ click.echo(
132
+ f"GTD: {counts.get('inbox', 0)} inbox · "
133
+ f"{counts.get('next-actions', 0)} next · "
134
+ f"{counts.get('projects', 0)} projects{stale_str} · "
135
+ f"{counts.get('waiting-for', 0)} waiting · "
136
+ f"{counts.get('someday-maybe', 0)} someday"
137
+ )
138
+ return
139
+
115
140
  console.print()
116
141
  total = 0
117
142
  rows = []
@@ -14,9 +14,9 @@ def register_housekeeping_commands(main: click.Group) -> None:
14
14
 
15
15
  @main.command("housekeeping")
16
16
  @click.option("--home", default=AGENT_HOME, type=click.Path(), help="Agent home directory.")
17
- @click.option("--skcomm-home", default="~/.skcomm", type=click.Path(), help="SKComm home directory.")
17
+ @click.option("--skcomms-home", default="~/.skcomms", type=click.Path(), help="SKComms home directory.")
18
18
  @click.option("--dry-run", is_flag=True, help="Report what would be deleted without deleting.")
19
- def housekeeping(home: str, skcomm_home: str, dry_run: bool):
19
+ def housekeeping(home: str, skcomms_home: str, dry_run: bool):
20
20
  """Prune stale ACKs, delivered envelopes, and old seeds.
21
21
 
22
22
  Reclaims disk space from files that accumulate in the agent
@@ -33,7 +33,7 @@ def register_housekeeping_commands(main: click.Group) -> None:
33
33
 
34
34
  results = run_housekeeping(
35
35
  skcapstone_home=Path(home).expanduser(),
36
- skcomm_home=Path(skcomm_home).expanduser(),
36
+ skcomms_home=Path(skcomms_home).expanduser(),
37
37
  dry_run=dry_run,
38
38
  )
39
39