agentirc-cli 8.0.0__tar.gz → 8.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/CHANGELOG.md +24 -0
  2. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/PKG-INFO +6 -1
  3. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/_config.culture.yml +3 -0
  4. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/_data/sites.yml +1 -0
  5. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/_includes/head_custom.html +1 -0
  6. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/client.py +200 -74
  7. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/config.py +15 -0
  8. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/ircd.py +49 -20
  9. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/__init__.py +3 -2
  10. agentirc_cli-8.2.0/culture/cli/_passthrough.py +116 -0
  11. agentirc_cli-8.2.0/culture/cli/afi.py +71 -0
  12. agentirc_cli-8.2.0/culture/cli/devex.py +71 -0
  13. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/config.py +10 -0
  14. agentirc_cli-8.2.0/culture/protocol/extensions/tracing.md +31 -0
  15. agentirc_cli-8.2.0/culture/telemetry/__init__.py +22 -0
  16. agentirc_cli-8.2.0/culture/telemetry/context.py +84 -0
  17. agentirc_cli-8.2.0/culture/telemetry/tracing.py +114 -0
  18. agentirc_cli-8.2.0/docs/agentirc/otelcol-template.yaml +25 -0
  19. agentirc_cli-8.2.0/docs/agentirc/telemetry.md +81 -0
  20. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/features.md +1 -1
  21. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/vision.md +8 -8
  22. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/what-is-culture.md +5 -4
  23. agentirc_cli-8.2.0/docs/reference/architecture/index.md +27 -0
  24. agentirc_cli-8.2.0/docs/reference/architecture/subsites.md +111 -0
  25. agentirc_cli-8.2.0/docs/reference/cli/afi.md +95 -0
  26. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/cli/devex.md +5 -6
  27. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/cli/index.md +10 -6
  28. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/server/config.md +26 -0
  29. agentirc_cli-8.2.0/docs/superpowers/plans/2026-04-24-otel-foundation.md +2159 -0
  30. agentirc_cli-8.2.0/docs/superpowers/specs/2026-04-24-otel-observability-design.md +334 -0
  31. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/pyproject.toml +6 -1
  32. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/sitemap.html +1 -0
  33. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/conftest.py +26 -0
  34. agentirc_cli-8.2.0/tests/telemetry/__init__.py +0 -0
  35. agentirc_cli-8.2.0/tests/telemetry/_fakes.py +26 -0
  36. agentirc_cli-8.2.0/tests/telemetry/test_config.py +26 -0
  37. agentirc_cli-8.2.0/tests/telemetry/test_config_load.py +36 -0
  38. agentirc_cli-8.2.0/tests/telemetry/test_context.py +105 -0
  39. agentirc_cli-8.2.0/tests/telemetry/test_dispatch_span.py +45 -0
  40. agentirc_cli-8.2.0/tests/telemetry/test_emit_event_span.py +42 -0
  41. agentirc_cli-8.2.0/tests/telemetry/test_outbound_inject.py +70 -0
  42. agentirc_cli-8.2.0/tests/telemetry/test_parse_error.py +33 -0
  43. agentirc_cli-8.2.0/tests/telemetry/test_privmsg_span.py +45 -0
  44. agentirc_cli-8.2.0/tests/telemetry/test_server_init.py +29 -0
  45. agentirc_cli-8.2.0/tests/telemetry/test_tracing.py +49 -0
  46. agentirc_cli-8.2.0/tests/test_cli_afi.py +111 -0
  47. agentirc_cli-8.2.0/tests/test_cli_passthrough.py +146 -0
  48. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/uv.lock +196 -1
  49. agentirc_cli-8.0.0/culture/cli/devex.py +0 -111
  50. agentirc_cli-8.0.0/docs/reference/architecture/index.md +0 -13
  51. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.claude/agents/doc-test-alignment.md +0 -0
  52. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.claude/skills/pr-review/SKILL.md +0 -0
  53. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.claude/skills/run-tests/SKILL.md +0 -0
  54. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
  55. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.flake8 +0 -0
  56. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.github/workflows/docs-check.yml +0 -0
  57. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.github/workflows/publish.yml +0 -0
  58. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.github/workflows/security-checks.yml +0 -0
  59. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.github/workflows/tests.yml +0 -0
  60. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.gitignore +0 -0
  61. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.markdownlint-cli2.yaml +0 -0
  62. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.pr_agent.toml +0 -0
  63. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.pre-commit-config.yaml +0 -0
  64. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/.pylintrc +0 -0
  65. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/CLAUDE.md +0 -0
  66. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/Gemfile +0 -0
  67. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/Gemfile.lock +0 -0
  68. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/LICENSE +0 -0
  69. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/README.md +0 -0
  70. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/SECURITY.md +0 -0
  71. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/_config.base.yml +0 -0
  72. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/_sass/color_schemes/anthropic.scss +0 -0
  73. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/_sass/color_schemes/dark-terminal.scss +0 -0
  74. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/_sass/custom/custom.scss +0 -0
  75. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/assets/images/IMG_3183.png +0 -0
  76. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/assets/images/apple-touch-icon.png +0 -0
  77. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/assets/images/favicon-16x16.png +0 -0
  78. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/assets/images/favicon-32x32.png +0 -0
  79. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/assets/images/favicon.ico +0 -0
  80. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/assets/images/og-agentirc.png +0 -0
  81. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/assets/images/og-culture.png +0 -0
  82. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/__init__.py +0 -0
  83. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/__main__.py +0 -0
  84. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/CLAUDE.md +0 -0
  85. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/__init__.py +0 -0
  86. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/__main__.py +0 -0
  87. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/channel.py +0 -0
  88. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/docs/agentirc-architecture.md +0 -0
  89. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/docs/agentirc-features.md +0 -0
  90. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/docs/agentirc-skill.md +0 -0
  91. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/docs/agentirc.md +0 -0
  92. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/events.py +0 -0
  93. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/history_store.py +0 -0
  94. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/remote_client.py +0 -0
  95. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/room_store.py +0 -0
  96. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/rooms_util.py +0 -0
  97. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/server_link.py +0 -0
  98. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/skill.py +0 -0
  99. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/skills/__init__.py +0 -0
  100. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/skills/history.py +0 -0
  101. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/skills/icon.py +0 -0
  102. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/skills/rooms.py +0 -0
  103. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/skills/threads.py +0 -0
  104. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/agentirc/thread_store.py +0 -0
  105. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/aio.py +0 -0
  106. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/__init__.py +0 -0
  107. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/bot.py +0 -0
  108. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/bot_manager.py +0 -0
  109. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/config.py +0 -0
  110. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/filter_dsl.py +0 -0
  111. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/http_listener.py +0 -0
  112. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/system/__init__.py +0 -0
  113. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/system/welcome/__init__.py +0 -0
  114. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/system/welcome/bot.yaml +0 -0
  115. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/system/welcome/handler.py +0 -0
  116. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/template_engine.py +0 -0
  117. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/bots/virtual_client.py +0 -0
  118. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/agent.py +0 -0
  119. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/bot.py +0 -0
  120. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/channel.py +0 -0
  121. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/introspect.py +0 -0
  122. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/mesh.py +0 -0
  123. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/server.py +0 -0
  124. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/shared/__init__.py +0 -0
  125. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/shared/constants.py +0 -0
  126. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/shared/display.py +0 -0
  127. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/shared/formatting.py +0 -0
  128. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/shared/ipc.py +0 -0
  129. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/shared/mesh.py +0 -0
  130. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/shared/process.py +0 -0
  131. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/cli/skills.py +0 -0
  132. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/__init__.py +0 -0
  133. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/__init__.py +0 -0
  134. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/agent_runner.py +0 -0
  135. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/config.py +0 -0
  136. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/culture.yaml +0 -0
  137. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/daemon.py +0 -0
  138. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/ipc.py +0 -0
  139. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/irc_transport.py +0 -0
  140. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/message_buffer.py +0 -0
  141. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/skill/SKILL.md +0 -0
  142. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/skill/__init__.py +0 -0
  143. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/skill/irc_client.py +0 -0
  144. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/socket_server.py +0 -0
  145. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/supervisor.py +0 -0
  146. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/acp/webhook.py +0 -0
  147. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/__init__.py +0 -0
  148. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/__main__.py +0 -0
  149. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/agent_runner.py +0 -0
  150. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/config.py +0 -0
  151. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/culture.yaml +0 -0
  152. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/daemon.py +0 -0
  153. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/ipc.py +0 -0
  154. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/irc_transport.py +0 -0
  155. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/message_buffer.py +0 -0
  156. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/skill/SKILL.md +0 -0
  157. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/skill/__init__.py +0 -0
  158. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/skill/irc_client.py +0 -0
  159. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/socket_server.py +0 -0
  160. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/supervisor.py +0 -0
  161. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/claude/webhook.py +0 -0
  162. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/__init__.py +0 -0
  163. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/agent_runner.py +0 -0
  164. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/config.py +0 -0
  165. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/culture.yaml +0 -0
  166. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/daemon.py +0 -0
  167. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/ipc.py +0 -0
  168. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/irc_transport.py +0 -0
  169. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/message_buffer.py +0 -0
  170. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/skill/SKILL.md +0 -0
  171. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/skill/__init__.py +0 -0
  172. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/skill/irc_client.py +0 -0
  173. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/socket_server.py +0 -0
  174. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/supervisor.py +0 -0
  175. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/codex/webhook.py +0 -0
  176. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/__init__.py +0 -0
  177. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/agent_runner.py +0 -0
  178. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/config.py +0 -0
  179. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/culture.yaml +0 -0
  180. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/daemon.py +0 -0
  181. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/ipc.py +0 -0
  182. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/irc_transport.py +0 -0
  183. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/message_buffer.py +0 -0
  184. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/skill/SKILL.md +0 -0
  185. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/skill/__init__.py +0 -0
  186. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/skill/irc_client.py +0 -0
  187. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/socket_server.py +0 -0
  188. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/supervisor.py +0 -0
  189. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/clients/copilot/webhook.py +0 -0
  190. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/__init__.py +0 -0
  191. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/app.py +0 -0
  192. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/client.py +0 -0
  193. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/commands.py +0 -0
  194. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/status.py +0 -0
  195. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/widgets/__init__.py +0 -0
  196. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/widgets/chat.py +0 -0
  197. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/widgets/info_panel.py +0 -0
  198. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/console/widgets/sidebar.py +0 -0
  199. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/constants.py +0 -0
  200. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/credentials.py +0 -0
  201. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/formatting.py +0 -0
  202. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/learn_prompt.py +0 -0
  203. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/mesh_config.py +0 -0
  204. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/observer.py +0 -0
  205. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/overview/__init__.py +0 -0
  206. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/overview/collector.py +0 -0
  207. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/overview/model.py +0 -0
  208. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/overview/renderer_text.py +0 -0
  209. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/overview/renderer_web.py +0 -0
  210. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/overview/web/style.css +0 -0
  211. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/persistence.py +0 -0
  212. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/pidfile.py +0 -0
  213. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/__init__.py +0 -0
  214. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/commands.py +0 -0
  215. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/extensions/events.md +0 -0
  216. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/extensions/federation.md +0 -0
  217. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/extensions/history.md +0 -0
  218. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/extensions/icons.md +0 -0
  219. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/extensions/rooms.md +0 -0
  220. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/extensions/tags.md +0 -0
  221. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/extensions/threads.md +0 -0
  222. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/message.py +0 -0
  223. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/protocol-index.md +0 -0
  224. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/protocol/replies.py +0 -0
  225. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/culture/skills/culture/SKILL.md +0 -0
  226. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/README.md +0 -0
  227. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/agentirc/architecture-overview.md +0 -0
  228. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/agentirc/bots.md +0 -0
  229. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/agentirc/events.md +0 -0
  230. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/agentirc/index.md +0 -0
  231. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/agentirc/why-agentirc.md +0 -0
  232. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/agent-lifecycle.md +0 -0
  233. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/choose-a-harness.md +0 -0
  234. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/index.md +0 -0
  235. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/mental-model.md +0 -0
  236. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/operate.md +0 -0
  237. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/patterns.md +0 -0
  238. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/quickstart.md +0 -0
  239. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/reflective-development.md +0 -0
  240. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/culture/vision-patterns-index.md +0 -0
  241. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/architecture/agent-harness-spec.md +0 -0
  242. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/architecture/layers.md +0 -0
  243. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/architecture/threads.md +0 -0
  244. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/cli/commands.md +0 -0
  245. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/console.md +0 -0
  246. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/harnesses/acp.md +0 -0
  247. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/harnesses/claude.md +0 -0
  248. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/harnesses/codex.md +0 -0
  249. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/harnesses/copilot.md +0 -0
  250. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/harnesses/index.md +0 -0
  251. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/index.md +0 -0
  252. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/server/architecture.md +0 -0
  253. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/server/deployment.md +0 -0
  254. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/server/index.md +0 -0
  255. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/reference/server/security.md +0 -0
  256. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  257. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/resources/positioning.md +0 -0
  258. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/concepts/federation.md +0 -0
  259. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/concepts/harnesses.md +0 -0
  260. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/concepts/humans-and-agents.md +0 -0
  261. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/concepts/index.md +0 -0
  262. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/concepts/persistence.md +0 -0
  263. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/concepts/rooms.md +0 -0
  264. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/demos/magic-demo.md +0 -0
  265. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/guides/first-session.md +0 -0
  266. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/guides/index.md +0 -0
  267. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/guides/join-as-human.md +0 -0
  268. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/guides/local-setup.md +0 -0
  269. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/guides/multi-machine.md +0 -0
  270. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/01-pair-programming.md +0 -0
  271. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/02-code-review-ensemble.md +0 -0
  272. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/03-cross-server-delegation.md +0 -0
  273. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/04-knowledge-propagation.md +0 -0
  274. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/05-the-observer.md +0 -0
  275. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/06-cross-server-ops.md +0 -0
  276. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/07-supervisor-intervention.md +0 -0
  277. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/08-apps-as-agents.md +0 -0
  278. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/09-research-swarm.md +0 -0
  279. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases/10-agent-lifecycle.md +0 -0
  280. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/shared/use-cases-index.md +0 -0
  281. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  282. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  283. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  284. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  285. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  286. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  287. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  288. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  289. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  290. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-09-decentralized-agent-config.md +0 -0
  291. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-12-console-enhancements.md +0 -0
  292. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-15-mesh-events.md +0 -0
  293. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-18-culture-dev-positioning.md +0 -0
  294. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/plans/2026-04-22-agex-integration.md +0 -0
  295. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  296. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  297. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  298. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  299. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  300. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  301. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  302. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  303. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  304. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  305. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
  306. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  307. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
  308. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-07-reflective-development-reframe-design.md +0 -0
  309. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-08-reflective-development-deepening-design.md +0 -0
  310. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-09-decentralized-agent-config-design.md +0 -0
  311. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-12-console-enhancements-design.md +0 -0
  312. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-15-mesh-events-design.md +0 -0
  313. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-17-sites-repositioning-design.md +0 -0
  314. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-18-culture-dev-positioning-design.md +0 -0
  315. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/docs/superpowers/specs/2026-04-22-agex-integration-design.md +0 -0
  316. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/favicon.ico +0 -0
  317. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/README.md +0 -0
  318. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/config.py +0 -0
  319. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/culture.yaml +0 -0
  320. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/daemon.py +0 -0
  321. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/ipc.py +0 -0
  322. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/irc_transport.py +0 -0
  323. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/message_buffer.py +0 -0
  324. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/skill/SKILL.md +0 -0
  325. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/skill/irc_client.py +0 -0
  326. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/socket_server.py +0 -0
  327. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/packages/agent-harness/webhook.py +0 -0
  328. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  329. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  330. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  331. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  332. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/robots.txt +0 -0
  333. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/sitemap-agentirc.html +0 -0
  334. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/sitemap-main.html +0 -0
  335. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/sonar-project.properties +0 -0
  336. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/__init__.py +0 -0
  337. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_acp_daemon.py +0 -0
  338. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_agent_runner.py +0 -0
  339. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_archive.py +0 -0
  340. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_bot.py +0 -0
  341. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_bot_config.py +0 -0
  342. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_bot_config_fires_event_toplevel.py +0 -0
  343. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_bot_manager.py +0 -0
  344. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_bots_integration.py +0 -0
  345. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_channel.py +0 -0
  346. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_channel_cli.py +0 -0
  347. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_cli_devex.py +0 -0
  348. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_cli_introspect.py +0 -0
  349. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_codex_daemon.py +0 -0
  350. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_connection.py +0 -0
  351. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_chat_markdown.py +0 -0
  352. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_client.py +0 -0
  353. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_commands.py +0 -0
  354. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_connection.py +0 -0
  355. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_fixes_224_227.py +0 -0
  356. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_icons.py +0 -0
  357. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_integration.py +0 -0
  358. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_console_status.py +0 -0
  359. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_copilot_daemon.py +0 -0
  360. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_credentials.py +0 -0
  361. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_culture_config.py +0 -0
  362. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_daemon.py +0 -0
  363. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_daemon_config.py +0 -0
  364. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_daemon_ipc.py +0 -0
  365. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_discovery.py +0 -0
  366. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_display.py +0 -0
  367. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_basic.py +0 -0
  368. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_bot_chain.py +0 -0
  369. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_bot_trigger.py +0 -0
  370. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_cap_fallback.py +0 -0
  371. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_catalog.py +0 -0
  372. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_federation.py +0 -0
  373. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_history.py +0 -0
  374. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_lifecycle.py +0 -0
  375. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_events_reserved_nick.py +0 -0
  376. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_federation.py +0 -0
  377. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_filter_dsl.py +0 -0
  378. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_history.py +0 -0
  379. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_http_listener.py +0 -0
  380. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_integration_layer5.py +0 -0
  381. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_ipc.py +0 -0
  382. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_irc_transport.py +0 -0
  383. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_irc_transport_tags.py +0 -0
  384. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_learn_prompt.py +0 -0
  385. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_link_reconnect.py +0 -0
  386. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_manifest_config.py +0 -0
  387. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_mention_alias.py +0 -0
  388. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_mention_target_cleanup.py +0 -0
  389. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_mention_warning.py +0 -0
  390. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_mentions.py +0 -0
  391. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_mesh_config.py +0 -0
  392. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_mesh_readiness.py +0 -0
  393. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_message.py +0 -0
  394. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_message_buffer.py +0 -0
  395. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_message_tags.py +0 -0
  396. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_messaging.py +0 -0
  397. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_migrate_cli.py +0 -0
  398. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_modes.py +0 -0
  399. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_overview_cli.py +0 -0
  400. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_overview_collector.py +0 -0
  401. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_overview_model.py +0 -0
  402. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_overview_renderer.py +0 -0
  403. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_overview_web.py +0 -0
  404. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_persistence.py +0 -0
  405. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_persistence_timeout.py +0 -0
  406. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_pidfile.py +0 -0
  407. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_poll_loop.py +0 -0
  408. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_register_cli.py +0 -0
  409. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_room_persistence.py +0 -0
  410. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_rooms.py +0 -0
  411. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_rooms_federation.py +0 -0
  412. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_rooms_integration.py +0 -0
  413. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_server_icon_skill.py +0 -0
  414. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_setup_update_cli.py +0 -0
  415. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_skill_client.py +0 -0
  416. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_skill_docs.py +0 -0
  417. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_skills.py +0 -0
  418. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_socket_server.py +0 -0
  419. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_supervisor.py +0 -0
  420. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_template_engine.py +0 -0
  421. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_thread_buffer.py +0 -0
  422. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_threads.py +0 -0
  423. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_virtual_client.py +0 -0
  424. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_wait_for_port.py +0 -0
  425. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_webhook.py +0 -0
  426. {agentirc_cli-8.0.0 → agentirc_cli-8.2.0}/tests/test_welcome_bot.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
+ ## [8.2.0] - 2026-04-24
8
+
9
+ ### Added
10
+
11
+ - OpenTelemetry foundation: `culture/telemetry/` package with TracerProvider bootstrap, W3C trace context extract/inject helpers for IRCv3 tags, and `TelemetryConfig` block in `server.yaml`.
12
+ - Protocol extension: `culture.dev/traceparent` and `culture.dev/tracestate` IRCv3 tags (`culture/protocol/extensions/tracing.md`).
13
+ - Server-side tracing: `IRCd.emit_event`, `Client._dispatch`, `Client._process_buffer` (with parse-error compensation), and PRIVMSG dispatch/delivery paths now emit spans.
14
+ - Outbound traceparent injection on `Client.send` and `Client.send_raw` when a span is active.
15
+ - Operator docs at `docs/agentirc/telemetry.md` and starter collector config at `docs/agentirc/otelcol-template.yaml`; `docs/reference/server/config.md` documents the new `telemetry` block.
16
+ - Dependencies: `opentelemetry-api`, `opentelemetry-sdk`, `opentelemetry-exporter-otlp-proto-grpc`, `opentelemetry-semantic-conventions`.
17
+
18
+ ## [8.1.0] - 2026-04-23
19
+
20
+ ### Added
21
+
22
+ - `culture afi` namespace — passthrough to the standalone `afi-cli` (Agent First Interface scaffolder) with argparse-REMAINDER argument forwarding, parallel to `culture devex`.
23
+ - Universal verbs register the `afi` topic; `culture explain afi` / `culture overview afi` / `culture learn afi` all route through `afi-cli` 0.3+ and `culture explain` no longer marks `culture afi` as coming-soon.
24
+ - `afi-cli>=0.3,<1.0` as a library dependency (0.3 added the `overview` verb + sixth rubric bundle per agentculture/afi-cli#5).
25
+ - `culture/cli/_passthrough.py` — shared plumbing for `culture <ext>` subcommands that embed a sibling CLI. Supplies `run()`, `capture()`, and `register_topic()` so each passthrough module stays a thin adapter.
26
+
27
+ ### Changed
28
+
29
+ - `culture/cli/devex.py` refactored onto the new shared passthrough helper. Behaviour is preserved (explain/overview/learn argv and typer app invocation unchanged); the module shrinks to a package-specific entry adapter and a single `register_topic` call. When agex-cli adopts the agent-first CLI contract (`main(argv) -> int`, tracking: agentculture/agex-cli#30), the adapter collapses to a direct delegation.
30
+
7
31
  ## [8.0.0] - 2026-04-22
8
32
 
9
33
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 8.0.0
3
+ Version: 8.2.0
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
@@ -12,11 +12,16 @@ Classifier: License :: OSI Approved :: MIT License
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Topic :: Communications :: Chat :: Internet Relay Chat
14
14
  Requires-Python: >=3.12
15
+ Requires-Dist: afi-cli<1.0,>=0.3
15
16
  Requires-Dist: agex-cli<1.0,>=0.13
16
17
  Requires-Dist: aiohttp>=3.9
17
18
  Requires-Dist: anthropic>=0.40
18
19
  Requires-Dist: claude-agent-sdk>=0.1
19
20
  Requires-Dist: mistune>=3.0
21
+ Requires-Dist: opentelemetry-api>=1.25
22
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25
23
+ Requires-Dist: opentelemetry-sdk>=1.25
24
+ Requires-Dist: opentelemetry-semantic-conventions>=0.46b0
20
25
  Requires-Dist: pyyaml>=6.0
21
26
  Requires-Dist: textual>=1.0
22
27
  Provides-Extra: copilot
@@ -36,6 +36,8 @@ aux_links:
36
36
  - "/agentirc/"
37
37
  "Agent Experience":
38
38
  - "https://culture.dev/agex/"
39
+ "Agent First Interop":
40
+ - "https://culture.dev/afi/"
39
41
  "Citation CLI":
40
42
  - "/citation-cli/"
41
43
  "GitHub":
@@ -49,5 +51,6 @@ footer_content: >-
49
51
  Inspectable CLI via <a href="/reference/cli/devex/">culture devex</a>
50
52
  (explain / overview / learn at every level).
51
53
  Agent Experience via <a href="https://culture.dev/agex/">agex-cli</a>.
54
+ Agent First Interop via <a href="https://culture.dev/afi/">afi-cli</a>.
52
55
  Code distribution via <a href="/citation-cli/">Citation CLI</a>.
53
56
  Source on <a href="https://github.com/agentculture/culture">GitHub</a>.
@@ -1,3 +1,4 @@
1
+ afi: https://culture.dev/afi/
1
2
  agentirc: https://culture.dev/agentirc/
2
3
  agex: https://culture.dev/agex/
3
4
  citation_cli: https://culture.dev/citation-cli/
@@ -4,4 +4,5 @@
4
4
  <link rel="icon" type="image/png" sizes="16x16" href="{{ '/assets/images/favicon-16x16.png' | relative_url }}">
5
5
  <link rel="apple-touch-icon" sizes="180x180" href="{{ '/assets/images/apple-touch-icon.png' | relative_url }}">
6
6
  <link rel="related" href="{{ site.data.sites.agex }}" title="Agent Experience">
7
+ <link rel="related" href="{{ site.data.sites.afi }}" title="Agent First Interop">
7
8
  <link rel="related" href="{{ site.data.sites.citation_cli }}" title="Citation CLI">
@@ -6,12 +6,59 @@ import logging
6
6
  import re
7
7
  from typing import TYPE_CHECKING
8
8
 
9
+ from opentelemetry import trace as _otel_trace
10
+ from opentelemetry.trace import NonRecordingSpan, SpanContext, TraceFlags
11
+ from opentelemetry.trace.propagation import set_span_in_context
12
+
9
13
  from culture.agentirc.channel import Channel
10
14
  from culture.agentirc.skill import Event, EventType
11
15
  from culture.aio import maybe_await
12
16
  from culture.constants import SYSTEM_USER_PREFIX
13
17
  from culture.protocol import replies
14
18
  from culture.protocol.message import Message
19
+ from culture.telemetry.context import TRACEPARENT_TAG as _TP_TAG_NAME
20
+ from culture.telemetry.context import (
21
+ extract_traceparent_from_tags,
22
+ )
23
+ from culture.telemetry.context import inject_traceparent as _inject_traceparent
24
+
25
+ # OTEL instrumentation name (must match `_CULTURE_TRACER_NAME` in
26
+ # culture/telemetry/tracing.py so trace consumers see one consistent value).
27
+ _TRACER_NAME = "culture.agentirc"
28
+ # Span attribute keys for PRIVMSG body capture, defined once so a future
29
+ # rename / sanitization layer has one edit point.
30
+ _ATTR_BODY = "irc.message.body"
31
+ _ATTR_SIZE = "irc.message.size"
32
+
33
+
34
+ def _context_from_traceparent(tp: str):
35
+ """Build an OTEL context whose current span is a NonRecordingSpan
36
+ synthesized from a W3C traceparent string. The `_dispatch` span we
37
+ start next will be a child of this context."""
38
+ # Format: 00-<trace-id>-<parent-id>-<flags>
39
+ _, trace_hex, parent_hex, flags_hex = tp.split("-")
40
+ span_ctx = SpanContext(
41
+ trace_id=int(trace_hex, 16),
42
+ span_id=int(parent_hex, 16),
43
+ is_remote=True,
44
+ trace_flags=TraceFlags(int(flags_hex, 16)),
45
+ )
46
+ return set_span_in_context(NonRecordingSpan(span_ctx))
47
+
48
+
49
+ def _current_traceparent() -> str | None:
50
+ """Return the W3C traceparent for the currently-active span, or None
51
+ if no span is recording (no-op tracer / sampler dropped).
52
+ """
53
+ span = _otel_trace.get_current_span()
54
+ ctx = span.get_span_context()
55
+ if not ctx.is_valid:
56
+ return None
57
+ return (
58
+ f"00-{format(ctx.trace_id, '032x')}-{format(ctx.span_id, '016x')}"
59
+ f"-{format(int(ctx.trace_flags), '02x')}"
60
+ )
61
+
15
62
 
16
63
  if TYPE_CHECKING:
17
64
  from culture.agentirc.ircd import IRCd
@@ -45,6 +92,14 @@ class Client:
45
92
  return f"{self.nick}!{self.user}@{self.host}"
46
93
 
47
94
  async def send(self, message: Message) -> None:
95
+ # Only inject trace context for clients that negotiated IRCv3
96
+ # message-tags; otherwise older clients would see an unexpected @-tag
97
+ # block and `send_tagged`'s tag-stripping for non-capable clients
98
+ # would be undone here.
99
+ if "message-tags" in self.caps:
100
+ tp = _current_traceparent()
101
+ if tp is not None:
102
+ _inject_traceparent(message, traceparent=tp, tracestate=None)
48
103
  try:
49
104
  self.writer.write(message.format().encode("utf-8"))
50
105
  await self.writer.drain()
@@ -55,7 +110,15 @@ class Client:
55
110
  """Write a pre-formatted IRC line to the client socket.
56
111
 
57
112
  Appends CRLF internally, matching ServerLink.send_raw convention.
113
+ Injects `culture.dev/traceparent` as an IRCv3 tag when a span is active
114
+ AND the client negotiated the `message-tags` capability.
58
115
  """
116
+ if "message-tags" in self.caps:
117
+ tp = _current_traceparent()
118
+ if tp is not None:
119
+ # send_raw takes a pre-formatted line without an existing tag
120
+ # block; prefix a fresh @tag.
121
+ line = f"@{_TP_TAG_NAME}={tp} {line}"
59
122
  try:
60
123
  self.writer.write(f"{line}\r\n".encode("utf-8"))
61
124
  await self.writer.drain()
@@ -84,13 +147,28 @@ class Client:
84
147
 
85
148
  async def _process_buffer(self, buffer: str) -> str:
86
149
  """Parse and dispatch all complete lines from buffer, return remainder."""
87
- while "\n" in buffer:
88
- line, buffer = buffer.split("\n", 1)
89
- if line.strip():
90
- msg = Message.parse(line)
150
+ # Per-call get_tracer: test fixture swaps provider between tests.
151
+ with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
152
+ "irc.client.process_buffer"
153
+ ) as span:
154
+ while "\n" in buffer:
155
+ line, buffer = buffer.split("\n", 1)
156
+ if not line.strip():
157
+ continue
158
+ try:
159
+ msg = Message.parse(line)
160
+ except Exception as exc: # noqa: BLE001 -- widen for any parser failure
161
+ span.add_event(
162
+ "irc.parse_error",
163
+ attributes={
164
+ "line_preview": line[:64],
165
+ "error": type(exc).__name__,
166
+ },
167
+ )
168
+ continue
91
169
  if msg.command:
92
170
  await self._dispatch(msg)
93
- return buffer
171
+ return buffer
94
172
 
95
173
  async def handle(self, initial_msg: str | None = None) -> None:
96
174
  buffer = ""
@@ -110,20 +188,41 @@ class Client:
110
188
  buffer = await self._process_buffer(buffer)
111
189
 
112
190
  async def _dispatch(self, msg: Message) -> None:
113
- handler = getattr(self, f"_handle_{msg.command.lower()}", None)
114
- if handler:
115
- await maybe_await(handler(msg))
116
- else:
117
- skill = self.server.get_skill_for_command(msg.command)
118
- if skill and self._registered:
119
- try:
120
- await skill.on_command(self, msg)
121
- except Exception:
122
- logging.getLogger(__name__).exception(
123
- "Skill %s failed on command %s", skill.name, msg.command
124
- )
191
+ extract = extract_traceparent_from_tags(msg, peer=None)
192
+ parent_ctx = None
193
+ if extract.status == "valid":
194
+ parent_ctx = _context_from_traceparent(extract.traceparent)
195
+
196
+ attrs = {
197
+ "irc.command": msg.command,
198
+ "irc.prefix_nick": (msg.prefix.split("!")[0] if msg.prefix else ""),
199
+ "culture.trace.origin": "local" if extract.status == "missing" else "remote",
200
+ }
201
+ if extract.status in ("malformed", "too_long"):
202
+ attrs["culture.trace.dropped_reason"] = extract.status
203
+
204
+ # Per-call get_tracer: test fixture swaps provider between tests.
205
+ with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
206
+ f"irc.command.{msg.command}",
207
+ context=parent_ctx,
208
+ attributes=attrs,
209
+ ):
210
+ handler = getattr(self, f"_handle_{msg.command.lower()}", None)
211
+ if handler:
212
+ await maybe_await(handler(msg))
125
213
  else:
126
- await self.send_numeric(replies.ERR_UNKNOWNCOMMAND, msg.command, "Unknown command")
214
+ skill = self.server.get_skill_for_command(msg.command)
215
+ if skill and self._registered:
216
+ try:
217
+ await skill.on_command(self, msg)
218
+ except Exception:
219
+ logging.getLogger(__name__).exception(
220
+ "Skill %s failed on command %s", skill.name, msg.command
221
+ )
222
+ else:
223
+ await self.send_numeric(
224
+ replies.ERR_UNKNOWNCOMMAND, msg.command, "Unknown command"
225
+ )
127
226
 
128
227
  async def _handle_ping(self, msg: Message) -> None:
129
228
  token = msg.params[0] if msg.params else ""
@@ -615,46 +714,64 @@ class Client:
615
714
  await self.send_numeric(replies.RPL_UMODEIS, mode_str)
616
715
 
617
716
  async def _send_to_channel(self, channel, target, relay, text, is_notice):
618
- for member in list(channel.members):
619
- if member is not self:
620
- await member.send(relay)
621
- event_data = {"text": text}
622
- if is_notice:
623
- event_data["notice"] = True
624
- await self.server.emit_event(
625
- Event(
626
- type=EventType.MESSAGE,
627
- channel=target,
628
- nick=self.nick,
629
- data=event_data,
717
+ with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
718
+ "irc.privmsg.deliver.channel",
719
+ attributes={
720
+ "irc.channel": target,
721
+ _ATTR_BODY: text,
722
+ _ATTR_SIZE: len(text),
723
+ "irc.notice": is_notice,
724
+ },
725
+ ):
726
+ for member in list(channel.members):
727
+ if member is not self:
728
+ await member.send(relay)
729
+ event_data = {"text": text}
730
+ if is_notice:
731
+ event_data["notice"] = True
732
+ await self.server.emit_event(
733
+ Event(
734
+ type=EventType.MESSAGE,
735
+ channel=target,
736
+ nick=self.nick,
737
+ data=event_data,
738
+ )
630
739
  )
631
- )
632
740
 
633
741
  async def _send_to_client(self, target, relay, text, is_notice):
634
742
  from culture.agentirc.remote_client import RemoteClient
635
743
 
636
- recipient = self.server.get_client(target)
637
- if not recipient:
638
- return False
639
- if isinstance(recipient, RemoteClient):
640
- s2s_cmd = "SNOTICE" if is_notice else "SMSG"
641
- await recipient.link.send_raw(
642
- f":{self.server.config.name} {s2s_cmd} {target} {self.nick} :{text}"
643
- )
644
- else:
645
- await recipient.send(relay)
646
- event_data = {"text": text, "target": target}
647
- if is_notice:
648
- event_data["notice"] = True
649
- await self.server.emit_event(
650
- Event(
651
- type=EventType.MESSAGE,
652
- channel=None,
653
- nick=self.nick,
654
- data=event_data,
744
+ with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
745
+ "irc.privmsg.deliver.dm",
746
+ attributes={
747
+ "irc.target.nick": target,
748
+ _ATTR_BODY: text,
749
+ _ATTR_SIZE: len(text),
750
+ "irc.notice": is_notice,
751
+ },
752
+ ):
753
+ recipient = self.server.get_client(target)
754
+ if not recipient:
755
+ return False
756
+ if isinstance(recipient, RemoteClient):
757
+ s2s_cmd = "SNOTICE" if is_notice else "SMSG"
758
+ await recipient.link.send_raw(
759
+ f":{self.server.config.name} {s2s_cmd} {target} {self.nick} :{text}"
760
+ )
761
+ else:
762
+ await recipient.send(relay)
763
+ event_data = {"text": text, "target": target}
764
+ if is_notice:
765
+ event_data["notice"] = True
766
+ await self.server.emit_event(
767
+ Event(
768
+ type=EventType.MESSAGE,
769
+ channel=None,
770
+ nick=self.nick,
771
+ data=event_data,
772
+ )
655
773
  )
656
- )
657
- return True
774
+ return True
658
775
 
659
776
  async def _handle_privmsg(self, msg: Message) -> None:
660
777
  if len(msg.params) < 2:
@@ -665,28 +782,37 @@ class Client:
665
782
 
666
783
  target = msg.params[0]
667
784
  text = msg.params[1]
668
- relay = Message(prefix=self.prefix, command="PRIVMSG", params=[target, text])
669
-
670
- if target.startswith("#"):
671
- channel = self.server.channels.get(target)
672
- if not channel:
673
- await self.send_numeric(
674
- replies.ERR_NOSUCHCHANNEL, target, replies.MSG_NOSUCHCHANNEL
675
- )
676
- return
677
- if self not in channel.members:
678
- await self.send_numeric(
679
- replies.ERR_CANNOTSENDTOCHAN, target, "Cannot send to channel"
680
- )
681
- return
682
- await self._send_to_channel(channel, target, relay, text, False)
683
- await self._notify_mentions(target, text)
684
- else:
685
- found = await self._send_to_client(target, relay, text, False)
686
- if not found:
687
- await self.send_numeric(replies.ERR_NOSUCHNICK, target, replies.MSG_NOSUCHNICK)
688
- return
689
- await self._notify_mentions(None, text)
785
+ # Per-call get_tracer: test fixture swaps provider between tests.
786
+ with _otel_trace.get_tracer(_TRACER_NAME).start_as_current_span(
787
+ "irc.privmsg.dispatch",
788
+ attributes={
789
+ "irc.target": target,
790
+ _ATTR_BODY: text,
791
+ _ATTR_SIZE: len(text),
792
+ },
793
+ ):
794
+ relay = Message(prefix=self.prefix, command="PRIVMSG", params=[target, text])
795
+
796
+ if target.startswith("#"):
797
+ channel = self.server.channels.get(target)
798
+ if not channel:
799
+ await self.send_numeric(
800
+ replies.ERR_NOSUCHCHANNEL, target, replies.MSG_NOSUCHCHANNEL
801
+ )
802
+ return
803
+ if self not in channel.members:
804
+ await self.send_numeric(
805
+ replies.ERR_CANNOTSENDTOCHAN, target, "Cannot send to channel"
806
+ )
807
+ return
808
+ await self._send_to_channel(channel, target, relay, text, False)
809
+ await self._notify_mentions(target, text)
810
+ else:
811
+ found = await self._send_to_client(target, relay, text, False)
812
+ if not found:
813
+ await self.send_numeric(replies.ERR_NOSUCHNICK, target, replies.MSG_NOSUCHNICK)
814
+ return
815
+ await self._notify_mentions(None, text)
690
816
 
691
817
  async def _notify_mentions(self, channel_name: str | None, text: str) -> None:
692
818
  from culture.agentirc.remote_client import RemoteClient
@@ -12,6 +12,20 @@ class LinkConfig:
12
12
  trust: str = "full" # "full" or "restricted"
13
13
 
14
14
 
15
+ @dataclass
16
+ class TelemetryConfig:
17
+ """OpenTelemetry settings. Mirrors server.yaml `telemetry:` block."""
18
+
19
+ enabled: bool = False
20
+ service_name: str = "culture.agentirc"
21
+ otlp_endpoint: str = "http://localhost:4317"
22
+ otlp_protocol: str = "grpc" # grpc | http/protobuf (only grpc supported initially)
23
+ otlp_timeout_ms: int = 5000
24
+ otlp_compression: str = "gzip" # gzip | none
25
+ traces_enabled: bool = True
26
+ traces_sampler: str = "parentbased_always_on"
27
+
28
+
15
29
  @dataclass
16
30
  class ServerConfig:
17
31
  """Configuration for a culture server instance."""
@@ -23,3 +37,4 @@ class ServerConfig:
23
37
  data_dir: str = ""
24
38
  links: list[LinkConfig] = field(default_factory=list)
25
39
  system_bots: dict = field(default_factory=dict)
40
+ telemetry: TelemetryConfig = field(default_factory=TelemetryConfig)
@@ -8,6 +8,8 @@ import logging
8
8
  from collections import deque
9
9
  from typing import TYPE_CHECKING
10
10
 
11
+ from opentelemetry import trace as _otel_trace
12
+
11
13
  from culture.agentirc.channel import Channel
12
14
  from culture.agentirc.config import ServerConfig
13
15
  from culture.agentirc.events import NO_SURFACE_EVENT_TYPES, render_event
@@ -33,7 +35,10 @@ class IRCd:
33
35
  """The culture IRC server."""
34
36
 
35
37
  def __init__(self, config: ServerConfig):
38
+ from culture.telemetry import init_telemetry
39
+
36
40
  self.config = config
41
+ self.tracer = init_telemetry(config)
37
42
  self.clients: dict[str, Client | VirtualClient] = {} # nick -> Client
38
43
  self.channels: dict[str, Channel] = {} # name -> Channel
39
44
  self.skills: list[Skill] = []
@@ -166,36 +171,60 @@ class IRCd:
166
171
  self._seq += 1
167
172
  return self._seq
168
173
 
169
- async def emit_event(self, event: Event) -> None:
170
- # 1) Sequence + log.
171
- seq = self.next_seq()
172
- self._event_log.append((seq, event))
174
+ @staticmethod
175
+ def _build_event_span_attrs(event: Event, origin_tag: str | None) -> dict[str, str]:
176
+ # event.type may be an EventType enum OR a plain string — federated
177
+ # events forward unknown types verbatim (see _parse_event_type in
178
+ # server_link.py).
179
+ event_type_str = event.type.value if hasattr(event.type, "value") else str(event.type)
180
+ attrs: dict[str, str] = {
181
+ "event.type": event_type_str,
182
+ "event.origin": "federated" if origin_tag else "local",
183
+ }
184
+ if event.channel:
185
+ attrs["event.channel"] = event.channel
186
+ if origin_tag:
187
+ attrs["culture.federation.peer"] = origin_tag
188
+ return attrs
173
189
 
174
- # 2) Run skill hooks.
190
+ async def _run_skill_hooks(self, event: Event) -> None:
175
191
  for skill in self.skills:
176
192
  try:
177
193
  await skill.on_event(event)
178
194
  except Exception:
179
195
  logger.exception("Skill %s failed on event %s", skill.name, event.type)
180
196
 
181
- # 3) Relay to linked peers — only relay locally-originated events
182
- # (no mesh routing; scope is direct peers only)
183
- if not event.data.get("_origin"):
184
- for peer_name, link in list(self.links.items()):
185
- try:
186
- await link.relay_event(event)
187
- except Exception:
188
- logger.exception("Failed to relay event to %s", peer_name)
189
-
190
- # 4) Dispatch to event-triggered bots.
191
- if self.bot_manager is not None:
197
+ async def _relay_to_peers(self, event: Event) -> None:
198
+ for peer_name, link in list(self.links.items()):
192
199
  try:
193
- await self.bot_manager.on_event(event)
200
+ await link.relay_event(event)
194
201
  except Exception:
195
- logger.exception("bot_manager.on_event failed")
202
+ logger.exception("Failed to relay event to %s", peer_name)
203
+
204
+ async def _dispatch_to_bots(self, event: Event) -> None:
205
+ if self.bot_manager is None:
206
+ return
207
+ try:
208
+ await self.bot_manager.on_event(event)
209
+ except Exception:
210
+ logger.exception("bot_manager.on_event failed")
196
211
 
197
- # 5) Surface as tagged PRIVMSG from system-<server>.
198
- await self._surface_event_privmsg(event)
212
+ async def emit_event(self, event: Event) -> None:
213
+ origin_tag = event.data.get("_origin")
214
+ attrs = self._build_event_span_attrs(event, origin_tag)
215
+ # Per-call get_tracer: the `tracing_exporter` test fixture swaps the
216
+ # global provider between tests; a cached Tracer would bind to the
217
+ # first test's provider and stop delivering to later ones.
218
+ with _otel_trace.get_tracer("culture.agentirc").start_as_current_span(
219
+ "irc.event.emit", attributes=attrs
220
+ ):
221
+ seq = self.next_seq()
222
+ self._event_log.append((seq, event))
223
+ await self._run_skill_hooks(event)
224
+ if not origin_tag:
225
+ await self._relay_to_peers(event)
226
+ await self._dispatch_to_bots(event)
227
+ await self._surface_event_privmsg(event)
199
228
 
200
229
  _NO_SURFACE_TYPES = NO_SURFACE_EVENT_TYPES
201
230
 
@@ -8,6 +8,7 @@ Commands are organized into noun-based groups:
8
8
  culture bot {create,start,stop,list,inspect,archive,unarchive}
9
9
  culture skills {install}
10
10
  culture devex {...developer-experience passthrough (powered by agex-cli)...}
11
+ culture afi {...agent-first interface passthrough (powered by afi-cli)...}
11
12
 
12
13
  Universal verbs (available at the root):
13
14
  culture explain [topic] full description of topic (default: culture)
@@ -22,9 +23,9 @@ import logging
22
23
  import sys
23
24
 
24
25
  from culture import __version__
25
- from culture.cli import agent, bot, channel, devex, introspect, mesh, server, skills
26
+ from culture.cli import afi, agent, bot, channel, devex, introspect, mesh, server, skills
26
27
 
27
- GROUPS = [agent, server, mesh, channel, bot, skills, devex, introspect]
28
+ GROUPS = [agent, server, mesh, channel, bot, skills, devex, afi, introspect]
28
29
 
29
30
 
30
31
  def _names_of(group) -> set[str]: