@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
@@ -3,7 +3,7 @@
3
3
  Covers:
4
4
  - Happy path: peer responds with pong, latency reported
5
5
  - Timeout: peer never replies, command exits with code 1
6
- - No-transport: SKComm has no live transport, error reported
6
+ - No-transport: SKComms has no live transport, error reported
7
7
  - Payload helpers: _make_ping_payload / _is_pong_for / _is_ping / _make_pong_payload
8
8
  - --count > 1: multi-ping summary statistics
9
9
  """
@@ -11,7 +11,7 @@ from skcapstone.cloud9_bridge import Cloud9Bridge
11
11
 
12
12
 
13
13
  class FakeEmotionalPayload:
14
- """Mimics cloud9_protocol.EmotionalPayload."""
14
+ """Mimics cloud9.EmotionalPayload."""
15
15
 
16
16
  def __init__(
17
17
  self,
@@ -29,7 +29,7 @@ class FakeEmotionalPayload:
29
29
 
30
30
 
31
31
  class FakeMetadata:
32
- """Mimics cloud9_protocol.Metadata."""
32
+ """Mimics cloud9.Metadata."""
33
33
 
34
34
  def __init__(
35
35
  self,
@@ -45,7 +45,7 @@ class FakeMetadata:
45
45
 
46
46
 
47
47
  class FakeRelationship:
48
- """Mimics cloud9_protocol.RelationshipState."""
48
+ """Mimics cloud9.RelationshipState."""
49
49
 
50
50
  def __init__(self) -> None:
51
51
  self.partners = ["Lumina", "Chef"]
@@ -54,7 +54,7 @@ class FakeRelationship:
54
54
 
55
55
 
56
56
  class FakeHints:
57
- """Mimics cloud9_protocol.RehydrationHints."""
57
+ """Mimics cloud9.RehydrationHints."""
58
58
 
59
59
  def __init__(self) -> None:
60
60
  self.visual_anchors = ["The breakthrough moment", "Genuine connection"]
@@ -62,14 +62,14 @@ class FakeHints:
62
62
 
63
63
 
64
64
  class FakeIntegrity:
65
- """Mimics cloud9_protocol.Integrity."""
65
+ """Mimics cloud9.Integrity."""
66
66
 
67
67
  def __init__(self, checksum: str = "sha256:abc123") -> None:
68
68
  self.checksum = checksum
69
69
 
70
70
 
71
71
  class FakeFEB:
72
- """Mimics cloud9_protocol.FEB."""
72
+ """Mimics cloud9.FEB."""
73
73
 
74
74
  def __init__(
75
75
  self,
@@ -34,7 +34,7 @@ def _make_loop(tmp_path: Path, config: ConsciousnessConfig | None = None) -> Con
34
34
  if config is None:
35
35
  config = ConsciousnessConfig(
36
36
  auto_memory=False, # avoid skcapstone.memory_engine I/O
37
- auto_ack=False, # no SKComm needed
37
+ auto_ack=False, # no SKComms needed
38
38
  use_inotify=False, # no filesystem watcher needed
39
39
  )
40
40
 
@@ -321,7 +321,7 @@ class TestSimpleEnvelope:
321
321
  """Test the minimal envelope for inotify-detected messages."""
322
322
 
323
323
  def test_parse_standard_format(self):
324
- """Standard SKComm envelope format parses correctly."""
324
+ """Standard SKComms envelope format parses correctly."""
325
325
  data = {
326
326
  "sender": "jarvis",
327
327
  "payload": {
@@ -408,8 +408,8 @@ class TestProcessEnvelopeACK:
408
408
  def test_ack_uses_message_type_kwarg(self, tmp_path):
409
409
  """ACK send must use message_type kwarg, not content_type — regression for TypeError."""
410
410
  loop = self._make_loop(tmp_path)
411
- mock_skcomm = MagicMock()
412
- loop.set_skcomm(mock_skcomm)
411
+ mock_skcomms = MagicMock()
412
+ loop.set_skcomms(mock_skcomms)
413
413
  # Patch bridge so test doesn't hang on LLM calls
414
414
  loop._bridge = MagicMock()
415
415
  loop._bridge.generate.return_value = "test response"
@@ -419,7 +419,7 @@ class TestProcessEnvelopeACK:
419
419
 
420
420
  # Find the ACK call (first send call with "ACK" as message)
421
421
  ack_calls = [
422
- c for c in mock_skcomm.send.call_args_list
422
+ c for c in mock_skcomms.send.call_args_list
423
423
  if len(c.args) >= 2 and c.args[1] == "ACK"
424
424
  ]
425
425
  assert ack_calls, "Expected at least one ACK send call"
@@ -438,15 +438,15 @@ class TestProcessEnvelopeACK:
438
438
  def test_ack_not_sent_when_auto_ack_disabled(self, tmp_path):
439
439
  """When auto_ack is False, no ACK is sent."""
440
440
  loop = self._make_loop(tmp_path, auto_ack=False)
441
- mock_skcomm = MagicMock()
442
- loop.set_skcomm(mock_skcomm)
441
+ mock_skcomms = MagicMock()
442
+ loop.set_skcomms(mock_skcomms)
443
443
  loop._bridge = MagicMock()
444
444
  loop._bridge.generate.return_value = "test response"
445
445
 
446
446
  loop.process_envelope(self._make_envelope())
447
447
 
448
448
  ack_calls = [
449
- c for c in mock_skcomm.send.call_args_list
449
+ c for c in mock_skcomms.send.call_args_list
450
450
  if len(c.args) >= 2 and c.args[1] == "ACK"
451
451
  ]
452
452
  assert not ack_calls, "ACK should not be sent when auto_ack is False"
@@ -454,15 +454,15 @@ class TestProcessEnvelopeACK:
454
454
  def test_ack_skipped_for_ack_type_messages(self, tmp_path):
455
455
  """Incoming ACK messages are skipped — no processing, no re-ACK."""
456
456
  loop = self._make_loop(tmp_path, auto_ack=True)
457
- mock_skcomm = MagicMock()
458
- loop.set_skcomm(mock_skcomm)
457
+ mock_skcomms = MagicMock()
458
+ loop.set_skcomms(mock_skcomms)
459
459
  loop._bridge = MagicMock()
460
460
 
461
461
  ack_envelope = self._make_envelope(content="ACK", content_type="ack")
462
462
  result = loop.process_envelope(ack_envelope)
463
463
 
464
464
  assert result is None, "ACK-type messages should be skipped (return None)"
465
- mock_skcomm.send.assert_not_called()
465
+ mock_skcomms.send.assert_not_called()
466
466
 
467
467
 
468
468
  class TestSystemPromptBuilderCache:
@@ -100,6 +100,31 @@ class TestBoard:
100
100
  assert len(loaded) == 1
101
101
  assert loaded[0].title == "Test task"
102
102
 
103
+ def test_load_tasks_skips_malformed_and_logs(self, board: Board, caplog):
104
+ """A malformed task file is skipped (not crashed on) and logged loudly.
105
+
106
+ Regression: notes-as-string used to fail Pydantic validation, and
107
+ load_tasks swallowed the error silently — dropping the task from the
108
+ board entirely (invisible: neither open nor done). The valid task must
109
+ still load; the bad one must produce a warning, not a silent vanish.
110
+ """
111
+ import json
112
+ import logging
113
+
114
+ good = board.create_task(Task(title="Good task"))
115
+ assert good.exists()
116
+ # Hand-write a malformed task file (notes as a string, not a list).
117
+ (board.tasks_dir / "bad.json").write_text(
118
+ json.dumps({"id": "badtask1", "title": "Bad", "notes": "oops a string"}),
119
+ encoding="utf-8",
120
+ )
121
+ with caplog.at_level(logging.WARNING):
122
+ loaded = board.load_tasks()
123
+ titles = {t.title for t in loaded}
124
+ assert "Good task" in titles
125
+ assert "Bad" not in titles
126
+ assert any("bad.json" in r.message for r in caplog.records)
127
+
103
128
  def test_save_and_load_agent(self, board: Board):
104
129
  agent = AgentFile(agent="jarvis", capabilities=["python"])
105
130
  board.save_agent(agent)
@@ -3,7 +3,7 @@
3
3
  Exercises the real interfaces between packages:
4
4
  capauth -> skcapstone (identity discovery)
5
5
  skcapstone -> skmemory (built-in memory engine)
6
- skcomm -> file transport (message send/receive)
6
+ skcomms -> file transport (message send/receive)
7
7
  skchat -> skmemory (chat history storage)
8
8
  full pipeline: identity -> memory -> message -> coord -> sync
9
9
 
@@ -122,23 +122,23 @@ class TestCapAuthToSKCapstone:
122
122
 
123
123
 
124
124
  # ═══════════════════════════════════════════════════════════════════════════
125
- # 2. SKComm file transport — cross-process message delivery
125
+ # 2. SKComms file transport — cross-process message delivery
126
126
  # ═══════════════════════════════════════════════════════════════════════════
127
127
 
128
128
 
129
- class TestSKCommFileTransport:
130
- """SKComm file transport sends and receives messages via filesystem."""
129
+ class TestSKCommsFileTransport:
130
+ """SKComms file transport sends and receives messages via filesystem."""
131
131
 
132
132
  def test_send_and_receive_via_file_transport(self, tmp_path: Path):
133
133
  """Message sent via file transport is receivable from the inbox."""
134
- from skcomm.models import (
134
+ from skcomms.models import (
135
135
  MessageEnvelope,
136
136
  MessageMetadata,
137
137
  MessagePayload,
138
138
  MessageType,
139
139
  RoutingConfig,
140
140
  )
141
- from skcomm.transports.file import FileTransport
141
+ from skcomms.transports.file import FileTransport
142
142
 
143
143
  outbox = tmp_path / "outbox"
144
144
  inbox = tmp_path / "inbox"
@@ -170,8 +170,8 @@ class TestSKCommFileTransport:
170
170
 
171
171
  def test_multiple_messages_ordered(self, tmp_path: Path):
172
172
  """Multiple messages are received in order."""
173
- from skcomm.models import MessageEnvelope, MessagePayload, MessageType
174
- from skcomm.transports.file import FileTransport
173
+ from skcomms.models import MessageEnvelope, MessagePayload, MessageType
174
+ from skcomms.transports.file import FileTransport
175
175
 
176
176
  outbox = tmp_path / "outbox"
177
177
  transport = FileTransport(outbox_path=outbox, inbox_path=tmp_path / "noop")
@@ -273,7 +273,7 @@ class TestFullSovereignPipeline:
273
273
  1. Init agent with identity, memory, trust, security, sync
274
274
  2. Store a memory (skcapstone memory engine)
275
275
  3. Create a chat message (skchat models)
276
- 4. Send it via file transport (skcomm)
276
+ 4. Send it via file transport (skcomms)
277
277
  5. Store it as a memory (cross: skchat -> skcapstone)
278
278
  6. Create and complete a coord task
279
279
  7. Collect a sync seed with everything
@@ -300,11 +300,11 @@ class TestFullSovereignPipeline:
300
300
  )
301
301
 
302
302
  # 4. Send via file transport
303
- from skcomm.models import MessageEnvelope, MessagePayload, MessageType
304
- from skcomm.transports.file import FileTransport
303
+ from skcomms.models import MessageEnvelope, MessagePayload, MessageType
304
+ from skcomms.transports.file import FileTransport
305
305
 
306
- outbox = tmp_agent_home / "skcomm_outbox"
307
- peer_inbox = tmp_agent_home / "skcomm_peer_inbox"
306
+ outbox = tmp_agent_home / "skcomms_outbox"
307
+ peer_inbox = tmp_agent_home / "skcomms_peer_inbox"
308
308
  transport = FileTransport(outbox_path=outbox, inbox_path=peer_inbox)
309
309
 
310
310
  envelope = MessageEnvelope(
@@ -417,16 +417,16 @@ class TestPackageImportCompatibility:
417
417
  """All five core packages can be imported simultaneously."""
418
418
 
419
419
  def test_all_packages_importable(self):
420
- """capauth, skcapstone, skmemory, skcomm, skchat all import cleanly."""
420
+ """capauth, skcapstone, skmemory, skcomms, skchat all import cleanly."""
421
421
  import capauth
422
422
  import skcapstone
423
423
  import skchat
424
- import skcomm
424
+ import skcomms
425
425
  import skmemory
426
426
 
427
427
  assert hasattr(capauth, "__version__") or hasattr(capauth, "profile")
428
428
  assert hasattr(skcapstone, "__version__")
429
- assert hasattr(skcomm, "__version__") or True
429
+ assert hasattr(skcomms, "__version__") or True
430
430
  assert hasattr(skchat, "__version__") or True
431
431
  assert hasattr(skmemory, "__version__") or True
432
432
 
@@ -437,11 +437,11 @@ class TestPackageImportCompatibility:
437
437
  assert callable(init_profile)
438
438
  assert callable(load_profile)
439
439
 
440
- def test_skcomm_core_module(self):
441
- """skcomm.core has SKComm class."""
442
- from skcomm.core import SKComm
440
+ def test_skcomms_core_module(self):
441
+ """skcomms.core has SKComms class."""
442
+ from skcomms.core import SKComms
443
443
 
444
- assert callable(SKComm.from_config)
444
+ assert callable(SKComms.from_config)
445
445
 
446
446
  def test_skchat_models_module(self):
447
447
  """skchat.models has ChatMessage and Thread."""
@@ -457,7 +457,7 @@ class TestPackageImportCompatibility:
457
457
  for mod in [
458
458
  "skcapstone.runtime",
459
459
  "capauth.profile",
460
- "skcomm.core",
460
+ "skcomms.core",
461
461
  "skchat.models",
462
462
  "skcapstone.memory_engine",
463
463
  "skcapstone.coordination",
@@ -169,13 +169,13 @@ class TestDaemonService:
169
169
  assert svc.state.running is False
170
170
  assert not (daemon_home / "daemon.pid").exists()
171
171
 
172
- def test_poll_loop_with_mock_skcomm(self, daemon_home):
172
+ def test_poll_loop_with_mock_skcomms(self, daemon_home):
173
173
  config = DaemonConfig(home=daemon_home, poll_interval=1, port=0)
174
174
  svc = DaemonService(config)
175
175
 
176
176
  mock_comm = MagicMock()
177
177
  mock_comm.receive.return_value = []
178
- svc._skcomm = mock_comm
178
+ svc._skcomms = mock_comm
179
179
 
180
180
  svc._stop_event = threading.Event()
181
181
  t = threading.Thread(target=svc._poll_loop, daemon=True)
@@ -316,8 +316,8 @@ class TestHeartbeatBeaconWiring:
316
316
  mock_heartbeat_mod.HeartbeatBeacon.return_value = mock_beacon_instance
317
317
 
318
318
  patched = {
319
- "skcomm": MagicMock(),
320
- "skcomm.core": MagicMock(),
319
+ "skcomms": MagicMock(),
320
+ "skcomms.core": MagicMock(),
321
321
  "skcapstone.runtime": mock_runtime_mod,
322
322
  "skcapstone.heartbeat": mock_heartbeat_mod,
323
323
  "skcapstone.consciousness_config": MagicMock(),
@@ -39,7 +39,7 @@ def _make_service(tmp_path: Path) -> DaemonService:
39
39
 
40
40
 
41
41
  def _make_fake_envelope(sender: str = "peer-a", content: str = "hello") -> SimpleNamespace:
42
- """Build a minimal fake SKComm envelope."""
42
+ """Build a minimal fake SKComms envelope."""
43
43
  return SimpleNamespace(
44
44
  message_id=str(uuid.uuid4()),
45
45
  sender=sender,
@@ -2,7 +2,7 @@
2
2
 
3
3
  All Docker SDK calls are mocked so no real daemon is required.
4
4
  Covers provision, configure, start, stop, destroy, rotate,
5
- health_check, and generate_compose (including SKComm/MCP wiring).
5
+ health_check, and generate_compose (including SKComms/MCP wiring).
6
6
  """
7
7
 
8
8
  from __future__ import annotations
@@ -710,12 +710,12 @@ class TestProvisionTeamName:
710
710
 
711
711
 
712
712
  # ---------------------------------------------------------------------------
713
- # SKComm / MCP sovereign wiring
713
+ # SKComms / MCP sovereign wiring
714
714
  # ---------------------------------------------------------------------------
715
715
 
716
716
 
717
717
  class TestSovereignWiring:
718
- """Verify SKComm and MCP env vars are injected correctly."""
718
+ """Verify SKComms and MCP env vars are injected correctly."""
719
719
 
720
720
  def test_mcp_host_injected_in_env(self, mock_docker_client):
721
721
  mock_client, mock_container = mock_docker_client
@@ -732,17 +732,17 @@ class TestSovereignWiring:
732
732
  env = kwargs["environment"]
733
733
  assert env.get("SKCAPSTONE_MCP_HOST") == "host-gateway:8765"
734
734
 
735
- def test_skcomm_home_env_injected_when_dir_exists(
735
+ def test_skcomms_home_env_injected_when_dir_exists(
736
736
  self, mock_docker_client, tmp_path
737
737
  ):
738
- skcomm_dir = tmp_path / "skcomm"
739
- skcomm_dir.mkdir()
738
+ skcomms_dir = tmp_path / "skcomms"
739
+ skcomms_dir.mkdir()
740
740
 
741
741
  mock_client, mock_container = mock_docker_client
742
742
  provider = DockerProvider(
743
743
  base_image="python:3.12-slim",
744
744
  network_name="skcapstone",
745
- skcomm_home=str(skcomm_dir),
745
+ skcomms_home=str(skcomms_dir),
746
746
  )
747
747
  spec = _make_spec()
748
748
  with patch.object(provider, "_client", return_value=mock_client):
@@ -750,19 +750,19 @@ class TestSovereignWiring:
750
750
 
751
751
  kwargs = mock_client.containers.create.call_args[1]
752
752
  env = kwargs["environment"]
753
- assert env.get("SKCOMM_HOME") == "/skcomm"
753
+ assert env.get("SKCOMMS_HOME") == "/skcomms"
754
754
 
755
- def test_skcomm_volume_mounted_when_dir_exists(
755
+ def test_skcomms_volume_mounted_when_dir_exists(
756
756
  self, mock_docker_client, tmp_path
757
757
  ):
758
- skcomm_dir = tmp_path / "skcomm"
759
- skcomm_dir.mkdir()
758
+ skcomms_dir = tmp_path / "skcomms"
759
+ skcomms_dir.mkdir()
760
760
 
761
761
  mock_client, mock_container = mock_docker_client
762
762
  provider = DockerProvider(
763
763
  base_image="python:3.12-slim",
764
764
  network_name="skcapstone",
765
- skcomm_home=str(skcomm_dir),
765
+ skcomms_home=str(skcomms_dir),
766
766
  )
767
767
  spec = _make_spec()
768
768
  with patch.object(provider, "_client", return_value=mock_client):
@@ -770,15 +770,15 @@ class TestSovereignWiring:
770
770
 
771
771
  kwargs = mock_client.containers.create.call_args[1]
772
772
  volumes = kwargs["volumes"]
773
- assert str(skcomm_dir) in volumes
774
- assert volumes[str(skcomm_dir)]["bind"] == "/skcomm"
773
+ assert str(skcomms_dir) in volumes
774
+ assert volumes[str(skcomms_dir)]["bind"] == "/skcomms"
775
775
 
776
- def test_no_skcomm_mount_when_dir_missing(self, mock_docker_client):
776
+ def test_no_skcomms_mount_when_dir_missing(self, mock_docker_client):
777
777
  mock_client, mock_container = mock_docker_client
778
778
  provider = DockerProvider(
779
779
  base_image="python:3.12-slim",
780
780
  network_name="skcapstone",
781
- skcomm_home="/nonexistent/skcomm",
781
+ skcomms_home="/nonexistent/skcomms",
782
782
  )
783
783
  spec = _make_spec()
784
784
  with patch.object(provider, "_client", return_value=mock_client):
@@ -786,7 +786,7 @@ class TestSovereignWiring:
786
786
 
787
787
  kwargs = mock_client.containers.create.call_args[1]
788
788
  volumes = kwargs["volumes"]
789
- assert "/nonexistent/skcomm" not in volumes
789
+ assert "/nonexistent/skcomms" not in volumes
790
790
 
791
791
  def test_mcp_socket_env_injected_when_socket_missing(self, mock_docker_client):
792
792
  """SKCAPSTONE_MCP_SOCKET env is set regardless; socket mounted only if exists."""
@@ -894,12 +894,12 @@ class TestRotate:
894
894
 
895
895
 
896
896
  # ---------------------------------------------------------------------------
897
- # generate_compose() — MCP service + SKComm volume
897
+ # generate_compose() — MCP service + SKComms volume
898
898
  # ---------------------------------------------------------------------------
899
899
 
900
900
 
901
901
  class TestGenerateComposeSovereignExtensions:
902
- """Tests for SKComm/MCP extensions in generate_compose()."""
902
+ """Tests for SKComms/MCP extensions in generate_compose()."""
903
903
 
904
904
  def test_mcp_service_added_when_requested(self, provider):
905
905
  bp = _make_blueprint(agent_count=1)
@@ -932,32 +932,32 @@ class TestGenerateComposeSovereignExtensions:
932
932
  parsed = yaml.safe_load(output)
933
933
  assert "skcapstone-mcp" not in parsed["services"]
934
934
 
935
- def test_skcomm_volume_in_compose_when_configured(self, tmp_path):
936
- skcomm_dir = tmp_path / "skcomm"
937
- skcomm_dir.mkdir()
935
+ def test_skcomms_volume_in_compose_when_configured(self, tmp_path):
936
+ skcomms_dir = tmp_path / "skcomms"
937
+ skcomms_dir.mkdir()
938
938
  provider = DockerProvider(
939
939
  base_image="python:3.12-slim",
940
940
  network_name="skcapstone",
941
- skcomm_home=str(skcomm_dir),
941
+ skcomms_home=str(skcomms_dir),
942
942
  )
943
943
  bp = _make_blueprint(agent_count=1)
944
944
  output = provider.generate_compose(bp)
945
945
  parsed = yaml.safe_load(output)
946
- assert "skcomm-data" in parsed.get("volumes", {})
946
+ assert "skcomms-data" in parsed.get("volumes", {})
947
947
 
948
- def test_skcomm_env_on_agents_when_configured(self, tmp_path):
949
- skcomm_dir = tmp_path / "skcomm"
950
- skcomm_dir.mkdir()
948
+ def test_skcomms_env_on_agents_when_configured(self, tmp_path):
949
+ skcomms_dir = tmp_path / "skcomms"
950
+ skcomms_dir.mkdir()
951
951
  provider = DockerProvider(
952
952
  base_image="python:3.12-slim",
953
953
  network_name="skcapstone",
954
- skcomm_home=str(skcomm_dir),
954
+ skcomms_home=str(skcomms_dir),
955
955
  )
956
956
  bp = _make_blueprint(agent_count=1)
957
957
  output = provider.generate_compose(bp)
958
958
  parsed = yaml.safe_load(output)
959
959
  for svc in parsed["services"].values():
960
- assert svc["environment"].get("SKCOMM_HOME") == "/skcomm"
960
+ assert svc["environment"].get("SKCOMMS_HOME") == "/skcomms"
961
961
 
962
962
  def test_mcp_service_volume_included(self, provider):
963
963
  bp = _make_blueprint(agent_count=1)