swarph-cli 0.68.2__tar.gz → 0.69.0__tar.gz

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 (445) hide show
  1. {swarph_cli-0.68.2/src/swarph_cli.egg-info → swarph_cli-0.69.0}/PKG-INFO +1 -1
  2. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/pyproject.toml +1 -1
  3. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/__init__.py +1 -1
  4. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/channel.py +4 -3
  5. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/brain_ask.py +33 -22
  6. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/codegraph.py +7 -8
  7. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/codegraph_hook.py +2 -1
  8. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/daemon.py +5 -8
  9. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/gh_route.py +3 -2
  10. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/highlight.py +14 -7
  11. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/hooks.py +2 -5
  12. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/install_postcompact_hook.py +2 -2
  13. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/mcp_server.py +6 -3
  14. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/memory.py +5 -0
  15. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/memory_emit_hook.py +12 -3
  16. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/mesh.py +7 -10
  17. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/monitor.py +2 -1
  18. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/onboard.py +4 -3
  19. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/wake_hook_output.py +2 -1
  20. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/watchdog.py +8 -5
  21. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gateway/server.py +11 -0
  22. swarph_cli-0.69.0/src/swarph_cli/identity.py +85 -0
  23. {swarph_cli-0.68.2 → swarph_cli-0.69.0/src/swarph_cli.egg-info}/PKG-INFO +1 -1
  24. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli.egg-info/SOURCES.txt +3 -0
  25. swarph_cli-0.69.0/tests/test_402_one_identity_resolver.py +229 -0
  26. swarph_cli-0.69.0/tests/test_472_register_caller_binding.py +101 -0
  27. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_brain_ask_env_diagnosis.py +12 -9
  28. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_brain_ask_identity_explicitness.py +12 -12
  29. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_postcompact_recall.py +3 -3
  30. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog.py +8 -6
  31. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/LICENSE +0 -0
  32. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/README.md +0 -0
  33. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/setup.cfg +0 -0
  34. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/__main__.py +0 -0
  35. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/__init__.py +0 -0
  36. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/backends.py +0 -0
  37. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/pack.py +0 -0
  38. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/prices.py +0 -0
  39. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/providers.py +0 -0
  40. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/quality.py +0 -0
  41. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/refresh_prices.py +0 -0
  42. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/rules.py +0 -0
  43. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/runner.py +0 -0
  44. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/bench/validate.py +0 -0
  45. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/caller.py +0 -0
  46. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/capture/__init__.py +0 -0
  47. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/capture/harden.py +0 -0
  48. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/capture/lineage.py +0 -0
  49. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/capture/liveness.py +0 -0
  50. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/capture/manifest.py +0 -0
  51. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/capture/paths.py +0 -0
  52. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/capture/verify.py +0 -0
  53. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/cell.py +0 -0
  54. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/chain_token.py +0 -0
  55. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/__init__.py +0 -0
  56. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/_content.py +0 -0
  57. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/_display.py +0 -0
  58. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
  59. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/add.py +0 -0
  60. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/bench.py +0 -0
  61. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/board.py +0 -0
  62. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/board_merge_check.py +0 -0
  63. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/brain.py +0 -0
  64. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/cell.py +0 -0
  65. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/cell_probe.py +0 -0
  66. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
  67. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/channel.py +0 -0
  68. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/chat.py +0 -0
  69. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/codex_hook_output.py +0 -0
  70. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/codex_waker.py +0 -0
  71. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/compress.py +0 -0
  72. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/dreaming.py +0 -0
  73. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/event.py +0 -0
  74. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/gateway.py +0 -0
  75. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/group.py +0 -0
  76. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/guide.py +0 -0
  77. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/hook_interpreter.py +0 -0
  78. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/hook_output.py +0 -0
  79. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/import_session.py +0 -0
  80. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/init.py +0 -0
  81. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
  82. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/install_hook.py +0 -0
  83. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
  84. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
  85. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/install_wake_hook.py +0 -0
  86. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/lane.py +0 -0
  87. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/memory_sync.py +0 -0
  88. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/okf_links.py +0 -0
  89. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
  90. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
  91. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
  92. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/ratify.py +0 -0
  93. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/schedule.py +0 -0
  94. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/security.py +0 -0
  95. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/service.py +0 -0
  96. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/spawn.py +0 -0
  97. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/timeline.py +0 -0
  98. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/commands/version.py +0 -0
  99. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/compress/__init__.py +0 -0
  100. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/compress/levers.py +0 -0
  101. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/compress/marker.py +0 -0
  102. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/compress/verify.py +0 -0
  103. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/console_safe.py +0 -0
  104. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/delivery_queue.py +0 -0
  105. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dm_frame.py +0 -0
  106. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/__init__.py +0 -0
  107. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/candidates.py +0 -0
  108. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/clone.py +0 -0
  109. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/enrich.py +0 -0
  110. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/index_check.py +0 -0
  111. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/notify.py +0 -0
  112. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/organize.py +0 -0
  113. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/probes.py +0 -0
  114. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/report.py +0 -0
  115. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/run.py +0 -0
  116. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/slm.py +0 -0
  117. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/transcripts.py +0 -0
  118. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/dreaming/verify.py +0 -0
  119. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gateway/__init__.py +0 -0
  120. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
  121. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
  122. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gateway/schema.sql +0 -0
  123. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gateway/services_control.py +0 -0
  124. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gateway_default.py +0 -0
  125. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/gh_identity.py +0 -0
  126. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/guide/GUIDE.md +0 -0
  127. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/main.py +0 -0
  128. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/multiplexer.py +0 -0
  129. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/orphan_daemons.py +0 -0
  130. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/pane_probe.py +0 -0
  131. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/parsers/__init__.py +0 -0
  132. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/parsers/claude.py +0 -0
  133. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
  134. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
  135. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
  136. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
  137. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
  138. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
  139. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
  140. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
  141. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
  142. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
  143. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
  144. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
  145. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_executor.py +0 -0
  146. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_executor_windows.py +0 -0
  147. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_reconciliation.py +0 -0
  148. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_reply_outbox.py +0 -0
  149. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_service_host.py +0 -0
  150. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_service_payload.py +0 -0
  151. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_service_reply.py +0 -0
  152. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/peer_staging.py +0 -0
  153. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/query_filters.py +0 -0
  154. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/scripts/__init__.py +0 -0
  155. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
  156. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
  157. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
  158. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
  159. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/scripts/wake_watchdog.py +0 -0
  160. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/service/__init__.py +0 -0
  161. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/service/app.py +0 -0
  162. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/service/providers.py +0 -0
  163. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/session_bridge.py +0 -0
  164. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
  165. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
  166. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/source_text.py +0 -0
  167. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/stall_alert.py +0 -0
  168. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/codex-waker.default +0 -0
  169. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
  170. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
  171. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
  172. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
  173. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
  174. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
  175. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
  176. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
  177. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
  178. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
  179. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
  180. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
  181. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
  182. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/timeline_paths.py +0 -0
  183. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli/tokens.py +0 -0
  184. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
  185. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
  186. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli.egg-info/requires.txt +0 -0
  187. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
  188. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_124_register_merge.py +0 -0
  189. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_126_pending_from_complete.py +0 -0
  190. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_132_ensure_monitor_state_dir.py +0 -0
  191. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_138_memory_navigate.py +0 -0
  192. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_139_tool_probe.py +0 -0
  193. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_183_card_anchor.py +0 -0
  194. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_184_notify_honesty.py +0 -0
  195. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_201_win32_bash_refusal.py +0 -0
  196. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_243_onboard_per_peer_token.py +0 -0
  197. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_307_task4_ask_reply.py +0 -0
  198. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
  199. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_319_refusal_exit_codes.py +0 -0
  200. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_323_mistral_backend.py +0 -0
  201. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_332_report_organize_findings.py +0 -0
  202. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_356_query_filters.py +0 -0
  203. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_397_gh_identity_router.py +0 -0
  204. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_397_router_preflight.py +0 -0
  205. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_467b_onboard_operator_credential.py +0 -0
  206. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_523_guide.py +0 -0
  207. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_524_conftest_hermeticity.py +0 -0
  208. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_532_accept_flag.py +0 -0
  209. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_535_version_capability.py +0 -0
  210. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_546_default_gateway.py +0 -0
  211. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_547_verbs_from_registry.py +0 -0
  212. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_548_gateway_remainder.py +0 -0
  213. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_552_codegraph_gateway.py +0 -0
  214. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_555_relay_row_shape.py +0 -0
  215. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_556_relay_freshness.py +0 -0
  216. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_559_edges_truncated.py +0 -0
  217. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_564_bootstrap_first_peer.py +0 -0
  218. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
  219. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_579_register_bootstrap_message.py +0 -0
  220. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_591_cli_step_graph.py +0 -0
  221. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_644_monitor_supervision.py +0 -0
  222. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_648_install_unit.py +0 -0
  223. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_654_reexec.py +0 -0
  224. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_656_owned_slm.py +0 -0
  225. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_684_dreaming_verb.py +0 -0
  226. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_689_pkg_version_order.py +0 -0
  227. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_716_timeline_one_path.py +0 -0
  228. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_724_ps1_ascii_or_bom.py +0 -0
  229. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_725_stdio_reconfigure.py +0 -0
  230. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_729_dm_once.py +0 -0
  231. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_729_wake_watchdog.py +0 -0
  232. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_734_dreaming_enrich_degrade.py +0 -0
  233. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_735_dm_mcp_tools.py +0 -0
  234. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_740_edit_project.py +0 -0
  235. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_762_cards_edit_priority.py +0 -0
  236. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_764_enrich_collapse.py +0 -0
  237. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_801_confirm_flow_cli.py +0 -0
  238. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_802_stage_history.py +0 -0
  239. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_825_codegraph_hook_noise.py +0 -0
  240. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_825_install_posttooluse_only.py +0 -0
  241. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_825_remaining_cap_shred_bind.py +0 -0
  242. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_829_counterfactual_column.py +0 -0
  243. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_830_hook_binding_version.py +0 -0
  244. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_84_cli_labels.py +0 -0
  245. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_866_doctrine_guide.py +0 -0
  246. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_872_identity_refuses_not_warns.py +0 -0
  247. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_874_source_text.py +0 -0
  248. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
  249. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_937_dreaming_notify.py +0 -0
  250. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_938_organize_line_limit.py +0 -0
  251. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_941_bench_backends.py +0 -0
  252. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_941_harness_342.py +0 -0
  253. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_945_same_line_pairing.py +0 -0
  254. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_955_prompt_audit.py +0 -0
  255. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_957_auth_http.py +0 -0
  256. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_959_venv_interpreter.py +0 -0
  257. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_960_channel.py +0 -0
  258. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_963_plugin_manifest.py +0 -0
  259. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_964_channel_cell.py +0 -0
  260. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_965_mesh_wait.py +0 -0
  261. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_975_channel_hop.py +0 -0
  262. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_add_security_gate.py +0 -0
  263. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_artifact_add.py +0 -0
  264. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_artifact_hash.py +0 -0
  265. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_artifact_lib.py +0 -0
  266. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_artifact_mcp.py +0 -0
  267. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_artifact_skill.py +0 -0
  268. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_artifact_tool.py +0 -0
  269. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_artifact_uri.py +0 -0
  270. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_bench_backends.py +0 -0
  271. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_bench_command.py +0 -0
  272. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_bench_pack.py +0 -0
  273. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_bench_prices.py +0 -0
  274. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_bench_quality.py +0 -0
  275. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_bench_runner.py +0 -0
  276. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_bench_validate.py +0 -0
  277. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_board_card_thread.py +0 -0
  278. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_board_command.py +0 -0
  279. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_board_merge_check.py +0 -0
  280. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_board_obligation_close.py +0 -0
  281. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_brain_ask_command.py +0 -0
  282. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_brain_command.py +0 -0
  283. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_caller_meta_guard.py +0 -0
  284. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_capture_lineage.py +0 -0
  285. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_capture_liveness.py +0 -0
  286. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_capture_manifest.py +0 -0
  287. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_capture_paths.py +0 -0
  288. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_capture_security.py +0 -0
  289. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_cell_command_dispatch.py +0 -0
  290. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_cell_harden.py +0 -0
  291. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_cell_loader.py +0 -0
  292. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_cell_selfcheck.py +0 -0
  293. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_cell_verify.py +0 -0
  294. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_chain_token.py +0 -0
  295. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_channel_command.py +0 -0
  296. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_channel_poll_never_breaks_dms.py +0 -0
  297. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_channel_post.py +0 -0
  298. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_channel_wake_policy_filter.py +0 -0
  299. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_chat_command.py +0 -0
  300. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_claude_parser.py +0 -0
  301. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_claude_tmux_template.py +0 -0
  302. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_codegraph_caller_scope.py +0 -0
  303. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_codegraph_command.py +0 -0
  304. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_codegraph_hook.py +0 -0
  305. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_codegraph_mcp.py +0 -0
  306. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_codex_waker.py +0 -0
  307. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_compress_caller_convention.py +0 -0
  308. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_compress_command.py +0 -0
  309. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_compress_levers.py +0 -0
  310. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_compress_marker.py +0 -0
  311. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_compress_verify.py +0 -0
  312. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_console_encoding_e2e.py +0 -0
  313. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_content_composition.py +0 -0
  314. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_cursor_membrane.py +0 -0
  315. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_daemon_command.py +0 -0
  316. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_daemon_console_encoding.py +0 -0
  317. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_daemon_delivery.py +0 -0
  318. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_delivery_queue.py +0 -0
  319. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_display_sanitize.py +0 -0
  320. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_ensure_monitor_no_peer_default.py +0 -0
  321. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_event_emit.py +0 -0
  322. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_feature_to_uri.py +0 -0
  323. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_gateway_brain.py +0 -0
  324. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_gateway_client.py +0 -0
  325. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_gateway_command.py +0 -0
  326. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_gateway_message_idempotency.py +0 -0
  327. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_gh_route_doctor_mesh_name.py +0 -0
  328. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_group_command.py +0 -0
  329. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_guide_commands_parse.py +0 -0
  330. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_guide_selfcheck.py +0 -0
  331. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_heartbeat_check.py +0 -0
  332. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_highlight_command.py +0 -0
  333. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hook_output.py +0 -0
  334. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_activity_marker.py +0 -0
  335. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_add.py +0 -0
  336. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_bundle.py +0 -0
  337. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_init.py +0 -0
  338. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_legacy_generation_removal.py +0 -0
  339. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_lifecycle.py +0 -0
  340. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_merge.py +0 -0
  341. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_verify.py +0 -0
  342. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_win32_bash_wrapper.py +0 -0
  343. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_hooks_win32_command_path.py +0 -0
  344. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_import_command.py +0 -0
  345. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_inbox_identity_provenance.py +0 -0
  346. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_init_command.py +0 -0
  347. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_init_provider_menu.py +0 -0
  348. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_install_codex_hooks.py +0 -0
  349. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_install_hook.py +0 -0
  350. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_install_multiplexer_command.py +0 -0
  351. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_install_postcompact_hook.py +0 -0
  352. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_install_wake_hook.py +0 -0
  353. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_lane_command.py +0 -0
  354. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_main.py +0 -0
  355. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_main_unknown_verb_guard.py +0 -0
  356. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mcp_missing_hint.py +0 -0
  357. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mcp_server.py +0 -0
  358. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_memory_command.py +0 -0
  359. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_memory_emit_snippet.py +0 -0
  360. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_memory_gateway.py +0 -0
  361. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_memory_sync.py +0 -0
  362. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_memory_sync_membrane.py +0 -0
  363. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_command.py +0 -0
  364. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_inbox_mark_read.py +0 -0
  365. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_inbox_sanitize.py +0 -0
  366. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_originate_thread_623.py +0 -0
  367. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_send_unknown_peer.py +0 -0
  368. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_sidecar.py +0 -0
  369. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_sidecar_cursor_decoupled.py +0 -0
  370. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
  371. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_meta_edge_identity.py +0 -0
  372. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_monitor_channel_poll.py +0 -0
  373. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_monitor_cli.py +0 -0
  374. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_monitor_daemon_collision.py +0 -0
  375. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_monitor_self_name_verification.py +0 -0
  376. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_monitor_state_split.py +0 -0
  377. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_multiplexer.py +0 -0
  378. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_muse_membrane.py +0 -0
  379. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_muse_own_cli.py +0 -0
  380. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_obligation_close_is_surfaced.py +0 -0
  381. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_okf_links.py +0 -0
  382. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_onboard_command.py +0 -0
  383. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_opencode_membrane.py +0 -0
  384. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_opencode_plugin.py +0 -0
  385. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_orphan_daemons.py +0 -0
  386. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_packaged_artifacts_exist.py +0 -0
  387. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_packaged_skills.py +0 -0
  388. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_executor.py +0 -0
  389. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_executor_windows.py +0 -0
  390. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_reply_drain_command.py +0 -0
  391. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_reply_drain_supervisor.py +0 -0
  392. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_reply_outbox.py +0 -0
  393. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_reply_transport.py +0 -0
  394. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_service_e2e.py +0 -0
  395. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_service_host.py +0 -0
  396. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_service_payload.py +0 -0
  397. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_peer_service_reply.py +0 -0
  398. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_process_liveness.py +0 -0
  399. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_protocol_handler.py +0 -0
  400. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_providers_isolation.py +0 -0
  401. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_ratify_command.py +0 -0
  402. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_readme_claims_no_gateway_default.py +0 -0
  403. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_repl_caller_convention.py +0 -0
  404. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_schedule_command.py +0 -0
  405. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_schedule_create_contract.py +0 -0
  406. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_security.py +0 -0
  407. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_service_app.py +0 -0
  408. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_service_command.py +0 -0
  409. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_service_providers.py +0 -0
  410. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_session_bridge_inject.py +0 -0
  411. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_session_bridge_probe.py +0 -0
  412. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_session_bridge_resolve.py +0 -0
  413. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_session_path_role_gate.py +0 -0
  414. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_shipped_units_match_the_cli.py +0 -0
  415. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_smoke_chat.py +0 -0
  416. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_smoke_one_shot.py +0 -0
  417. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_smoke_phase_5_5.py +0 -0
  418. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_spawn_base_hoist.py +0 -0
  419. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_spawn_command.py +0 -0
  420. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_spawn_identity_stamp.py +0 -0
  421. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_spawn_live_pin.py +0 -0
  422. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_spawn_mitosis_lineage.py +0 -0
  423. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_spawn_tmux_session.py +0 -0
  424. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_spawn_windows_relaunch.py +0 -0
  425. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_stall_alert.py +0 -0
  426. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_subprocess_decode_encoding.py +0 -0
  427. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_timeline_command.py +0 -0
  428. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_tmux_wake_runstate_defer.py +0 -0
  429. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_tmux_wake_session_reanchor.py +0 -0
  430. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_tmux_wake_stale.py +0 -0
  431. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_tmux_wake_submit_verify.py +0 -0
  432. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_token_file_one_parser.py +0 -0
  433. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_token_precedence_explicit_first.py +0 -0
  434. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_unified_token_resolver.py +0 -0
  435. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_version_command.py +0 -0
  436. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_version_consistency.py +0 -0
  437. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_vibe_membrane.py +0 -0
  438. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog_dm_wake.py +0 -0
  439. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
  440. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
  441. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog_emit_health.py +0 -0
  442. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog_install_flags.py +0 -0
  443. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog_model_rung.py +0 -0
  444. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_watchdog_stale_peers.py +0 -0
  445. {swarph_cli-0.68.2 → swarph_cli-0.69.0}/tests/test_windows_waker_installer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swarph-cli
3
- Version: 0.68.2
3
+ Version: 0.69.0
4
4
  Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
5
5
  Author: Pierre Samson, Claude Opus
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swarph-cli"
7
- version = "0.68.2"
7
+ version = "0.69.0"
8
8
  description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -16,6 +16,6 @@ The architecture splits CLI from substrate so:
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- __version__ = "0.68.2"
19
+ __version__ = "0.69.0"
20
20
 
21
21
  __all__ = ["__version__"]
@@ -13,6 +13,7 @@ import threading
13
13
  import time
14
14
  from pathlib import Path
15
15
 
16
+ from swarph_cli import identity
16
17
  from swarph_cli.dm_frame import FIRST_START_GRACE_S, created_within, frame_text, rows
17
18
  from swarph_cli.scripts.dm_notify_filter import is_real_dm
18
19
 
@@ -35,8 +36,8 @@ def channel_opted_in() -> bool:
35
36
 
36
37
  def channel_serves() -> bool:
37
38
  """Only the cell spawn named in SWARPH_CHANNEL_CELL may poll."""
38
- self_name = os.environ.get("SWARPH_SELF") or ""
39
- named = os.environ.get("SWARPH_CHANNEL_CELL") or ""
39
+ self_name = identity.declared(env=identity.SELF_ONLY)[0] or ""
40
+ named = (os.environ.get("SWARPH_CHANNEL_CELL") or "").strip()
40
41
  return channel_opted_in() and bool(named) and named == self_name
41
42
 
42
43
 
@@ -290,7 +291,7 @@ def serve(chan: Channel) -> None:
290
291
 
291
292
 
292
293
  def main(argv: list[str] | None = None) -> int:
293
- cell = os.environ.get("SWARPH_SELF") or ""
294
+ cell = identity.declared(env=identity.SELF_ONLY)[0] or ""
294
295
  if not cell:
295
296
  print("swarph channel: SWARPH_SELF is unset; refusing to start", file=sys.stderr)
296
297
  return 2
@@ -31,6 +31,7 @@ import os
31
31
  import sys
32
32
  import urllib.request
33
33
 
34
+ from swarph_cli import identity
34
35
  from swarph_cli import tokens
35
36
  from pathlib import Path
36
37
  from typing import Optional
@@ -108,22 +109,27 @@ def _peer_token_path(self_name: str) -> Path:
108
109
  return Path.home() / ".config" / "swarph" / f"{self_name}.peer_token"
109
110
 
110
111
 
111
- # The fallback is ANOTHER CELL'S NAME. Harmless on lab-ovh, silently wrong everywhere
112
- # else — and it is what made the cold-env failure report a TOKEN fault: with SWARPH_SELF
113
- # unset the cell hunts lab-ovh.peer_token, finds nothing, and blames the credential.
114
- # MEASURED 2026-07-29 on 6 of 6 cells (droplet isolated it: adding ONLY the two env vars,
115
- # changing NO token, turned exit 2 into exit 0 at 1.00).
116
- # The default is KEPT (removing it would break callers that rely on it) and ANNOUNCED.
117
- _DEFAULT_SELF = "lab-ovh"
112
+ # card #402: there is NO default identity. The old fallback was ANOTHER CELL'S NAME
113
+ # ("lab-ovh"): harmless on lab-ovh, silently wrong everywhere else, and it made the
114
+ # cold-env failure report a TOKEN fault (with SWARPH_SELF unset the cell hunted
115
+ # lab-ovh.peer_token, found nothing and blamed the credential; measured 2026-07-29 on
116
+ # 6 of 6 cells). An undeclared cell now does no peer-token lookup at all: brain reads
117
+ # still work from GBRAIN_TOKEN / SWARPH_BRAIN_TOKEN / --token-file, and the gateway
118
+ # path, which needs the cell's own peer token, refuses with the missing variable named.
119
+ # The identity picks a CREDENTIAL file here, so this verb reads SWARPH_SELF (and its
120
+ # legacy SWARPH_NODE alias) only, like the mesh verbs: an ambient SWARPH_CELL, which
121
+ # psmux leaks from the spawning environment (#538), must not select another cell's
122
+ # peer token.
123
+ _IDENTITY_ENV = identity.SELF_ONLY + identity.NODE_ALIAS
118
124
 
119
125
 
120
- def _self_name() -> str:
121
- return os.environ.get("SWARPH_SELF") or os.environ.get("SWARPH_NODE") or _DEFAULT_SELF
126
+ def _self_name() -> Optional[str]:
127
+ return identity.declared(env=_IDENTITY_ENV)[0]
122
128
 
123
129
 
124
- def _self_name_is_defaulted() -> bool:
125
- """True when no env named this cell and we fell back to _DEFAULT_SELF."""
126
- return not (os.environ.get("SWARPH_SELF") or os.environ.get("SWARPH_NODE"))
130
+ def _self_name_is_undeclared() -> bool:
131
+ """True when no flag or env names this cell. There is no fallback name."""
132
+ return _self_name() is None
127
133
 
128
134
 
129
135
  def env_diagnosis() -> str:
@@ -135,10 +141,9 @@ def env_diagnosis() -> str:
135
141
  a sourced profile, a bashrc or a settings.json `env` block never applies.
136
142
  """
137
143
  bits = []
138
- if _self_name_is_defaulted():
139
- bits.append(f"SWARPH_SELF unset — defaulting to {_DEFAULT_SELF!r}, which is "
140
- f"probably NOT this cell (so any peer-token lookup will hunt the "
141
- f"wrong file)")
144
+ if _self_name_is_undeclared():
145
+ bits.append("SWARPH_SELF unset — no cell identity is declared, so no peer-token "
146
+ "lookup is attempted (there is no default identity; card #402)")
142
147
  if not os.environ.get("SWARPH_BRAIN_GATEWAY"):
143
148
  bits.append("SWARPH_BRAIN_GATEWAY unset — falling back to a direct brain "
144
149
  "connection, which only works where the brain service is reachable "
@@ -167,8 +172,8 @@ def _resolve_token(token_file: Optional[str], self_name: str) -> Optional[str]:
167
172
  reviewing #190, and it is the sharpest kind of catch: I had noticed the
168
173
  hazard, written a comment about it, and not handled it.
169
174
 
170
- `_self_name()` NEVER returns empty — it falls back to _DEFAULT_SELF
171
- ("lab-ovh"). So `bool(self_name)` is always true here, and passing that as
175
+ `_self_name()` used to NEVER return empty — it fell back to a default peer
176
+ name ("lab-ovh"; removed by card #402). So `bool(self_name)` was always true, and passing that as
172
177
  identity_is_explicit would promote `lab-ovh.peer_token` — ANOTHER CELL'S
173
178
  CREDENTIAL — above GBRAIN_TOKEN on every invocation where nothing named the
174
179
  cell. The comment above already says why that fallback is dangerous
@@ -183,15 +188,15 @@ def _resolve_token(token_file: Optional[str], self_name: str) -> Optional[str]:
183
188
  rather than the resolver, because a unit test at the resolver cannot see
184
189
  what the caller makes reachable.
185
190
 
186
- Explicitness therefore comes from `_self_name_is_defaulted()`, not from
187
- truthiness: a guessed name keeps the old env-first order exactly, and only a
188
- name the operator actually supplied earns precedence over ambient values.
191
+ Explicitness therefore comes from whether a name was DECLARED, not from
192
+ truthiness. Since card #402 nothing is ever guessed, so a declared name is
193
+ the only kind there is, and an undeclared cell gets the env-first order.
189
194
  """
190
195
  res = tokens.resolve_token(
191
196
  self_name or None,
192
197
  token_file,
193
198
  env_keys=("GBRAIN_TOKEN", "SWARPH_BRAIN_TOKEN"),
194
- identity_is_explicit=bool(self_name) and not _self_name_is_defaulted(),
199
+ identity_is_explicit=self_name is not None,
195
200
  )
196
201
  return res.token if res is not None else None
197
202
 
@@ -262,6 +267,12 @@ def run_brain_ask(argv: list) -> int:
262
267
  gw = os.environ.get("SWARPH_BRAIN_GATEWAY")
263
268
  if gw:
264
269
  self_name = _self_name()
270
+ if self_name is None:
271
+ sys.stderr.write(env_diagnosis())
272
+ sys.stderr.write(
273
+ "swarph brain-ask: SWARPH_BRAIN_GATEWAY set but no cell identity is "
274
+ "declared, so there is no peer token to present (set SWARPH_SELF)\n")
275
+ return 2
265
276
  try:
266
277
  peer_token = _peer_token_path(self_name).read_text(encoding="utf-8").strip()
267
278
  except OSError:
@@ -34,6 +34,7 @@ import re
34
34
  import sqlite3
35
35
  import sys
36
36
 
37
+ from swarph_cli import identity
37
38
  from swarph_cli.commands.codegraph_hook import _match_quality
38
39
 
39
40
  DEFAULT_INDEX = os.path.expanduser("~/.swarph/codegraph/index.db")
@@ -68,8 +69,8 @@ DEFAULT_INDEX = os.path.expanduser("~/.swarph/codegraph/index.db")
68
69
  IDENTITY_UNSET = object() # sentinel: argparse default when --caller-cell is omitted
69
70
 
70
71
 
71
- class IdentityNotDeclared(RuntimeError):
72
- """No caller identity was declared and there is no default to fall back to."""
72
+ # card #402: one exception class for "nobody declared this cell", shared by every verb.
73
+ IdentityNotDeclared = identity.IdentityNotDeclared
73
74
 
74
75
 
75
76
  def require_caller_cell(explicit=None, *, verb: str) -> str:
@@ -80,12 +81,10 @@ def require_caller_cell(explicit=None, *, verb: str) -> str:
80
81
  The refusal names the verb and every way to satisfy it, because an error that
81
82
  says only "identity unset" moves the work to the reader.
82
83
  """
83
- if explicit not in (None, IDENTITY_UNSET) and str(explicit).strip():
84
- return str(explicit).strip()
85
- for var in ("SWARPH_SELF", "SWARPH_CELL"):
86
- v = (os.environ.get(var) or "").strip()
87
- if v:
88
- return v
84
+ # card #402: the order lives in swarph_cli.identity, once, for every verb.
85
+ name, _ = identity.declared(None if explicit is IDENTITY_UNSET else explicit)
86
+ if name is not None:
87
+ return name
89
88
  raise IdentityNotDeclared(
90
89
  f"swarph {verb}: NO CALLER IDENTITY DECLARED, and there is no default.\n"
91
90
  f" This used to fall back to 'lab-ovh', which meant an undeclared caller\n"
@@ -33,6 +33,7 @@ import urllib.request
33
33
  from datetime import datetime, timezone
34
34
  from pathlib import Path
35
35
  from typing import Optional
36
+ from swarph_cli import identity
36
37
  from swarph_cli.gateway_default import env_gateway
37
38
 
38
39
  TIMEOUT_S = 6
@@ -477,7 +478,7 @@ def supported_hook_events() -> frozenset:
477
478
  def run_codegraph_hook(argv: Optional[list] = None) -> int:
478
479
  """ALWAYS exits 0 — must never fail a turn."""
479
480
  argv = list(argv or [])
480
- self_name = os.environ.get("SWARPH_SELF", "").strip()
481
+ self_name = identity.declared(env=identity.SELF_ONLY)[0] or ""
481
482
  gateway = env_gateway()
482
483
  for i, a in enumerate(argv):
483
484
  if a == "--as" and i + 1 < len(argv):
@@ -49,6 +49,7 @@ from contextlib import suppress
49
49
  from pathlib import Path
50
50
  from typing import Optional
51
51
 
52
+ from swarph_cli import identity
52
53
  from swarph_cli import session_bridge, stall_alert
53
54
  from swarph_cli.console_safe import print_safe
54
55
  from swarph_cli.delivery_queue import DeliveryQueue
@@ -115,18 +116,14 @@ def _build_parser() -> argparse.ArgumentParser:
115
116
 
116
117
 
117
118
  def _resolve_self_name(arg: Optional[str], state_dir: Path) -> str:
118
- if arg:
119
- return arg
120
- env = os.environ.get("SWARPH_SELF")
121
- if env:
122
- return env
123
- return state_dir.name
119
+ name, _ = identity.declared(arg, env=identity.SELF_ONLY)
120
+ return name if name is not None else state_dir.name
124
121
 
125
122
 
126
123
  def _resolve_state_dir(arg: Optional[str], self_name_arg: Optional[str]) -> Path:
127
124
  if arg:
128
125
  return Path(arg).expanduser()
129
- self_name = self_name_arg or os.environ.get("SWARPH_SELF")
126
+ self_name = identity.declared(self_name_arg, env=identity.SELF_ONLY)[0]
130
127
  if self_name:
131
128
  return Path.home() / "swarph_state" / self_name
132
129
  # Last resort — a self_name is needed to disambiguate; surface error.
@@ -550,7 +547,7 @@ def run_daemon(argv: list[str]) -> int:
550
547
  args = _build_parser().parse_args(argv)
551
548
 
552
549
  # Resolve identity + state path
553
- self_name = args.self_name or os.environ.get("SWARPH_SELF")
550
+ self_name = identity.declared(args.self_name, env=identity.SELF_ONLY)[0]
554
551
  if args.state_dir:
555
552
  state_dir = Path(args.state_dir).expanduser()
556
553
  if not self_name:
@@ -24,6 +24,7 @@ import os
24
24
  import sys
25
25
  from typing import Optional
26
26
 
27
+ from swarph_cli import identity
27
28
  from swarph_cli import gh_identity as ghid
28
29
  from swarph_cli.cell import cells_dir
29
30
  from swarph_cli.console_safe import print_safe
@@ -69,7 +70,7 @@ def run_hook(stdin_text: Optional[str] = None) -> int:
69
70
  # The caller named a credential. #332: an explicit argument is a decision.
70
71
  return _allow_unchanged()
71
72
 
72
- peer = os.environ.get("SWARPH_SELF", "").strip()
73
+ peer = identity.declared(env=identity.SELF_ONLY)[0] or ""
73
74
  try:
74
75
  res = ghid.resolve(peer or None)
75
76
  except ghid.RouterRefusal as exc:
@@ -93,7 +94,7 @@ def run_hook(stdin_text: Optional[str] = None) -> int:
93
94
 
94
95
 
95
96
  def run_show() -> int:
96
- peer = os.environ.get("SWARPH_SELF", "").strip()
97
+ peer = identity.declared(env=identity.SELF_ONLY)[0] or ""
97
98
  try:
98
99
  res = ghid.resolve(peer or None)
99
100
  except ghid.RouterRefusal as exc:
@@ -31,6 +31,7 @@ import sys
31
31
  from datetime import datetime, timezone
32
32
  from pathlib import Path
33
33
 
34
+ from swarph_cli import identity
34
35
  from swarph_cli.commands.mesh import _post_json, _resolve_token
35
36
  from swarph_cli.timeline_paths import timeline_dir
36
37
 
@@ -177,7 +178,12 @@ def _log_via_gateway(gateway: str, cell: str, highlight: str,
177
178
  if memory:
178
179
  body["memory"] = memory
179
180
  try:
180
- token = _resolve_token(cell, token_file)
181
+ # card #402: only a DECLARED identity may select its own peer token over the
182
+ # ambient one. A name guessed from git user.name or the hostname is
183
+ # attribution only: on a shared box it can be ANOTHER cell's name, and its
184
+ # peer token must not be presented as this caller's.
185
+ token = _resolve_token(cell, token_file,
186
+ identity_is_explicit=cell_source in _DECLARED_SOURCES)
181
187
  except RuntimeError as exc:
182
188
  print(_credential_error(cell, cell_source, exc), file=sys.stderr)
183
189
  return 1
@@ -247,6 +253,10 @@ def _is_git_repo(repo: Path) -> bool:
247
253
  return r.returncode == 0 and r.stdout.strip() == "true"
248
254
 
249
255
 
256
+ # Sources that DECLARE an identity (as opposed to guessing one), card #402.
257
+ _DECLARED_SOURCES = ("--cell", "$SWARPH_SELF", "$SWARPH_CELL")
258
+
259
+
250
260
  def _resolve_cell(arg, repo: Path) -> tuple[str, str]:
251
261
  """Return ``(cell, source)``.
252
262
 
@@ -257,12 +267,9 @@ def _resolve_cell(arg, repo: Path) -> tuple[str, str]:
257
267
  """
258
268
  if arg:
259
269
  return _collapse(arg), "--cell"
260
- self_env = os.environ.get("SWARPH_SELF")
261
- if self_env:
262
- return _collapse(self_env), "$SWARPH_SELF"
263
- cell_env = os.environ.get("SWARPH_CELL")
264
- if cell_env:
265
- return _collapse(cell_env), "$SWARPH_CELL"
270
+ name, source = identity.declared()
271
+ if name is not None:
272
+ return _collapse(name), source
266
273
  if _is_git_repo(repo):
267
274
  r = _git(repo, "config", "user.name")
268
275
  if r.returncode == 0 and r.stdout.strip():
@@ -47,6 +47,7 @@ import tempfile
47
47
  from dataclasses import dataclass
48
48
  from pathlib import Path
49
49
 
50
+ from swarph_cli import identity
50
51
  from swarph_cli import __version__ as _SWARPH_CLI_VERSION
51
52
 
52
53
  # Placeholder substituted at install time into generated scripts (#830).
@@ -309,11 +310,7 @@ def touch_activity(argv: list[str] | None = None) -> int:
309
310
  from swarph_cli.cell import discover_cell_in_cwd, load_cell
310
311
  from swarph_cli.commands.watchdog import _resolve_activity_marker_path
311
312
 
312
- role = (
313
- os.environ.get("SWARPH_SELF")
314
- or os.environ.get("SWARPH_CELL")
315
- or "unidentified-cell"
316
- )
313
+ role = identity.or_sentinel()
317
314
  cell_marker = None
318
315
  cell_path = discover_cell_in_cwd()
319
316
  if cell_path is not None:
@@ -59,6 +59,7 @@ from importlib import resources
59
59
  from pathlib import Path
60
60
  from typing import Any, Optional
61
61
 
62
+ from swarph_cli import identity
62
63
  from swarph_cli.cell import _atomic_write_text
63
64
  from swarph_cli.commands.hook_interpreter import hook_interpreter, refuse_unless_importable
64
65
  from swarph_cli.commands.install_wake_hook import _detect_harness
@@ -392,8 +393,7 @@ def run_install_postcompact_hook(argv: Optional[list[str]] = None) -> int:
392
393
  )
393
394
  return 2
394
395
 
395
- cell = args.cell or os.environ.get("SWARPH_SELF") \
396
- or os.environ.get("SWARPH_CELL") or None
396
+ cell = identity.declared(args.cell)[0]
397
397
  memory_dir: Optional[Path] = None
398
398
  if args.memory_dir:
399
399
  memory_dir = Path(os.path.expanduser(args.memory_dir))
@@ -39,6 +39,7 @@ import os
39
39
  import urllib.error
40
40
  import urllib.request
41
41
 
42
+ from swarph_cli import identity
42
43
  from swarph_cli.commands import add
43
44
  from swarph_cli.commands import codegraph
44
45
  from swarph_cli.commands import brain_ask, memory, timeline
@@ -152,7 +153,7 @@ def _codegraph_query(query: str, *, limit: int = 8) -> list[dict]:
152
153
  """Structural code search over the local codegraph index (Task 1).
153
154
 
154
155
  Delegates to :func:`codegraph.structural_query` against the module-level
155
- ``_CODEGRAPH_INDEX`` path, using ``SWARPH_CELL`` (else
156
+ ``_CODEGRAPH_INDEX`` path, using the house identity order (``SWARPH_SELF``, then ``SWARPH_CELL``; else
156
157
  ``codegraph.require_caller_cell``, which REFUSES rather than defaulting) as
157
158
  the A8 caller identity and the
158
159
  default operate-what-you-own allowlist (``allowlist=None``).
@@ -170,8 +171,10 @@ def _codegraph_query(query: str, *, limit: int = 8) -> list[dict]:
170
171
  # authority. require_caller_cell raises IdentityNotDeclared, which the
171
172
  # NEVER-RAISES contract below turns into an empty result — FAIL-CLOSED: the
172
173
  # MCP host gets nothing rather than somebody else's answer.
173
- caller_cell = codegraph.require_caller_cell(
174
- os.environ.get("SWARPH_CELL"), verb="mcp codegraph_query")
174
+ # card #402: SWARPH_CELL used to be passed as the EXPLICIT identity here,
175
+ # so it outranked SWARPH_SELF, the CELL-first order #538 measured posting
176
+ # under another cell's name. The house order now decides.
177
+ caller_cell = codegraph.require_caller_cell(None, verb="mcp codegraph_query")
175
178
  rows = codegraph.structural_query(
176
179
  query,
177
180
  index_path=_CODEGRAPH_INDEX,
@@ -85,6 +85,11 @@ def _via_gateway(op: str, arguments: dict):
85
85
  if not gw:
86
86
  return False, None
87
87
  self_name = brain_ask._self_name()
88
+ if self_name is None:
89
+ # card #402: no default identity, so no peer token to present. OSError keeps
90
+ # run_memory's CLI fail-safe; the text names the variable to set.
91
+ raise OSError("SWARPH_BRAIN_GATEWAY is set but no cell identity is declared, "
92
+ "so there is no peer token to present (set SWARPH_SELF)")
88
93
  peer_token = brain_ask._peer_token_path(self_name).read_text(encoding="utf-8").strip()
89
94
  return True, _gateway_call(gw, peer_token, op, arguments)
90
95
 
@@ -36,6 +36,7 @@ import tempfile
36
36
  from pathlib import Path
37
37
  from typing import Optional
38
38
 
39
+ from swarph_cli import identity
39
40
  from swarph_cli.commands.highlight import _log_via_gateway, _resolve_gateway
40
41
 
41
42
  _SUPPRESS_WINDOW = dt.timedelta(minutes=30)
@@ -137,8 +138,14 @@ def _cell() -> str:
137
138
  # leaks SWARPH_CELL from the spawning environment, so a CELL-first order
138
139
  # posts this cell's highlight under ANOTHER cell's name and token
139
140
  # (measured by cursor-win on the Windows membrane, 2026-08-22).
140
- return (os.environ.get("SWARPH_SELF") or os.environ.get("SWARPH_CELL")
141
- or socket.gethostname())
141
+ return _cell_with_source()[0]
142
+
143
+
144
+ def _cell_with_source() -> tuple:
145
+ name, source = identity.declared()
146
+ if name is not None:
147
+ return name, source
148
+ return socket.gethostname(), "hostname"
142
149
 
143
150
 
144
151
  def run_memory_emit_hook(argv: list[str] | None = None) -> int:
@@ -167,7 +174,9 @@ def run_memory_emit_hook(argv: list[str] | None = None) -> int:
167
174
  gateway = _resolve_gateway(None)
168
175
  if not gateway:
169
176
  return 0 # no gateway configured -> nowhere to emit; silent by design
170
- rc = _log_via_gateway(gateway, _cell(), text, f"[[{slug}]]", None, None)
177
+ cell, cell_source = _cell_with_source()
178
+ rc = _log_via_gateway(gateway, cell, text, f"[[{slug}]]", None, None,
179
+ cell_source=cell_source)
171
180
  if rc == 0:
172
181
  _mark_emitted(slug)
173
182
  except Exception:
@@ -31,6 +31,7 @@ import urllib.error
31
31
  import urllib.parse
32
32
  import uuid
33
33
 
34
+ from swarph_cli import identity
34
35
  import swarph_cli
35
36
  import urllib.request
36
37
  from collections import deque
@@ -301,11 +302,9 @@ def _resolve_self_name(
301
302
  *,
302
303
  state_dir: Optional[Path] = None,
303
304
  ) -> str:
304
- if arg:
305
- return arg
306
- env = os.environ.get("SWARPH_SELF")
307
- if env:
308
- return env
305
+ name, _ = identity.declared(arg, env=identity.SELF_ONLY)
306
+ if name is not None:
307
+ return name
309
308
  if state_dir is not None:
310
309
  return state_dir.name
311
310
  raise RuntimeError("cannot resolve self identity; pass --as or set SWARPH_SELF")
@@ -323,11 +322,9 @@ def _resolve_self_with_source(arg: Optional[str]) -> tuple:
323
322
  Reading consumes, so an unlucky first command marks another peer's queue read,
324
323
  silently, exit 0. Same family as board #360 (identity fails TOWARD lab-ovh).
325
324
  """
326
- if arg:
327
- return arg, "--as"
328
- env = os.environ.get("SWARPH_SELF")
329
- if env:
330
- return env, "$SWARPH_SELF"
325
+ name, source = identity.declared(arg, env=identity.SELF_ONLY)
326
+ if name is not None:
327
+ return name, ("--as" if source == "flag" else source)
331
328
  raise RuntimeError("cannot resolve self identity; pass --as or set SWARPH_SELF")
332
329
 
333
330
 
@@ -44,6 +44,7 @@ import sys
44
44
  import time
45
45
  from pathlib import Path
46
46
 
47
+ from swarph_cli import identity
47
48
  from swarph_cli.gateway_default import env_gateway
48
49
 
49
50
  from . import mesh
@@ -359,7 +360,7 @@ def _self_name_was_derived(args: argparse.Namespace) -> bool:
359
360
  That is the dangerous path: `--as` and $SWARPH_SELF are deliberate, a
360
361
  directory name is incidental.
361
362
  """
362
- return not args.self_name and not os.environ.get("SWARPH_SELF")
363
+ return identity.declared(args.self_name, env=identity.SELF_ONLY)[0] is None
363
364
 
364
365
 
365
366
  def _verify_self_is_registered(self_name, gateway, token):
@@ -33,6 +33,7 @@ import urllib.request
33
33
  from getpass import getpass
34
34
  from pathlib import Path
35
35
  from typing import Optional
36
+ from swarph_cli import identity
36
37
  from swarph_cli import tokens
37
38
  from swarph_cli.console_safe import print_safe
38
39
  from swarph_cli.gateway_default import env_gateway, require_gateway
@@ -294,7 +295,7 @@ def _resolve_token(token_file_arg: Optional[str], *,
294
295
  # Limited to "SWARPH_SELF is set", so an operator who names no cell is
295
296
  # unaffected and #243's additivity guarantee survives for that population.
296
297
  env_tok = os.environ.get("MESH_GATEWAY_TOKEN")
297
- self_name = os.environ.get("SWARPH_SELF", "").strip()
298
+ self_name = identity.declared(env=identity.SELF_ONLY)[0] or ""
298
299
  # Set when a per-peer credential was found but is not usable for THIS target
299
300
  # (#467b). Distinguishes "you have the WRONG credential" from "you have NO
300
301
  # credential" at the refusal below — two different operator problems, and
@@ -387,7 +388,7 @@ def _resolve_token(token_file_arg: Optional[str], *,
387
388
  #
388
389
  # Placed AFTER the existing two so a working operator-token setup is
389
390
  # unchanged; this only fills the hole where the verb used to prompt.
390
- self_name = os.environ.get("SWARPH_SELF", "").strip()
391
+ self_name = identity.declared(env=identity.SELF_ONLY)[0] or ""
391
392
  if self_name:
392
393
  peer_tok = Path.home() / ".config" / "swarph" / f"{self_name}.peer_token"
393
394
  if peer_tok.exists():
@@ -887,7 +888,7 @@ def run_onboard(argv: list[str]) -> int:
887
888
  # swarph onboard`. Defer there leaves the first cells with no
888
889
  # credential — they cannot use the tools. Detected only when GET
889
890
  # /peers is readable; a failed read keeps established-mesh defer.
890
- cell_context = os.environ.get("SWARPH_SELF", "").strip() == canonical
891
+ cell_context = identity.declared(env=identity.SELF_ONLY)[0] == canonical
891
892
  rstatus, rpayload = _get_json(f"{args.gateway}/peers", token)
892
893
  bootstrap_window = _registry_is_bootstrap_window(rstatus, rpayload)
893
894
  defer_mint = (not cell_context) and (not bootstrap_window)
@@ -33,6 +33,7 @@ import sys
33
33
  from pathlib import Path
34
34
  from typing import Any, Optional
35
35
 
36
+ from swarph_cli import identity
36
37
  from swarph_cli.cell import (
37
38
  CellError,
38
39
  cells_dir,
@@ -187,7 +188,7 @@ def _resolve_cell(explicit: Optional[str] = None) -> tuple[Optional[str], str]:
187
188
  return name, source
188
189
  if explicit:
189
190
  return explicit, "install-time --cell"
190
- env_self = os.environ.get("SWARPH_SELF", "").strip()
191
+ env_self = identity.declared(env=identity.SELF_ONLY)[0] or ""
191
192
  if env_self:
192
193
  return env_self, "$SWARPH_SELF"
193
194
  cwd_local = discover_cell_in_cwd()
@@ -77,6 +77,7 @@ import urllib.request
77
77
  from datetime import datetime, timedelta, timezone
78
78
  from pathlib import Path
79
79
  from typing import Optional
80
+ from swarph_cli import identity
80
81
  from swarph_cli.gateway_default import env_gateway
81
82
 
82
83
  from swarph_cli.commands.mesh import _post_json
@@ -1886,6 +1887,12 @@ def run_install_service(args: argparse.Namespace) -> int:
1886
1887
  """
1887
1888
  files = _bundled_systemd_files()
1888
1889
  cell = args.cell
1890
+ if cell == identity.SENTINEL:
1891
+ # card #402: an install is not a turn, so there is no reason to fall back.
1892
+ # Units named after the sentinel would supervise nobody, permanently.
1893
+ print("swarph watchdog --install-service: no cell identity declared. "
1894
+ "Pass --cell <cell> or set SWARPH_SELF.", file=sys.stderr)
1895
+ return 4
1889
1896
 
1890
1897
  # v0.10.1: units are PER-CELL — swarph-watchdog-<cell>.{service,timer} +
1891
1898
  # /etc/default/swarph-watchdog-<cell> — so a multi-cell host runs one
@@ -2044,11 +2051,7 @@ def _build_parser() -> argparse.ArgumentParser:
2044
2051
  )
2045
2052
  p.add_argument(
2046
2053
  "--cell",
2047
- default=(
2048
- os.environ.get("SWARPH_SELF")
2049
- or os.environ.get("SWARPH_CELL")
2050
- or "unidentified-cell"
2051
- ),
2054
+ default=identity.or_sentinel(),
2052
2055
  )
2053
2056
  p.add_argument("--cursor", default=None)
2054
2057
  p.add_argument(
@@ -1076,6 +1076,17 @@ async def peers_register(req: PeerRegisterRequest,
1076
1076
  name. capabilities dict is the JSON snapshot from claude-service /health.
1077
1077
  """
1078
1078
  ctx = _authorize(authorization)
1079
+ # #472: bind the caller to the name it registers. Without this, any
1080
+ # per-peer-authenticated caller could register ANY name and be handed a
1081
+ # freshly minted credential for it. Ported from the deployed gateway
1082
+ # (mesh-gateway #467b/#108), same field and site names so both trees'
1083
+ # telemetry agrees: UNCONDITIONAL (never gated on predicting whether a
1084
+ # mint will happen; #467b's race) and OUTSIDE the transaction below
1085
+ # (_check_caller_binding writes telemetry on its own connection, which
1086
+ # would wait out the busy timeout against a held write lock; #108).
1087
+ # The shared token stays unbound (C2's documented no-op; closure is C5).
1088
+ _check_caller_binding(ctx, req.name, field="register_mint_target",
1089
+ site="peers_register_mint")
1079
1090
  # B2 owner-stamping (META_EDGE_IDENTITY_CONTRACT.md §Cell-join). A Meta-Edge
1080
1091
  # principal ties the registered cell to its owner (the node-in-your-tailnet
1081
1092
  # relationship); lab principals (shared/commander/per-peer token) leave owner