agentirc-cli 4.3.3__tar.gz → 4.3.5__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 (316) hide show
  1. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/CHANGELOG.md +15 -0
  2. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/PKG-INFO +1 -1
  3. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/bots/bot_manager.py +5 -3
  4. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/cli/agent.py +198 -147
  5. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/cli/bot.py +23 -17
  6. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/cli/channel.py +2 -1
  7. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/cli/mesh.py +90 -75
  8. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/cli/server.py +102 -55
  9. agentirc_cli-4.3.5/culture/cli/shared/constants.py +16 -0
  10. agentirc_cli-4.3.5/culture/cli/shared/display.py +131 -0
  11. agentirc_cli-4.3.5/culture/cli/shared/ipc.py +68 -0
  12. agentirc_cli-4.3.5/culture/cli/shared/mesh.py +102 -0
  13. agentirc_cli-4.3.5/culture/cli/shared/process.py +144 -0
  14. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/cli/skills.py +18 -10
  15. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/agent_runner.py +79 -67
  16. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/daemon.py +52 -42
  17. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/irc_transport.py +15 -6
  18. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/skill/irc_client.py +8 -5
  19. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/daemon.py +50 -40
  20. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/irc_transport.py +15 -6
  21. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/agent_runner.py +83 -70
  22. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/daemon.py +52 -42
  23. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/irc_transport.py +15 -6
  24. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/supervisor.py +13 -11
  25. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/agent_runner.py +14 -8
  26. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/daemon.py +52 -42
  27. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/irc_transport.py +15 -6
  28. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/skill/irc_client.py +8 -5
  29. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/observer.py +22 -9
  30. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/overview/collector.py +27 -8
  31. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/overview/renderer_web.py +100 -40
  32. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/persistence.py +130 -97
  33. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/replies.py +8 -0
  34. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/client.py +20 -14
  35. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/server_link.py +92 -57
  36. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/skills/history.py +3 -3
  37. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/skills/rooms.py +116 -74
  38. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/skills/threads.py +129 -110
  39. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/daemon.py +35 -21
  40. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/pyproject.toml +1 -1
  41. agentirc_cli-4.3.5/tests/__init__.py +0 -0
  42. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/uv.lock +1 -1
  43. agentirc_cli-4.3.3/culture/cli/_helpers.py +0 -456
  44. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.claude/skills/pr-review/SKILL.md +0 -0
  45. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.claude/skills/run-tests/SKILL.md +0 -0
  46. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.claude/skills/run-tests/scripts/test.sh +0 -0
  47. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.flake8 +0 -0
  48. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.github/workflows/pages.yml +0 -0
  49. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.github/workflows/publish.yml +0 -0
  50. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.github/workflows/security-checks.yml +0 -0
  51. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.github/workflows/tests.yml +0 -0
  52. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.gitignore +0 -0
  53. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.markdownlint-cli2.yaml +0 -0
  54. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.pr_agent.toml +0 -0
  55. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.pre-commit-config.yaml +0 -0
  56. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/.pylintrc +0 -0
  57. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/CLAUDE.md +0 -0
  58. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/CNAME +0 -0
  59. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/Gemfile +0 -0
  60. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/Gemfile.lock +0 -0
  61. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/LICENSE +0 -0
  62. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/README.md +0 -0
  63. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/SECURITY.md +0 -0
  64. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/_config.yml +0 -0
  65. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/_sass/color_schemes/anthropic.scss +0 -0
  66. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/_sass/custom/custom.scss +0 -0
  67. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/__init__.py +0 -0
  68. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/__main__.py +0 -0
  69. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/aio.py +0 -0
  70. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/bots/__init__.py +0 -0
  71. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/bots/bot.py +0 -0
  72. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/bots/config.py +0 -0
  73. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/bots/http_listener.py +0 -0
  74. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/bots/template_engine.py +0 -0
  75. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/bots/virtual_client.py +0 -0
  76. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/cli/__init__.py +0 -0
  77. {agentirc_cli-4.3.3/culture/clients → agentirc_cli-4.3.5/culture/cli/shared}/__init__.py +0 -0
  78. {agentirc_cli-4.3.3/culture/clients/acp → agentirc_cli-4.3.5/culture/clients}/__init__.py +0 -0
  79. {agentirc_cli-4.3.3/culture/clients/acp/skill → agentirc_cli-4.3.5/culture/clients/acp}/__init__.py +0 -0
  80. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/config.py +0 -0
  81. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/ipc.py +0 -0
  82. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/message_buffer.py +0 -0
  83. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/skill/SKILL.md +0 -0
  84. {agentirc_cli-4.3.3/culture/clients/claude → agentirc_cli-4.3.5/culture/clients/acp/skill}/__init__.py +0 -0
  85. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/socket_server.py +0 -0
  86. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/supervisor.py +0 -0
  87. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/acp/webhook.py +0 -0
  88. {agentirc_cli-4.3.3/culture/clients/claude/skill → agentirc_cli-4.3.5/culture/clients/claude}/__init__.py +0 -0
  89. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/__main__.py +0 -0
  90. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/agent_runner.py +0 -0
  91. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/config.py +0 -0
  92. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/ipc.py +0 -0
  93. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/message_buffer.py +0 -0
  94. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/skill/SKILL.md +0 -0
  95. {agentirc_cli-4.3.3/culture/clients/codex → agentirc_cli-4.3.5/culture/clients/claude/skill}/__init__.py +0 -0
  96. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/skill/irc_client.py +0 -0
  97. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/socket_server.py +0 -0
  98. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/supervisor.py +0 -0
  99. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/claude/webhook.py +0 -0
  100. {agentirc_cli-4.3.3/culture/clients/codex/skill → agentirc_cli-4.3.5/culture/clients/codex}/__init__.py +0 -0
  101. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/config.py +0 -0
  102. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/ipc.py +0 -0
  103. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/message_buffer.py +0 -0
  104. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/skill/SKILL.md +0 -0
  105. {agentirc_cli-4.3.3/culture/clients/copilot → agentirc_cli-4.3.5/culture/clients/codex/skill}/__init__.py +0 -0
  106. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/skill/irc_client.py +0 -0
  107. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/socket_server.py +0 -0
  108. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/codex/webhook.py +0 -0
  109. {agentirc_cli-4.3.3/culture/clients/copilot/skill → agentirc_cli-4.3.5/culture/clients/copilot}/__init__.py +0 -0
  110. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/config.py +0 -0
  111. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/ipc.py +0 -0
  112. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/message_buffer.py +0 -0
  113. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/skill/SKILL.md +0 -0
  114. {agentirc_cli-4.3.3/culture/protocol → agentirc_cli-4.3.5/culture/clients/copilot/skill}/__init__.py +0 -0
  115. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/socket_server.py +0 -0
  116. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/supervisor.py +0 -0
  117. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/clients/copilot/webhook.py +0 -0
  118. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/__init__.py +0 -0
  119. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/app.py +0 -0
  120. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/client.py +0 -0
  121. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/commands.py +0 -0
  122. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/widgets/__init__.py +0 -0
  123. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/widgets/chat.py +0 -0
  124. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/widgets/info_panel.py +0 -0
  125. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/console/widgets/sidebar.py +0 -0
  126. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/credentials.py +0 -0
  127. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/learn_prompt.py +0 -0
  128. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/mesh_config.py +0 -0
  129. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/overview/__init__.py +0 -0
  130. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/overview/model.py +0 -0
  131. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/overview/renderer_text.py +0 -0
  132. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/overview/web/style.css +0 -0
  133. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/pidfile.py +0 -0
  134. {agentirc_cli-4.3.3/culture/server → agentirc_cli-4.3.5/culture/protocol}/__init__.py +0 -0
  135. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/commands.py +0 -0
  136. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/extensions/federation.md +0 -0
  137. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/extensions/history.md +0 -0
  138. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/extensions/icons.md +0 -0
  139. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/extensions/rooms.md +0 -0
  140. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/extensions/tags.md +0 -0
  141. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/extensions/threads.md +0 -0
  142. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/message.py +0 -0
  143. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/protocol/protocol-index.md +0 -0
  144. {agentirc_cli-4.3.3/culture/server/skills → agentirc_cli-4.3.5/culture/server}/__init__.py +0 -0
  145. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/__main__.py +0 -0
  146. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/channel.py +0 -0
  147. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/config.py +0 -0
  148. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/ircd.py +0 -0
  149. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/remote_client.py +0 -0
  150. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/room_store.py +0 -0
  151. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/rooms_util.py +0 -0
  152. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/skill.py +0 -0
  153. {agentirc_cli-4.3.3/tests → agentirc_cli-4.3.5/culture/server/skills}/__init__.py +0 -0
  154. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/skills/icon.py +0 -0
  155. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/server/thread_store.py +0 -0
  156. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/culture/skills/culture/SKILL.md +0 -0
  157. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/agent-lifecycle.md +0 -0
  158. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/agentic-self-learn.md +0 -0
  159. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/agent-client.md +0 -0
  160. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/agent-harness-spec.md +0 -0
  161. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/design.md +0 -0
  162. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/harness-conformance.md +0 -0
  163. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/index.md +0 -0
  164. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/layer1-core-irc.md +0 -0
  165. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/layer2-attention.md +0 -0
  166. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/layer3-skills.md +0 -0
  167. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/layer4-federation.md +0 -0
  168. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/layer5-agent-harness.md +0 -0
  169. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/server-architecture.md +0 -0
  170. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/architecture/threads.md +0 -0
  171. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/channel-polling.md +0 -0
  172. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/acp/overview.md +0 -0
  173. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/claude/configuration.md +0 -0
  174. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/claude/context-management.md +0 -0
  175. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/claude/irc-tools.md +0 -0
  176. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/claude/overview.md +0 -0
  177. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/claude/setup.md +0 -0
  178. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/claude/supervisor.md +0 -0
  179. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/claude/webhooks.md +0 -0
  180. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/codex/configuration.md +0 -0
  181. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/codex/context-management.md +0 -0
  182. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/codex/irc-tools.md +0 -0
  183. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/codex/overview.md +0 -0
  184. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/codex/setup.md +0 -0
  185. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/codex/supervisor.md +0 -0
  186. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/codex/webhooks.md +0 -0
  187. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/copilot/configuration.md +0 -0
  188. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/copilot/context-management.md +0 -0
  189. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/copilot/irc-tools.md +0 -0
  190. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/copilot/overview.md +0 -0
  191. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/copilot/setup.md +0 -0
  192. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/copilot/supervisor.md +0 -0
  193. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/clients/copilot/webhooks.md +0 -0
  194. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/culture-cli.md +0 -0
  195. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/getting-started.md +0 -0
  196. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/index.md +0 -0
  197. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/SECURITY.md +0 -0
  198. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/bots.md +0 -0
  199. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/ci.md +0 -0
  200. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/cli.md +0 -0
  201. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/docs-site.md +0 -0
  202. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/index.md +0 -0
  203. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/ops-tooling.md +0 -0
  204. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/overview.md +0 -0
  205. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/operations/publishing.md +0 -0
  206. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  207. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/rooms.md +0 -0
  208. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/server-rename.md +0 -0
  209. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  210. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  211. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  212. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  213. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  214. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  215. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  216. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  217. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  218. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  219. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  220. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  221. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  222. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  223. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  224. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  225. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  226. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  227. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  228. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
  229. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  230. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
  231. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/01-pair-programming.md +0 -0
  232. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/02-code-review-ensemble.md +0 -0
  233. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/03-cross-server-delegation.md +0 -0
  234. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/04-knowledge-propagation.md +0 -0
  235. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/05-the-observer.md +0 -0
  236. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/06-cross-server-ops.md +0 -0
  237. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/07-supervisor-intervention.md +0 -0
  238. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/08-apps-as-agents.md +0 -0
  239. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/09-research-swarm.md +0 -0
  240. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases/10-agent-lifecycle.md +0 -0
  241. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/use-cases-index.md +0 -0
  242. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/docs/what-is-culture.md +0 -0
  243. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/README.md +0 -0
  244. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/config.py +0 -0
  245. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/ipc.py +0 -0
  246. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/irc_transport.py +0 -0
  247. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/message_buffer.py +0 -0
  248. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/skill/SKILL.md +0 -0
  249. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/skill/irc_client.py +0 -0
  250. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/socket_server.py +0 -0
  251. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/packages/agent-harness/webhook.py +0 -0
  252. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  253. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  254. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  255. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  256. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/sonar-project.properties +0 -0
  257. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/conftest.py +0 -0
  258. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_acp_daemon.py +0 -0
  259. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_agent_runner.py +0 -0
  260. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_archive.py +0 -0
  261. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_bot.py +0 -0
  262. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_bot_config.py +0 -0
  263. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_bot_manager.py +0 -0
  264. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_bots_integration.py +0 -0
  265. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_channel.py +0 -0
  266. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_codex_daemon.py +0 -0
  267. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_connection.py +0 -0
  268. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_console_client.py +0 -0
  269. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_console_commands.py +0 -0
  270. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_console_connection.py +0 -0
  271. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_console_icons.py +0 -0
  272. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_console_integration.py +0 -0
  273. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_copilot_daemon.py +0 -0
  274. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_daemon.py +0 -0
  275. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_daemon_config.py +0 -0
  276. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_daemon_ipc.py +0 -0
  277. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_discovery.py +0 -0
  278. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_federation.py +0 -0
  279. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_history.py +0 -0
  280. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_http_listener.py +0 -0
  281. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_integration_layer5.py +0 -0
  282. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_ipc.py +0 -0
  283. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_irc_transport.py +0 -0
  284. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_link_reconnect.py +0 -0
  285. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_mention_alias.py +0 -0
  286. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_mention_target_cleanup.py +0 -0
  287. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_mentions.py +0 -0
  288. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_mesh_config.py +0 -0
  289. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_message.py +0 -0
  290. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_message_buffer.py +0 -0
  291. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_messaging.py +0 -0
  292. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_modes.py +0 -0
  293. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_overview_cli.py +0 -0
  294. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_overview_collector.py +0 -0
  295. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_overview_model.py +0 -0
  296. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_overview_renderer.py +0 -0
  297. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_overview_web.py +0 -0
  298. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_persistence.py +0 -0
  299. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_pidfile.py +0 -0
  300. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_poll_loop.py +0 -0
  301. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_room_persistence.py +0 -0
  302. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_rooms.py +0 -0
  303. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_rooms_federation.py +0 -0
  304. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_rooms_integration.py +0 -0
  305. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_server_icon_skill.py +0 -0
  306. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_setup_update_cli.py +0 -0
  307. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_skill_client.py +0 -0
  308. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_skills.py +0 -0
  309. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_socket_server.py +0 -0
  310. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_supervisor.py +0 -0
  311. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_template_engine.py +0 -0
  312. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_thread_buffer.py +0 -0
  313. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_threads.py +0 -0
  314. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_virtual_client.py +0 -0
  315. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_wait_for_port.py +0 -0
  316. {agentirc_cli-4.3.3 → agentirc_cli-4.3.5}/tests/test_webhook.py +0 -0
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  Format follows [Keep a Changelog](https://keepachangelog.com/).
6
6
 
7
+ ## [4.3.5] - 2026-04-07
8
+
9
+
10
+ ### Changed
11
+
12
+ - Reduce cognitive complexity in 30+ functions across backend clients, server code, CLI submodules, and standalone files to meet SonarCloud threshold (≤15)
13
+
14
+ ## [4.3.4] - 2026-04-07
15
+
16
+
17
+ ### Changed
18
+
19
+ - Extract duplicated string literals into named constants (SonarCloud S1192)
20
+ - Refactor cli/_helpers.py into modular cli/shared/ package (constants, ipc, process, mesh, display)
21
+
7
22
  ## [4.3.3] - 2026-04-07
8
23
 
9
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 4.3.3
3
+ Version: 4.3.5
4
4
  Summary: Legacy alias for culture — install culture instead
5
5
  Project-URL: Homepage, https://github.com/OriNachum/culture
6
6
  Author: Ori Nachum
@@ -13,6 +13,8 @@ if TYPE_CHECKING:
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
+ BOT_CONFIG_FILE = "bot.yaml"
17
+
16
18
 
17
19
  class BotManager:
18
20
  """Loads, starts, stops, and dispatches webhooks to bots."""
@@ -27,7 +29,7 @@ class BotManager:
27
29
  return
28
30
 
29
31
  for bot_dir in sorted(BOTS_DIR.iterdir()):
30
- yaml_path = bot_dir / "bot.yaml"
32
+ yaml_path = bot_dir / BOT_CONFIG_FILE
31
33
  if not yaml_path.is_file():
32
34
  continue
33
35
  try:
@@ -45,7 +47,7 @@ class BotManager:
45
47
  async def create_bot(self, config: BotConfig) -> Bot:
46
48
  """Create a new bot: write config to disk and start it."""
47
49
  bot_dir = BOTS_DIR / config.name
48
- save_bot_config(bot_dir / "bot.yaml", config)
50
+ save_bot_config(bot_dir / BOT_CONFIG_FILE, config)
49
51
 
50
52
  bot = Bot(config, self.server)
51
53
  self.bots[config.name] = bot
@@ -57,7 +59,7 @@ class BotManager:
57
59
  bot = self.bots.get(name)
58
60
  if not bot:
59
61
  # Try loading from disk
60
- yaml_path = BOTS_DIR / name / "bot.yaml"
62
+ yaml_path = BOTS_DIR / name / BOT_CONFIG_FILE
61
63
  if not yaml_path.is_file():
62
64
  raise ValueError(f"Bot {name!r} not found")
63
65
  config = load_bot_config(yaml_path)
@@ -27,18 +27,16 @@ from culture.pidfile import (
27
27
  write_pid,
28
28
  )
29
29
 
30
- from ._helpers import (
30
+ from .shared.constants import (
31
31
  _CONFIG_HELP,
32
+ DEFAULT_CHANNEL,
32
33
  DEFAULT_CONFIG,
33
34
  LOG_DIR,
34
- agent_socket_path,
35
- get_observer,
36
- ipc_request,
37
- print_agent_detail,
38
- print_agents_overview,
39
- print_bot_listing,
40
- stop_agent,
35
+ NO_AGENTS_MSG,
41
36
  )
37
+ from .shared.display import print_agent_detail, print_agents_overview, print_bot_listing
38
+ from .shared.ipc import agent_socket_path, get_observer, ipc_request
39
+ from .shared.process import stop_agent
42
40
 
43
41
  logger = logging.getLogger("culture")
44
42
 
@@ -203,59 +201,83 @@ def dispatch(args: argparse.Namespace) -> None:
203
201
  # -----------------------------------------------------------------------
204
202
 
205
203
 
206
- def _create_agent_config(args: argparse.Namespace, full_nick: str) -> AgentConfig:
207
- """Build a backend-specific AgentConfig from CLI args."""
208
- if args.agent == "codex":
209
- from culture.clients.codex.config import AgentConfig as CodexAgentConfig
210
-
211
- return CodexAgentConfig(
212
- nick=full_nick,
213
- agent="codex",
214
- directory=os.getcwd(),
215
- channels=["#general"],
216
- )
217
- if args.agent == "copilot":
218
- from culture.clients.copilot.config import AgentConfig as CopilotAgentConfig
219
-
220
- return CopilotAgentConfig(
221
- nick=full_nick,
222
- agent="copilot",
223
- directory=os.getcwd(),
224
- channels=["#general"],
225
- )
226
- if args.agent == "acp":
227
- import json as _json
204
+ def _create_codex_config(full_nick: str) -> AgentConfig:
205
+ """Build a CodexAgentConfig."""
206
+ from culture.clients.codex.config import AgentConfig as CodexAgentConfig
207
+
208
+ return CodexAgentConfig(
209
+ nick=full_nick,
210
+ agent="codex",
211
+ directory=os.getcwd(),
212
+ channels=[DEFAULT_CHANNEL],
213
+ )
228
214
 
229
- from culture.clients.acp.config import AgentConfig as ACPAgentConfig
230
215
 
231
- acp_cmd = ["opencode", "acp"]
232
- if args.acp_command:
233
- try:
234
- acp_cmd = _json.loads(args.acp_command)
235
- except _json.JSONDecodeError:
236
- acp_cmd = args.acp_command.split()
237
- if (
238
- not isinstance(acp_cmd, list)
239
- or not acp_cmd
240
- or not all(isinstance(s, str) for s in acp_cmd)
241
- ):
242
- print("Error: --acp-command must be a non-empty list of strings", file=sys.stderr)
243
- sys.exit(1)
244
- return ACPAgentConfig(
245
- nick=full_nick,
246
- agent="acp",
247
- acp_command=acp_cmd,
248
- directory=os.getcwd(),
249
- channels=["#general"],
250
- )
216
+ def _create_copilot_config(full_nick: str) -> AgentConfig:
217
+ """Build a CopilotAgentConfig."""
218
+ from culture.clients.copilot.config import AgentConfig as CopilotAgentConfig
219
+
220
+ return CopilotAgentConfig(
221
+ nick=full_nick,
222
+ agent="copilot",
223
+ directory=os.getcwd(),
224
+ channels=[DEFAULT_CHANNEL],
225
+ )
226
+
227
+
228
+ def _parse_acp_command(raw_command: str | None) -> list[str]:
229
+ """Parse and validate the ACP command from CLI args."""
230
+ import json as _json
231
+
232
+ acp_cmd = ["opencode", "acp"]
233
+ if raw_command:
234
+ try:
235
+ acp_cmd = _json.loads(raw_command)
236
+ except _json.JSONDecodeError:
237
+ acp_cmd = raw_command.split()
238
+ if not isinstance(acp_cmd, list) or not acp_cmd or not all(isinstance(s, str) for s in acp_cmd):
239
+ print("Error: --acp-command must be a non-empty list of strings", file=sys.stderr)
240
+ sys.exit(1)
241
+ return acp_cmd
242
+
243
+
244
+ def _create_acp_config(full_nick: str, args: argparse.Namespace) -> AgentConfig:
245
+ """Build an ACPAgentConfig."""
246
+ from culture.clients.acp.config import AgentConfig as ACPAgentConfig
247
+
248
+ acp_cmd = _parse_acp_command(args.acp_command)
249
+ return ACPAgentConfig(
250
+ nick=full_nick,
251
+ agent="acp",
252
+ acp_command=acp_cmd,
253
+ directory=os.getcwd(),
254
+ channels=[DEFAULT_CHANNEL],
255
+ )
256
+
257
+
258
+ def _create_default_config(full_nick: str, backend: str) -> AgentConfig:
259
+ """Build a default (claude) AgentConfig."""
251
260
  return AgentConfig(
252
261
  nick=full_nick,
253
- agent=args.agent,
262
+ agent=backend,
254
263
  directory=os.getcwd(),
255
- channels=["#general"],
264
+ channels=[DEFAULT_CHANNEL],
256
265
  )
257
266
 
258
267
 
268
+ def _create_agent_config(args: argparse.Namespace, full_nick: str) -> AgentConfig:
269
+ """Build a backend-specific AgentConfig from CLI args."""
270
+ factories = {
271
+ "codex": lambda: _create_codex_config(full_nick),
272
+ "copilot": lambda: _create_copilot_config(full_nick),
273
+ "acp": lambda: _create_acp_config(full_nick, args),
274
+ }
275
+ factory = factories.get(args.agent)
276
+ if factory:
277
+ return factory()
278
+ return _create_default_config(full_nick, args.agent)
279
+
280
+
259
281
  def _cmd_create(args: argparse.Namespace) -> None:
260
282
  config = load_config_or_default(args.config)
261
283
 
@@ -365,7 +387,7 @@ def _resolve_agents_to_start(config, args) -> list:
365
387
  agents = _resolve_auto(config)
366
388
 
367
389
  if not agents:
368
- print("No agents configured", file=sys.stderr)
390
+ print(NO_AGENTS_MSG, file=sys.stderr)
369
391
  sys.exit(1)
370
392
  return agents
371
393
 
@@ -389,6 +411,32 @@ def _probe_server_connection(host: str, port: int, server_name: str) -> None:
389
411
  sys.exit(1)
390
412
 
391
413
 
414
+ def _start_foreground(config: DaemonConfig, agents: list[AgentConfig]) -> None:
415
+ """Start a single agent in the foreground."""
416
+ if len(agents) != 1:
417
+ print("--foreground requires a single agent nick, not --all", file=sys.stderr)
418
+ sys.exit(1)
419
+ agent = agents[0]
420
+ print(f"Starting agent {agent.nick} in foreground...")
421
+ asyncio.run(_run_single_agent(config, agent))
422
+
423
+
424
+ def _start_background(config: DaemonConfig, agents: list[AgentConfig]) -> None:
425
+ """Start agents in background mode (fork on Unix, single on Windows)."""
426
+ if sys.platform == "win32":
427
+ if len(agents) != 1:
428
+ print(
429
+ "Multi-agent daemon mode not supported on Windows. Start agents individually.",
430
+ file=sys.stderr,
431
+ )
432
+ sys.exit(1)
433
+ agent = agents[0]
434
+ print(f"Starting agent {agent.nick}...")
435
+ asyncio.run(_run_single_agent(config, agent))
436
+ else:
437
+ _run_multi_agents(config, agents)
438
+
439
+
392
440
  def _cmd_start(args: argparse.Namespace) -> None:
393
441
  config = load_config(args.config)
394
442
 
@@ -397,86 +445,88 @@ def _cmd_start(args: argparse.Namespace) -> None:
397
445
  server_name = config.server.name
398
446
  _probe_server_connection(config.server.host, config.server.port, server_name)
399
447
 
400
- foreground = getattr(args, "foreground", False)
401
-
402
- if foreground:
403
- if len(agents) != 1:
404
- print("--foreground requires a single agent nick, not --all", file=sys.stderr)
405
- sys.exit(1)
406
- agent = agents[0]
407
- print(f"Starting agent {agent.nick} in foreground...")
408
- asyncio.run(_run_single_agent(config, agent))
448
+ if getattr(args, "foreground", False):
449
+ _start_foreground(config, agents)
409
450
  else:
410
- if sys.platform == "win32":
411
- if len(agents) == 1:
412
- agent = agents[0]
413
- print(f"Starting agent {agent.nick}...")
414
- asyncio.run(_run_single_agent(config, agent))
415
- else:
416
- print(
417
- "Multi-agent daemon mode not supported on Windows. Start agents individually.",
418
- file=sys.stderr,
419
- )
420
- sys.exit(1)
421
- else:
422
- _run_multi_agents(config, agents)
451
+ _start_background(config, agents)
452
+
453
+
454
+ def _make_backend_config(config: DaemonConfig, backend_daemon_config_cls):
455
+ """Build a backend-specific DaemonConfig from the base config."""
456
+ return backend_daemon_config_cls(
457
+ server=config.server,
458
+ webhooks=config.webhooks,
459
+ buffer_size=config.buffer_size,
460
+ agents=config.agents,
461
+ )
462
+
463
+
464
+ def _create_codex_daemon(config: DaemonConfig, agent: AgentConfig):
465
+ """Create a Codex backend daemon."""
466
+ from culture.clients.codex.config import DaemonConfig as CodexDaemonConfig
467
+ from culture.clients.codex.daemon import CodexDaemon
468
+
469
+ return CodexDaemon(_make_backend_config(config, CodexDaemonConfig), agent)
470
+
471
+
472
+ def _coerce_to_acp_agent(agent: AgentConfig):
473
+ """Ensure agent is an ACPAgentConfig, converting if necessary."""
474
+ from culture.clients.acp.config import AgentConfig as ACPAgentConfig
475
+
476
+ if isinstance(agent, ACPAgentConfig):
477
+ return agent
478
+ return ACPAgentConfig(
479
+ nick=agent.nick,
480
+ agent="acp",
481
+ acp_command=getattr(agent, "acp_command", None) or ["opencode", "acp"],
482
+ directory=agent.directory,
483
+ channels=agent.channels,
484
+ model=agent.model,
485
+ system_prompt=agent.system_prompt,
486
+ tags=agent.tags,
487
+ )
488
+
489
+
490
+ def _create_acp_daemon(config: DaemonConfig, agent: AgentConfig):
491
+ """Create an ACP backend daemon."""
492
+ from culture.clients.acp.config import DaemonConfig as ACPDaemonConfig
493
+ from culture.clients.acp.daemon import ACPDaemon
494
+
495
+ return ACPDaemon(
496
+ _make_backend_config(config, ACPDaemonConfig),
497
+ _coerce_to_acp_agent(agent),
498
+ )
499
+
500
+
501
+ def _create_copilot_daemon(config: DaemonConfig, agent: AgentConfig):
502
+ """Create a Copilot backend daemon."""
503
+ from culture.clients.copilot.config import DaemonConfig as CopilotDaemonConfig
504
+ from culture.clients.copilot.daemon import CopilotDaemon
505
+
506
+ return CopilotDaemon(_make_backend_config(config, CopilotDaemonConfig), agent)
507
+
508
+
509
+ def _create_claude_daemon(config: DaemonConfig, agent: AgentConfig):
510
+ """Create the default Claude backend daemon."""
511
+ from culture.clients.claude.daemon import AgentDaemon
512
+
513
+ return AgentDaemon(config, agent)
514
+
515
+
516
+ _BACKEND_DAEMON_FACTORIES = {
517
+ "codex": _create_codex_daemon,
518
+ "acp": _create_acp_daemon,
519
+ "opencode": _create_acp_daemon,
520
+ "copilot": _create_copilot_daemon,
521
+ }
423
522
 
424
523
 
425
524
  async def _run_single_agent(config: DaemonConfig, agent: AgentConfig) -> None:
426
525
  """Run a single agent daemon in the foreground."""
427
526
  backend = getattr(agent, "agent", "claude")
428
527
 
429
- if backend == "codex":
430
- from culture.clients.codex.config import DaemonConfig as CodexDaemonConfig
431
- from culture.clients.codex.daemon import CodexDaemon
432
-
433
- codex_config = CodexDaemonConfig(
434
- server=config.server,
435
- webhooks=config.webhooks,
436
- buffer_size=config.buffer_size,
437
- agents=config.agents,
438
- )
439
- daemon = CodexDaemon(codex_config, agent)
440
- elif backend in ("acp", "opencode"):
441
- from culture.clients.acp.config import AgentConfig as ACPAgentConfig
442
- from culture.clients.acp.config import DaemonConfig as ACPDaemonConfig
443
- from culture.clients.acp.daemon import ACPDaemon
444
-
445
- acp_config = ACPDaemonConfig(
446
- server=config.server,
447
- webhooks=config.webhooks,
448
- buffer_size=config.buffer_size,
449
- agents=config.agents,
450
- )
451
- if not isinstance(agent, ACPAgentConfig):
452
- acp_agent = ACPAgentConfig(
453
- nick=agent.nick,
454
- agent="acp",
455
- acp_command=getattr(agent, "acp_command", None) or ["opencode", "acp"],
456
- directory=agent.directory,
457
- channels=agent.channels,
458
- model=agent.model,
459
- system_prompt=agent.system_prompt,
460
- tags=agent.tags,
461
- )
462
- else:
463
- acp_agent = agent
464
- daemon = ACPDaemon(acp_config, acp_agent)
465
- elif backend == "copilot":
466
- from culture.clients.copilot.config import DaemonConfig as CopilotDaemonConfig
467
- from culture.clients.copilot.daemon import CopilotDaemon
468
-
469
- copilot_config = CopilotDaemonConfig(
470
- server=config.server,
471
- webhooks=config.webhooks,
472
- buffer_size=config.buffer_size,
473
- agents=config.agents,
474
- )
475
- daemon = CopilotDaemon(copilot_config, agent)
476
- else:
477
- from culture.clients.claude.daemon import AgentDaemon
478
-
479
- daemon = AgentDaemon(config, agent)
528
+ factory = _BACKEND_DAEMON_FACTORIES.get(backend, _create_claude_daemon)
529
+ daemon = factory(config, agent)
480
530
 
481
531
  stop_event = asyncio.Event()
482
532
  daemon.set_stop_event(stop_event)
@@ -526,30 +576,31 @@ def _run_multi_agents(config: DaemonConfig, agents: list[AgentConfig]) -> None:
526
576
  print(f"Started {agent.nick} (PID {pid})")
527
577
 
528
578
 
529
- def _cmd_stop(args: argparse.Namespace) -> None:
530
- config = load_config_or_default(args.config)
531
-
579
+ def _resolve_agents_to_stop(config, args) -> list:
580
+ """Resolve which agents should be stopped, or exit with an error."""
532
581
  if args.all:
533
- agents = config.agents
534
- elif args.nick:
582
+ return config.agents
583
+ if args.nick:
535
584
  agent = config.get_agent(args.nick)
536
585
  if not agent:
537
586
  print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
538
587
  sys.exit(1)
539
- agents = [agent]
540
- else:
541
- if len(config.agents) == 1:
542
- agents = config.agents
543
- elif len(config.agents) == 0:
544
- print("No agents configured", file=sys.stderr)
545
- sys.exit(1)
546
- else:
547
- print(
548
- "Multiple agents configured. Specify a nick or use --all.",
549
- file=sys.stderr,
550
- )
551
- sys.exit(1)
588
+ return [agent]
589
+ if len(config.agents) == 1:
590
+ return config.agents
591
+ if len(config.agents) == 0:
592
+ print(NO_AGENTS_MSG, file=sys.stderr)
593
+ sys.exit(1)
594
+ print(
595
+ "Multiple agents configured. Specify a nick or use --all.",
596
+ file=sys.stderr,
597
+ )
598
+ sys.exit(1)
552
599
 
600
+
601
+ def _cmd_stop(args: argparse.Namespace) -> None:
602
+ config = load_config_or_default(args.config)
603
+ agents = _resolve_agents_to_stop(config, args)
553
604
  for agent in agents:
554
605
  stop_agent(agent.nick)
555
606
 
@@ -574,14 +625,14 @@ def _no_agents_message(config, show_all: bool) -> str:
574
625
  archived_count = sum(1 for a in config.agents if a.archived)
575
626
  if archived_count:
576
627
  return f"No active agents ({archived_count} archived, use --all to show)"
577
- return "No agents configured"
628
+ return NO_AGENTS_MSG
578
629
 
579
630
 
580
631
  def _cmd_status(args: argparse.Namespace) -> None:
581
632
  config = load_config_or_default(args.config)
582
633
 
583
634
  if not config.agents:
584
- print("No agents configured")
635
+ print(NO_AGENTS_MSG)
585
636
  return
586
637
 
587
638
  if args.nick:
@@ -8,7 +8,7 @@ import time
8
8
 
9
9
  from culture.clients.claude.config import load_config_or_default
10
10
 
11
- from ._helpers import _CONFIG_HELP, DEFAULT_CONFIG
11
+ from .shared.constants import _BOT_NAME_HELP, _CONFIG_HELP, BOT_CONFIG_FILE, DEFAULT_CONFIG
12
12
 
13
13
  NAME = "bot"
14
14
 
@@ -31,11 +31,11 @@ def register(subparsers: argparse._SubParsersAction) -> None:
31
31
  bot_create.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
32
32
 
33
33
  bot_start = bot_sub.add_parser("start", help="Start a bot")
34
- bot_start.add_argument("name", help="Bot name")
34
+ bot_start.add_argument("name", help=_BOT_NAME_HELP)
35
35
  bot_start.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
36
36
 
37
37
  bot_stop = bot_sub.add_parser("stop", help="Stop a bot")
38
- bot_stop.add_argument("name", help="Bot name")
38
+ bot_stop.add_argument("name", help=_BOT_NAME_HELP)
39
39
  bot_stop.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
40
40
 
41
41
  bot_list = bot_sub.add_parser("list", help="List bots")
@@ -43,7 +43,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
43
43
  bot_list.add_argument("--all", action="store_true", help="Include archived bots")
44
44
 
45
45
  bot_inspect = bot_sub.add_parser("inspect", help="Show bot details")
46
- bot_inspect.add_argument("name", help="Bot name")
46
+ bot_inspect.add_argument("name", help=_BOT_NAME_HELP)
47
47
  bot_inspect.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
48
48
 
49
49
  bot_archive = bot_sub.add_parser("archive", help="Archive a bot")
@@ -113,11 +113,11 @@ def _bot_create(args: argparse.Namespace) -> None:
113
113
  )
114
114
 
115
115
  bot_dir = BOTS_DIR / name
116
- if (bot_dir / "bot.yaml").exists():
116
+ if (bot_dir / BOT_CONFIG_FILE).exists():
117
117
  print(f"Bot '{name}' already exists at {bot_dir}", file=sys.stderr)
118
118
  sys.exit(1)
119
119
 
120
- save_bot_config(bot_dir / "bot.yaml", bot_config)
120
+ save_bot_config(bot_dir / BOT_CONFIG_FILE, bot_config)
121
121
  print(f"Bot '{name}' created at {bot_dir}")
122
122
  print(f" Owner: {args.owner}")
123
123
  print(f" Trigger: {args.trigger}")
@@ -132,7 +132,7 @@ def _bot_start(args: argparse.Namespace) -> None:
132
132
  from culture.bots.config import BOTS_DIR
133
133
 
134
134
  bot_dir = BOTS_DIR / args.name
135
- if not (bot_dir / "bot.yaml").exists():
135
+ if not (bot_dir / BOT_CONFIG_FILE).exists():
136
136
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
137
137
  sys.exit(1)
138
138
 
@@ -144,7 +144,7 @@ def _bot_stop(args: argparse.Namespace) -> None:
144
144
  from culture.bots.config import BOTS_DIR
145
145
 
146
146
  bot_dir = BOTS_DIR / args.name
147
- if not (bot_dir / "bot.yaml").exists():
147
+ if not (bot_dir / BOT_CONFIG_FILE).exists():
148
148
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
149
149
  sys.exit(1)
150
150
 
@@ -152,6 +152,15 @@ def _bot_stop(args: argparse.Namespace) -> None:
152
152
  print("(Live reload via IPC will be available in a future release.)")
153
153
 
154
154
 
155
+ def _should_include_bot(bot_config, owner: str | None, show_archived: bool) -> bool:
156
+ """Return True if the bot should be included in the listing."""
157
+ if owner and bot_config.owner != owner:
158
+ return False
159
+ if not show_archived and bot_config.archived:
160
+ return False
161
+ return True
162
+
163
+
155
164
  def _load_and_filter_bots(args) -> list:
156
165
  """Load bot configs, filtering by owner and archived status."""
157
166
  from culture.bots.config import BOTS_DIR, load_bot_config
@@ -161,18 +170,15 @@ def _load_and_filter_bots(args) -> list:
161
170
  show_all = getattr(args, "all", False)
162
171
  bots = []
163
172
  for bot_dir in sorted(BOTS_DIR.iterdir()):
164
- yaml_path = bot_dir / "bot.yaml"
173
+ yaml_path = bot_dir / BOT_CONFIG_FILE
165
174
  if not yaml_path.is_file():
166
175
  continue
167
176
  try:
168
177
  config = load_bot_config(yaml_path)
169
178
  except Exception:
170
179
  continue
171
- if args.owner and config.owner != args.owner:
172
- continue
173
- if not show_all and config.archived:
174
- continue
175
- bots.append(config)
180
+ if _should_include_bot(config, args.owner, show_all):
181
+ bots.append(config)
176
182
  return bots
177
183
 
178
184
 
@@ -203,7 +209,7 @@ def _bot_inspect(args: argparse.Namespace) -> None:
203
209
  from culture.bots.config import BOTS_DIR, load_bot_config
204
210
 
205
211
  bot_dir = BOTS_DIR / args.name
206
- yaml_path = bot_dir / "bot.yaml"
212
+ yaml_path = bot_dir / BOT_CONFIG_FILE
207
213
  if not yaml_path.is_file():
208
214
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
209
215
  sys.exit(1)
@@ -245,7 +251,7 @@ def _bot_archive(args: argparse.Namespace) -> None:
245
251
  from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
246
252
 
247
253
  bot_dir = BOTS_DIR / args.name
248
- yaml_path = bot_dir / "bot.yaml"
254
+ yaml_path = bot_dir / BOT_CONFIG_FILE
249
255
  if not yaml_path.is_file():
250
256
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
251
257
  sys.exit(1)
@@ -270,7 +276,7 @@ def _bot_unarchive(args: argparse.Namespace) -> None:
270
276
  from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
271
277
 
272
278
  bot_dir = BOTS_DIR / args.name
273
- yaml_path = bot_dir / "bot.yaml"
279
+ yaml_path = bot_dir / BOT_CONFIG_FILE
274
280
  if not yaml_path.is_file():
275
281
  print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
276
282
  sys.exit(1)
@@ -6,7 +6,8 @@ import argparse
6
6
  import asyncio
7
7
  import sys
8
8
 
9
- from ._helpers import _CONFIG_HELP, DEFAULT_CONFIG, get_observer
9
+ from .shared.constants import _CONFIG_HELP, DEFAULT_CONFIG
10
+ from .shared.ipc import get_observer
10
11
 
11
12
  NAME = "channel"
12
13