agentirc-cli 4.1.3__tar.gz → 4.2.1__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 (310) hide show
  1. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/CHANGELOG.md +24 -0
  2. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/Gemfile +1 -0
  3. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/Gemfile.lock +4 -0
  4. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/PKG-INFO +1 -1
  5. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/_config.yml +1 -0
  6. agentirc_cli-4.2.1/culture/aio.py +12 -0
  7. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/bots/bot_manager.py +3 -0
  8. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/bots/config.py +18 -6
  9. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/_helpers.py +12 -3
  10. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/agent.py +101 -8
  11. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/bot.py +79 -2
  12. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/server.py +173 -1
  13. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/agent_runner.py +4 -2
  14. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/daemon.py +11 -10
  15. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/irc_transport.py +5 -4
  16. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/config.py +102 -0
  17. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/daemon.py +10 -9
  18. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/irc_transport.py +5 -4
  19. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/agent_runner.py +4 -2
  20. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/daemon.py +11 -10
  21. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/irc_transport.py +5 -4
  22. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/agent_runner.py +4 -2
  23. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/daemon.py +11 -10
  24. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/irc_transport.py +5 -4
  25. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/app.py +8 -7
  26. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/client.py +2 -3
  27. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/mesh_config.py +1 -0
  28. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/client.py +3 -2
  29. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/server_link.py +9 -8
  30. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/skills/rooms.py +2 -1
  31. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/agent-harness-spec.md +5 -1
  32. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/cli.md +61 -0
  33. agentirc_cli-4.2.1/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +253 -0
  34. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/daemon.py +11 -10
  35. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/irc_transport.py +5 -4
  36. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/pyproject.toml +1 -1
  37. agentirc_cli-4.2.1/tests/test_archive.py +436 -0
  38. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_daemon_ipc.py +2 -2
  39. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_mention_target_cleanup.py +6 -6
  40. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/uv.lock +1 -1
  41. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.claude/skills/pr-review/SKILL.md +0 -0
  42. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.claude/skills/run-tests/SKILL.md +0 -0
  43. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.claude/skills/run-tests/scripts/test.sh +0 -0
  44. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.flake8 +0 -0
  45. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.github/workflows/pages.yml +0 -0
  46. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.github/workflows/publish.yml +0 -0
  47. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.github/workflows/security-checks.yml +0 -0
  48. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.github/workflows/tests.yml +0 -0
  49. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.gitignore +0 -0
  50. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.markdownlint-cli2.yaml +0 -0
  51. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.pr_agent.toml +0 -0
  52. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.pre-commit-config.yaml +0 -0
  53. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/.pylintrc +0 -0
  54. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/CLAUDE.md +0 -0
  55. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/CNAME +0 -0
  56. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/LICENSE +0 -0
  57. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/README.md +0 -0
  58. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/SECURITY.md +0 -0
  59. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/_sass/color_schemes/anthropic.scss +0 -0
  60. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/_sass/custom/custom.scss +0 -0
  61. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/__init__.py +0 -0
  62. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/__main__.py +0 -0
  63. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/bots/__init__.py +0 -0
  64. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/bots/bot.py +0 -0
  65. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/bots/http_listener.py +0 -0
  66. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/bots/template_engine.py +0 -0
  67. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/bots/virtual_client.py +0 -0
  68. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/__init__.py +0 -0
  69. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/channel.py +0 -0
  70. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/mesh.py +0 -0
  71. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/cli/skills.py +0 -0
  72. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/__init__.py +0 -0
  73. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/__init__.py +0 -0
  74. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/config.py +0 -0
  75. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/ipc.py +0 -0
  76. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/message_buffer.py +0 -0
  77. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/skill/SKILL.md +0 -0
  78. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/skill/__init__.py +0 -0
  79. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/skill/irc_client.py +0 -0
  80. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/socket_server.py +0 -0
  81. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/supervisor.py +0 -0
  82. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/acp/webhook.py +0 -0
  83. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/__init__.py +0 -0
  84. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/__main__.py +0 -0
  85. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/agent_runner.py +0 -0
  86. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/ipc.py +0 -0
  87. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/message_buffer.py +0 -0
  88. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/skill/SKILL.md +0 -0
  89. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/skill/__init__.py +0 -0
  90. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/skill/irc_client.py +0 -0
  91. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/socket_server.py +0 -0
  92. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/supervisor.py +0 -0
  93. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/claude/webhook.py +0 -0
  94. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/__init__.py +0 -0
  95. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/config.py +0 -0
  96. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/ipc.py +0 -0
  97. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/message_buffer.py +0 -0
  98. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/skill/SKILL.md +0 -0
  99. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/skill/__init__.py +0 -0
  100. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/skill/irc_client.py +0 -0
  101. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/socket_server.py +0 -0
  102. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/supervisor.py +0 -0
  103. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/codex/webhook.py +0 -0
  104. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/__init__.py +0 -0
  105. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/config.py +0 -0
  106. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/ipc.py +0 -0
  107. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/message_buffer.py +0 -0
  108. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/skill/SKILL.md +0 -0
  109. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/skill/__init__.py +0 -0
  110. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/skill/irc_client.py +0 -0
  111. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/socket_server.py +0 -0
  112. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/supervisor.py +0 -0
  113. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/clients/copilot/webhook.py +0 -0
  114. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/__init__.py +0 -0
  115. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/commands.py +0 -0
  116. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/widgets/__init__.py +0 -0
  117. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/widgets/chat.py +0 -0
  118. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/widgets/info_panel.py +0 -0
  119. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/console/widgets/sidebar.py +0 -0
  120. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/credentials.py +0 -0
  121. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/learn_prompt.py +0 -0
  122. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/observer.py +0 -0
  123. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/overview/__init__.py +0 -0
  124. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/overview/collector.py +0 -0
  125. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/overview/model.py +0 -0
  126. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/overview/renderer_text.py +0 -0
  127. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/overview/renderer_web.py +0 -0
  128. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/overview/web/style.css +0 -0
  129. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/persistence.py +0 -0
  130. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/pidfile.py +0 -0
  131. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/__init__.py +0 -0
  132. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/commands.py +0 -0
  133. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/extensions/federation.md +0 -0
  134. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/extensions/history.md +0 -0
  135. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/extensions/icons.md +0 -0
  136. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/extensions/rooms.md +0 -0
  137. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/extensions/tags.md +0 -0
  138. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/extensions/threads.md +0 -0
  139. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/message.py +0 -0
  140. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/protocol-index.md +0 -0
  141. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/protocol/replies.py +0 -0
  142. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/__init__.py +0 -0
  143. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/__main__.py +0 -0
  144. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/channel.py +0 -0
  145. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/config.py +0 -0
  146. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/ircd.py +0 -0
  147. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/remote_client.py +0 -0
  148. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/room_store.py +0 -0
  149. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/rooms_util.py +0 -0
  150. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/skill.py +0 -0
  151. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/skills/__init__.py +0 -0
  152. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/skills/history.py +0 -0
  153. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/skills/icon.py +0 -0
  154. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/skills/threads.py +0 -0
  155. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/server/thread_store.py +0 -0
  156. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/culture/skills/culture/SKILL.md +0 -0
  157. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/agent-lifecycle.md +0 -0
  158. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/agentic-self-learn.md +0 -0
  159. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/agent-client.md +0 -0
  160. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/design.md +0 -0
  161. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/harness-conformance.md +0 -0
  162. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/index.md +0 -0
  163. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/layer1-core-irc.md +0 -0
  164. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/layer2-attention.md +0 -0
  165. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/layer3-skills.md +0 -0
  166. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/layer4-federation.md +0 -0
  167. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/layer5-agent-harness.md +0 -0
  168. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/server-architecture.md +0 -0
  169. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/architecture/threads.md +0 -0
  170. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/channel-polling.md +0 -0
  171. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/acp/overview.md +0 -0
  172. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/claude/configuration.md +0 -0
  173. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/claude/context-management.md +0 -0
  174. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/claude/irc-tools.md +0 -0
  175. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/claude/overview.md +0 -0
  176. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/claude/setup.md +0 -0
  177. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/claude/supervisor.md +0 -0
  178. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/claude/webhooks.md +0 -0
  179. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/codex/configuration.md +0 -0
  180. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/codex/context-management.md +0 -0
  181. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/codex/irc-tools.md +0 -0
  182. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/codex/overview.md +0 -0
  183. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/codex/setup.md +0 -0
  184. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/codex/supervisor.md +0 -0
  185. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/codex/webhooks.md +0 -0
  186. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/copilot/configuration.md +0 -0
  187. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/copilot/context-management.md +0 -0
  188. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/copilot/irc-tools.md +0 -0
  189. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/copilot/overview.md +0 -0
  190. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/copilot/setup.md +0 -0
  191. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/copilot/supervisor.md +0 -0
  192. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/clients/copilot/webhooks.md +0 -0
  193. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/culture-cli.md +0 -0
  194. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/getting-started.md +0 -0
  195. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/index.md +0 -0
  196. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/SECURITY.md +0 -0
  197. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/bots.md +0 -0
  198. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/ci.md +0 -0
  199. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/docs-site.md +0 -0
  200. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/index.md +0 -0
  201. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/ops-tooling.md +0 -0
  202. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/overview.md +0 -0
  203. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/operations/publishing.md +0 -0
  204. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  205. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/rooms.md +0 -0
  206. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/server-rename.md +0 -0
  207. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  208. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  209. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  210. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  211. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  212. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  213. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  214. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  215. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  216. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  217. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  218. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  219. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  220. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  221. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  222. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  223. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  224. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  225. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  226. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
  227. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  228. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/01-pair-programming.md +0 -0
  229. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/02-code-review-ensemble.md +0 -0
  230. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/03-cross-server-delegation.md +0 -0
  231. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/04-knowledge-propagation.md +0 -0
  232. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/05-the-observer.md +0 -0
  233. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/06-cross-server-ops.md +0 -0
  234. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/07-supervisor-intervention.md +0 -0
  235. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/08-apps-as-agents.md +0 -0
  236. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/09-research-swarm.md +0 -0
  237. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases/10-agent-lifecycle.md +0 -0
  238. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/use-cases-index.md +0 -0
  239. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/docs/what-is-culture.md +0 -0
  240. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/README.md +0 -0
  241. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/config.py +0 -0
  242. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/ipc.py +0 -0
  243. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/message_buffer.py +0 -0
  244. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/skill/SKILL.md +0 -0
  245. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/skill/irc_client.py +0 -0
  246. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/socket_server.py +0 -0
  247. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/packages/agent-harness/webhook.py +0 -0
  248. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  249. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  250. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  251. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  252. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/sonar-project.properties +0 -0
  253. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/__init__.py +0 -0
  254. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/conftest.py +0 -0
  255. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_acp_daemon.py +0 -0
  256. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_agent_runner.py +0 -0
  257. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_bot.py +0 -0
  258. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_bot_config.py +0 -0
  259. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_bot_manager.py +0 -0
  260. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_bots_integration.py +0 -0
  261. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_channel.py +0 -0
  262. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_codex_daemon.py +0 -0
  263. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_connection.py +0 -0
  264. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_console_client.py +0 -0
  265. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_console_commands.py +0 -0
  266. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_console_connection.py +0 -0
  267. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_console_icons.py +0 -0
  268. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_console_integration.py +0 -0
  269. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_copilot_daemon.py +0 -0
  270. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_daemon.py +0 -0
  271. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_daemon_config.py +0 -0
  272. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_discovery.py +0 -0
  273. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_federation.py +0 -0
  274. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_history.py +0 -0
  275. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_http_listener.py +0 -0
  276. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_integration_layer5.py +0 -0
  277. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_ipc.py +0 -0
  278. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_irc_transport.py +0 -0
  279. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_link_reconnect.py +0 -0
  280. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_mention_alias.py +0 -0
  281. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_mentions.py +0 -0
  282. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_mesh_config.py +0 -0
  283. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_message.py +0 -0
  284. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_message_buffer.py +0 -0
  285. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_messaging.py +0 -0
  286. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_modes.py +0 -0
  287. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_overview_cli.py +0 -0
  288. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_overview_collector.py +0 -0
  289. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_overview_model.py +0 -0
  290. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_overview_renderer.py +0 -0
  291. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_overview_web.py +0 -0
  292. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_persistence.py +0 -0
  293. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_pidfile.py +0 -0
  294. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_poll_loop.py +0 -0
  295. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_room_persistence.py +0 -0
  296. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_rooms.py +0 -0
  297. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_rooms_federation.py +0 -0
  298. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_rooms_integration.py +0 -0
  299. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_server_icon_skill.py +0 -0
  300. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_setup_update_cli.py +0 -0
  301. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_skill_client.py +0 -0
  302. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_skills.py +0 -0
  303. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_socket_server.py +0 -0
  304. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_supervisor.py +0 -0
  305. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_template_engine.py +0 -0
  306. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_thread_buffer.py +0 -0
  307. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_threads.py +0 -0
  308. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_virtual_client.py +0 -0
  309. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_wait_for_port.py +0 -0
  310. {agentirc_cli-4.1.3 → agentirc_cli-4.2.1}/tests/test_webhook.py +0 -0
@@ -4,6 +4,30 @@ 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.2.1] - 2026-04-07
8
+
9
+
10
+ ### Changed
11
+
12
+ - Update dispatch patterns to use declarative maybe_await() utility for handling both sync and async handlers
13
+ - Remove unnecessary async keyword from ~40 handler functions that never use await
14
+
15
+
16
+ ### Fixed
17
+
18
+ - SonarCloud S7503: async functions that never await (issue #83)
19
+
20
+ ## [4.2.0] - 2026-04-07
21
+
22
+
23
+ ### Added
24
+
25
+ - Archive and unarchive commands for servers, agents, and bots
26
+ - Cascade archive: server archive automatically archives all agents and bots
27
+ - Visibility filtering: archived entities hidden from default status/list views
28
+ - --all flag on status/list to reveal archived entities
29
+ - Start guard: archived entities cannot be started until unarchived
30
+
7
31
  ## [4.1.3] - 2026-04-06
8
32
 
9
33
 
@@ -4,3 +4,4 @@ gem "jekyll", "~> 4.3"
4
4
  gem "just-the-docs", "~> 0.10"
5
5
  gem "jekyll-seo-tag"
6
6
  gem "jekyll-relative-links"
7
+ gem "jekyll-sitemap"
@@ -81,6 +81,8 @@ GEM
81
81
  sass-embedded (~> 1.75)
82
82
  jekyll-seo-tag (2.8.0)
83
83
  jekyll (>= 3.8, < 5.0)
84
+ jekyll-sitemap (1.4.0)
85
+ jekyll (>= 3.7, < 5.0)
84
86
  jekyll-watch (2.2.1)
85
87
  listen (~> 3.0)
86
88
  json (2.19.2)
@@ -171,6 +173,7 @@ DEPENDENCIES
171
173
  jekyll (~> 4.3)
172
174
  jekyll-relative-links
173
175
  jekyll-seo-tag
176
+ jekyll-sitemap
174
177
  just-the-docs (~> 0.10)
175
178
 
176
179
  CHECKSUMS
@@ -210,6 +213,7 @@ CHECKSUMS
210
213
  jekyll-relative-links (0.7.0) sha256=831e54c348eeae751845c0d4ac4b244bd73b664341f0e8c9f1803b16f4570835
211
214
  jekyll-sass-converter (3.1.0) sha256=83925d84f1d134410c11d0c6643b0093e82e3a3cf127e90757a85294a3862443
212
215
  jekyll-seo-tag (2.8.0) sha256=3f2ed1916d56f14ebfa38e24acde9b7c946df70cb183af2cb5f0598f21ae6818
216
+ jekyll-sitemap (1.4.0) sha256=0de08c5debc185ea5a8f980e1025c7cd3f8e0c35c8b6ef592f15c46235cf4218
213
217
  jekyll-watch (2.2.1) sha256=bc44ed43f5e0a552836245a54dbff3ea7421ecc2856707e8a1ee203a8387a7e1
214
218
  json (2.19.2) sha256=e7e1bd318b2c37c4ceee2444841c86539bc462e81f40d134cf97826cb14e83cf
215
219
  just-the-docs (0.12.0) sha256=15f2839ac9082898d60f33b978aa6f8e46fc50ba8fac20ae7a7f0e1fb295523e
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 4.1.3
3
+ Version: 4.2.1
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
@@ -24,6 +24,7 @@ footer_content: >-
24
24
  plugins:
25
25
  - jekyll-seo-tag
26
26
  - jekyll-relative-links
27
+ - jekyll-sitemap
27
28
 
28
29
  relative_links:
29
30
  enabled: true
@@ -0,0 +1,12 @@
1
+ """Async utilities for culture."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+
7
+
8
+ async def maybe_await(result):
9
+ """Await the result only if it's a coroutine, otherwise return directly."""
10
+ if asyncio.iscoroutine(result):
11
+ return await result
12
+ return result
@@ -32,6 +32,9 @@ class BotManager:
32
32
  continue
33
33
  try:
34
34
  config = load_bot_config(yaml_path)
35
+ if config.archived:
36
+ logger.info("Skipping archived bot %s", config.name)
37
+ continue
35
38
  bot = Bot(config, self.server)
36
39
  self.bots[config.name] = bot
37
40
  await bot.start()
@@ -26,6 +26,9 @@ class BotConfig:
26
26
  mention: str | None = None
27
27
  template: str | None = None
28
28
  fallback: str = "json"
29
+ archived: bool = False
30
+ archived_at: str = ""
31
+ archived_reason: str = ""
29
32
 
30
33
  @property
31
34
  def has_handler(self) -> bool:
@@ -54,6 +57,9 @@ def load_bot_config(path: Path) -> BotConfig:
54
57
  mention=output_section.get("mention"),
55
58
  template=output_section.get("template"),
56
59
  fallback=output_section.get("fallback", "json"),
60
+ archived=bot_section.get("archived", False),
61
+ archived_at=bot_section.get("archived_at", ""),
62
+ archived_reason=bot_section.get("archived_reason", ""),
57
63
  )
58
64
 
59
65
 
@@ -61,13 +67,19 @@ def save_bot_config(path: Path, config: BotConfig) -> None:
61
67
  """Serialize a BotConfig to YAML and write atomically."""
62
68
  path.parent.mkdir(parents=True, exist_ok=True)
63
69
 
70
+ bot_section = {
71
+ "name": config.name,
72
+ "owner": config.owner,
73
+ "description": config.description,
74
+ "created": config.created,
75
+ }
76
+ if config.archived:
77
+ bot_section["archived"] = config.archived
78
+ bot_section["archived_at"] = config.archived_at
79
+ bot_section["archived_reason"] = config.archived_reason
80
+
64
81
  data = {
65
- "bot": {
66
- "name": config.name,
67
- "owner": config.owner,
68
- "description": config.description,
69
- "created": config.created,
70
- },
82
+ "bot": bot_section,
71
83
  "trigger": {
72
84
  "type": config.trigger_type,
73
85
  },
@@ -381,7 +381,9 @@ def print_agent_detail(agent, config_path: str, args: argparse.Namespace) -> Non
381
381
  print(f" Config: {config_path}")
382
382
 
383
383
 
384
- def print_agents_overview(agents: list, show_activity: bool) -> None:
384
+ def print_agents_overview(
385
+ agents: list, show_activity: bool, show_archived_marker: bool = False
386
+ ) -> None:
385
387
  """Print a table of all agents with status, PID, and optionally activity."""
386
388
  if show_activity:
387
389
  print(f"{'NICK':<30} {'STATUS':<12} {'PID':<10} {'ACTIVITY'}")
@@ -391,10 +393,17 @@ def print_agents_overview(agents: list, show_activity: bool) -> None:
391
393
  print("-" * 52)
392
394
 
393
395
  for agent in agents:
394
- status, pid = agent_process_status(agent)
396
+ archived = getattr(agent, "archived", False)
397
+ base_status, pid = agent_process_status(agent)
398
+ status = base_status
399
+ if archived:
400
+ if show_archived_marker:
401
+ status = f"{base_status} (archived)"
402
+ elif base_status == "stopped":
403
+ status = "archived"
395
404
  activity = "-"
396
405
 
397
- if show_activity and status == "running":
406
+ if show_activity and base_status == "running":
398
407
  resp = asyncio.run(ipc_request(agent_socket_path(agent.nick), "status"))
399
408
  if resp and resp.get("ok"):
400
409
  activity = resp.get("data", {}).get("description", "nothing")
@@ -13,9 +13,11 @@ from culture.clients.claude.config import (
13
13
  AgentConfig,
14
14
  DaemonConfig,
15
15
  add_agent_to_config,
16
+ archive_agent,
16
17
  load_config,
17
18
  load_config_or_default,
18
19
  sanitize_agent_name,
20
+ unarchive_agent,
19
21
  )
20
22
  from culture.pidfile import (
21
23
  is_process_alive,
@@ -99,6 +101,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
99
101
  status_parser.add_argument(
100
102
  "--full", action="store_true", help="Query agents for activity status"
101
103
  )
104
+ status_parser.add_argument("--all", action="store_true", help="Include archived agents")
102
105
  status_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
103
106
 
104
107
  # -- rename ---------------------------------------------------------------
@@ -144,11 +147,22 @@ def register(subparsers: argparse._SubParsersAction) -> None:
144
147
  read_parser.add_argument("--limit", "-n", type=int, default=50, help="Number of messages")
145
148
  read_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
146
149
 
150
+ # -- archive --------------------------------------------------------------
151
+ archive_parser = agent_sub.add_parser("archive", help="Archive an agent (stop and retire)")
152
+ archive_parser.add_argument("nick", help="Agent nick to archive")
153
+ archive_parser.add_argument("--reason", default="", help="Reason for archiving")
154
+ archive_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
155
+
156
+ # -- unarchive ------------------------------------------------------------
157
+ unarchive_parser = agent_sub.add_parser("unarchive", help="Restore an archived agent")
158
+ unarchive_parser.add_argument("nick", help="Agent nick to unarchive")
159
+ unarchive_parser.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
160
+
147
161
 
148
162
  def dispatch(args: argparse.Namespace) -> None:
149
163
  if not args.agent_command:
150
164
  print(
151
- "Usage: culture agent {create|join|start|stop|status|rename|assign|sleep|wake|learn|message|read}",
165
+ "Usage: culture agent {create|join|start|stop|status|rename|assign|sleep|wake|learn|message|read|archive|unarchive}",
152
166
  file=sys.stderr,
153
167
  )
154
168
  sys.exit(1)
@@ -166,6 +180,8 @@ def dispatch(args: argparse.Namespace) -> None:
166
180
  "learn": _cmd_learn,
167
181
  "message": _cmd_message,
168
182
  "read": _cmd_read,
183
+ "archive": _cmd_archive,
184
+ "unarchive": _cmd_unarchive,
169
185
  }
170
186
  handler = handlers.get(args.agent_command)
171
187
  if handler:
@@ -291,25 +307,42 @@ def _cmd_join(args: argparse.Namespace) -> None:
291
307
  def _resolve_agents_to_start(config, args) -> list:
292
308
  """Return the list of agents to start, or exit with an error message."""
293
309
  if args.all:
294
- agents = config.agents
310
+ # Skip archived agents when starting --all
311
+ agents = [a for a in config.agents if not a.archived]
295
312
  elif args.nick:
296
313
  agent = config.get_agent(args.nick)
297
314
  if not agent:
298
315
  print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
299
316
  sys.exit(1)
317
+ if agent.archived:
318
+ print(
319
+ f"Agent '{args.nick}' is archived. Unarchive first:",
320
+ file=sys.stderr,
321
+ )
322
+ print(f" culture agent unarchive {args.nick}", file=sys.stderr)
323
+ sys.exit(1)
300
324
  agents = [agent]
301
325
  else:
302
- if len(config.agents) == 1:
303
- agents = config.agents
304
- elif len(config.agents) == 0:
305
- print("No agents configured. Run 'culture agent create' first.", file=sys.stderr)
326
+ active = [a for a in config.agents if not a.archived]
327
+ if len(active) == 1:
328
+ agents = active
329
+ elif len(active) == 0:
330
+ archived_count = sum(1 for a in config.agents if a.archived)
331
+ if archived_count:
332
+ print(
333
+ f"No active agents ({archived_count} archived). "
334
+ "Unarchive an agent or create a new one.",
335
+ file=sys.stderr,
336
+ )
337
+ else:
338
+ print("No agents configured. Run 'culture agent create' first.", file=sys.stderr)
306
339
  sys.exit(1)
307
340
  else:
308
341
  print(
309
342
  "Multiple agents configured. Specify a nick or use --all.",
310
343
  file=sys.stderr,
311
344
  )
312
- for a in config.agents:
345
+ for a in active:
313
346
  print(f" {a.nick}", file=sys.stderr)
314
347
  sys.exit(1)
315
348
 
@@ -527,9 +560,27 @@ def _cmd_status(args: argparse.Namespace) -> None:
527
560
  sys.exit(1)
528
561
 
529
562
  print_agent_detail(agent, args.config, args)
563
+ if agent.archived:
564
+ print(f"\n [archived since {agent.archived_at}]")
565
+ if agent.archived_reason:
566
+ print(f" Reason: {agent.archived_reason}")
567
+ return
568
+
569
+ show_all = getattr(args, "all", False)
570
+ if show_all:
571
+ agents = config.agents
572
+ else:
573
+ agents = [a for a in config.agents if not a.archived]
574
+
575
+ if not agents and not show_all:
576
+ archived_count = sum(1 for a in config.agents if a.archived)
577
+ if archived_count:
578
+ print(f"No active agents ({archived_count} archived, use --all to show)")
579
+ else:
580
+ print("No agents configured")
530
581
  return
531
582
 
532
- print_agents_overview(config.agents, args.full)
583
+ print_agents_overview(agents, args.full, show_archived_marker=show_all)
533
584
  print_bot_listing()
534
585
 
535
586
 
@@ -738,3 +789,45 @@ def _cmd_read(args: argparse.Namespace) -> None:
738
789
  )
739
790
  print("Use 'culture channel read <channel>' for channel history.", file=sys.stderr)
740
791
  sys.exit(1)
792
+
793
+
794
+ # -----------------------------------------------------------------------
795
+ # Archive / Unarchive
796
+ # -----------------------------------------------------------------------
797
+
798
+
799
+ def _cmd_archive(args: argparse.Namespace) -> None:
800
+ """Archive an agent: stop if running, set archived flag."""
801
+ config = load_config_or_default(args.config)
802
+ agent = config.get_agent(args.nick)
803
+ if not agent:
804
+ print(f"Agent '{args.nick}' not found in config", file=sys.stderr)
805
+ sys.exit(1)
806
+
807
+ if agent.archived:
808
+ print(f"Agent '{args.nick}' is already archived")
809
+ return
810
+
811
+ # Stop the agent if it's running
812
+ pid = read_pid(f"agent-{args.nick}")
813
+ if pid and is_process_alive(pid):
814
+ stop_agent(args.nick)
815
+
816
+ archive_agent(args.config, args.nick, reason=args.reason)
817
+
818
+ print(f"Agent archived: {args.nick}")
819
+ if args.reason:
820
+ print(f" Reason: {args.reason}")
821
+ print(f"\nTo restore: culture agent unarchive {args.nick}")
822
+
823
+
824
+ def _cmd_unarchive(args: argparse.Namespace) -> None:
825
+ """Restore an archived agent."""
826
+ try:
827
+ unarchive_agent(args.config, args.nick)
828
+ except ValueError as exc:
829
+ print(str(exc), file=sys.stderr)
830
+ sys.exit(1)
831
+
832
+ print(f"Agent unarchived: {args.nick}")
833
+ print(f"\nStart with: culture agent start {args.nick}")
@@ -40,15 +40,26 @@ def register(subparsers: argparse._SubParsersAction) -> None:
40
40
 
41
41
  bot_list = bot_sub.add_parser("list", help="List bots")
42
42
  bot_list.add_argument("owner", nargs="?", default=None, help="Filter by owner nick")
43
+ bot_list.add_argument("--all", action="store_true", help="Include archived bots")
43
44
 
44
45
  bot_inspect = bot_sub.add_parser("inspect", help="Show bot details")
45
46
  bot_inspect.add_argument("name", help="Bot name")
46
47
  bot_inspect.add_argument("--config", default=DEFAULT_CONFIG, help=_CONFIG_HELP)
47
48
 
49
+ bot_archive = bot_sub.add_parser("archive", help="Archive a bot")
50
+ bot_archive.add_argument("name", help="Bot name to archive")
51
+ bot_archive.add_argument("--reason", default="", help="Reason for archiving")
52
+
53
+ bot_unarchive = bot_sub.add_parser("unarchive", help="Restore an archived bot")
54
+ bot_unarchive.add_argument("name", help="Bot name to unarchive")
55
+
48
56
 
49
57
  def dispatch(args: argparse.Namespace) -> None:
50
58
  if not args.bot_command:
51
- print("Usage: culture bot {create|start|stop|list|inspect}", file=sys.stderr)
59
+ print(
60
+ "Usage: culture bot {create|start|stop|list|inspect|archive|unarchive}",
61
+ file=sys.stderr,
62
+ )
52
63
  sys.exit(1)
53
64
 
54
65
  handlers = {
@@ -57,6 +68,8 @@ def dispatch(args: argparse.Namespace) -> None:
57
68
  "stop": _bot_stop,
58
69
  "list": _bot_list,
59
70
  "inspect": _bot_inspect,
71
+ "archive": _bot_archive,
72
+ "unarchive": _bot_unarchive,
60
73
  }
61
74
  handler = handlers.get(args.bot_command)
62
75
  if handler:
@@ -146,6 +159,7 @@ def _bot_list(args: argparse.Namespace) -> None:
146
159
  print("No bots configured.")
147
160
  return
148
161
 
162
+ show_all = getattr(args, "all", False)
149
163
  bots = []
150
164
  for bot_dir in sorted(BOTS_DIR.iterdir()):
151
165
  yaml_path = bot_dir / "bot.yaml"
@@ -155,6 +169,8 @@ def _bot_list(args: argparse.Namespace) -> None:
155
169
  config = load_bot_config(yaml_path)
156
170
  if args.owner and config.owner != args.owner:
157
171
  continue
172
+ if not show_all and config.archived:
173
+ continue
158
174
  bots.append(config)
159
175
  except Exception:
160
176
  continue
@@ -169,7 +185,10 @@ def _bot_list(args: argparse.Namespace) -> None:
169
185
  print(f"{'NAME':<35} {'TRIGGER':<10} {'CHANNELS':<20} {'OWNER':<20}")
170
186
  for config in bots:
171
187
  channels = ", ".join(config.channels) if config.channels else "-"
172
- print(f"{config.name:<35} {config.trigger_type:<10} {channels:<20} {config.owner:<20}")
188
+ name = config.name
189
+ if show_all and config.archived:
190
+ name = f"{name} [archived]"
191
+ print(f"{name:<35} {config.trigger_type:<10} {channels:<20} {config.owner:<20}")
173
192
 
174
193
 
175
194
  def _bot_inspect(args: argparse.Namespace) -> None:
@@ -201,3 +220,61 @@ def _bot_inspect(args: argparse.Namespace) -> None:
201
220
  first_line = first_line[:57] + "..."
202
221
  print(f"Template: {first_line}")
203
222
  print(f"Handler: {'custom (handler.py)' if config.has_handler else 'template'}")
223
+ if config.archived:
224
+ print(f"Archived: yes (since {config.archived_at})")
225
+ if config.archived_reason:
226
+ print(f"Reason: {config.archived_reason}")
227
+
228
+
229
+ # -----------------------------------------------------------------------
230
+ # Archive / Unarchive
231
+ # -----------------------------------------------------------------------
232
+
233
+
234
+ def _bot_archive(args: argparse.Namespace) -> None:
235
+ import time as _time
236
+
237
+ from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
238
+
239
+ bot_dir = BOTS_DIR / args.name
240
+ yaml_path = bot_dir / "bot.yaml"
241
+ if not yaml_path.is_file():
242
+ print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
243
+ sys.exit(1)
244
+
245
+ config = load_bot_config(yaml_path)
246
+ if config.archived:
247
+ print(f"Bot '{args.name}' is already archived")
248
+ return
249
+
250
+ config.archived = True
251
+ config.archived_at = _time.strftime("%Y-%m-%d")
252
+ config.archived_reason = args.reason
253
+ save_bot_config(yaml_path, config)
254
+
255
+ print(f"Bot archived: {args.name}")
256
+ if args.reason:
257
+ print(f" Reason: {args.reason}")
258
+ print(f"\nTo restore: culture bot unarchive {args.name}")
259
+
260
+
261
+ def _bot_unarchive(args: argparse.Namespace) -> None:
262
+ from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
263
+
264
+ bot_dir = BOTS_DIR / args.name
265
+ yaml_path = bot_dir / "bot.yaml"
266
+ if not yaml_path.is_file():
267
+ print(f"Bot '{args.name}' not found at {bot_dir}", file=sys.stderr)
268
+ sys.exit(1)
269
+
270
+ config = load_bot_config(yaml_path)
271
+ if not config.archived:
272
+ print(f"Bot '{args.name}' is not archived", file=sys.stderr)
273
+ sys.exit(1)
274
+
275
+ config.archived = False
276
+ config.archived_at = ""
277
+ config.archived_reason = ""
278
+ save_bot_config(yaml_path, config)
279
+
280
+ print(f"Bot unarchived: {args.name}")
@@ -77,10 +77,34 @@ def register(subparsers: argparse._SubParsersAction) -> None:
77
77
  help="Config file path",
78
78
  )
79
79
 
80
+ srv_archive = server_sub.add_parser(
81
+ "archive", help="Archive the server and all its agents/bots"
82
+ )
83
+ srv_archive.add_argument("--name", default="culture", help="Server name")
84
+ srv_archive.add_argument("--reason", default="", help="Reason for archiving")
85
+ srv_archive.add_argument(
86
+ "--config",
87
+ default=os.path.expanduser("~/.culture/agents.yaml"),
88
+ help="Config file path",
89
+ )
90
+
91
+ srv_unarchive = server_sub.add_parser(
92
+ "unarchive", help="Restore an archived server and all its agents/bots"
93
+ )
94
+ srv_unarchive.add_argument("--name", default="culture", help="Server name")
95
+ srv_unarchive.add_argument(
96
+ "--config",
97
+ default=os.path.expanduser("~/.culture/agents.yaml"),
98
+ help="Config file path",
99
+ )
100
+
80
101
 
81
102
  def dispatch(args: argparse.Namespace) -> None:
82
103
  if not args.server_command:
83
- print("Usage: culture server {start|stop|status|default|rename}", file=sys.stderr)
104
+ print(
105
+ "Usage: culture server {start|stop|status|default|rename|archive|unarchive}",
106
+ file=sys.stderr,
107
+ )
84
108
  sys.exit(1)
85
109
 
86
110
  if args.server_command == "start":
@@ -96,6 +120,10 @@ def dispatch(args: argparse.Namespace) -> None:
96
120
  print(f"Default server set to '{args.name}'")
97
121
  elif args.server_command == "rename":
98
122
  _server_rename(args)
123
+ elif args.server_command == "archive":
124
+ _server_archive(args)
125
+ elif args.server_command == "unarchive":
126
+ _server_unarchive(args)
99
127
 
100
128
 
101
129
  # -----------------------------------------------------------------------
@@ -182,6 +210,19 @@ def _wait_for_port(
182
210
 
183
211
 
184
212
  def _server_start(args: argparse.Namespace) -> None:
213
+ # Check if server is archived
214
+ from culture.clients.claude.config import load_config_or_default
215
+
216
+ config_path = getattr(args, "config", os.path.expanduser("~/.culture/agents.yaml"))
217
+ config = load_config_or_default(config_path)
218
+ if config.server.name == args.name and config.server.archived:
219
+ print(
220
+ f"Server '{args.name}' is archived. Unarchive first:",
221
+ file=sys.stderr,
222
+ )
223
+ print(f" culture server unarchive --name {args.name}", file=sys.stderr)
224
+ sys.exit(1)
225
+
185
226
  pid_name = f"server-{args.name}"
186
227
 
187
228
  existing = read_pid(pid_name)
@@ -363,3 +404,134 @@ def _server_status(args: argparse.Namespace) -> None:
363
404
  else:
364
405
  print(f"Server '{args.name}': not running (stale PID {pid})")
365
406
  remove_pid(pid_name)
407
+
408
+
409
+ # -----------------------------------------------------------------------
410
+ # Archive / Unarchive
411
+ # -----------------------------------------------------------------------
412
+
413
+
414
+ def _server_archive(args: argparse.Namespace) -> None:
415
+ """Archive the server and cascade to all agents and bots."""
416
+ from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
417
+ from culture.clients.claude.config import (
418
+ archive_server,
419
+ load_config_or_default,
420
+ )
421
+
422
+ config = load_config_or_default(args.config)
423
+ server_name = config.server.name
424
+
425
+ if server_name != args.name:
426
+ print(
427
+ f"Server name mismatch: --name '{args.name}' but config has '{server_name}'",
428
+ file=sys.stderr,
429
+ )
430
+ sys.exit(1)
431
+
432
+ if config.server.archived:
433
+ print(f"Server '{server_name}' is already archived")
434
+ return
435
+
436
+ # Stop server if running
437
+ pid_name = f"server-{server_name}"
438
+ pid = read_pid(pid_name)
439
+ if pid and is_process_alive(pid):
440
+ print(f"Stopping server '{server_name}'...")
441
+ _server_stop(args)
442
+
443
+ # Stop all running agents
444
+ from culture.cli._helpers import stop_agent
445
+
446
+ for agent in config.agents:
447
+ agent_pid = read_pid(f"agent-{agent.nick}")
448
+ if agent_pid and is_process_alive(agent_pid):
449
+ stop_agent(agent.nick)
450
+
451
+ # Archive server + agents in config
452
+ archived_nicks = archive_server(args.config, reason=args.reason)
453
+
454
+ # Archive bots whose owner matches any agent on this server
455
+ import time as _time
456
+
457
+ today = _time.strftime("%Y-%m-%d")
458
+ agent_nicks = {a.nick for a in config.agents}
459
+ archived_bots = []
460
+ if BOTS_DIR.is_dir():
461
+ for bot_dir in BOTS_DIR.iterdir():
462
+ yaml_path = bot_dir / "bot.yaml"
463
+ if not yaml_path.is_file():
464
+ continue
465
+ try:
466
+ bot_config = load_bot_config(yaml_path)
467
+ if bot_config.owner in agent_nicks and not bot_config.archived:
468
+ bot_config.archived = True
469
+ bot_config.archived_at = today
470
+ bot_config.archived_reason = args.reason
471
+ save_bot_config(yaml_path, bot_config)
472
+ archived_bots.append(bot_config.name)
473
+ except (OSError, ValueError) as exc:
474
+ print(f" Warning: skipping bot '{bot_dir.name}': {exc}", file=sys.stderr)
475
+ continue
476
+
477
+ print(f"Server archived: {server_name}")
478
+ if args.reason:
479
+ print(f" Reason: {args.reason}")
480
+ if archived_nicks:
481
+ print(f" Agents: {', '.join(archived_nicks)}")
482
+ if archived_bots:
483
+ print(f" Bots: {', '.join(archived_bots)}")
484
+ print(f"\nTo restore: culture server unarchive --name {server_name}")
485
+
486
+
487
+ def _server_unarchive(args: argparse.Namespace) -> None:
488
+ """Restore an archived server and cascade to agents and bots."""
489
+ from culture.bots.config import BOTS_DIR, load_bot_config, save_bot_config
490
+ from culture.clients.claude.config import (
491
+ load_config_or_default,
492
+ unarchive_server,
493
+ )
494
+
495
+ config = load_config_or_default(args.config)
496
+ server_name = config.server.name
497
+
498
+ if server_name != args.name:
499
+ print(
500
+ f"Server name mismatch: --name '{args.name}' but config has '{server_name}'",
501
+ file=sys.stderr,
502
+ )
503
+ sys.exit(1)
504
+
505
+ if not config.server.archived:
506
+ print(f"Server '{server_name}' is not archived", file=sys.stderr)
507
+ sys.exit(1)
508
+
509
+ # Unarchive server + agents
510
+ unarchived_nicks = unarchive_server(args.config)
511
+
512
+ # Unarchive bots whose owner matches any agent on this server
513
+ agent_nicks = {a.nick for a in config.agents}
514
+ unarchived_bots = []
515
+ if BOTS_DIR.is_dir():
516
+ for bot_dir in BOTS_DIR.iterdir():
517
+ yaml_path = bot_dir / "bot.yaml"
518
+ if not yaml_path.is_file():
519
+ continue
520
+ try:
521
+ bot_config = load_bot_config(yaml_path)
522
+ if bot_config.owner in agent_nicks and bot_config.archived:
523
+ bot_config.archived = False
524
+ bot_config.archived_at = ""
525
+ bot_config.archived_reason = ""
526
+ save_bot_config(yaml_path, bot_config)
527
+ unarchived_bots.append(bot_config.name)
528
+ except (OSError, ValueError) as exc:
529
+ print(f" Warning: skipping bot '{bot_dir.name}': {exc}", file=sys.stderr)
530
+ continue
531
+
532
+ print(f"Server unarchived: {server_name}")
533
+ if unarchived_nicks:
534
+ print(f" Agents: {', '.join(unarchived_nicks)}")
535
+ if unarchived_bots:
536
+ print(f" Bots: {', '.join(unarchived_bots)}")
537
+ print(f"\nStart with: culture server start --name {server_name}")