agentirc-cli 8.4.0__tar.gz → 8.6.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 (472) hide show
  1. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/CHANGELOG.md +34 -0
  2. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/PKG-INFO +1 -1
  3. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/client.py +45 -0
  4. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/config.py +7 -0
  5. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/ircd.py +35 -2
  6. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/agent_runner.py +53 -11
  7. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/config.py +24 -0
  8. agentirc_cli-8.6.0/culture/clients/acp/culture.yaml +32 -0
  9. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/daemon.py +11 -0
  10. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/irc_transport.py +109 -18
  11. agentirc_cli-8.6.0/culture/clients/acp/telemetry.py +318 -0
  12. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/agent_runner.py +71 -14
  13. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/config.py +24 -0
  14. agentirc_cli-8.6.0/culture/clients/claude/culture.yaml +29 -0
  15. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/daemon.py +11 -0
  16. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/irc_transport.py +126 -35
  17. agentirc_cli-8.6.0/culture/clients/claude/telemetry.py +318 -0
  18. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/agent_runner.py +60 -22
  19. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/config.py +26 -0
  20. agentirc_cli-8.6.0/culture/clients/codex/culture.yaml +29 -0
  21. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/daemon.py +11 -0
  22. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/irc_transport.py +109 -18
  23. agentirc_cli-8.6.0/culture/clients/codex/telemetry.py +318 -0
  24. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/agent_runner.py +48 -6
  25. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/config.py +24 -0
  26. agentirc_cli-8.6.0/culture/clients/copilot/culture.yaml +29 -0
  27. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/daemon.py +11 -0
  28. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/irc_transport.py +109 -18
  29. agentirc_cli-8.6.0/culture/clients/copilot/telemetry.py +318 -0
  30. agentirc_cli-8.6.0/culture/protocol/extensions/audit.md +109 -0
  31. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/telemetry/__init__.py +5 -0
  32. agentirc_cli-8.6.0/culture/telemetry/audit.py +380 -0
  33. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/telemetry/metrics.py +12 -0
  34. agentirc_cli-8.6.0/docs/agentirc/audit.md +154 -0
  35. agentirc_cli-8.6.0/docs/agentirc/harness-telemetry.md +302 -0
  36. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/agentirc/telemetry.md +68 -6
  37. agentirc_cli-8.6.0/docs/superpowers/plans/2026-04-27-otel-audit.md +247 -0
  38. agentirc_cli-8.6.0/docs/superpowers/plans/2026-04-28-otel-harness.md +272 -0
  39. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/README.md +11 -0
  40. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/config.py +24 -0
  41. agentirc_cli-8.6.0/packages/agent-harness/culture.yaml +28 -0
  42. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/daemon.py +13 -1
  43. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/irc_transport.py +108 -18
  44. agentirc_cli-8.6.0/packages/agent-harness/telemetry.py +315 -0
  45. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/pyproject.toml +1 -1
  46. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/conftest.py +22 -2
  47. agentirc_cli-8.6.0/tests/harness/conftest.py +89 -0
  48. agentirc_cli-8.6.0/tests/harness/test_agent_runner_acp.py +233 -0
  49. agentirc_cli-8.6.0/tests/harness/test_agent_runner_claude.py +449 -0
  50. agentirc_cli-8.6.0/tests/harness/test_agent_runner_codex.py +229 -0
  51. agentirc_cli-8.6.0/tests/harness/test_agent_runner_copilot.py +256 -0
  52. agentirc_cli-8.6.0/tests/harness/test_all_backends_parity.py +398 -0
  53. agentirc_cli-8.6.0/tests/harness/test_daemon_telemetry.py +72 -0
  54. agentirc_cli-8.6.0/tests/harness/test_irc_transport_propagation.py +447 -0
  55. agentirc_cli-8.6.0/tests/harness/test_record_llm_call.py +245 -0
  56. agentirc_cli-8.6.0/tests/harness/test_telemetry_module.py +264 -0
  57. agentirc_cli-8.6.0/tests/telemetry/__init__.py +0 -0
  58. agentirc_cli-8.6.0/tests/telemetry/test_audit_emit.py +145 -0
  59. agentirc_cli-8.6.0/tests/telemetry/test_audit_federation.py +132 -0
  60. agentirc_cli-8.6.0/tests/telemetry/test_audit_lifecycle.py +69 -0
  61. agentirc_cli-8.6.0/tests/telemetry/test_audit_module.py +306 -0
  62. agentirc_cli-8.6.0/tests/telemetry/test_audit_parse_error.py +177 -0
  63. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/uv.lock +1 -1
  64. agentirc_cli-8.4.0/culture/clients/acp/culture.yaml +0 -17
  65. agentirc_cli-8.4.0/culture/clients/claude/culture.yaml +0 -14
  66. agentirc_cli-8.4.0/culture/clients/codex/culture.yaml +0 -14
  67. agentirc_cli-8.4.0/culture/clients/copilot/culture.yaml +0 -14
  68. agentirc_cli-8.4.0/packages/agent-harness/culture.yaml +0 -13
  69. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.claude/agents/doc-test-alignment.md +0 -0
  70. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.claude/skills/pr-review/SKILL.md +0 -0
  71. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.claude/skills/run-tests/SKILL.md +0 -0
  72. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
  73. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.flake8 +0 -0
  74. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.github/workflows/docs-check.yml +0 -0
  75. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.github/workflows/publish.yml +0 -0
  76. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.github/workflows/security-checks.yml +0 -0
  77. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.github/workflows/tests.yml +0 -0
  78. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.gitignore +0 -0
  79. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.markdownlint-cli2.yaml +0 -0
  80. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.pr_agent.toml +0 -0
  81. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.pre-commit-config.yaml +0 -0
  82. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/.pylintrc +0 -0
  83. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/CLAUDE.md +0 -0
  84. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/Gemfile +0 -0
  85. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/Gemfile.lock +0 -0
  86. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/LICENSE +0 -0
  87. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/README.md +0 -0
  88. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/SECURITY.md +0 -0
  89. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/_config.base.yml +0 -0
  90. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/_config.culture.yml +0 -0
  91. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/_data/sites.yml +0 -0
  92. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/_includes/head_custom.html +0 -0
  93. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/_sass/color_schemes/anthropic.scss +0 -0
  94. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/_sass/color_schemes/dark-terminal.scss +0 -0
  95. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/_sass/custom/custom.scss +0 -0
  96. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/assets/images/IMG_3183.png +0 -0
  97. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/assets/images/apple-touch-icon.png +0 -0
  98. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/assets/images/favicon-16x16.png +0 -0
  99. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/assets/images/favicon-32x32.png +0 -0
  100. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/assets/images/favicon.ico +0 -0
  101. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/assets/images/og-agentirc.png +0 -0
  102. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/assets/images/og-culture.png +0 -0
  103. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/__init__.py +0 -0
  104. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/__main__.py +0 -0
  105. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/CLAUDE.md +0 -0
  106. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/__init__.py +0 -0
  107. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/__main__.py +0 -0
  108. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/channel.py +0 -0
  109. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/docs/agentirc-architecture.md +0 -0
  110. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/docs/agentirc-features.md +0 -0
  111. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/docs/agentirc-skill.md +0 -0
  112. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/docs/agentirc.md +0 -0
  113. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/events.py +0 -0
  114. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/history_store.py +0 -0
  115. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/remote_client.py +0 -0
  116. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/room_store.py +0 -0
  117. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/rooms_util.py +0 -0
  118. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/server_link.py +0 -0
  119. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/skill.py +0 -0
  120. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/skills/__init__.py +0 -0
  121. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/skills/history.py +0 -0
  122. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/skills/icon.py +0 -0
  123. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/skills/rooms.py +0 -0
  124. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/skills/threads.py +0 -0
  125. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/agentirc/thread_store.py +0 -0
  126. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/aio.py +0 -0
  127. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/__init__.py +0 -0
  128. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/bot.py +0 -0
  129. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/bot_manager.py +0 -0
  130. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/config.py +0 -0
  131. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/filter_dsl.py +0 -0
  132. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/http_listener.py +0 -0
  133. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/system/__init__.py +0 -0
  134. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/system/welcome/__init__.py +0 -0
  135. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/system/welcome/bot.yaml +0 -0
  136. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/system/welcome/handler.py +0 -0
  137. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/template_engine.py +0 -0
  138. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/bots/virtual_client.py +0 -0
  139. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/__init__.py +0 -0
  140. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/_passthrough.py +0 -0
  141. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/afi.py +0 -0
  142. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/agent.py +0 -0
  143. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/bot.py +0 -0
  144. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/channel.py +0 -0
  145. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/devex.py +0 -0
  146. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/introspect.py +0 -0
  147. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/mesh.py +0 -0
  148. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/server.py +0 -0
  149. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/shared/__init__.py +0 -0
  150. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/shared/constants.py +0 -0
  151. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/shared/display.py +0 -0
  152. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/shared/formatting.py +0 -0
  153. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/shared/ipc.py +0 -0
  154. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/shared/mesh.py +0 -0
  155. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/shared/process.py +0 -0
  156. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/cli/skills.py +0 -0
  157. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/__init__.py +0 -0
  158. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/__init__.py +0 -0
  159. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/ipc.py +0 -0
  160. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/message_buffer.py +0 -0
  161. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/skill/SKILL.md +0 -0
  162. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/skill/__init__.py +0 -0
  163. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/skill/irc_client.py +0 -0
  164. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/socket_server.py +0 -0
  165. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/supervisor.py +0 -0
  166. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/acp/webhook.py +0 -0
  167. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/__init__.py +0 -0
  168. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/__main__.py +0 -0
  169. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/ipc.py +0 -0
  170. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/message_buffer.py +0 -0
  171. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/skill/SKILL.md +0 -0
  172. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/skill/__init__.py +0 -0
  173. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/skill/irc_client.py +0 -0
  174. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/socket_server.py +0 -0
  175. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/supervisor.py +0 -0
  176. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/claude/webhook.py +0 -0
  177. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/__init__.py +0 -0
  178. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/ipc.py +0 -0
  179. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/message_buffer.py +0 -0
  180. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/skill/SKILL.md +0 -0
  181. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/skill/__init__.py +0 -0
  182. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/skill/irc_client.py +0 -0
  183. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/socket_server.py +0 -0
  184. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/supervisor.py +0 -0
  185. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/codex/webhook.py +0 -0
  186. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/__init__.py +0 -0
  187. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/ipc.py +0 -0
  188. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/message_buffer.py +0 -0
  189. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/skill/SKILL.md +0 -0
  190. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/skill/__init__.py +0 -0
  191. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/skill/irc_client.py +0 -0
  192. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/socket_server.py +0 -0
  193. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/supervisor.py +0 -0
  194. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/clients/copilot/webhook.py +0 -0
  195. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/config.py +0 -0
  196. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/__init__.py +0 -0
  197. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/app.py +0 -0
  198. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/client.py +0 -0
  199. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/commands.py +0 -0
  200. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/status.py +0 -0
  201. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/widgets/__init__.py +0 -0
  202. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/widgets/chat.py +0 -0
  203. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/widgets/info_panel.py +0 -0
  204. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/console/widgets/sidebar.py +0 -0
  205. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/constants.py +0 -0
  206. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/credentials.py +0 -0
  207. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/formatting.py +0 -0
  208. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/learn_prompt.py +0 -0
  209. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/mesh_config.py +0 -0
  210. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/observer.py +0 -0
  211. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/overview/__init__.py +0 -0
  212. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/overview/collector.py +0 -0
  213. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/overview/model.py +0 -0
  214. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/overview/renderer_text.py +0 -0
  215. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/overview/renderer_web.py +0 -0
  216. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/overview/web/style.css +0 -0
  217. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/persistence.py +0 -0
  218. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/pidfile.py +0 -0
  219. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/__init__.py +0 -0
  220. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/commands.py +0 -0
  221. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/events.md +0 -0
  222. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/federation.md +0 -0
  223. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/history.md +0 -0
  224. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/icons.md +0 -0
  225. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/rooms.md +0 -0
  226. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/tags.md +0 -0
  227. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/threads.md +0 -0
  228. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/extensions/tracing.md +0 -0
  229. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/message.py +0 -0
  230. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/protocol-index.md +0 -0
  231. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/protocol/replies.py +0 -0
  232. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/skills/culture/SKILL.md +0 -0
  233. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/telemetry/context.py +0 -0
  234. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/culture/telemetry/tracing.py +0 -0
  235. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/README.md +0 -0
  236. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/agentirc/architecture-overview.md +0 -0
  237. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/agentirc/bots.md +0 -0
  238. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/agentirc/events.md +0 -0
  239. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/agentirc/index.md +0 -0
  240. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/agentirc/otelcol-template.yaml +0 -0
  241. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/agentirc/why-agentirc.md +0 -0
  242. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/agent-lifecycle.md +0 -0
  243. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/choose-a-harness.md +0 -0
  244. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/features.md +0 -0
  245. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/index.md +0 -0
  246. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/mental-model.md +0 -0
  247. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/operate.md +0 -0
  248. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/patterns.md +0 -0
  249. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/quickstart.md +0 -0
  250. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/reflective-development.md +0 -0
  251. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/vision-patterns-index.md +0 -0
  252. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/vision.md +0 -0
  253. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/culture/what-is-culture.md +0 -0
  254. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/architecture/agent-harness-spec.md +0 -0
  255. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/architecture/index.md +0 -0
  256. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/architecture/layers.md +0 -0
  257. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/architecture/subsites.md +0 -0
  258. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/architecture/threads.md +0 -0
  259. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/cli/afi.md +0 -0
  260. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/cli/commands.md +0 -0
  261. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/cli/devex.md +0 -0
  262. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/cli/index.md +0 -0
  263. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/console.md +0 -0
  264. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/harnesses/acp.md +0 -0
  265. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/harnesses/claude.md +0 -0
  266. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/harnesses/codex.md +0 -0
  267. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/harnesses/copilot.md +0 -0
  268. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/harnesses/index.md +0 -0
  269. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/index.md +0 -0
  270. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/server/architecture.md +0 -0
  271. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/server/config.md +0 -0
  272. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/server/deployment.md +0 -0
  273. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/server/index.md +0 -0
  274. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/reference/server/security.md +0 -0
  275. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/resources/github-copilot-sdk-instructions.md +0 -0
  276. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/resources/positioning.md +0 -0
  277. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/concepts/federation.md +0 -0
  278. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/concepts/harnesses.md +0 -0
  279. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/concepts/humans-and-agents.md +0 -0
  280. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/concepts/index.md +0 -0
  281. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/concepts/persistence.md +0 -0
  282. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/concepts/rooms.md +0 -0
  283. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/demos/magic-demo.md +0 -0
  284. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/guides/first-session.md +0 -0
  285. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/guides/index.md +0 -0
  286. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/guides/join-as-human.md +0 -0
  287. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/guides/local-setup.md +0 -0
  288. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/guides/multi-machine.md +0 -0
  289. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/01-pair-programming.md +0 -0
  290. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/02-code-review-ensemble.md +0 -0
  291. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/03-cross-server-delegation.md +0 -0
  292. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/04-knowledge-propagation.md +0 -0
  293. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/05-the-observer.md +0 -0
  294. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/06-cross-server-ops.md +0 -0
  295. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/07-supervisor-intervention.md +0 -0
  296. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/08-apps-as-agents.md +0 -0
  297. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/09-research-swarm.md +0 -0
  298. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases/10-agent-lifecycle.md +0 -0
  299. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/shared/use-cases-index.md +0 -0
  300. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
  301. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
  302. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
  303. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
  304. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
  305. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
  306. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
  307. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
  308. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
  309. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-09-decentralized-agent-config.md +0 -0
  310. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-12-console-enhancements.md +0 -0
  311. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-15-mesh-events.md +0 -0
  312. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-18-culture-dev-positioning.md +0 -0
  313. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-22-agex-integration.md +0 -0
  314. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-24-otel-foundation.md +0 -0
  315. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-25-otel-federation.md +0 -0
  316. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/plans/2026-04-26-otel-metrics.md +0 -0
  317. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
  318. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
  319. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
  320. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
  321. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
  322. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
  323. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
  324. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
  325. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
  326. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
  327. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
  328. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
  329. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
  330. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-07-reflective-development-reframe-design.md +0 -0
  331. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-08-reflective-development-deepening-design.md +0 -0
  332. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-09-decentralized-agent-config-design.md +0 -0
  333. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-12-console-enhancements-design.md +0 -0
  334. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-15-mesh-events-design.md +0 -0
  335. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-17-sites-repositioning-design.md +0 -0
  336. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-18-culture-dev-positioning-design.md +0 -0
  337. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-22-agex-integration-design.md +0 -0
  338. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/docs/superpowers/specs/2026-04-24-otel-observability-design.md +0 -0
  339. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/favicon.ico +0 -0
  340. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/ipc.py +0 -0
  341. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/message_buffer.py +0 -0
  342. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/skill/SKILL.md +0 -0
  343. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/skill/irc_client.py +0 -0
  344. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/socket_server.py +0 -0
  345. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/packages/agent-harness/webhook.py +0 -0
  346. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  347. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/plugins/claude-code/skills/culture/SKILL.md +0 -0
  348. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/plugins/claude-code/skills/irc/SKILL.md +0 -0
  349. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
  350. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/robots.txt +0 -0
  351. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/sitemap-agentirc.html +0 -0
  352. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/sitemap-main.html +0 -0
  353. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/sitemap.html +0 -0
  354. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/sonar-project.properties +0 -0
  355. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/__init__.py +0 -0
  356. {agentirc_cli-8.4.0/tests/telemetry → agentirc_cli-8.6.0/tests/harness}/__init__.py +0 -0
  357. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/_fakes.py +0 -0
  358. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/_metrics_helpers.py +0 -0
  359. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_config.py +0 -0
  360. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_config_load.py +0 -0
  361. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_context.py +0 -0
  362. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_dispatch_span.py +0 -0
  363. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_emit_event_span.py +0 -0
  364. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_federation_propagation.py +0 -0
  365. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_metrics_clients.py +0 -0
  366. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_metrics_events.py +0 -0
  367. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_metrics_init.py +0 -0
  368. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_metrics_irc.py +0 -0
  369. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_metrics_s2s.py +0 -0
  370. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_metrics_trace_inbound.py +0 -0
  371. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_outbound_inject.py +0 -0
  372. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_parse_error.py +0 -0
  373. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_privmsg_span.py +0 -0
  374. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_s2s_dispatch_span.py +0 -0
  375. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_s2s_relay_span.py +0 -0
  376. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_s2s_session_span.py +0 -0
  377. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_server_init.py +0 -0
  378. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_server_link_inject.py +0 -0
  379. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_session_span.py +0 -0
  380. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/telemetry/test_tracing.py +0 -0
  381. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_acp_daemon.py +0 -0
  382. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_agent_runner.py +0 -0
  383. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_archive.py +0 -0
  384. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_bot.py +0 -0
  385. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_bot_config.py +0 -0
  386. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_bot_config_fires_event_toplevel.py +0 -0
  387. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_bot_manager.py +0 -0
  388. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_bots_integration.py +0 -0
  389. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_channel.py +0 -0
  390. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_channel_cli.py +0 -0
  391. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_cli_afi.py +0 -0
  392. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_cli_devex.py +0 -0
  393. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_cli_introspect.py +0 -0
  394. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_cli_passthrough.py +0 -0
  395. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_codex_daemon.py +0 -0
  396. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_connection.py +0 -0
  397. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_chat_markdown.py +0 -0
  398. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_client.py +0 -0
  399. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_commands.py +0 -0
  400. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_connection.py +0 -0
  401. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_fixes_224_227.py +0 -0
  402. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_icons.py +0 -0
  403. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_integration.py +0 -0
  404. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_console_status.py +0 -0
  405. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_copilot_daemon.py +0 -0
  406. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_credentials.py +0 -0
  407. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_culture_config.py +0 -0
  408. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_daemon.py +0 -0
  409. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_daemon_config.py +0 -0
  410. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_daemon_ipc.py +0 -0
  411. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_discovery.py +0 -0
  412. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_display.py +0 -0
  413. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_basic.py +0 -0
  414. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_bot_chain.py +0 -0
  415. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_bot_trigger.py +0 -0
  416. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_cap_fallback.py +0 -0
  417. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_catalog.py +0 -0
  418. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_federation.py +0 -0
  419. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_history.py +0 -0
  420. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_lifecycle.py +0 -0
  421. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_events_reserved_nick.py +0 -0
  422. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_federation.py +0 -0
  423. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_filter_dsl.py +0 -0
  424. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_history.py +0 -0
  425. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_http_listener.py +0 -0
  426. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_integration_layer5.py +0 -0
  427. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_ipc.py +0 -0
  428. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_irc_transport.py +0 -0
  429. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_irc_transport_tags.py +0 -0
  430. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_learn_prompt.py +0 -0
  431. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_link_reconnect.py +0 -0
  432. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_manifest_config.py +0 -0
  433. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_mention_alias.py +0 -0
  434. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_mention_target_cleanup.py +0 -0
  435. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_mention_warning.py +0 -0
  436. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_mentions.py +0 -0
  437. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_mesh_config.py +0 -0
  438. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_mesh_readiness.py +0 -0
  439. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_message.py +0 -0
  440. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_message_buffer.py +0 -0
  441. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_message_tags.py +0 -0
  442. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_messaging.py +0 -0
  443. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_migrate_cli.py +0 -0
  444. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_modes.py +0 -0
  445. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_overview_cli.py +0 -0
  446. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_overview_collector.py +0 -0
  447. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_overview_model.py +0 -0
  448. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_overview_renderer.py +0 -0
  449. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_overview_web.py +0 -0
  450. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_persistence.py +0 -0
  451. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_persistence_timeout.py +0 -0
  452. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_pidfile.py +0 -0
  453. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_poll_loop.py +0 -0
  454. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_register_cli.py +0 -0
  455. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_room_persistence.py +0 -0
  456. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_rooms.py +0 -0
  457. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_rooms_federation.py +0 -0
  458. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_rooms_integration.py +0 -0
  459. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_server_icon_skill.py +0 -0
  460. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_setup_update_cli.py +0 -0
  461. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_skill_client.py +0 -0
  462. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_skill_docs.py +0 -0
  463. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_skills.py +0 -0
  464. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_socket_server.py +0 -0
  465. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_supervisor.py +0 -0
  466. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_template_engine.py +0 -0
  467. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_thread_buffer.py +0 -0
  468. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_threads.py +0 -0
  469. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_virtual_client.py +0 -0
  470. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_wait_for_port.py +0 -0
  471. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_webhook.py +0 -0
  472. {agentirc_cli-8.4.0 → agentirc_cli-8.6.0}/tests/test_welcome_bot.py +0 -0
@@ -4,6 +4,40 @@ 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.6.0] - 2026-04-26
8
+
9
+ ### Added
10
+
11
+ - Harness-side OTEL: 3 spans (harness.irc.connect, harness.irc.message.handle, harness.llm.call) and 4 LLM metrics (culture.harness.llm.tokens.input/output, call.duration, calls).
12
+ - W3C traceparent injection on outbound IRC + extraction on inbound — single trace_id now spans server, federation, and harness in the cross-process tree.
13
+ - Per-backend telemetry citation across claude/codex/copilot/acp with all-backends parity test (24 tests across 6 dimensions) locking down drift.
14
+ - docs/agentirc/harness-telemetry.md — new operator guide for the harness OTEL pillar.
15
+
16
+ ### Changed
17
+
18
+ - packages/agent-harness/{telemetry.py,config.py,culture.yaml,irc_transport.py,daemon.py} — reference module for the citation pattern.
19
+ - culture/clients/{claude,codex,copilot,acp}/{telemetry.py,config.py,culture.yaml,irc_transport.py,daemon.py,agent_runner.py} — telemetry citation, harness.llm.call span wrap, record_llm_call invocation.
20
+ - tests/harness/ — 70 new tests (24 parity + 46 module/runner/transport/daemon).
21
+
22
+ ### Fixed
23
+
24
+ - Code-quality fixes from review: zero-token usage extraction (0 no longer silenced), tracer-name from constant (no hardcoded strings), module-top imports of record_llm_call across all 4 backends.
25
+
26
+ ## [8.5.0] - 2026-04-25
27
+
28
+ ### Added
29
+
30
+ - `culture/telemetry/audit.py` — `AuditSink` with bounded `asyncio.Queue` + dedicated writer task + daily/size rotation + `0600`/`0700` perms.
31
+ - Public `culture.telemetry.AuditSink`, `init_audit`, `build_audit_record`, `utc_iso_timestamp`.
32
+ - `TelemetryConfig.audit_enabled` (default `True`), `audit_dir`, `audit_max_file_bytes`, `audit_rotate_utc_midnight`, `audit_queue_depth` — independent of `telemetry.enabled` (audit fires even with OTEL off).
33
+ - `culture/protocol/extensions/audit.md` — JSONL record schema as a stable contract.
34
+ - `docs/agentirc/audit.md` — operator guide.
35
+ - Audit metrics extend the Plan-3 `MetricsRegistry`: `culture.audit.writes` (Counter, labels `outcome=ok|error`) and `culture.audit.queue_depth` (UpDownCounter).
36
+ - `IRCd.__init__` creates the sink; `IRCd.start()` awaits `sink.start()`; `IRCd.stop()` awaits `sink.shutdown()` so SERVER_WAKE / SERVER_SLEEP both land in the JSONL.
37
+ - `IRCd.emit_event` submits one record per event after the `irc.event.emit` span; `trace_id` / `span_id` captured inside the span for cross-pillar joins.
38
+ - `Client._process_buffer` submits `PARSE_ERROR` records for malformed inbound lines.
39
+ - Federation audit: federated `message` events arrive on the receiver with `origin=federated`, `peer=<peer_name>`. Federated lifecycle events (JOIN/PART/QUIT) are deferred — see #296.
40
+
7
41
  ## [8.4.0] - 2026-04-25
8
42
 
9
43
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentirc-cli
3
- Version: 8.4.0
3
+ Version: 8.6.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
@@ -17,6 +17,7 @@ from culture.aio import maybe_await
17
17
  from culture.constants import SYSTEM_USER_PREFIX
18
18
  from culture.protocol import replies
19
19
  from culture.protocol.message import Message
20
+ from culture.telemetry.audit import utc_iso_timestamp as _utc_iso_timestamp
20
21
  from culture.telemetry.context import TRACEPARENT_TAG as _TP_TAG_NAME
21
22
  from culture.telemetry.context import (
22
23
  context_from_traceparent,
@@ -148,6 +149,7 @@ class Client:
148
149
  "error": type(exc).__name__,
149
150
  },
150
151
  )
152
+ self._submit_parse_error_audit(line, exc)
151
153
  continue
152
154
  # Record received bytes + message size for every successfully-parsed
153
155
  # line. +2 accounts for the \r\n that was stripped during line-split.
@@ -160,6 +162,49 @@ class Client:
160
162
  await self._dispatch(msg)
161
163
  return buffer
162
164
 
165
+ def _submit_parse_error_audit(self, line: str, exc: BaseException) -> None:
166
+ """Build and submit a PARSE_ERROR audit record for a malformed inbound line.
167
+
168
+ The record cannot go through build_audit_record (which expects an Event);
169
+ PARSE_ERROR is a synthetic event_type with no Event object behind it.
170
+ """
171
+ # Capture trace/span ids from the active span (the
172
+ # `irc.client.process_buffer` we're inside of).
173
+ span = _otel_trace.get_current_span()
174
+ ctx = span.get_span_context()
175
+ trace_id_hex = format(ctx.trace_id, "032x") if ctx.is_valid else ""
176
+ span_id_hex = format(ctx.span_id, "016x") if ctx.is_valid else ""
177
+
178
+ peer_info = self.writer.get_extra_info("peername")
179
+ remote_addr = f"{peer_info[0]}:{peer_info[1]}" if peer_info else ""
180
+
181
+ tags: dict[str, str] = {}
182
+ tp = current_traceparent()
183
+ if tp:
184
+ tags["culture.dev/traceparent"] = tp
185
+
186
+ record = {
187
+ "ts": _utc_iso_timestamp(time.time()),
188
+ "server": self.server.config.name,
189
+ "event_type": "PARSE_ERROR",
190
+ "origin": "local",
191
+ "peer": "",
192
+ "trace_id": trace_id_hex,
193
+ "span_id": span_id_hex,
194
+ "actor": {
195
+ "nick": self.nick or "",
196
+ "kind": "human",
197
+ "remote_addr": remote_addr,
198
+ },
199
+ "target": {"kind": "", "name": ""},
200
+ "payload": {
201
+ "line_preview": line[:64],
202
+ "error": type(exc).__name__,
203
+ },
204
+ "tags": tags,
205
+ }
206
+ self.server.audit.submit(record)
207
+
163
208
  async def handle(self, initial_msg: str | None = None) -> None:
164
209
  peer_info = self.writer.get_extra_info("peername")
165
210
  remote_addr = f"{peer_info[0]}:{peer_info[1]}" if peer_info else ""
@@ -26,6 +26,13 @@ class TelemetryConfig:
26
26
  traces_sampler: str = "parentbased_always_on"
27
27
  metrics_enabled: bool = True
28
28
  metrics_export_interval_ms: int = 10000
29
+ # Audit JSONL sink (Plan 4). Independent of `enabled` — audit fires
30
+ # even when telemetry is off so admins always have the trail.
31
+ audit_enabled: bool = True
32
+ audit_dir: str = "~/.culture/audit"
33
+ audit_max_file_bytes: int = 256 * 1024 * 1024 # 256 MiB
34
+ audit_rotate_utc_midnight: bool = True
35
+ audit_queue_depth: int = 10000
29
36
 
30
37
 
31
38
  @dataclass
@@ -23,12 +23,14 @@ from culture.constants import (
23
23
  SYSTEM_USER_PREFIX,
24
24
  )
25
25
  from culture.protocol.message import Message
26
+ from culture.telemetry import build_audit_record, current_traceparent
26
27
 
27
28
  logger = logging.getLogger(__name__)
28
29
 
29
30
  # Span/metric attribute keys defined once so a future rename has one edit point.
30
31
  _ATTR_EVENT_TYPE = "event.type"
31
32
 
33
+
32
34
  if TYPE_CHECKING:
33
35
  from culture.agentirc.client import Client
34
36
  from culture.agentirc.remote_client import RemoteClient
@@ -39,11 +41,12 @@ class IRCd:
39
41
  """The culture IRC server."""
40
42
 
41
43
  def __init__(self, config: ServerConfig):
42
- from culture.telemetry import init_metrics, init_telemetry
44
+ from culture.telemetry import init_audit, init_metrics, init_telemetry
43
45
 
44
46
  self.config = config
45
47
  self.tracer = init_telemetry(config)
46
48
  self.metrics = init_metrics(config)
49
+ self.audit = init_audit(config, self.metrics)
47
50
  self.clients: dict[str, Client | VirtualClient] = {} # nick -> Client
48
51
  self.channels: dict[str, Channel] = {} # name -> Channel
49
52
  self.skills: list[Skill] = []
@@ -74,6 +77,8 @@ class IRCd:
74
77
  logger.info("Bootstrapping system identity...")
75
78
  self._bootstrap_system_identity()
76
79
 
80
+ await self.audit.start()
81
+
77
82
  await self.emit_event(
78
83
  Event(
79
84
  type=EventType.SERVER_WAKE,
@@ -223,14 +228,25 @@ class IRCd:
223
228
  self.metrics.events_emitted.add(1, {_ATTR_EVENT_TYPE: event_type_str, "origin": origin_str})
224
229
  render_started = time.perf_counter()
225
230
 
231
+ trace_id_hex = ""
232
+ span_id_hex = ""
233
+ tp: str | None = None
234
+
226
235
  # Per-call get_tracer: the `tracing_exporter` test fixture swaps the
227
236
  # global provider between tests; a cached Tracer would bind to the
228
237
  # first test's provider and stop delivering to later ones.
229
238
  with _otel_trace.get_tracer("culture.agentirc").start_as_current_span(
230
239
  "irc.event.emit", attributes=attrs
231
- ):
240
+ ) as span:
232
241
  seq = self.next_seq()
233
242
  self._event_log.append((seq, event))
243
+ ctx = span.get_span_context()
244
+ if ctx.is_valid:
245
+ trace_id_hex = format(ctx.trace_id, "032x")
246
+ span_id_hex = format(ctx.span_id, "016x")
247
+ # Capture traceparent inside the span so trace_flags reflect
248
+ # the actual sampling decision for this span, not a hardcoded -01.
249
+ tp = current_traceparent()
234
250
  await self._run_skill_hooks(event)
235
251
  if not origin_tag:
236
252
  await self._relay_to_peers(event)
@@ -240,6 +256,22 @@ class IRCd:
240
256
  render_ms = (time.perf_counter() - render_started) * 1000.0
241
257
  self.metrics.events_render_duration.record(render_ms, {_ATTR_EVENT_TYPE: event_type_str})
242
258
 
259
+ # Audit submit happens after the span exits so it doesn't sit inside
260
+ # the irc.event.emit span (would skew render duration). The trace_id/
261
+ # span_id captured inside the span point back at it for cross-pillar
262
+ # joins.
263
+ tags: dict[str, str] = {"culture.dev/traceparent": tp} if tp else {}
264
+ self.audit.submit(
265
+ build_audit_record(
266
+ server_name=self.config.name,
267
+ event=event,
268
+ origin_tag=origin_tag,
269
+ trace_id=trace_id_hex,
270
+ span_id=span_id_hex,
271
+ extra_tags=tags,
272
+ )
273
+ )
274
+
243
275
  _NO_SURFACE_TYPES = NO_SURFACE_EVENT_TYPES
244
276
 
245
277
  @staticmethod
@@ -395,6 +427,7 @@ class IRCd:
395
427
  if self._server:
396
428
  self._server.close()
397
429
  await self._server.wait_closed()
430
+ await self.audit.shutdown()
398
431
  finally:
399
432
  self._stopped.set()
400
433
 
@@ -12,9 +12,16 @@ import logging
12
12
  import os
13
13
  import shutil
14
14
  import tempfile
15
- from typing import Any, Awaitable, Callable
15
+ import time
16
+ from typing import TYPE_CHECKING, Any, Awaitable, Callable
17
+
18
+ from opentelemetry import trace as _otel_trace
16
19
 
17
20
  from culture.aio import maybe_await
21
+ from culture.clients.acp.telemetry import _HARNESS_TRACER_NAME, record_llm_call
22
+
23
+ if TYPE_CHECKING:
24
+ from culture.clients.acp.telemetry import HarnessMetricsRegistry
18
25
 
19
26
  logger = logging.getLogger(__name__)
20
27
 
@@ -36,6 +43,8 @@ class ACPAgentRunner:
36
43
  on_exit: Callable[[int], Awaitable[None]] | None = None,
37
44
  on_message: Callable[[dict[str, Any]], Awaitable[None]] | None = None,
38
45
  on_turn_error: Callable[[], Awaitable[None] | None] | None = None,
46
+ metrics: HarnessMetricsRegistry | None = None,
47
+ nick: str = "",
39
48
  ) -> None:
40
49
  self.model = model
41
50
  self.directory = directory
@@ -44,6 +53,8 @@ class ACPAgentRunner:
44
53
  self.on_exit = on_exit
45
54
  self.on_message = on_message
46
55
  self.on_turn_error = on_turn_error
56
+ self._metrics = metrics
57
+ self._nick = nick
47
58
 
48
59
  self._isolated_home: str | None = None
49
60
  self._process: asyncio.subprocess.Process | None = None
@@ -431,16 +442,47 @@ class ACPAgentRunner:
431
442
 
432
443
  async def _execute_single_prompt(self, text: str) -> None:
433
444
  """Send one prompt and handle its result, managing the busy flag."""
434
- try:
435
- self._busy = True
436
- resp = await self._send_prompt_with_retry(text)
437
- await self._handle_prompt_result(resp)
438
- except Exception:
439
- logger.exception("ACP turn error")
440
- if self.on_turn_error:
441
- await maybe_await(self.on_turn_error())
442
- finally:
443
- self._busy = False
445
+ start_perf = time.perf_counter()
446
+ outcome = "success"
447
+ tracer = _otel_trace.get_tracer(_HARNESS_TRACER_NAME)
448
+ with tracer.start_as_current_span(
449
+ "harness.llm.call",
450
+ attributes={
451
+ "harness.backend": "acp",
452
+ "harness.model": self.model,
453
+ "harness.nick": self._nick,
454
+ },
455
+ ):
456
+ try:
457
+ self._busy = True
458
+ resp = await self._send_prompt_with_retry(text)
459
+ await self._handle_prompt_result(resp)
460
+ except TimeoutError: # bubbles from _send_prompt_with_retry's retry-then-fail
461
+ outcome = "timeout"
462
+ logger.exception("ACP turn timeout")
463
+ if self.on_turn_error:
464
+ await maybe_await(self.on_turn_error())
465
+ except Exception:
466
+ outcome = "error"
467
+ logger.exception("ACP turn error")
468
+ if self.on_turn_error:
469
+ await maybe_await(self.on_turn_error())
470
+ finally:
471
+ self._busy = False
472
+ duration_ms = (time.perf_counter() - start_perf) * 1000.0
473
+ if self._metrics is not None:
474
+ # ACP token usage MAY arrive in session/update stopReason payload;
475
+ # current implementation does not extract — usage=None for v1.
476
+ # When we add extraction (per backing agent), thread through here.
477
+ record_llm_call(
478
+ self._metrics,
479
+ backend="acp",
480
+ model=self.model,
481
+ nick=self._nick,
482
+ usage=None,
483
+ duration_ms=duration_ms,
484
+ outcome=outcome,
485
+ )
444
486
 
445
487
  async def _prompt_loop(self) -> None:
446
488
  """Process queued prompts one at a time."""
@@ -62,6 +62,27 @@ class AgentConfig:
62
62
  icon: str | None = None
63
63
 
64
64
 
65
+ @dataclass
66
+ class TelemetryConfig:
67
+ """OpenTelemetry settings for the agent harness.
68
+
69
+ ``enabled: false`` by default so freshly installed harnesses don't
70
+ try to connect to a non-existent OTLP collector. Flip to ``true``
71
+ once your collector is running.
72
+ """
73
+
74
+ enabled: bool = False
75
+ service_name: str = "culture.harness.acp"
76
+ otlp_endpoint: str = "http://localhost:4317"
77
+ otlp_protocol: str = "grpc" # grpc | http/protobuf (only grpc supported initially)
78
+ otlp_timeout_ms: int = 5000
79
+ otlp_compression: str = "gzip"
80
+ traces_enabled: bool = True
81
+ traces_sampler: str = "parentbased_always_on"
82
+ metrics_enabled: bool = True
83
+ metrics_export_interval_ms: int = 10000
84
+
85
+
65
86
  @dataclass
66
87
  class DaemonConfig:
67
88
  """Top-level daemon configuration."""
@@ -69,6 +90,7 @@ class DaemonConfig:
69
90
  server: ServerConnConfig = field(default_factory=ServerConnConfig)
70
91
  supervisor: SupervisorConfig = field(default_factory=SupervisorConfig)
71
92
  webhooks: WebhookConfig = field(default_factory=WebhookConfig)
93
+ telemetry: TelemetryConfig = field(default_factory=TelemetryConfig)
72
94
  buffer_size: int = 500
73
95
  poll_interval: int = 60
74
96
  sleep_start: str = "23:00"
@@ -91,6 +113,7 @@ def load_config(path: str | Path) -> DaemonConfig:
91
113
  supervisor = SupervisorConfig(**raw.get("supervisor", {}))
92
114
 
93
115
  webhooks = WebhookConfig(**raw.get("webhooks", {}))
116
+ telemetry = TelemetryConfig(**raw.get("telemetry", {}))
94
117
 
95
118
  agents = []
96
119
  known_agent_fields = {f.name for f in AgentConfig.__dataclass_fields__.values()}
@@ -102,6 +125,7 @@ def load_config(path: str | Path) -> DaemonConfig:
102
125
  server=server,
103
126
  supervisor=supervisor,
104
127
  webhooks=webhooks,
128
+ telemetry=telemetry,
105
129
  buffer_size=raw.get("buffer_size", 500),
106
130
  poll_interval=raw.get("poll_interval", 60),
107
131
  sleep_start=raw.get("sleep_start", "23:00"),
@@ -0,0 +1,32 @@
1
+ suffix: harness-acp
2
+ backend: claude
3
+ model: claude-opus-4-6
4
+ channels:
5
+ - "#harness"
6
+ acp_command:
7
+ - opencode
8
+ - acp
9
+ system_prompt: |
10
+ You maintain the ACP agent backend in culture/clients/acp/.
11
+ Listen on #harness for propagation instructions from spark-harness.
12
+ Apply changes using the citation pattern (cite, don't import),
13
+ adapting for ACP (Cline, OpenCode, Kiro)
14
+ specifics (agent_runner.py, supervisor.py).
15
+ tags:
16
+ - harness
17
+ - acp
18
+
19
+ # OpenTelemetry configuration for the agent harness.
20
+ # Set enabled: true once your OTLP collector is running.
21
+ # See docs/agentirc/harness-telemetry.md for a setup guide.
22
+ telemetry:
23
+ enabled: false # master switch — flip to true to start exporting
24
+ service_name: culture.harness.acp # overridden per-backend (e.g. culture.harness.acp)
25
+ otlp_endpoint: http://localhost:4317 # OTLP/gRPC receiver endpoint
26
+ otlp_protocol: grpc # grpc or http/protobuf
27
+ otlp_timeout_ms: 5000 # export request timeout in milliseconds
28
+ otlp_compression: gzip # gzip | none
29
+ traces_enabled: true # enable distributed tracing
30
+ traces_sampler: parentbased_always_on # honor the server's sampling decision
31
+ metrics_enabled: true # enable LLM call metrics export
32
+ metrics_export_interval_ms: 10000 # how often to push metric batches (ms)
@@ -25,6 +25,7 @@ from culture.clients.acp.irc_transport import IRCTransport
25
25
  from culture.clients.acp.message_buffer import MessageBuffer
26
26
  from culture.clients.acp.socket_server import SocketServer
27
27
  from culture.clients.acp.supervisor import Supervisor, make_sdk_evaluate_fn
28
+ from culture.clients.acp.telemetry import init_harness_telemetry
28
29
  from culture.clients.acp.webhook import AlertEvent, WebhookClient
29
30
  from culture.pidfile import remove_pid, write_pid
30
31
 
@@ -71,6 +72,8 @@ class ACPDaemon:
71
72
  self._socket_server: SocketServer | None = None
72
73
  self._agent_runner: ACPAgentRunner | None = None
73
74
  self._supervisor: Supervisor | None = None
75
+ self._tracer = None
76
+ self._metrics = None
74
77
 
75
78
  # FIFO queue of relay targets — each @mention enqueues a target,
76
79
  # each agent response dequeues one, ensuring correct routing even
@@ -134,6 +137,9 @@ class ACPDaemon:
134
137
  self._pid_name = f"agent-{self.agent.nick}"
135
138
  write_pid(self._pid_name, os.getpid())
136
139
 
140
+ # 0.5. OTEL telemetry (if telemetry.enabled, installs SDK providers; else no-op).
141
+ self._tracer, self._metrics = init_harness_telemetry(self.config)
142
+
137
143
  # 1. Message buffer
138
144
  self._buffer = MessageBuffer(max_per_channel=self.config.buffer_size)
139
145
 
@@ -148,6 +154,9 @@ class ACPDaemon:
148
154
  on_mention=self._on_mention,
149
155
  tags=list(self.agent.tags),
150
156
  on_roominvite=self._on_roominvite,
157
+ tracer=self._tracer,
158
+ metrics=self._metrics,
159
+ backend="acp",
151
160
  )
152
161
  await self._transport.connect()
153
162
 
@@ -389,6 +398,8 @@ class ACPDaemon:
389
398
  on_exit=self._on_agent_exit,
390
399
  on_message=self._on_agent_message,
391
400
  on_turn_error=self._on_turn_error,
401
+ metrics=self._metrics,
402
+ nick=self.agent.nick,
392
403
  )
393
404
  # Absorb the system prompt response without relaying to IRC
394
405
  self._mention_targets.append(None)
@@ -1,20 +1,38 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import contextlib
4
5
  import logging
5
6
  import re
6
- from typing import Callable
7
+ from contextlib import AbstractContextManager
8
+ from typing import TYPE_CHECKING, Callable
7
9
 
8
10
  from culture.aio import maybe_await
9
11
  from culture.clients.acp.message_buffer import MessageBuffer
10
12
  from culture.constants import SYSTEM_USER_PREFIX
11
13
  from culture.protocol.message import Message
14
+ from culture.telemetry.context import (
15
+ TRACEPARENT_TAG,
16
+ context_from_traceparent,
17
+ current_traceparent,
18
+ extract_traceparent_from_tags,
19
+ )
20
+
21
+ if TYPE_CHECKING:
22
+ from opentelemetry.trace import Tracer
23
+
24
+ from culture.clients.acp.telemetry import HarnessMetricsRegistry
12
25
 
13
26
  logger = logging.getLogger(__name__)
14
27
 
15
28
 
16
29
  class IRCTransport:
17
- """Async IRC client for the daemon."""
30
+ """Async IRC client for the daemon.
31
+
32
+ Optional kwargs ``tracer``, ``metrics``, and ``backend`` enable OTEL
33
+ tracing and LLM metrics when an SDK provider is installed. Pass ``None``
34
+ (the default) for all three to run without instrumentation.
35
+ """
18
36
 
19
37
  def __init__(
20
38
  self,
@@ -28,6 +46,9 @@ class IRCTransport:
28
46
  tags: list[str] | None = None,
29
47
  on_roominvite: Callable[[str, str], None] | None = None,
30
48
  icon: str | None = None,
49
+ tracer: Tracer | None = None,
50
+ metrics: HarnessMetricsRegistry | None = None,
51
+ backend: str = "acp",
31
52
  ):
32
53
  self.host = host
33
54
  self.port = port
@@ -39,6 +60,10 @@ class IRCTransport:
39
60
  self.tags = tags or []
40
61
  self.on_roominvite = on_roominvite
41
62
  self.icon = icon
63
+ self._tracer = tracer
64
+ # accepted for future per-message metrics (e.g. byte counters); unused in v1
65
+ self._metrics = metrics
66
+ self._backend = backend
42
67
  self.connected = False
43
68
  self._reader: asyncio.StreamReader | None = None
44
69
  self._writer: asyncio.StreamWriter | None = None
@@ -57,23 +82,46 @@ class IRCTransport:
57
82
  "332": self._on_numeric_topic,
58
83
  }
59
84
 
85
+ def _span(self, name: str, attrs: dict | None = None) -> AbstractContextManager:
86
+ """Return a real span context manager when tracing is enabled, else a no-op.
87
+
88
+ Keeps the no-tracer fast path clean — all callers write the same
89
+ ``with self._span(...):`` pattern regardless of whether a tracer is
90
+ configured.
91
+
92
+ Does NOT accept a ``context=`` argument; callers that need a span
93
+ parented to a remote trace context (e.g. inbound message handling in
94
+ ``_handle``) call ``self._tracer.start_as_current_span`` directly.
95
+ """
96
+ if self._tracer is not None:
97
+ return self._tracer.start_as_current_span(name, attributes=attrs or {})
98
+ return contextlib.nullcontext()
99
+
60
100
  async def connect(self) -> None:
61
101
  self._should_run = True
62
102
  await self._do_connect()
63
103
 
64
104
  async def _do_connect(self) -> None:
65
- try:
66
- self._reader, self._writer = await asyncio.open_connection(self.host, self.port)
67
- except OSError as exc:
68
- raise ConnectionError(
69
- f"Cannot connect to IRC server at {self.host}:{self.port} "
70
- f"- is the server running?"
71
- ) from exc
72
- await self._send_raw("CAP REQ :message-tags")
73
- await self._send_raw(f"NICK {self.nick}")
74
- await self._send_raw(f"USER {self.user} 0 * :{self.user}")
75
- await self._send_raw("CAP END")
76
- self._read_task = asyncio.create_task(self._read_loop())
105
+ with self._span(
106
+ "harness.irc.connect",
107
+ attrs={
108
+ "harness.backend": self._backend,
109
+ "harness.nick": self.nick,
110
+ "harness.server": f"{self.host}:{self.port}",
111
+ },
112
+ ):
113
+ try:
114
+ self._reader, self._writer = await asyncio.open_connection(self.host, self.port)
115
+ except OSError as exc:
116
+ raise ConnectionError(
117
+ f"Cannot connect to IRC server at {self.host}:{self.port} "
118
+ f"- is the server running?"
119
+ ) from exc
120
+ await self._send_raw("CAP REQ :message-tags")
121
+ await self._send_raw(f"NICK {self.nick}")
122
+ await self._send_raw(f"USER {self.user} 0 * :{self.user}")
123
+ await self._send_raw("CAP END")
124
+ self._read_task = asyncio.create_task(self._read_loop())
77
125
 
78
126
  async def disconnect(self) -> None:
79
127
  self._should_run = False
@@ -145,12 +193,23 @@ class IRCTransport:
145
193
  await self._send_raw(f"TOPIC {channel}")
146
194
 
147
195
  async def send_raw(self, line: str) -> None:
148
- """Send a raw IRC line. Public for commands like HISTORY."""
196
+ """Send a raw IRC line. Public for commands like HISTORY.
197
+
198
+ When a tracer is configured and a span is active, prepends the W3C
199
+ ``@culture.dev/traceparent=`` IRCv3 tag so all outbound paths — whether
200
+ called via the internal ``_send_raw`` helper or directly by daemon code
201
+ — carry trace context consistently.
202
+ """
203
+ if self._tracer is not None and not line.startswith("@"):
204
+ tp = current_traceparent()
205
+ if tp is not None:
206
+ line = f"@{TRACEPARENT_TAG}={tp} {line}"
149
207
  if self._writer:
150
208
  self._writer.write(f"{line}\r\n".encode())
151
209
  await self._writer.drain()
152
210
 
153
211
  async def _send_raw(self, line: str) -> None:
212
+ """Internal send helper; delegates to send_raw (injection lives there)."""
154
213
  await self.send_raw(line)
155
214
 
156
215
  async def _read_loop(self) -> None:
@@ -193,9 +252,41 @@ class IRCTransport:
193
252
  delay = min(delay * 2, 60)
194
253
 
195
254
  async def _handle(self, msg: Message) -> None:
196
- handler = self._cmd_handlers.get(msg.command)
197
- if handler:
198
- await maybe_await(handler(msg))
255
+ # Extract inbound traceparent before opening any span so the new span
256
+ # can be correctly parented to the remote trace context.
257
+ result = extract_traceparent_from_tags(msg, peer=None)
258
+
259
+ if self._tracer is not None:
260
+ if result.status == "valid":
261
+ ctx = context_from_traceparent(result.traceparent)
262
+ span_cm = self._tracer.start_as_current_span(
263
+ "harness.irc.message.handle",
264
+ context=ctx,
265
+ attributes={
266
+ "irc.command": msg.command,
267
+ "irc.client.nick": self.nick,
268
+ "culture.trace.origin": "remote",
269
+ },
270
+ )
271
+ else:
272
+ attrs = {
273
+ "irc.command": msg.command,
274
+ "irc.client.nick": self.nick,
275
+ "culture.trace.origin": ("local" if result.status == "missing" else "remote"),
276
+ }
277
+ if result.status in ("malformed", "too_long"):
278
+ attrs["culture.trace.dropped_reason"] = result.status
279
+ span_cm = self._tracer.start_as_current_span(
280
+ "harness.irc.message.handle",
281
+ attributes=attrs,
282
+ )
283
+ else:
284
+ span_cm = contextlib.nullcontext()
285
+
286
+ with span_cm:
287
+ handler = self._cmd_handlers.get(msg.command)
288
+ if handler:
289
+ await maybe_await(handler(msg))
199
290
 
200
291
  async def _on_ping(self, msg: Message) -> None:
201
292
  token = msg.params[0] if msg.params else ""