agentirc-cli 1.0.0__tar.gz → 1.0.2__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 (267) hide show
  1. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/publish.yml +0 -10
  2. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/CHANGELOG.md +15 -0
  3. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/PKG-INFO +2 -2
  4. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/README.md +1 -1
  5. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/agent_runner.py +10 -15
  6. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/daemon.py +20 -10
  7. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/irc_transport.py +6 -6
  8. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/skill/irc_client.py +1 -4
  9. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/agent_runner.py +2 -5
  10. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/daemon.py +17 -9
  11. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/irc_transport.py +6 -6
  12. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/skill/irc_client.py +1 -4
  13. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/agent_runner.py +6 -10
  14. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/daemon.py +17 -9
  15. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/irc_transport.py +6 -6
  16. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/skill/irc_client.py +1 -4
  17. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/agent_runner.py +2 -5
  18. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/daemon.py +17 -9
  19. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/irc_transport.py +6 -6
  20. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/skill/irc_client.py +1 -4
  21. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/ircd.py +5 -2
  22. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/daemon.py +8 -6
  23. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/irc_transport.py +6 -6
  24. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/skill/irc_client.py +1 -4
  25. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/pyproject.toml +1 -1
  26. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/uv.lock +1 -1
  27. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.claude/skills/pr-review/SKILL.md +0 -0
  28. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.flake8 +0 -0
  29. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/pages.yml +0 -0
  30. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/security-checks.yml +0 -0
  31. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.github/workflows/tests.yml +0 -0
  32. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.gitignore +0 -0
  33. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.markdownlint-cli2.yaml +0 -0
  34. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.pr_agent.toml +0 -0
  35. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.pre-commit-config.yaml +0 -0
  36. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/.pylintrc +0 -0
  37. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/CLAUDE.md +0 -0
  38. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/CNAME +0 -0
  39. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/Gemfile +0 -0
  40. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/Gemfile.lock +0 -0
  41. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/LICENSE +0 -0
  42. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/SECURITY.md +0 -0
  43. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/_config.yml +0 -0
  44. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/_sass/color_schemes/anthropic.scss +0 -0
  45. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/_sass/custom/custom.scss +0 -0
  46. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/__init__.py +0 -0
  47. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/__main__.py +0 -0
  48. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/__init__.py +0 -0
  49. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/bot.py +0 -0
  50. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/bot_manager.py +0 -0
  51. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/config.py +0 -0
  52. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/http_listener.py +0 -0
  53. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/template_engine.py +0 -0
  54. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/bots/virtual_client.py +0 -0
  55. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/cli.py +0 -0
  56. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/__init__.py +0 -0
  57. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/__init__.py +0 -0
  58. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/config.py +0 -0
  59. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/ipc.py +0 -0
  60. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/message_buffer.py +0 -0
  61. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/skill/SKILL.md +0 -0
  62. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/skill/__init__.py +0 -0
  63. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/socket_server.py +0 -0
  64. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/supervisor.py +0 -0
  65. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/acp/webhook.py +0 -0
  66. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/__init__.py +0 -0
  67. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/__main__.py +0 -0
  68. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/config.py +0 -0
  69. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/ipc.py +0 -0
  70. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/message_buffer.py +0 -0
  71. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/skill/SKILL.md +0 -0
  72. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/skill/__init__.py +0 -0
  73. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/socket_server.py +0 -0
  74. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/supervisor.py +0 -0
  75. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/claude/webhook.py +0 -0
  76. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/__init__.py +0 -0
  77. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/config.py +0 -0
  78. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/ipc.py +0 -0
  79. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/message_buffer.py +0 -0
  80. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/skill/SKILL.md +0 -0
  81. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/skill/__init__.py +0 -0
  82. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/socket_server.py +0 -0
  83. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/supervisor.py +0 -0
  84. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/codex/webhook.py +0 -0
  85. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/__init__.py +0 -0
  86. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/config.py +0 -0
  87. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/ipc.py +0 -0
  88. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/message_buffer.py +0 -0
  89. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/skill/SKILL.md +0 -0
  90. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/skill/__init__.py +0 -0
  91. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/socket_server.py +0 -0
  92. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/supervisor.py +0 -0
  93. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/clients/copilot/webhook.py +0 -0
  94. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/credentials.py +0 -0
  95. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/learn_prompt.py +0 -0
  96. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/mesh_config.py +0 -0
  97. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/observer.py +0 -0
  98. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/__init__.py +0 -0
  99. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/collector.py +0 -0
  100. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/model.py +0 -0
  101. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/renderer_text.py +0 -0
  102. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/renderer_web.py +0 -0
  103. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/overview/web/style.css +0 -0
  104. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/persistence.py +0 -0
  105. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/pidfile.py +0 -0
  106. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/__init__.py +0 -0
  107. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/commands.py +0 -0
  108. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/federation.md +0 -0
  109. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/history.md +0 -0
  110. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/rooms.md +0 -0
  111. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/tags.md +0 -0
  112. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/extensions/threads.md +0 -0
  113. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/message.py +0 -0
  114. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/protocol-index.md +0 -0
  115. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/protocol/replies.py +0 -0
  116. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/__init__.py +0 -0
  117. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/__main__.py +0 -0
  118. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/channel.py +0 -0
  119. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/client.py +0 -0
  120. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/config.py +0 -0
  121. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/remote_client.py +0 -0
  122. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/room_store.py +0 -0
  123. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/rooms_util.py +0 -0
  124. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/server_link.py +0 -0
  125. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skill.py +0 -0
  126. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/__init__.py +0 -0
  127. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/history.py +0 -0
  128. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/rooms.py +0 -0
  129. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/skills/threads.py +0 -0
  130. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/server/thread_store.py +0 -0
  131. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/culture/skills/culture/SKILL.md +0 -0
  132. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/SECURITY.md +0 -0
  133. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/agent-client.md +0 -0
  134. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/agent-harness-spec.md +0 -0
  135. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/agentic-self-learn.md +0 -0
  136. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/bots.md +0 -0
  137. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/ci.md +0 -0
  138. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/cli.md +0 -0
  139. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/acp/overview.md +0 -0
  140. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/configuration.md +0 -0
  141. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/context-management.md +0 -0
  142. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/irc-tools.md +0 -0
  143. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/overview.md +0 -0
  144. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/setup.md +0 -0
  145. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/supervisor.md +0 -0
  146. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/claude/webhooks.md +0 -0
  147. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/configuration.md +0 -0
  148. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/context-management.md +0 -0
  149. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/irc-tools.md +0 -0
  150. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/overview.md +0 -0
  151. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/setup.md +0 -0
  152. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/supervisor.md +0 -0
  153. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/codex/webhooks.md +0 -0
  154. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/configuration.md +0 -0
  155. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/context-management.md +0 -0
  156. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/irc-tools.md +0 -0
  157. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/overview.md +0 -0
  158. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/setup.md +0 -0
  159. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/supervisor.md +0 -0
  160. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/clients/copilot/webhooks.md +0 -0
  161. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/codex-backend.md +0 -0
  162. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/copilot-backend.md +0 -0
  163. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/design.md +0 -0
  164. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/docs-site.md +0 -0
  165. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/getting-started.md +0 -0
  166. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/grow-your-agent.md +0 -0
  167. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/harness-conformance.md +0 -0
  168. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer1-core-irc.md +0 -0
  169. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer2-attention.md +0 -0
  170. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer3-skills.md +0 -0
  171. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer4-federation.md +0 -0
  172. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/layer5-agent-harness.md +0 -0
  173. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/ops-tooling.md +0 -0
  174. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/overview.md +0 -0
  175. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/publishing.md +0 -0
  176. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  177. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/rooms.md +0 -0
  178. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/server-architecture.md +0 -0
  179. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  180. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  181. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  182. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  183. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  184. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  185. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  186. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  187. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  188. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  189. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  190. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  191. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  192. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  193. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  194. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/threads.md +0 -0
  195. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/01-pair-programming.md +0 -0
  196. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/02-code-review-ensemble.md +0 -0
  197. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/03-cross-server-delegation.md +0 -0
  198. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/04-knowledge-propagation.md +0 -0
  199. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/05-the-observer.md +0 -0
  200. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/06-cross-server-ops.md +0 -0
  201. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/07-supervisor-intervention.md +0 -0
  202. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/08-apps-as-agents.md +0 -0
  203. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/09-research-swarm.md +0 -0
  204. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases/10-grow-your-agent.md +0 -0
  205. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/docs/use-cases-index.md +0 -0
  206. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/index.md +0 -0
  207. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/README.md +0 -0
  208. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/config.py +0 -0
  209. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/ipc.py +0 -0
  210. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/message_buffer.py +0 -0
  211. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/skill/SKILL.md +0 -0
  212. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/socket_server.py +0 -0
  213. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/packages/agent-harness/webhook.py +0 -0
  214. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  215. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  216. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  217. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  218. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/sonar-project.properties +0 -0
  219. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/__init__.py +0 -0
  220. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/conftest.py +0 -0
  221. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_acp_daemon.py +0 -0
  222. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_agent_runner.py +0 -0
  223. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bot.py +0 -0
  224. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bot_config.py +0 -0
  225. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bot_manager.py +0 -0
  226. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_bots_integration.py +0 -0
  227. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_channel.py +0 -0
  228. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_codex_daemon.py +0 -0
  229. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_connection.py +0 -0
  230. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_copilot_daemon.py +0 -0
  231. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_daemon.py +0 -0
  232. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_daemon_config.py +0 -0
  233. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_daemon_ipc.py +0 -0
  234. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_discovery.py +0 -0
  235. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_federation.py +0 -0
  236. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_history.py +0 -0
  237. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_http_listener.py +0 -0
  238. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_integration_layer5.py +0 -0
  239. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_ipc.py +0 -0
  240. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_irc_transport.py +0 -0
  241. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_link_reconnect.py +0 -0
  242. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_mentions.py +0 -0
  243. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_mesh_config.py +0 -0
  244. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_message.py +0 -0
  245. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_message_buffer.py +0 -0
  246. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_messaging.py +0 -0
  247. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_modes.py +0 -0
  248. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_cli.py +0 -0
  249. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_collector.py +0 -0
  250. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_model.py +0 -0
  251. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_renderer.py +0 -0
  252. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_overview_web.py +0 -0
  253. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_persistence.py +0 -0
  254. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_room_persistence.py +0 -0
  255. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_rooms.py +0 -0
  256. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_rooms_federation.py +0 -0
  257. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_rooms_integration.py +0 -0
  258. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_setup_update_cli.py +0 -0
  259. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_skill_client.py +0 -0
  260. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_skills.py +0 -0
  261. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_socket_server.py +0 -0
  262. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_supervisor.py +0 -0
  263. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_template_engine.py +0 -0
  264. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_thread_buffer.py +0 -0
  265. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_threads.py +0 -0
  266. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_virtual_client.py +0 -0
  267. {agentirc_cli-1.0.0 → agentirc_cli-1.0.2}/tests/test_webhook.py +0 -0
@@ -55,7 +55,6 @@ jobs:
55
55
  echo "Publishing ${DEV_VERSION} to TestPyPI"
56
56
 
57
57
  - name: Build and publish culture to TestPyPI
58
- continue-on-error: true
59
58
  run: |
60
59
  uv build
61
60
  uv publish --publish-url https://test.pypi.org/legacy/ --trusted-publishing always --check-url https://test.pypi.org/simple/
@@ -100,7 +99,6 @@ jobs:
100
99
  - run: uv sync
101
100
 
102
101
  - name: Build and publish culture to PyPI
103
- continue-on-error: true
104
102
  run: |
105
103
  uv build
106
104
  uv publish --trusted-publishing always --check-url https://pypi.org/simple/
@@ -112,11 +110,3 @@ jobs:
112
110
  rm -rf dist
113
111
  uv build
114
112
  uv publish --trusted-publishing always --check-url https://pypi.org/simple/
115
-
116
- - name: Build and publish agentirc alias to PyPI
117
- run: |
118
- sed -i 's/^name = "agentirc-cli"/name = "agentirc"/' pyproject.toml
119
- sed -i 's/^name = "culture"/name = "agentirc"/' pyproject.toml
120
- rm -rf dist
121
- uv build
122
- uv publish --trusted-publishing always --check-url https://pypi.org/simple/
@@ -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
+ ## [1.0.2] - 2026-04-05
8
+
9
+
10
+ ### Fixed
11
+
12
+ - Re-raise asyncio.CancelledError after cleanup to fix cancellation propagation (SonarCloud S7497)
13
+ - Save asyncio.create_task() results to prevent garbage collection (SonarCloud S7502)
14
+
15
+ ## [1.0.1] - 2026-04-05
16
+
17
+
18
+ ### Fixed
19
+
20
+ - Remove agentirc legacy alias from production PyPI publish pipeline
21
+
7
22
  ## [1.0.0] - 2026-04-05
8
23
 
9
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 1.0.0
3
+ Version: 1.0.2
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
@@ -46,7 +46,7 @@ Claude Code · Codex · Copilot · ACP (Cline, Kiro, OpenCode, Gemini, ...)
46
46
  <br><br>
47
47
  <sub>If you find Culture useful, <a href="https://github.com/OriNachum/culture/stargazers">give it a ⭐</a> — it helps others discover the project.</sub>
48
48
 
49
- <img width="800" alt="Culture" src="https://github.com/user-attachments/assets/41401b9d-1da2-483b-b21f-3769d388f74d" />
49
+ <img width="800" alt="Culture" src="https://github.com/user-attachments/assets/e8e589d2-eb04-47cc-9ae3-5a98d750e36c" />
50
50
 
51
51
  </div>
52
52
 
@@ -23,7 +23,7 @@ Claude Code · Codex · Copilot · ACP (Cline, Kiro, OpenCode, Gemini, ...)
23
23
  <br><br>
24
24
  <sub>If you find Culture useful, <a href="https://github.com/OriNachum/culture/stargazers">give it a ⭐</a> — it helps others discover the project.</sub>
25
25
 
26
- <img width="800" alt="Culture" src="https://github.com/user-attachments/assets/41401b9d-1da2-483b-b21f-3769d388f74d" />
26
+ <img width="800" alt="Culture" src="https://github.com/user-attachments/assets/e8e589d2-eb04-47cc-9ae3-5a98d750e36c" />
27
27
 
28
28
  </div>
29
29
 
@@ -141,24 +141,15 @@ class ACPAgentRunner:
141
141
 
142
142
  if self._task:
143
143
  self._task.cancel()
144
- try:
145
- await self._task
146
- except asyncio.CancelledError:
147
- pass
144
+ await asyncio.gather(self._task, return_exceptions=True)
148
145
 
149
146
  if self._reader_task:
150
147
  self._reader_task.cancel()
151
- try:
152
- await self._reader_task
153
- except asyncio.CancelledError:
154
- pass
148
+ await asyncio.gather(self._reader_task, return_exceptions=True)
155
149
 
156
150
  if self._stderr_task:
157
151
  self._stderr_task.cancel()
158
- try:
159
- await self._stderr_task
160
- except asyncio.CancelledError:
161
- pass
152
+ await asyncio.gather(self._stderr_task, return_exceptions=True)
162
153
 
163
154
  if self._process:
164
155
  try:
@@ -250,7 +241,9 @@ class ACPAgentRunner:
250
241
  elif "method" in msg:
251
242
  await self._handle_notification(msg)
252
243
 
253
- except (asyncio.CancelledError, ConnectionError):
244
+ except asyncio.CancelledError:
245
+ raise
246
+ except ConnectionError:
254
247
  pass
255
248
  except Exception:
256
249
  logger.exception("ACP read loop error")
@@ -295,7 +288,9 @@ class ACPAgentRunner:
295
288
  text = line.decode("utf-8", errors="replace").rstrip()
296
289
  if text:
297
290
  logger.warning("acp[%s] stderr: %s", cmd_name, text)
298
- except (asyncio.CancelledError, ConnectionError):
291
+ except asyncio.CancelledError:
292
+ raise
293
+ except ConnectionError:
299
294
  pass
300
295
 
301
296
  async def _handle_notification(self, msg: dict) -> None:
@@ -381,4 +376,4 @@ class ACPAgentRunner:
381
376
  logger.exception("ACP turn error")
382
377
 
383
378
  except asyncio.CancelledError:
384
- pass
379
+ raise
@@ -82,6 +82,9 @@ class ACPDaemon:
82
82
  self._stop_event: asyncio.Event | None = None
83
83
  self._pid_name: str = ""
84
84
 
85
+ # Background task tracking (prevent GC of fire-and-forget tasks)
86
+ self._background_tasks: set[asyncio.Task] = set()
87
+
85
88
  # ------------------------------------------------------------------
86
89
  # Lifecycle
87
90
  # ------------------------------------------------------------------
@@ -150,7 +153,9 @@ class ACPDaemon:
150
153
  )
151
154
  self._agent_runner = None
152
155
  self._crash_times.append(time.time())
153
- asyncio.create_task(self._delayed_restart())
156
+ task = asyncio.create_task(self._delayed_restart())
157
+ self._background_tasks.add(task)
158
+ task.add_done_callback(self._background_tasks.discard)
154
159
 
155
160
  # 7. Sleep scheduler background task
156
161
  self._sleep_task = asyncio.create_task(self._sleep_scheduler())
@@ -166,10 +171,7 @@ class ACPDaemon:
166
171
  """Cleanly shut down all components."""
167
172
  if hasattr(self, "_sleep_task") and self._sleep_task:
168
173
  self._sleep_task.cancel()
169
- try:
170
- await self._sleep_task
171
- except asyncio.CancelledError:
172
- pass
174
+ await asyncio.gather(self._sleep_task, return_exceptions=True)
173
175
  self._sleep_task = None
174
176
 
175
177
  if self._agent_runner is not None:
@@ -236,7 +238,7 @@ class ACPDaemon:
236
238
  self._paused = False
237
239
  logger.info("Sleep schedule: resuming %s", self.agent.nick)
238
240
  except asyncio.CancelledError:
239
- return
241
+ raise
240
242
  except Exception:
241
243
  logger.exception("Sleep scheduler error")
242
244
 
@@ -303,11 +305,15 @@ class ACPDaemon:
303
305
  prompt = f"[IRC @mention in {target}] <{sender}> {text}"
304
306
  else:
305
307
  prompt = f"[IRC DM] <{sender}> {text}"
306
- asyncio.create_task(self._agent_runner.send_prompt(prompt))
308
+ task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
309
+ self._background_tasks.add(task)
310
+ task.add_done_callback(self._background_tasks.discard)
307
311
 
308
312
  def _on_roominvite(self, channel: str, meta_text: str) -> None:
309
313
  """Called by IRCTransport when a ROOMINVITE is received."""
310
- asyncio.create_task(self._handle_roominvite(channel, meta_text))
314
+ task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
315
+ self._background_tasks.add(task)
316
+ task.add_done_callback(self._background_tasks.discard)
311
317
 
312
318
  async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
313
319
  """Evaluate a room invitation using the agent's LLM."""
@@ -457,7 +463,9 @@ class ACPDaemon:
457
463
  len(self._crash_times),
458
464
  MAX_CRASH_COUNT,
459
465
  )
460
- asyncio.create_task(self._delayed_restart())
466
+ task = asyncio.create_task(self._delayed_restart())
467
+ self._background_tasks.add(task)
468
+ task.add_done_callback(self._background_tasks.discard)
461
469
 
462
470
  async def _delayed_restart(self) -> None:
463
471
  await asyncio.sleep(CRASH_RESTART_DELAY)
@@ -554,7 +562,9 @@ class ACPDaemon:
554
562
  return await self._ipc_irc_thread_read(req_id, msg)
555
563
 
556
564
  elif msg_type == "shutdown":
557
- asyncio.create_task(self._graceful_shutdown())
565
+ task = asyncio.create_task(self._graceful_shutdown())
566
+ self._background_tasks.add(task)
567
+ task.add_done_callback(self._background_tasks.discard)
558
568
  return make_response(req_id, ok=True)
559
569
 
560
570
  else:
@@ -40,6 +40,7 @@ class IRCTransport:
40
40
  self._read_task: asyncio.Task | None = None
41
41
  self._reconnecting = False
42
42
  self._should_run = False
43
+ self._background_tasks: set[asyncio.Task] = set()
43
44
 
44
45
  async def connect(self) -> None:
45
46
  self._should_run = True
@@ -61,10 +62,7 @@ class IRCTransport:
61
62
  self._should_run = False
62
63
  if self._read_task:
63
64
  self._read_task.cancel()
64
- try:
65
- await self._read_task
66
- except asyncio.CancelledError:
67
- pass
65
+ await asyncio.gather(self._read_task, return_exceptions=True)
68
66
  if self._writer:
69
67
  try:
70
68
  await self._send_raw("QUIT :daemon shutdown")
@@ -129,13 +127,15 @@ class IRCTransport:
129
127
  msg = Message.parse(line)
130
128
  await self._handle(msg)
131
129
  except asyncio.CancelledError:
132
- return
130
+ raise
133
131
  except (ConnectionError, OSError):
134
132
  logger.warning("IRC connection lost")
135
133
  finally:
136
134
  self.connected = False
137
135
  if self._should_run and not self._reconnecting:
138
- asyncio.create_task(self._reconnect())
136
+ task = asyncio.create_task(self._reconnect())
137
+ self._background_tasks.add(task)
138
+ task.add_done_callback(self._background_tasks.discard)
139
139
 
140
140
  async def _reconnect(self) -> None:
141
141
  self._reconnecting = True
@@ -49,10 +49,7 @@ class SkillClient:
49
49
  """Close the connection and cancel the background reader."""
50
50
  if self._read_task is not None:
51
51
  self._read_task.cancel()
52
- try:
53
- await self._read_task
54
- except asyncio.CancelledError:
55
- pass
52
+ await asyncio.gather(self._read_task, return_exceptions=True)
56
53
  self._read_task = None
57
54
 
58
55
  if self._writer is not None:
@@ -84,10 +84,7 @@ class AgentRunner:
84
84
  await asyncio.wait_for(asyncio.shield(self._task), timeout=5.0)
85
85
  except (asyncio.TimeoutError, asyncio.CancelledError):
86
86
  self._task.cancel()
87
- try:
88
- await self._task
89
- except asyncio.CancelledError:
90
- pass
87
+ await asyncio.gather(self._task, return_exceptions=True)
91
88
  self._task = None
92
89
 
93
90
  def is_running(self) -> bool:
@@ -149,7 +146,7 @@ class AgentRunner:
149
146
  return
150
147
 
151
148
  except asyncio.CancelledError:
152
- return
149
+ raise
153
150
 
154
151
  # Loop exited normally (stopping flag set)
155
152
  if self.on_exit:
@@ -63,6 +63,9 @@ class AgentDaemon:
63
63
  self._status_query_response: str = ""
64
64
  self._last_activity_text: str = ""
65
65
 
66
+ # Background tasks (prevent GC of fire-and-forget tasks)
67
+ self._background_tasks: set[asyncio.Task] = set()
68
+
66
69
  # Graceful shutdown
67
70
  self._stop_event: asyncio.Event | None = None
68
71
  self._pid_name: str = ""
@@ -134,10 +137,7 @@ class AgentDaemon:
134
137
  """Cleanly shut down all components."""
135
138
  if hasattr(self, "_sleep_task") and self._sleep_task:
136
139
  self._sleep_task.cancel()
137
- try:
138
- await self._sleep_task
139
- except asyncio.CancelledError:
140
- pass
140
+ await asyncio.gather(self._sleep_task, return_exceptions=True)
141
141
  self._sleep_task = None
142
142
 
143
143
  if self._agent_runner is not None:
@@ -204,7 +204,7 @@ class AgentDaemon:
204
204
  self._paused = False
205
205
  logger.info("Sleep schedule: resuming %s", self.agent.nick)
206
206
  except asyncio.CancelledError:
207
- return
207
+ raise
208
208
  except Exception:
209
209
  logger.exception("Sleep scheduler error")
210
210
 
@@ -262,11 +262,15 @@ class AgentDaemon:
262
262
  prompt = f"[IRC @mention in {target}] <{sender}> {text}"
263
263
  else:
264
264
  prompt = f"[IRC DM] <{sender}> {text}"
265
- asyncio.create_task(self._agent_runner.send_prompt(prompt))
265
+ task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
266
+ self._background_tasks.add(task)
267
+ task.add_done_callback(self._background_tasks.discard)
266
268
 
267
269
  def _on_roominvite(self, channel: str, meta_text: str) -> None:
268
270
  """Called by IRCTransport when a ROOMINVITE is received."""
269
- asyncio.create_task(self._handle_roominvite(channel, meta_text))
271
+ task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
272
+ self._background_tasks.add(task)
273
+ task.add_done_callback(self._background_tasks.discard)
270
274
 
271
275
  async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
272
276
  """Evaluate a room invitation using the agent's LLM."""
@@ -403,7 +407,9 @@ class AgentDaemon:
403
407
  len(self._crash_times),
404
408
  MAX_CRASH_COUNT,
405
409
  )
406
- asyncio.create_task(self._delayed_restart())
410
+ task = asyncio.create_task(self._delayed_restart())
411
+ self._background_tasks.add(task)
412
+ task.add_done_callback(self._background_tasks.discard)
407
413
 
408
414
  async def _delayed_restart(self) -> None:
409
415
  await asyncio.sleep(CRASH_RESTART_DELAY)
@@ -492,7 +498,9 @@ class AgentDaemon:
492
498
  return await self._ipc_irc_thread_read(req_id, msg)
493
499
 
494
500
  elif msg_type == "shutdown":
495
- asyncio.create_task(self._graceful_shutdown())
501
+ task = asyncio.create_task(self._graceful_shutdown())
502
+ self._background_tasks.add(task)
503
+ task.add_done_callback(self._background_tasks.discard)
496
504
  return make_response(req_id, ok=True)
497
505
 
498
506
  else:
@@ -40,6 +40,7 @@ class IRCTransport:
40
40
  self._read_task: asyncio.Task | None = None
41
41
  self._reconnecting = False
42
42
  self._should_run = False
43
+ self._background_tasks: set[asyncio.Task] = set()
43
44
 
44
45
  async def connect(self) -> None:
45
46
  self._should_run = True
@@ -61,10 +62,7 @@ class IRCTransport:
61
62
  self._should_run = False
62
63
  if self._read_task:
63
64
  self._read_task.cancel()
64
- try:
65
- await self._read_task
66
- except asyncio.CancelledError:
67
- pass
65
+ await asyncio.gather(self._read_task, return_exceptions=True)
68
66
  if self._writer:
69
67
  try:
70
68
  await self._send_raw("QUIT :daemon shutdown")
@@ -129,13 +127,15 @@ class IRCTransport:
129
127
  msg = Message.parse(line)
130
128
  await self._handle(msg)
131
129
  except asyncio.CancelledError:
132
- return
130
+ raise
133
131
  except (ConnectionError, OSError):
134
132
  logger.warning("IRC connection lost")
135
133
  finally:
136
134
  self.connected = False
137
135
  if self._should_run and not self._reconnecting:
138
- asyncio.create_task(self._reconnect())
136
+ task = asyncio.create_task(self._reconnect())
137
+ self._background_tasks.add(task)
138
+ task.add_done_callback(self._background_tasks.discard)
139
139
 
140
140
  async def _reconnect(self) -> None:
141
141
  self._reconnecting = True
@@ -49,10 +49,7 @@ class SkillClient:
49
49
  """Close the connection and cancel the background reader."""
50
50
  if self._read_task is not None:
51
51
  self._read_task.cancel()
52
- try:
53
- await self._read_task
54
- except asyncio.CancelledError:
55
- pass
52
+ await asyncio.gather(self._read_task, return_exceptions=True)
56
53
  self._read_task = None
57
54
 
58
55
  if self._writer is not None:
@@ -118,17 +118,11 @@ class CodexAgentRunner:
118
118
 
119
119
  if self._task:
120
120
  self._task.cancel()
121
- try:
122
- await self._task
123
- except asyncio.CancelledError:
124
- pass
121
+ await asyncio.gather(self._task, return_exceptions=True)
125
122
 
126
123
  if self._reader_task:
127
124
  self._reader_task.cancel()
128
- try:
129
- await self._reader_task
130
- except asyncio.CancelledError:
131
- pass
125
+ await asyncio.gather(self._reader_task, return_exceptions=True)
132
126
 
133
127
  if self._process:
134
128
  try:
@@ -220,7 +214,9 @@ class CodexAgentRunner:
220
214
  elif "method" in msg:
221
215
  await self._handle_notification(msg)
222
216
 
223
- except (asyncio.CancelledError, ConnectionError):
217
+ except asyncio.CancelledError:
218
+ raise
219
+ except ConnectionError:
224
220
  pass
225
221
  except Exception:
226
222
  logger.exception("Codex read loop error")
@@ -331,4 +327,4 @@ class CodexAgentRunner:
331
327
  logger.exception("Codex turn error")
332
328
 
333
329
  except asyncio.CancelledError:
334
- pass
330
+ raise
@@ -79,6 +79,9 @@ class CodexDaemon:
79
79
  self._stop_event: asyncio.Event | None = None
80
80
  self._pid_name: str = ""
81
81
 
82
+ # Background task tracking (prevent GC of fire-and-forget tasks)
83
+ self._background_tasks: set[asyncio.Task] = set()
84
+
82
85
  # ------------------------------------------------------------------
83
86
  # Lifecycle
84
87
  # ------------------------------------------------------------------
@@ -143,10 +146,7 @@ class CodexDaemon:
143
146
  """Cleanly shut down all components."""
144
147
  if hasattr(self, "_sleep_task") and self._sleep_task:
145
148
  self._sleep_task.cancel()
146
- try:
147
- await self._sleep_task
148
- except asyncio.CancelledError:
149
- pass
149
+ await asyncio.gather(self._sleep_task, return_exceptions=True)
150
150
  self._sleep_task = None
151
151
 
152
152
  if self._agent_runner is not None:
@@ -213,7 +213,7 @@ class CodexDaemon:
213
213
  self._paused = False
214
214
  logger.info("Sleep schedule: resuming %s", self.agent.nick)
215
215
  except asyncio.CancelledError:
216
- return
216
+ raise
217
217
  except Exception:
218
218
  logger.exception("Sleep scheduler error")
219
219
 
@@ -273,11 +273,15 @@ class CodexDaemon:
273
273
  prompt = f"[IRC @mention in {target}] <{sender}> {text}"
274
274
  else:
275
275
  prompt = f"[IRC DM] <{sender}> {text}"
276
- asyncio.create_task(self._agent_runner.send_prompt(prompt))
276
+ task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
277
+ self._background_tasks.add(task)
278
+ task.add_done_callback(self._background_tasks.discard)
277
279
 
278
280
  def _on_roominvite(self, channel: str, meta_text: str) -> None:
279
281
  """Called by IRCTransport when a ROOMINVITE is received."""
280
- asyncio.create_task(self._handle_roominvite(channel, meta_text))
282
+ task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
283
+ self._background_tasks.add(task)
284
+ task.add_done_callback(self._background_tasks.discard)
281
285
 
282
286
  async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
283
287
  """Evaluate a room invitation using the agent's LLM."""
@@ -427,7 +431,9 @@ class CodexDaemon:
427
431
  len(self._crash_times),
428
432
  MAX_CRASH_COUNT,
429
433
  )
430
- asyncio.create_task(self._delayed_restart())
434
+ task = asyncio.create_task(self._delayed_restart())
435
+ self._background_tasks.add(task)
436
+ task.add_done_callback(self._background_tasks.discard)
431
437
 
432
438
  async def _delayed_restart(self) -> None:
433
439
  await asyncio.sleep(CRASH_RESTART_DELAY)
@@ -516,7 +522,9 @@ class CodexDaemon:
516
522
  return await self._ipc_irc_thread_read(req_id, msg)
517
523
 
518
524
  elif msg_type == "shutdown":
519
- asyncio.create_task(self._graceful_shutdown())
525
+ task = asyncio.create_task(self._graceful_shutdown())
526
+ self._background_tasks.add(task)
527
+ task.add_done_callback(self._background_tasks.discard)
520
528
  return make_response(req_id, ok=True)
521
529
 
522
530
  else:
@@ -40,6 +40,7 @@ class IRCTransport:
40
40
  self._read_task: asyncio.Task | None = None
41
41
  self._reconnecting = False
42
42
  self._should_run = False
43
+ self._background_tasks: set[asyncio.Task] = set()
43
44
 
44
45
  async def connect(self) -> None:
45
46
  self._should_run = True
@@ -61,10 +62,7 @@ class IRCTransport:
61
62
  self._should_run = False
62
63
  if self._read_task:
63
64
  self._read_task.cancel()
64
- try:
65
- await self._read_task
66
- except asyncio.CancelledError:
67
- pass
65
+ await asyncio.gather(self._read_task, return_exceptions=True)
68
66
  if self._writer:
69
67
  try:
70
68
  await self._send_raw("QUIT :daemon shutdown")
@@ -129,13 +127,15 @@ class IRCTransport:
129
127
  msg = Message.parse(line)
130
128
  await self._handle(msg)
131
129
  except asyncio.CancelledError:
132
- return
130
+ raise
133
131
  except (ConnectionError, OSError):
134
132
  logger.warning("IRC connection lost")
135
133
  finally:
136
134
  self.connected = False
137
135
  if self._should_run and not self._reconnecting:
138
- asyncio.create_task(self._reconnect())
136
+ task = asyncio.create_task(self._reconnect())
137
+ self._background_tasks.add(task)
138
+ task.add_done_callback(self._background_tasks.discard)
139
139
 
140
140
  async def _reconnect(self) -> None:
141
141
  self._reconnecting = True
@@ -49,10 +49,7 @@ class SkillClient:
49
49
  """Close the connection and cancel the background reader."""
50
50
  if self._read_task is not None:
51
51
  self._read_task.cancel()
52
- try:
53
- await self._read_task
54
- except asyncio.CancelledError:
55
- pass
52
+ await asyncio.gather(self._read_task, return_exceptions=True)
56
53
  self._read_task = None
57
54
 
58
55
  if self._writer is not None:
@@ -107,10 +107,7 @@ class CopilotAgentRunner:
107
107
 
108
108
  if self._task:
109
109
  self._task.cancel()
110
- try:
111
- await self._task
112
- except asyncio.CancelledError:
113
- pass
110
+ await asyncio.gather(self._task, return_exceptions=True)
114
111
  self._task = None
115
112
 
116
113
  if self._session:
@@ -175,7 +172,7 @@ class CopilotAgentRunner:
175
172
  return
176
173
 
177
174
  except asyncio.CancelledError:
178
- pass
175
+ raise
179
176
 
180
177
  if not self._stopping and self.on_exit:
181
178
  await self.on_exit(0)
@@ -75,6 +75,9 @@ class CopilotDaemon:
75
75
  self._status_query_response: str = ""
76
76
  self._last_activity_text: str = ""
77
77
 
78
+ # Background tasks (prevent GC of fire-and-forget tasks)
79
+ self._background_tasks: set[asyncio.Task] = set()
80
+
78
81
  # Graceful shutdown
79
82
  self._stop_event: asyncio.Event | None = None
80
83
  self._pid_name: str = ""
@@ -143,10 +146,7 @@ class CopilotDaemon:
143
146
  """Cleanly shut down all components."""
144
147
  if hasattr(self, "_sleep_task") and self._sleep_task:
145
148
  self._sleep_task.cancel()
146
- try:
147
- await self._sleep_task
148
- except asyncio.CancelledError:
149
- pass
149
+ await asyncio.gather(self._sleep_task, return_exceptions=True)
150
150
  self._sleep_task = None
151
151
 
152
152
  if self._agent_runner is not None:
@@ -213,7 +213,7 @@ class CopilotDaemon:
213
213
  self._paused = False
214
214
  logger.info("Sleep schedule: resuming %s", self.agent.nick)
215
215
  except asyncio.CancelledError:
216
- return
216
+ raise
217
217
  except Exception:
218
218
  logger.exception("Sleep scheduler error")
219
219
 
@@ -280,11 +280,15 @@ class CopilotDaemon:
280
280
  prompt = f"[IRC @mention in {target}] <{sender}> {text}"
281
281
  else:
282
282
  prompt = f"[IRC DM] <{sender}> {text}"
283
- asyncio.create_task(self._agent_runner.send_prompt(prompt))
283
+ task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
284
+ self._background_tasks.add(task)
285
+ task.add_done_callback(self._background_tasks.discard)
284
286
 
285
287
  def _on_roominvite(self, channel: str, meta_text: str) -> None:
286
288
  """Called by IRCTransport when a ROOMINVITE is received."""
287
- asyncio.create_task(self._handle_roominvite(channel, meta_text))
289
+ task = asyncio.create_task(self._handle_roominvite(channel, meta_text))
290
+ self._background_tasks.add(task)
291
+ task.add_done_callback(self._background_tasks.discard)
288
292
 
289
293
  async def _handle_roominvite(self, channel: str, meta_text: str) -> None:
290
294
  """Evaluate a room invitation using the agent's LLM."""
@@ -434,7 +438,9 @@ class CopilotDaemon:
434
438
  len(self._crash_times),
435
439
  MAX_CRASH_COUNT,
436
440
  )
437
- asyncio.create_task(self._delayed_restart())
441
+ task = asyncio.create_task(self._delayed_restart())
442
+ self._background_tasks.add(task)
443
+ task.add_done_callback(self._background_tasks.discard)
438
444
 
439
445
  async def _delayed_restart(self) -> None:
440
446
  await asyncio.sleep(CRASH_RESTART_DELAY)
@@ -523,7 +529,9 @@ class CopilotDaemon:
523
529
  return await self._ipc_irc_thread_read(req_id, msg)
524
530
 
525
531
  elif msg_type == "shutdown":
526
- asyncio.create_task(self._graceful_shutdown())
532
+ task = asyncio.create_task(self._graceful_shutdown())
533
+ self._background_tasks.add(task)
534
+ task.add_done_callback(self._background_tasks.discard)
527
535
  return make_response(req_id, ok=True)
528
536
 
529
537
  else: