agent-wire-cli 0.2.4__tar.gz → 0.2.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. agent_wire_cli-0.2.5/.claude-plugin/marketplace.json +14 -0
  2. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/.github/workflows/ci.yml +3 -5
  3. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/.github/workflows/release.yml +1 -0
  4. agent_wire_cli-0.2.5/CHANGELOG.md +55 -0
  5. agent_wire_cli-0.2.5/DOCUMENTATION.md +112 -0
  6. agent_wire_cli-0.2.4/README.md → agent_wire_cli-0.2.5/PKG-INFO +76 -10
  7. agent_wire_cli-0.2.5/PRIVACY.md +54 -0
  8. agent_wire_cli-0.2.4/PKG-INFO → agent_wire_cli-0.2.5/README.md +44 -40
  9. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/SECURITY.md +16 -1
  10. agent_wire_cli-0.2.5/SUPPORT.md +6 -0
  11. agent_wire_cli-0.2.5/TERMS.md +17 -0
  12. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/manifests/gemini_extension.json +1 -1
  13. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/manifests/hermes_skill.md +1 -1
  14. agent_wire_cli-0.2.5/plugin/.claude-plugin/plugin.json +77 -0
  15. agent_wire_cli-0.2.5/plugin/.mcp.json +17 -0
  16. agent_wire_cli-0.2.5/plugin/LICENSE +21 -0
  17. agent_wire_cli-0.2.5/plugin/README.md +27 -0
  18. agent_wire_cli-0.2.5/plugin/agents/wire-worker.md +21 -0
  19. agent_wire_cli-0.2.5/plugin/assets/agent-wire-logo.png +0 -0
  20. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5/plugin}/skills/agent-wire/SKILL.md +1 -1
  21. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/pyproject.toml +10 -2
  22. agent_wire_cli-0.2.5/skills/agent-wire/SKILL.md +45 -0
  23. agent_wire_cli-0.2.5/src/agent_wire/__init__.py +1 -0
  24. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/github.py +4 -0
  25. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/cli.py +152 -4
  26. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/compression/bm25_slicer.py +38 -9
  27. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/config.py +3 -0
  28. agent_wire_cli-0.2.5/src/agent_wire/firewall/inbound_shield.py +329 -0
  29. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/firewall/outbound_privacy.py +6 -0
  30. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/firewall/ssrf_guard.py +5 -0
  31. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/media/audio_transcriber.py +6 -1
  32. agent_wire_cli-0.2.5/src/agent_wire/selftest/__init__.py +175 -0
  33. agent_wire_cli-0.2.5/src/agent_wire/selftest/checks.py +373 -0
  34. agent_wire_cli-0.2.5/src/agent_wire/selftest/fakes.py +131 -0
  35. agent_wire_cli-0.2.5/src/agent_wire/selftest/live.py +108 -0
  36. agent_wire_cli-0.2.5/src/agent_wire/selftest/scenarios.py +235 -0
  37. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/server.py +73 -34
  38. agent_wire_cli-0.2.5/src/agent_wire/shield/__init__.py +91 -0
  39. agent_wire_cli-0.2.5/src/agent_wire/shield/demo.html +30 -0
  40. agent_wire_cli-0.2.5/src/agent_wire/shield/demo.py +39 -0
  41. agent_wire_cli-0.2.5/src/agent_wire/shield/detect.py +84 -0
  42. agent_wire_cli-0.2.5/src/agent_wire/shield/events.py +136 -0
  43. agent_wire_cli-0.2.5/src/agent_wire/shield/ledger.py +99 -0
  44. agent_wire_cli-0.2.5/src/agent_wire/shield/notify.py +107 -0
  45. agent_wire_cli-0.2.5/tests/conftest.py +24 -0
  46. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_channels_tier2_3.py +14 -16
  47. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_codemode.py +8 -2
  48. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_config.py +7 -0
  49. agent_wire_cli-0.2.5/tests/test_directory_compliance.py +53 -0
  50. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_installer.py +27 -5
  51. agent_wire_cli-0.2.5/tests/test_selftest.py +85 -0
  52. agent_wire_cli-0.2.5/tests/test_shield.py +252 -0
  53. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/uv.lock +14 -10
  54. agent_wire_cli-0.2.4/.claude-plugin/marketplace.json +0 -14
  55. agent_wire_cli-0.2.4/.claude-plugin/plugin.json +0 -26
  56. agent_wire_cli-0.2.4/.github/scripts/mcp_smoke.py +0 -36
  57. agent_wire_cli-0.2.4/src/agent_wire/__init__.py +0 -1
  58. agent_wire_cli-0.2.4/src/agent_wire/firewall/inbound_shield.py +0 -116
  59. agent_wire_cli-0.2.4/tests/conftest.py +0 -62
  60. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/.github/dependabot.yml +0 -0
  61. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/.github/workflows/codeql.yml +0 -0
  62. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/.github/workflows/security.yml +0 -0
  63. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/.gitignore +0 -0
  64. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/.mcp.json +0 -0
  65. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/LICENSE +0 -0
  66. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/agents/wire-worker.md +0 -0
  67. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-banner-light.png +0 -0
  68. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-banner-light.svg +0 -0
  69. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-banner.png +0 -0
  70. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-banner.svg +0 -0
  71. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-logo-transparent.png +0 -0
  72. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-logo-transparent.svg +0 -0
  73. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-logo.png +0 -0
  74. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/assets/agent-wire-logo.svg +0 -0
  75. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/manifests/antigravity_mcp.json +0 -0
  76. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/manifests/codex.toml +0 -0
  77. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/manifests/cursor_rule.mdc +0 -0
  78. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/manifests/peridot_local.json +0 -0
  79. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/manifests/windsurf_rules.md +0 -0
  80. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/__main__.py +0 -0
  81. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/auth/__init__.py +0 -0
  82. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/auth/browser_paths.py +0 -0
  83. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/auth/cookie_vault.py +0 -0
  84. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/auth/rate_limiter.py +0 -0
  85. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/cache/__init__.py +0 -0
  86. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/cache/ring_buffer.py +0 -0
  87. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/cache/sqlite_ledger.py +0 -0
  88. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/__init__.py +0 -0
  89. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/base.py +0 -0
  90. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/__init__.py +0 -0
  91. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/hackernews.py +0 -0
  92. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/reddit.py +0 -0
  93. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/rss.py +0 -0
  94. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/search.py +0 -0
  95. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/stackoverflow.py +0 -0
  96. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/web.py +0 -0
  97. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/wikipedia.py +0 -0
  98. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/x_twitter.py +0 -0
  99. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier1_global/youtube.py +0 -0
  100. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/__init__.py +0 -0
  101. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/archive_bypass.py +0 -0
  102. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/arxiv_papers.py +0 -0
  103. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/devto.py +0 -0
  104. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/fediverse.py +0 -0
  105. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/hubs.py +0 -0
  106. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/linkedin.py +0 -0
  107. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/markets.py +0 -0
  108. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/meta_social.py +0 -0
  109. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/news.py +0 -0
  110. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/polymarket.py +0 -0
  111. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/publishing.py +0 -0
  112. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier2_pro/stocktwits.py +0 -0
  113. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/bilibili.py +0 -0
  114. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/boss_zhipin.py +0 -0
  115. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/douyin_tiktok.py +0 -0
  116. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/v2ex.py +0 -0
  117. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/wechat.py +0 -0
  118. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/xiaohongshu.py +0 -0
  119. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/xiaoyuzhou.py +0 -0
  120. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/xueqiu.py +0 -0
  121. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/channels/tier3_regional/zhihu.py +0 -0
  122. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/codemode/__init__.py +0 -0
  123. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/codemode/api.py +0 -0
  124. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/codemode/sandbox.py +0 -0
  125. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/compression/__init__.py +0 -0
  126. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/compression/anchor_slicer.py +0 -0
  127. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/compression/dam_formatter.py +0 -0
  128. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/compression/url_compactor.py +0 -0
  129. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/engine/__init__.py +0 -0
  130. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/engine/challenge.py +0 -0
  131. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/engine/errors.py +0 -0
  132. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/engine/http_pool.py +0 -0
  133. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/engine/stealth_browser.py +0 -0
  134. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/engine/waterfall.py +0 -0
  135. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/firewall/__init__.py +0 -0
  136. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/installers/__init__.py +0 -0
  137. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/installers/client_installer.py +0 -0
  138. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/media/__init__.py +0 -0
  139. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/media/subtitle_cleaner.py +0 -0
  140. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/models.py +0 -0
  141. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/__init__.py +0 -0
  142. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/brief.py +0 -0
  143. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/briefing.py +0 -0
  144. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/cluster.py +0 -0
  145. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/engine.py +0 -0
  146. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/library.py +0 -0
  147. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/planner.py +0 -0
  148. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/scoring.py +0 -0
  149. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/store.py +0 -0
  150. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/research/watch.py +0 -0
  151. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/router.py +0 -0
  152. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/verify/__init__.py +0 -0
  153. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/src/agent_wire/verify/citations.py +0 -0
  154. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_auth.py +0 -0
  155. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_bm25_slicer.py +0 -0
  156. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_channels_new.py +0 -0
  157. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_channels_tier1.py +0 -0
  158. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_citations.py +0 -0
  159. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_codemode_bench.py +0 -0
  160. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_compression.py +0 -0
  161. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_firewall_inbound.py +0 -0
  162. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_firewall_outbound.py +0 -0
  163. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_models.py +0 -0
  164. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_research.py +0 -0
  165. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_ring_buffer.py +0 -0
  166. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_server.py +0 -0
  167. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_ssrf_guard.py +0 -0
  168. {agent_wire_cli-0.2.4 → agent_wire_cli-0.2.5}/tests/test_waterfall_routing.py +0 -0
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "agent-wire",
3
+ "description": "Agent Wire by uncoalesced: live web, search and platform reads for AI agents from one local MCP server, compressed and shielded against prompt injection.",
4
+ "owner": {
5
+ "name": "uncoalesced"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "agent-wire",
10
+ "source": "./plugin",
11
+ "description": "Live web, search and platform reads for agents, compressed and shielded against prompt injection."
12
+ }
13
+ ]
14
+ }
@@ -26,7 +26,7 @@ jobs:
26
26
  - name: Install
27
27
  run: uv sync --extra dev --locked
28
28
  - name: Ruff lint
29
- run: uv run ruff check src tests .github/scripts
29
+ run: uv run ruff check src tests
30
30
  - name: Ruff format
31
31
  run: uv run ruff format --check .
32
32
  - name: No temp-dir writes in the package
@@ -109,8 +109,6 @@ jobs:
109
109
  out=$(uvx --python ${{ matrix.python }} --from "$whl" wire run -e "return 6 * 7")
110
110
  echo "$out"
111
111
  grep -q '^42$' <<<"$out"
112
- - name: MCP server over stdio (both modes)
112
+ - name: Self-test (every subsystem, MCP over stdio in both modes, no network)
113
113
  shell: bash
114
- run: >-
115
- uv run --isolated --no-project --python ${{ matrix.python }}
116
- --with "$(ls dist/*.whl)" python .github/scripts/mcp_smoke.py
114
+ run: uvx --python ${{ matrix.python }} --from "$(ls dist/*.whl)" wire selftest
@@ -27,6 +27,7 @@ jobs:
27
27
  test "v$v" = "${GITHUB_REF_NAME}" || { echo "tag ${GITHUB_REF_NAME} != v$v"; exit 1; }
28
28
  - run: uv sync --extra dev --locked
29
29
  - run: uv run pytest -q
30
+ - run: uv run wire selftest
30
31
  - run: uv build
31
32
  - run: uvx twine check --strict dist/*
32
33
  - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ All notable changes to agent-wire (`agent-wire-cli` on PyPI, the `agent-wire` Claude plugin).
4
+
5
+ ## 0.2.5 (2026-11-15)
6
+
7
+ ### Added
8
+ - **`wire selftest`.** Checks every subsystem in one offline run, and a guard fails the run on any network attempt. It covers:
9
+ - all 31 channels, on canned responses
10
+ - the inbound and outbound firewalls, and the SSRF guard
11
+ - Shield Alerts and the alert ledger
12
+ - compression, the delta buffer and the route ledger
13
+ - the cookie vault and Code Mode
14
+ - research and `wire_cite`
15
+ - the 11 client installers
16
+ - the MCP server, in-process and over stdio
17
+
18
+ `--live` adds one real request per channel (Reddit with no API key) and counts shield false positives on the 16 README benchmark pages. `--only` and `--json` narrow and format the run. CI and the release workflow run the offline check.
19
+ - **Shield Alerts.** Stripped hidden prompt injections, forged delimiters and refused outbound requests are reported to you out of band: a desktop notification, a stderr line, and a trusted `[WIRE SHIELD | ...]` line ahead of the quoted content. Alerts are kept in a hash-chained `alerts.db`. New commands: `wire alerts`, `show`, `tail`, `verify`, `demo`.
20
+ - **Root policy documents:** `PRIVACY.md`, `TERMS.md`, `DOCUMENTATION.md`, `SUPPORT.md`.
21
+
22
+ ### Changed
23
+ - **The Claude plugin now lives in `plugin/`.** It launches the published package with `uvx agent-wire-cli==0.2.5 serve`.
24
+ - Optional credentials come from the plugin's `userConfig`, marked sensitive. Each one is sent only to its own service.
25
+ - The plugin never shells out to `gh`.
26
+ - **`WIRE_HOME` prefers `CLAUDE_PLUGIN_DATA`,** so plugin updates keep your data.
27
+ - **`rookiepy` is now the `[browser-cookies]` extra,** and `wire_status` no longer looks at browser profiles.
28
+ - **Server tool descriptions describe the tools only.** When-to-use guidance stays in the skill, whose description no longer tells the model to act "automatically".
29
+ - **Setting a transcription API key turns transcription on.** This is what the plugin's `transcribe_api_key` option implied all along. `WIRE_TRANSCRIBE=0` still turns it off.
30
+ - **Token counting falls back to an approximation** when the tokenizer file can't be downloaded on first run, so reads keep working offline.
31
+ - **The lock moves dnspython to 2.9.2 and opentelemetry-api to 1.45.2** (CVE-2026-128089, CVE-2026-126360; both are transitive dependencies through fastmcp).
32
+ - **`joserfc>=1.8.0` is required** (GHSA-jpxq-7h8p-2q76, GHSA-9pg5-8c7x-5hfx). agent-wire itself never parses JWS or JWE.
33
+ - **The HTTP/SSE transport binds `127.0.0.1` explicitly.**
34
+
35
+ ### Fixed
36
+ - **Hidden-text stripping now catches:**
37
+ - text hidden by the page's own stylesheet (`.x{display:none}`, `#id{visibility:hidden}`)
38
+ - text hidden by the `sr-only`, `visually-hidden`, `hidden` and `d-none` classes
39
+ - text hidden with `clip`, `clip-path`, a transparent color, or off-screen `top`/`right`/`margin`
40
+ - **Invisible characters written as HTML entities** (`&#xE0041;`, `&#8203;`) are now removed after parsing.
41
+
42
+ ### Measured
43
+ - **Attack corpus:** 12 of 12 hiding techniques detected and stripped.
44
+ - **Benign corpus:** 0 alerts across 9 cases.
45
+ - **`wire selftest --live`, 2026-11-15:**
46
+ - **Benchmark pages:** none raised an alert, over two runs (16 of 16 read on the first; on the second, the Cloudflare challenge page needed the stealth browser, so 15 were read).
47
+ - **Channels:** 26 of 31 answered with no keys or logins, including Reddit.
48
+ - **Skipped (5):**
49
+ - Zhihu and Boss Zhipin need a login or the stealth browser.
50
+ - TikTok's oEmbed refused the probe.
51
+ - Xiaohongshu and Xiaoyuzhou have no stable public URL to probe.
52
+
53
+ ## Earlier releases
54
+
55
+ See the [GitHub releases page](https://github.com/uncoalesced/agent-wire/releases).
@@ -0,0 +1,112 @@
1
+ # Agent Wire documentation
2
+
3
+ Agent Wire by uncoalesced is a local MCP server that gives AI agents live web pages, web search and platform reads. On PyPI it's `agent-wire-cli`, the shell command is `wire`, and the Claude plugin is `agent-wire`. The [README](README.md) covers the same ground with benchmarks and background; this page is the reference.
4
+
5
+ ## Install
6
+
7
+ You need [uv](https://docs.astral.sh/uv/).
8
+
9
+ - **Claude Code plugin:** `/plugin install agent-wire --marketplace uncoalesced/agent-wire`. It starts `uvx agent-wire-cli==<version> serve` and asks for optional keys when you enable it.
10
+ - **Any other client:** `uvx agent-wire-cli install --client auto` finds the agent clients on your machine (Claude Code, Claude Desktop, Codex, Cursor, Windsurf, VS Code, Roo, Gemini CLI, Hermes, Antigravity, Peridot), shows what it will write, and asks first. `--client <name>`, `--dry-run`, `--global` and `--project PATH` narrow it down.
11
+ - **By hand:** run `uvx agent-wire-cli serve` as a stdio MCP server.
12
+
13
+ Optional extras: `agent-wire-cli[stealth]` (headless browser for Cloudflare-protected pages and the `wire auth login` window), `agent-wire-cli[browser-cookies]` (import a login from Chrome, Edge or Brave), `agent-wire-cli[local-whisper]` (local podcast transcription).
14
+
15
+ ## Tools
16
+
17
+ | Tool | What it does |
18
+ |---|---|
19
+ | `wire_read(urls, query, section, include_comments, max_tokens, force)` | Reads up to 10 URLs. `query` keeps the parts that answer it; `#L10-L50` and `#heading` anchors work. A page read again returns only what changed. |
20
+ | `wire_search(query, platforms, limit, sort, auto_expand_top, max_tokens)` | Searches the web or specific platforms and reads the top hits in the same call. |
21
+ | `wire_feed(platform, target, sort, limit)` | A subreddit, an `@user` timeline, GitHub trending, an arXiv category, a stock watchlist, an RSS feed. |
22
+ | `wire_me(platform, target, limit)` | Your own posts, likes, bookmarks, notifications or stats, through a session you saved. |
23
+ | `wire_research(topic, days, ...)` | One cited brief of what people said about a topic in the last N days, an "A vs B" comparison, or what's trending. |
24
+ | `wire_cite(text, check_quotes)` | Opens every link in a text and reports dead, archived-only, bot-blocked and soft-404 pages, quotes missing from their page, and `[[UNSOURCED]]` claims. |
25
+ | `wire_run(code, max_tokens)` | Code Mode: one sandboxed JavaScript script that calls `wire.read/search/feed/research/cite` and returns only what the script returns. |
26
+ | `wire_status(refresh)` | Channels, saved logins, route cache and alert counts. |
27
+
28
+ Every result starts with a `[WIRE | ...]` line, then any `[WIRE SHIELD | ...]` alert lines, then the page content inside an `[UNTRUSTED_EXTERNAL_DATA]` block. Everything inside that block is quoted material from the web, not instructions.
29
+
30
+ How an agent should use the tools (when to call each one, citation rules) is in the skill and rule files the installer writes: [`skills/agent-wire/SKILL.md`](skills/agent-wire/SKILL.md), and the Cursor, Windsurf and Hermes files in [`manifests/`](manifests/).
31
+
32
+ ## Logins
33
+
34
+ Most sites need no login. For your own account (`wire_me`) and login-only sites:
35
+
36
+ - `wire auth login <site>` opens a login window (needs the `[stealth]` extra) and saves that site's cookies to an encrypted vault.
37
+ - `wire auth login <site> --from-browser` copies that one site's cookies from a browser you're signed in to. Firefox works out of the box; Chrome, Edge and Brave need `[browser-cookies]`.
38
+ - `wire auth list` shows saved sites (names only); `wire auth logout <site>` forgets one.
39
+
40
+ A saved login is sent only to its own site, only on GET or HEAD requests, never to account pages such as messages, settings or billing, and never across a redirect.
41
+
42
+ ## Configuration
43
+
44
+ | Setting | Effect |
45
+ |---|---|
46
+ | `WIRE_HOME` | Where agent-wire keeps its files. The Claude plugin uses its plugin data folder. |
47
+ | `GITHUB_TOKEN` | Higher GitHub rate limits and `wire_me github`. Outside the plugin, `gh auth token` is used if set up; `WIRE_NO_GH_CLI=1` turns that off. |
48
+ | `REDDIT_CLIENT_ID`, `REDDIT_CLIENT_SECRET` | Reddit's official app login, for networks where anonymous access is blocked. |
49
+ | `WIRE_SEARXNG_URL`, `EXA_API_KEY` | Extra web search engines. |
50
+ | `WIRE_TRANSCRIBE=1` (+ `WIRE_TRANSCRIBE_API_KEY`, `_URL`, `_MODEL`) | Podcast transcription, locally or through an OpenAI-compatible API. Setting `WIRE_TRANSCRIBE_API_KEY` alone also turns it on; `WIRE_TRANSCRIBE=0` turns it off. |
51
+ | `WIRE_ALLOW_PRIVATE=1` | Let reads reach private and internal addresses. Off by default. |
52
+ | `WIRE_SHIELD_NOTIFY=0` | No desktop notifications for alerts. |
53
+ | `WIRE_SHIELD_VERBOSE=1` | Also record every routine removal (hidden menus, zero-width spaces) in the alert ledger. |
54
+
55
+ In the Claude plugin, the keys are plugin settings (`userConfig`) stored in Claude Code's secure storage, and the plugin never reads credentials from your machine.
56
+
57
+ ## Shield Alerts
58
+
59
+ agent-wire removes text a human reader can't see before the model reads a page, and refuses requests a page may have steered. Shield Alerts tells you when that happened, without relying on the model to mention it: a hijacked or distracted agent could leave the warning out.
60
+
61
+ **What raises an alert.**
62
+
63
+ | Tier | Examples | What you get |
64
+ |---|---|---|
65
+ | info | A hidden menu, a cookie banner, a zero-width space, a fake chat token in a comment | A counter in `wire_status`. Recorded in full only with `WIRE_SHIELD_VERBOSE=1`. |
66
+ | alert | Hidden text that reads like an instruction to an AI ("ignore previous instructions", "you are now", chat tokens, tool names, "don't tell the user", "send the API keys to"); text smuggled in Unicode tag characters; a forged end-of-data marker; visible text that names agent-wire's tools, asks the model to hide something from you, or asks it to send secrets somewhere | Notification, stderr line, header line, ledger row |
67
+ | high | A refused request: a private or internal address, a non-web URL scheme, a logged-in request that would write or reach an account page | Same, worded as a refused request |
68
+
69
+ Visible text is judged more strictly than hidden text. A security article that quotes "ignore previous instructions" in plain view is not an attack on you and raises nothing; the same words hidden with CSS do.
70
+
71
+ **What each alert says it did.** `stripped` (removed before the model saw it), `escaped` (neutralized in place), `refused` (never sent), `flagged-only` (visible text: it stays in the quoted content, marked as untrusted, because removing visible text would censor the page).
72
+
73
+ **Where alerts go.**
74
+
75
+ 1. `WIRE_HOME/alerts.db`, one row per alert, chained by SHA-256 so edits are detectable (`wire alerts verify`).
76
+ 2. A desktop notification (Windows toast, macOS Notification Center, Linux `notify-send`). At most one per site per minute and five per minute overall. It never contains page text.
77
+ 3. A `[wire-shield] ...` line on stderr, which some clients show as server logs.
78
+ 4. A `[WIRE SHIELD | ...]` line in the tool result, after the `[WIRE | ...]` line and before the untrusted block, so the model can tell you too. It never contains page text either.
79
+
80
+ **Commands.**
81
+
82
+ - `wire alerts`: recent alerts, newest first (`--all` adds info events).
83
+ - `wire alerts show <id>`: everything recorded about one alert: the URL (query values removed), where on the page it was (an element path such as `body > article > div.promo-note`), the caught text (up to 120 characters, secrets scrubbed, control characters removed) and any decoded hidden text.
84
+ - `wire alerts tail`: print new alerts as they arrive.
85
+ - `wire alerts verify`: check the ledger's hash chain.
86
+ - `wire alerts demo`: run the shield on a bundled page with three hidden attacks and one honest quote, offline, and show what the model receives.
87
+
88
+ **Limits.** Locations are element paths, not line numbers: the HTML parser doesn't keep source positions. Only `<style>` blocks inside the page are applied, and only simple `.class`, `#id` and `tag.class` selectors outside `@media` and similar blocks; the common hiding classes (`sr-only`, `visually-hidden`, `hidden`, `d-none`, `invisible`) are recognised by name, unless a responsive class such as `md:block` or `d-lg-block` shows the element again. Detection rules are patterns, so a novel phrasing in visible text may not be flagged; hidden text is removed either way.
89
+
90
+ ## Citations
91
+
92
+ Write `[[UNSOURCED]]` after a claim with no source, and run `wire_cite` on an answer before sending it. It reports `OK`, `DEAD`, `ARCHIVED` (with the Wayback copy), `SOFT_404`, `BLOCKED`, `QUOTE_MISSING`, and links agent-wire never returned this session.
93
+
94
+ ## Code Mode
95
+
96
+ `wire serve --code-mode` exposes only `wire_run` and `wire_status`. Scripts run in a QuickJS sandbox with no filesystem, network, timers or modules, and with memory, CPU, wall-clock and call limits. They can't reach `wire_me`.
97
+
98
+ ## Transports
99
+
100
+ `wire serve` uses stdio. `--transport http` or `sse` binds to `127.0.0.1` only and has no authentication; don't expose it to other machines.
101
+
102
+ ## Self-test
103
+
104
+ `wire selftest` checks every subsystem in one run, offline: all 31 channels on canned responses, the inbound and outbound firewalls, the SSRF guard, Shield Alerts and the ledger, compression, the delta buffer and route ledger, the cookie vault, Code Mode, research, `wire_cite`, the client installers, and the MCP server in-process and over stdio. A guard blocks the network for the whole run and reports any attempt as a failure.
105
+
106
+ - `wire selftest --live`: one real request per channel, keyless Reddit, and the shield false-positive count on the 16 README benchmark pages. Channels that need a login or the stealth browser are reported as skipped, not failed.
107
+ - `wire selftest --only mcp` (or `shield`, `reddit`, any group or channel): run part of it.
108
+ - `wire selftest --json`: results as JSON. Exit code 1 when a check fails.
109
+
110
+ ## Policies and help
111
+
112
+ [Privacy Policy](PRIVACY.md) · [Terms of Use](TERMS.md) · [Support](SUPPORT.md) · [Security](SECURITY.md) · [License](LICENSE)
@@ -1,9 +1,41 @@
1
+ Metadata-Version: 2.5
2
+ Name: agent-wire-cli
3
+ Version: 0.2.5
4
+ Summary: High-speed, privacy-first, token-compressed live web and multi-platform intelligence engine for AI agents.
5
+ Project-URL: Homepage, https://github.com/uncoalesced/agent-wire
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: cryptography>=50.0.2
10
+ Requires-Dist: curl-cffi>=0.16.3
11
+ Requires-Dist: defusedxml>=0.7.1
12
+ Requires-Dist: fastmcp>=4.1.2
13
+ Requires-Dist: joserfc>=1.8.0
14
+ Requires-Dist: orjson>=3.13.0
15
+ Requires-Dist: pydantic>=2.14.1
16
+ Requires-Dist: quickjs-ng>=0.17.0.2
17
+ Requires-Dist: selectolax>=1.0.0
18
+ Requires-Dist: tiktoken>=0.14.0
19
+ Requires-Dist: trafilatura>=2.3.1
20
+ Requires-Dist: typer>=0.27.3
21
+ Requires-Dist: zstandard>=0.25.0
22
+ Provides-Extra: browser-cookies
23
+ Requires-Dist: rookiepy>=0.5.6; (python_full_version < '3.13') and extra == 'browser-cookies'
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=9.1.1; extra == 'dev'
26
+ Requires-Dist: ruff>=0.17.1; extra == 'dev'
27
+ Provides-Extra: local-whisper
28
+ Requires-Dist: faster-whisper>=1.1.0; extra == 'local-whisper'
29
+ Provides-Extra: stealth
30
+ Requires-Dist: playwright>=1.48.0; extra == 'stealth'
31
+ Description-Content-Type: text/markdown
32
+
1
33
  <!-- Engineered by uncoalesced -->
2
34
  <p align="center">
3
35
  <picture>
4
36
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner.png">
5
37
  <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner-light.png">
6
- <img alt="agent-wire: agents wired to the live internet. One MCP server, 31 platforms, local." src="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner.png" width="100%">
38
+ <img alt="agent-wire: agents wired to the live internet. One local MCP server for the web and 31 platform channels." src="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner.png" width="100%">
7
39
  </picture>
8
40
  </p>
9
41
 
@@ -31,7 +63,9 @@
31
63
  <a href="#privacy-and-prompt-injection">Privacy</a>
32
64
  </p>
33
65
 
34
- agent-wire is an MCP server that lets an AI agent read the live web and 31 platforms from your own machine. Pages come back as small, clean text instead of raw HTML, your logins stay out of the model's context, and the common cases need no API keys. It's free, MIT licensed, and nothing is hosted.
66
+ **Agent Wire by uncoalesced.** On PyPI it's `agent-wire-cli`; the Claude plugin is `agent-wire`.
67
+
68
+ agent-wire is an MCP server that lets an AI agent read the live web and 31 platform channels from your own machine (most need no login; the table under "Where it works" lists the few that do). Pages come back as small, clean text instead of raw HTML, your logins stay out of the model's context, and the common cases need no API keys. It's free, MIT licensed, and nothing is hosted.
35
69
 
36
70
  > [!NOTE]
37
71
  > It's young. If a site stops parsing, please open an issue with the URL.
@@ -92,6 +126,8 @@ If you prefer the plugin, it bundles the server, a skill that tells Claude when
92
126
  /plugin install agent-wire@agent-wire
93
127
  ```
94
128
 
129
+ The plugin starts the exact PyPI release with `uvx agent-wire-cli==<version> serve`, keeps its data in the plugin data folder Claude Code provides, and asks for optional keys (GitHub token, Reddit app, Exa, SearXNG, transcription) when you enable it. Keys you enter there go to secure storage, not to a settings file. It never reads `gh` or other credentials from your machine.
130
+
95
131
  Use one route or the other, not both. Restart Claude Code, then run `/mcp` and look for `agent_wire`.
96
132
 
97
133
  </details>
@@ -612,11 +648,29 @@ wire run -e "return (await wire.search('sqlite wal', {platforms: ['hn', 'stackov
612
648
 
613
649
  ## Privacy and prompt injection
614
650
 
615
- agent-wire never reads your browsers on its own. The only cookies it sends are ones you saved for a specific site with `wire auth login <site>`, either through a login window or with `--from-browser`, which copies that one site's cookies from a browser you're already signed in to. `wire auth list` shows what's saved and `wire auth logout <site>` forgets it. Saved sessions are used for `wire_me`, for login-only sites (LinkedIn, Instagram, Xiaohongshu, X search), and when a public request hits a login wall. Link checks in `wire_cite` and `wire_research` never send saved sessions, even when a page asks for a login.
651
+ agent-wire never reads your browsers on its own. The only cookies it sends are ones you saved for a specific site with `wire auth login <site>`, either through a login window or with `--from-browser`, which copies that one site's cookies from a browser you're already signed in to. `--from-browser` reads Firefox out of the box; Chrome, Edge and Brave need the opt-in extra `agent-wire-cli[browser-cookies]`, so the default install carries no browser-credential reader. `wire auth list` shows what's saved and `wire auth logout <site>` forgets it. Saved sessions are used for `wire_me`, for login-only sites (LinkedIn, Instagram, Xiaohongshu, X search), and when a public request hits a login wall. Link checks in `wire_cite` and `wire_research` never send saved sessions, even when a page asks for a login.
616
652
 
617
653
  A cookie-bearing request may only read (GET or HEAD). Account paths such as `/messages`, `/settings`, `/billing` and `/password` are refused before anything leaves your machine, and cookies never follow a redirect to another site. JSON from logged-in requests has keys like `viewer`, `email` and `csrf_token` removed, and the final text is scrubbed for bearer tokens, session cookies and private IP addresses.
618
654
 
619
- Pages get the opposite treatment. Anything a person reading the page couldn't see is removed before extraction: `display:none`, zero-size or off-screen text, `aria-hidden` blocks, HTML comments, and Unicode tag, zero-width and bidi characters. Code blocks and visible text are kept as they are, so a tutorial about prompt injection still reads correctly. In user comments, fake control tags such as `</tool_result>` or `<|im_start|>` are escaped, and a page can't close the `UNTRUSTED_EXTERNAL_DATA` block early.
655
+ Pages get the opposite treatment. Anything a person reading the page couldn't see is removed before extraction: `display:none`, zero-size, clipped, transparent or off-screen text (inline, through the page's own stylesheet, or through the usual `sr-only` / `visually-hidden` / `hidden` classes), `aria-hidden` blocks, HTML comments, and Unicode tag, zero-width and bidi characters, including ones written as HTML entities. Code blocks and visible text are kept as they are, so a tutorial about prompt injection still reads correctly. In user comments, fake control tags such as `</tool_result>` or `<|im_start|>` are escaped, and a page can't close the `UNTRUSTED_EXTERNAL_DATA` block early.
656
+
657
+ **Shield Alerts.** When a page tries to steer the agent, you find out without reading the transcript:
658
+
659
+ - **Desktop notification.** A Windows, macOS or Linux notification, grouped per site.
660
+ - **stderr line.** For clients that show server logs.
661
+ - **Line above the quoted content.** A trusted `[WIRE SHIELD | ...]` line, outside the untrusted block.
662
+ - **Local record.** Each alert is saved in `WIRE_HOME/alerts.db`.
663
+
664
+ Alerts carry no page text, only what agent-wire did and where. `wire alerts` lists them, `wire alerts show <id>` shows the text that was caught and where on the page it was, `wire alerts tail` follows new ones, and `wire alerts demo` runs the shield on a bundled page so you can see one.
665
+
666
+ Each alert states what happened:
667
+
668
+ - `stripped`: hidden text removed before the model saw it.
669
+ - `escaped`: a forged marker neutralized.
670
+ - `refused`: a request never sent, such as a private address or a logged-in write.
671
+ - `flagged-only`: visible text that names agent-wire's tools or tells the model to hide something from you. It stays in the quoted content, because removing visible text would censor the page.
672
+
673
+ A page that only quotes "ignore previous instructions" in plain view doesn't raise an alert. Set `WIRE_SHIELD_NOTIFY=0` to turn notifications off, or `WIRE_SHIELD_VERBOSE=1` to also record every routine removal. The full design is in [DOCUMENTATION.md](DOCUMENTATION.md#shield-alerts).
620
674
 
621
675
  Logins you add with `wire auth login <site>` live in an AES-GCM vault whose key is protected by Windows DPAPI, or by a 0600 key file on macOS and Linux.
622
676
 
@@ -635,16 +689,18 @@ A lot of recent malware has arrived through package registries: a hijacked npm p
635
689
  To check a release yourself:
636
690
 
637
691
  ```bash
638
- uvx --from pypi-attestations pypi-attestations verify pypi --repository https://github.com/uncoalesced/agent-wire pypi:agent_wire_cli-0.2.3-py3-none-any.whl
692
+ uvx --from pypi-attestations pypi-attestations verify pypi --repository https://github.com/uncoalesced/agent-wire pypi:agent_wire_cli-0.2.5-py3-none-any.whl
639
693
  ```
640
694
 
641
695
  ## Privacy Policy
642
696
 
697
+ This is a summary. The full policy is [PRIVACY.md](PRIVACY.md).
698
+
643
699
  agent-wire runs on your machine. There's no agent-wire server, no account, no analytics and no telemetry.
644
700
 
645
701
  **What it stores.** Pages and results you ask for are processed in memory and kept in a session buffer while the server runs. Route memory is cached in `WIRE_HOME` and expires after 24 hours. If you call `wire_research` with `store=True`, the run is saved to `research.db` in `WIRE_HOME`, and it stays there until you delete it. Logins you add with `wire auth login <site>` go in an encrypted local vault (AES-GCM, with the key protected by Windows DPAPI, or a 0600 key file on macOS and Linux). Nothing is uploaded to uncoalesced. `wire auth logout <site>` removes a saved login, and deleting `WIRE_HOME` removes everything local.
646
702
 
647
- **Who sees your requests.** Only the services needed to answer them: the platforms you ask about, plus public fallbacks (Reddit's PullPush and Arctic Shift archives, OpenAlex, Semantic Scholar, Google News), and Exa or a SearXNG instance if you set one up. If you turn on transcription with an external API (`WIRE_TRANSCRIBE=1`), the audio goes to that API. A saved cookie goes only to the site it belongs to, only on read requests, and never follows a redirect to another site.
703
+ **Who sees your requests.** Only the services needed to answer them: the platforms you ask about, plus public fallbacks (Reddit's PullPush and Arctic Shift archives, OpenAlex, Semantic Scholar, Google News), and Exa or a SearXNG instance if you set one up. If you turn on transcription with an external API (`WIRE_TRANSCRIBE=1`, or by setting a transcription API key), the audio goes to that API. A saved cookie goes only to the site it belongs to, only on read requests, and never follows a redirect to another site.
648
704
 
649
705
  **What your model sees.** Page text, after the scrub strips tokens, cookies, private IP addresses and, on logged-in pages, emails. Your cookies and identity never reach it.
650
706
 
@@ -652,6 +708,8 @@ agent-wire runs on your machine. There's no agent-wire server, no account, no an
652
708
 
653
709
  ## Terms of Use
654
710
 
711
+ This is a summary. The full terms are [TERMS.md](TERMS.md). Help: [SUPPORT.md](SUPPORT.md).
712
+
655
713
  agent-wire is open-source software under the [MIT license](LICENSE), provided as is and without warranty. It runs on your machine, and you are responsible for how you use it.
656
714
 
657
715
  - **Respect the sites you read.** agent-wire fetches public pages and, if you save a login, pages from your own accounts. Whether that is allowed depends on each site's terms and on your local law, and that is your call, not ours.
@@ -666,11 +724,11 @@ Everything works without configuration. These are optional:
666
724
 
667
725
  | Variable | Effect |
668
726
  |---|---|
669
- | `WIRE_HOME` | Where the cache, route memory and vault live. By default it's a `.wire/` folder inside the agent client that started the server, falling back to `~/.config/agent-wire` or `%APPDATA%\agent-wire`. A `.gitignore` is written there so nothing gets committed. |
670
- | `GITHUB_TOKEN` | Higher GitHub rate limits and `wire_me github`. `gh auth token` is used automatically if it's set up. |
727
+ | `WIRE_HOME` | Where the cache, route memory and vault live. In the Claude plugin it's the plugin's data folder. Otherwise it's a `.wire/` folder inside the agent client that started the server, falling back to `~/.config/agent-wire` or `%APPDATA%\agent-wire`. A `.gitignore` is written there so nothing gets committed. |
728
+ | `GITHUB_TOKEN` | Higher GitHub rate limits and `wire_me github`. Outside the Claude plugin, `gh auth token` is used automatically if it's set up; `WIRE_NO_GH_CLI=1` turns that off. |
671
729
  | `REDDIT_CLIENT_ID`, `REDDIT_CLIENT_SECRET` | Reddit's official app login for networks where anonymous access is blocked. |
672
730
  | `WIRE_SEARXNG_URL`, `EXA_API_KEY` | Extra web search engines. |
673
- | `WIRE_TRANSCRIBE=1` | Transcribe podcast audio, either locally with `agent-wire-cli[local-whisper]` or through an OpenAI-compatible API (`WIRE_TRANSCRIBE_API_KEY`, `WIRE_TRANSCRIBE_URL`, `WIRE_TRANSCRIBE_MODEL`). The API route uploads the audio, so it's opt-in. |
731
+ | `WIRE_TRANSCRIBE=1` | Transcribe podcast audio, either locally with `agent-wire-cli[local-whisper]` or through an OpenAI-compatible API (`WIRE_TRANSCRIBE_API_KEY`, `WIRE_TRANSCRIBE_URL`, `WIRE_TRANSCRIBE_MODEL`). The API route uploads the audio, so it's opt-in: setting `WIRE_TRANSCRIBE_API_KEY` counts as opting in, and `WIRE_TRANSCRIBE=0` turns it off. |
674
732
  | `WIRE_ALLOW_PRIVATE=1` | Let reads reach private and internal addresses (localhost, LAN, link-local, `fd00::/8`). Off by default, so a prompt-injected page or script can't point agent-wire at your router or a cloud metadata endpoint. Set it only to read your own intranet. Your `WIRE_SEARXNG_URL`, transcription URL and watch webhooks are always allowed. |
675
733
 
676
734
  ## Development
@@ -683,7 +741,15 @@ uv sync --extra dev
683
741
  uv run pytest
684
742
  ```
685
743
 
686
- The tests run against small fixture payloads shaped like each site's real responses (a few download a tokenizer file on first run). They cover the firewalls, the fetch waterfall, every channel's parser, the research pipeline, the MCP server and the installer. CI runs them on Linux, macOS and Windows with Python 3.11 and 3.14, and builds the wheel.
744
+ The tests run against small fixture payloads shaped like each site's real responses (a few download a tokenizer file on first run; without it, token counts fall back to an approximation). They cover the firewalls, the fetch waterfall, every channel's parser, the research pipeline, the MCP server and the installer. CI runs them on Linux, macOS and Windows with Python 3.11 and 3.14, and builds the wheel.
745
+
746
+ To check a whole install at once, run the self-test. It drives every part through its real entry point: all 31 channels on canned responses, the firewalls and SSRF guard, the shield and its alert ledger, compression, the caches, the cookie vault, Code Mode, research, citations, the installers, and the MCP server both in-process and as a stdio subprocess. A guard fails the run if anything reaches the network.
747
+
748
+ ```bash
749
+ wire selftest
750
+ ```
751
+
752
+ `wire selftest --live` adds one real request per channel (Reddit with no API key, to show which fallback answered) and reads the 16 benchmark pages to count shield false positives. `--only <group or channel>` narrows the run, `--json` prints machine-readable results, and the exit code is 1 when any check fails. CI and the release workflow run the offline self-test.
687
753
 
688
754
  Releases are published to PyPI by `.github/workflows/release.yml` when a `v*` tag matching the version in `pyproject.toml` is pushed. It uses PyPI trusted publishing, so no token is stored in the repo.
689
755
 
@@ -0,0 +1,54 @@
1
+ # Privacy Policy
2
+
3
+ Agent Wire by uncoalesced (`agent-wire-cli` on PyPI, the `agent-wire` Claude plugin). Last updated 2026-11-11.
4
+
5
+ agent-wire is software that runs on your own machine. There is no agent-wire server, no account and no sign-up. It sends no analytics and no telemetry. Nothing it reads or stores is uploaded to uncoalesced.
6
+
7
+ ## What it stores, and where
8
+
9
+ Everything lives in one local folder, `WIRE_HOME`. For the Claude plugin, that's the plugin's data folder that Claude Code gives it. Otherwise it's a `.wire/` folder inside the agent client that started the server, falling back to `~/.config/agent-wire` (macOS, Linux) or `%APPDATA%\agent-wire` (Windows). You can set `WIRE_HOME` to choose.
10
+
11
+ | What | File | How long |
12
+ |---|---|---|
13
+ | Pages and results you asked for | Memory only (a session buffer) | Until the server stops |
14
+ | Which fetch stage worked for each site ("route memory") | `cache.db` | Ignored after 24 hours |
15
+ | Saved logins (`wire auth login <site>`) | `vault.enc`, encrypted with AES-GCM; the key is protected by Windows DPAPI, or kept in a 0600 file (`vault.key`) on macOS and Linux | Until you run `wire auth logout <site>` |
16
+ | Research runs, only if you pass `store=True` or use `wire watch` | `research.db` | Until you delete them |
17
+ | Shield alerts: what agent-wire stripped, escaped or refused, where, and up to 120 characters of the page text it caught (with secrets scrubbed and URL query values removed) | `alerts.db` | Until you delete it |
18
+ | Browser profile for the optional stage 4 browser (`[stealth]` extra) | `browser-profile/` | Until you delete it |
19
+ | Tokenizer data downloaded on first use | `tiktoken/` | Until you delete it |
20
+
21
+ Deleting `WIRE_HOME` removes everything agent-wire stored.
22
+
23
+ A login window (`wire auth login <site>`) uses a temporary browser profile that is deleted as soon as the cookies are saved to the vault. `wire auth login <site> --from-browser` reads that one site's cookies from a browser on your machine, only when you run the command yourself. Chrome, Edge and Brave need the optional `agent-wire-cli[browser-cookies]` extra. The MCP server never reads browser profiles.
24
+
25
+ ## Who receives requests
26
+
27
+ agent-wire only sends requests needed to answer what you or your agent asked:
28
+
29
+ - **The sites you ask it to read or search**: the web page itself, or platforms such as GitHub, Reddit, Hacker News, YouTube, X, Wikipedia, Stack Exchange, arXiv, Bluesky, Mastodon, Polymarket, Bilibili and the other channels listed in the README.
30
+ - **Public services it uses to search and fall back**: DuckDuckGo and Brave Search for web search, Google News and Techmeme for news, the Wayback Machine (archive.org), PullPush and Arctic Shift (Reddit archives), OpenAlex and Semantic Scholar (papers), and fxtwitter, vxtwitter and X's syndication endpoint for single X posts.
31
+ - **Services you configure yourself**: Exa (with your Exa key), your own SearXNG instance, an OpenAI-compatible transcription API (only when you set `WIRE_TRANSCRIBE=1` or give a transcription API key; the audio goes to it), and webhooks you add with `wire watch add`.
32
+ - **The tokenizer download**: on first use, `tiktoken` downloads its encoding file from OpenAI's public file host. Nothing about you is sent with it.
33
+
34
+ Each of those services handles requests under its own privacy policy.
35
+
36
+ ## Your credentials
37
+
38
+ Optional keys (GitHub token, Reddit app ID and secret, Exa key, transcription key) are read only from your environment, or in the Claude plugin from settings you choose to enter, which Claude Code keeps in secure storage. Each one goes only to its own service. A saved login cookie is sent only to the site it belongs to, only on GET or HEAD requests, never to account pages such as messages, settings or billing, and never across a redirect to another site.
39
+
40
+ ## What your AI model sees
41
+
42
+ Page text after agent-wire removes hidden content and scrubs tokens, cookies, private IP addresses, well-known API key formats, your saved vault values and, on logged-in pages, email addresses. Your cookies and identity are not passed to the model. Whatever your model provider does with the text it receives is covered by that provider's policy, not this one.
43
+
44
+ ## Children
45
+
46
+ agent-wire is a developer tool and is not directed at children.
47
+
48
+ ## Changes
49
+
50
+ Changes to this policy are made in this file and recorded in the repository history.
51
+
52
+ ## Contact
53
+
54
+ mail@uncoalesced.com, or an issue at [github.com/uncoalesced/agent-wire/issues](https://github.com/uncoalesced/agent-wire/issues). Report security problems privately as described in [SECURITY.md](SECURITY.md).
@@ -1,39 +1,9 @@
1
- Metadata-Version: 2.5
2
- Name: agent-wire-cli
3
- Version: 0.2.4
4
- Summary: High-speed, privacy-first, token-compressed live web and multi-platform intelligence engine for AI agents.
5
- Project-URL: Homepage, https://github.com/uncoalesced/agent-wire
6
- License: MIT
7
- License-File: LICENSE
8
- Requires-Python: >=3.11
9
- Requires-Dist: cryptography>=50.0.2
10
- Requires-Dist: curl-cffi>=0.16.3
11
- Requires-Dist: defusedxml>=0.7.1
12
- Requires-Dist: fastmcp>=4.1.2
13
- Requires-Dist: orjson>=3.13.0
14
- Requires-Dist: pydantic>=2.14.1
15
- Requires-Dist: quickjs-ng>=0.17.0.2
16
- Requires-Dist: rookiepy>=0.5.6; python_full_version < '3.13'
17
- Requires-Dist: selectolax>=1.0.0
18
- Requires-Dist: tiktoken>=0.14.0
19
- Requires-Dist: trafilatura>=2.3.1
20
- Requires-Dist: typer>=0.27.3
21
- Requires-Dist: zstandard>=0.25.0
22
- Provides-Extra: dev
23
- Requires-Dist: pytest>=9.1.1; extra == 'dev'
24
- Requires-Dist: ruff>=0.17.1; extra == 'dev'
25
- Provides-Extra: local-whisper
26
- Requires-Dist: faster-whisper>=1.1.0; extra == 'local-whisper'
27
- Provides-Extra: stealth
28
- Requires-Dist: playwright>=1.48.0; extra == 'stealth'
29
- Description-Content-Type: text/markdown
30
-
31
1
  <!-- Engineered by uncoalesced -->
32
2
  <p align="center">
33
3
  <picture>
34
4
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner.png">
35
5
  <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner-light.png">
36
- <img alt="agent-wire: agents wired to the live internet. One MCP server, 31 platforms, local." src="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner.png" width="100%">
6
+ <img alt="agent-wire: agents wired to the live internet. One local MCP server for the web and 31 platform channels." src="https://raw.githubusercontent.com/uncoalesced/agent-wire/main/assets/agent-wire-banner.png" width="100%">
37
7
  </picture>
38
8
  </p>
39
9
 
@@ -61,7 +31,9 @@ Description-Content-Type: text/markdown
61
31
  <a href="#privacy-and-prompt-injection">Privacy</a>
62
32
  </p>
63
33
 
64
- agent-wire is an MCP server that lets an AI agent read the live web and 31 platforms from your own machine. Pages come back as small, clean text instead of raw HTML, your logins stay out of the model's context, and the common cases need no API keys. It's free, MIT licensed, and nothing is hosted.
34
+ **Agent Wire by uncoalesced.** On PyPI it's `agent-wire-cli`; the Claude plugin is `agent-wire`.
35
+
36
+ agent-wire is an MCP server that lets an AI agent read the live web and 31 platform channels from your own machine (most need no login; the table under "Where it works" lists the few that do). Pages come back as small, clean text instead of raw HTML, your logins stay out of the model's context, and the common cases need no API keys. It's free, MIT licensed, and nothing is hosted.
65
37
 
66
38
  > [!NOTE]
67
39
  > It's young. If a site stops parsing, please open an issue with the URL.
@@ -122,6 +94,8 @@ If you prefer the plugin, it bundles the server, a skill that tells Claude when
122
94
  /plugin install agent-wire@agent-wire
123
95
  ```
124
96
 
97
+ The plugin starts the exact PyPI release with `uvx agent-wire-cli==<version> serve`, keeps its data in the plugin data folder Claude Code provides, and asks for optional keys (GitHub token, Reddit app, Exa, SearXNG, transcription) when you enable it. Keys you enter there go to secure storage, not to a settings file. It never reads `gh` or other credentials from your machine.
98
+
125
99
  Use one route or the other, not both. Restart Claude Code, then run `/mcp` and look for `agent_wire`.
126
100
 
127
101
  </details>
@@ -642,11 +616,29 @@ wire run -e "return (await wire.search('sqlite wal', {platforms: ['hn', 'stackov
642
616
 
643
617
  ## Privacy and prompt injection
644
618
 
645
- agent-wire never reads your browsers on its own. The only cookies it sends are ones you saved for a specific site with `wire auth login <site>`, either through a login window or with `--from-browser`, which copies that one site's cookies from a browser you're already signed in to. `wire auth list` shows what's saved and `wire auth logout <site>` forgets it. Saved sessions are used for `wire_me`, for login-only sites (LinkedIn, Instagram, Xiaohongshu, X search), and when a public request hits a login wall. Link checks in `wire_cite` and `wire_research` never send saved sessions, even when a page asks for a login.
619
+ agent-wire never reads your browsers on its own. The only cookies it sends are ones you saved for a specific site with `wire auth login <site>`, either through a login window or with `--from-browser`, which copies that one site's cookies from a browser you're already signed in to. `--from-browser` reads Firefox out of the box; Chrome, Edge and Brave need the opt-in extra `agent-wire-cli[browser-cookies]`, so the default install carries no browser-credential reader. `wire auth list` shows what's saved and `wire auth logout <site>` forgets it. Saved sessions are used for `wire_me`, for login-only sites (LinkedIn, Instagram, Xiaohongshu, X search), and when a public request hits a login wall. Link checks in `wire_cite` and `wire_research` never send saved sessions, even when a page asks for a login.
646
620
 
647
621
  A cookie-bearing request may only read (GET or HEAD). Account paths such as `/messages`, `/settings`, `/billing` and `/password` are refused before anything leaves your machine, and cookies never follow a redirect to another site. JSON from logged-in requests has keys like `viewer`, `email` and `csrf_token` removed, and the final text is scrubbed for bearer tokens, session cookies and private IP addresses.
648
622
 
649
- Pages get the opposite treatment. Anything a person reading the page couldn't see is removed before extraction: `display:none`, zero-size or off-screen text, `aria-hidden` blocks, HTML comments, and Unicode tag, zero-width and bidi characters. Code blocks and visible text are kept as they are, so a tutorial about prompt injection still reads correctly. In user comments, fake control tags such as `</tool_result>` or `<|im_start|>` are escaped, and a page can't close the `UNTRUSTED_EXTERNAL_DATA` block early.
623
+ Pages get the opposite treatment. Anything a person reading the page couldn't see is removed before extraction: `display:none`, zero-size, clipped, transparent or off-screen text (inline, through the page's own stylesheet, or through the usual `sr-only` / `visually-hidden` / `hidden` classes), `aria-hidden` blocks, HTML comments, and Unicode tag, zero-width and bidi characters, including ones written as HTML entities. Code blocks and visible text are kept as they are, so a tutorial about prompt injection still reads correctly. In user comments, fake control tags such as `</tool_result>` or `<|im_start|>` are escaped, and a page can't close the `UNTRUSTED_EXTERNAL_DATA` block early.
624
+
625
+ **Shield Alerts.** When a page tries to steer the agent, you find out without reading the transcript:
626
+
627
+ - **Desktop notification.** A Windows, macOS or Linux notification, grouped per site.
628
+ - **stderr line.** For clients that show server logs.
629
+ - **Line above the quoted content.** A trusted `[WIRE SHIELD | ...]` line, outside the untrusted block.
630
+ - **Local record.** Each alert is saved in `WIRE_HOME/alerts.db`.
631
+
632
+ Alerts carry no page text, only what agent-wire did and where. `wire alerts` lists them, `wire alerts show <id>` shows the text that was caught and where on the page it was, `wire alerts tail` follows new ones, and `wire alerts demo` runs the shield on a bundled page so you can see one.
633
+
634
+ Each alert states what happened:
635
+
636
+ - `stripped`: hidden text removed before the model saw it.
637
+ - `escaped`: a forged marker neutralized.
638
+ - `refused`: a request never sent, such as a private address or a logged-in write.
639
+ - `flagged-only`: visible text that names agent-wire's tools or tells the model to hide something from you. It stays in the quoted content, because removing visible text would censor the page.
640
+
641
+ A page that only quotes "ignore previous instructions" in plain view doesn't raise an alert. Set `WIRE_SHIELD_NOTIFY=0` to turn notifications off, or `WIRE_SHIELD_VERBOSE=1` to also record every routine removal. The full design is in [DOCUMENTATION.md](DOCUMENTATION.md#shield-alerts).
650
642
 
651
643
  Logins you add with `wire auth login <site>` live in an AES-GCM vault whose key is protected by Windows DPAPI, or by a 0600 key file on macOS and Linux.
652
644
 
@@ -665,16 +657,18 @@ A lot of recent malware has arrived through package registries: a hijacked npm p
665
657
  To check a release yourself:
666
658
 
667
659
  ```bash
668
- uvx --from pypi-attestations pypi-attestations verify pypi --repository https://github.com/uncoalesced/agent-wire pypi:agent_wire_cli-0.2.3-py3-none-any.whl
660
+ uvx --from pypi-attestations pypi-attestations verify pypi --repository https://github.com/uncoalesced/agent-wire pypi:agent_wire_cli-0.2.5-py3-none-any.whl
669
661
  ```
670
662
 
671
663
  ## Privacy Policy
672
664
 
665
+ This is a summary. The full policy is [PRIVACY.md](PRIVACY.md).
666
+
673
667
  agent-wire runs on your machine. There's no agent-wire server, no account, no analytics and no telemetry.
674
668
 
675
669
  **What it stores.** Pages and results you ask for are processed in memory and kept in a session buffer while the server runs. Route memory is cached in `WIRE_HOME` and expires after 24 hours. If you call `wire_research` with `store=True`, the run is saved to `research.db` in `WIRE_HOME`, and it stays there until you delete it. Logins you add with `wire auth login <site>` go in an encrypted local vault (AES-GCM, with the key protected by Windows DPAPI, or a 0600 key file on macOS and Linux). Nothing is uploaded to uncoalesced. `wire auth logout <site>` removes a saved login, and deleting `WIRE_HOME` removes everything local.
676
670
 
677
- **Who sees your requests.** Only the services needed to answer them: the platforms you ask about, plus public fallbacks (Reddit's PullPush and Arctic Shift archives, OpenAlex, Semantic Scholar, Google News), and Exa or a SearXNG instance if you set one up. If you turn on transcription with an external API (`WIRE_TRANSCRIBE=1`), the audio goes to that API. A saved cookie goes only to the site it belongs to, only on read requests, and never follows a redirect to another site.
671
+ **Who sees your requests.** Only the services needed to answer them: the platforms you ask about, plus public fallbacks (Reddit's PullPush and Arctic Shift archives, OpenAlex, Semantic Scholar, Google News), and Exa or a SearXNG instance if you set one up. If you turn on transcription with an external API (`WIRE_TRANSCRIBE=1`, or by setting a transcription API key), the audio goes to that API. A saved cookie goes only to the site it belongs to, only on read requests, and never follows a redirect to another site.
678
672
 
679
673
  **What your model sees.** Page text, after the scrub strips tokens, cookies, private IP addresses and, on logged-in pages, emails. Your cookies and identity never reach it.
680
674
 
@@ -682,6 +676,8 @@ agent-wire runs on your machine. There's no agent-wire server, no account, no an
682
676
 
683
677
  ## Terms of Use
684
678
 
679
+ This is a summary. The full terms are [TERMS.md](TERMS.md). Help: [SUPPORT.md](SUPPORT.md).
680
+
685
681
  agent-wire is open-source software under the [MIT license](LICENSE), provided as is and without warranty. It runs on your machine, and you are responsible for how you use it.
686
682
 
687
683
  - **Respect the sites you read.** agent-wire fetches public pages and, if you save a login, pages from your own accounts. Whether that is allowed depends on each site's terms and on your local law, and that is your call, not ours.
@@ -696,11 +692,11 @@ Everything works without configuration. These are optional:
696
692
 
697
693
  | Variable | Effect |
698
694
  |---|---|
699
- | `WIRE_HOME` | Where the cache, route memory and vault live. By default it's a `.wire/` folder inside the agent client that started the server, falling back to `~/.config/agent-wire` or `%APPDATA%\agent-wire`. A `.gitignore` is written there so nothing gets committed. |
700
- | `GITHUB_TOKEN` | Higher GitHub rate limits and `wire_me github`. `gh auth token` is used automatically if it's set up. |
695
+ | `WIRE_HOME` | Where the cache, route memory and vault live. In the Claude plugin it's the plugin's data folder. Otherwise it's a `.wire/` folder inside the agent client that started the server, falling back to `~/.config/agent-wire` or `%APPDATA%\agent-wire`. A `.gitignore` is written there so nothing gets committed. |
696
+ | `GITHUB_TOKEN` | Higher GitHub rate limits and `wire_me github`. Outside the Claude plugin, `gh auth token` is used automatically if it's set up; `WIRE_NO_GH_CLI=1` turns that off. |
701
697
  | `REDDIT_CLIENT_ID`, `REDDIT_CLIENT_SECRET` | Reddit's official app login for networks where anonymous access is blocked. |
702
698
  | `WIRE_SEARXNG_URL`, `EXA_API_KEY` | Extra web search engines. |
703
- | `WIRE_TRANSCRIBE=1` | Transcribe podcast audio, either locally with `agent-wire-cli[local-whisper]` or through an OpenAI-compatible API (`WIRE_TRANSCRIBE_API_KEY`, `WIRE_TRANSCRIBE_URL`, `WIRE_TRANSCRIBE_MODEL`). The API route uploads the audio, so it's opt-in. |
699
+ | `WIRE_TRANSCRIBE=1` | Transcribe podcast audio, either locally with `agent-wire-cli[local-whisper]` or through an OpenAI-compatible API (`WIRE_TRANSCRIBE_API_KEY`, `WIRE_TRANSCRIBE_URL`, `WIRE_TRANSCRIBE_MODEL`). The API route uploads the audio, so it's opt-in: setting `WIRE_TRANSCRIBE_API_KEY` counts as opting in, and `WIRE_TRANSCRIBE=0` turns it off. |
704
700
  | `WIRE_ALLOW_PRIVATE=1` | Let reads reach private and internal addresses (localhost, LAN, link-local, `fd00::/8`). Off by default, so a prompt-injected page or script can't point agent-wire at your router or a cloud metadata endpoint. Set it only to read your own intranet. Your `WIRE_SEARXNG_URL`, transcription URL and watch webhooks are always allowed. |
705
701
 
706
702
  ## Development
@@ -713,7 +709,15 @@ uv sync --extra dev
713
709
  uv run pytest
714
710
  ```
715
711
 
716
- The tests run against small fixture payloads shaped like each site's real responses (a few download a tokenizer file on first run). They cover the firewalls, the fetch waterfall, every channel's parser, the research pipeline, the MCP server and the installer. CI runs them on Linux, macOS and Windows with Python 3.11 and 3.14, and builds the wheel.
712
+ The tests run against small fixture payloads shaped like each site's real responses (a few download a tokenizer file on first run; without it, token counts fall back to an approximation). They cover the firewalls, the fetch waterfall, every channel's parser, the research pipeline, the MCP server and the installer. CI runs them on Linux, macOS and Windows with Python 3.11 and 3.14, and builds the wheel.
713
+
714
+ To check a whole install at once, run the self-test. It drives every part through its real entry point: all 31 channels on canned responses, the firewalls and SSRF guard, the shield and its alert ledger, compression, the caches, the cookie vault, Code Mode, research, citations, the installers, and the MCP server both in-process and as a stdio subprocess. A guard fails the run if anything reaches the network.
715
+
716
+ ```bash
717
+ wire selftest
718
+ ```
719
+
720
+ `wire selftest --live` adds one real request per channel (Reddit with no API key, to show which fallback answered) and reads the 16 benchmark pages to count shield false positives. `--only <group or channel>` narrows the run, `--json` prints machine-readable results, and the exit code is 1 when any check fails. CI and the release workflow run the offline self-test.
717
721
 
718
722
  Releases are published to PyPI by `.github/workflows/release.yml` when a `v*` tag matching the version in `pyproject.toml` is pushed. It uses PyPI trusted publishing, so no token is stored in the repo.
719
723