cli-bridge-mcp 0.1.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 (201) hide show
  1. cli_bridge_mcp-0.1.0/.github/CODE_OF_CONDUCT.md +29 -0
  2. cli_bridge_mcp-0.1.0/.github/CONTRIBUTING.md +49 -0
  3. cli_bridge_mcp-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
  4. cli_bridge_mcp-0.1.0/.github/ISSUE_TEMPLATE/cli_flag_broken.md +26 -0
  5. cli_bridge_mcp-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. cli_bridge_mcp-0.1.0/.github/ISSUE_TEMPLATE/lane_request.md +30 -0
  7. cli_bridge_mcp-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  8. cli_bridge_mcp-0.1.0/.github/SECURITY.md +73 -0
  9. cli_bridge_mcp-0.1.0/.github/workflows/drift-check.yml +47 -0
  10. cli_bridge_mcp-0.1.0/.github/workflows/pages.yml +35 -0
  11. cli_bridge_mcp-0.1.0/.github/workflows/release.yml +47 -0
  12. cli_bridge_mcp-0.1.0/.github/workflows/tests.yml +92 -0
  13. cli_bridge_mcp-0.1.0/.gitignore +30 -0
  14. cli_bridge_mcp-0.1.0/.gitleaks.toml +14 -0
  15. cli_bridge_mcp-0.1.0/AGENTS.md +124 -0
  16. cli_bridge_mcp-0.1.0/CHANGELOG.md +526 -0
  17. cli_bridge_mcp-0.1.0/CLAUDE.md +1 -0
  18. cli_bridge_mcp-0.1.0/LICENSE +21 -0
  19. cli_bridge_mcp-0.1.0/PKG-INFO +437 -0
  20. cli_bridge_mcp-0.1.0/README.md +420 -0
  21. cli_bridge_mcp-0.1.0/assets/banner-dark.svg +1 -0
  22. cli_bridge_mcp-0.1.0/assets/banner-light.svg +1 -0
  23. cli_bridge_mcp-0.1.0/assets/banner.gif +0 -0
  24. cli_bridge_mcp-0.1.0/assets/demo-borrow.gif +0 -0
  25. cli_bridge_mcp-0.1.0/assets/demo.gif +0 -0
  26. cli_bridge_mcp-0.1.0/assets/mark-dark.svg +1 -0
  27. cli_bridge_mcp-0.1.0/assets/mark-light.svg +1 -0
  28. cli_bridge_mcp-0.1.0/assets/mark.gif +0 -0
  29. cli_bridge_mcp-0.1.0/assets/social-card.png +0 -0
  30. cli_bridge_mcp-0.1.0/assets/social-dark.svg +1 -0
  31. cli_bridge_mcp-0.1.0/assets/social-light.svg +1 -0
  32. cli_bridge_mcp-0.1.0/docs/ARCHITECTURE.md +139 -0
  33. cli_bridge_mcp-0.1.0/docs/BENCHMARKS.md +125 -0
  34. cli_bridge_mcp-0.1.0/docs/COMPARISON.md +71 -0
  35. cli_bridge_mcp-0.1.0/docs/COSTS.md +123 -0
  36. cli_bridge_mcp-0.1.0/docs/demo/borrow.tape +40 -0
  37. cli_bridge_mcp-0.1.0/docs/demo/demo.tape +55 -0
  38. cli_bridge_mcp-0.1.0/docs/demo/render.sh +33 -0
  39. cli_bridge_mcp-0.1.0/docs/demo/setup.sh +40 -0
  40. cli_bridge_mcp-0.1.0/docs/i18n/README.de.md +410 -0
  41. cli_bridge_mcp-0.1.0/docs/i18n/README.es.md +403 -0
  42. cli_bridge_mcp-0.1.0/docs/i18n/README.fr.md +414 -0
  43. cli_bridge_mcp-0.1.0/docs/i18n/README.ja.md +380 -0
  44. cli_bridge_mcp-0.1.0/docs/i18n/README.pt-BR.md +400 -0
  45. cli_bridge_mcp-0.1.0/docs/i18n/README.zh-CN.md +367 -0
  46. cli_bridge_mcp-0.1.0/examples/byo-api-lane.json +29 -0
  47. cli_bridge_mcp-0.1.0/examples/community-lanes.json +98 -0
  48. cli_bridge_mcp-0.1.0/examples/free-apis.json +85 -0
  49. cli_bridge_mcp-0.1.0/examples/github-action-pr-review.yml +44 -0
  50. cli_bridge_mcp-0.1.0/examples/lanes.example.json +20 -0
  51. cli_bridge_mcp-0.1.0/examples/llamacpp.lane.json +28 -0
  52. cli_bridge_mcp-0.1.0/examples/lmstudio.lane.json +26 -0
  53. cli_bridge_mcp-0.1.0/examples/local-first-host.md +85 -0
  54. cli_bridge_mcp-0.1.0/examples/mcp.example.json +14 -0
  55. cli_bridge_mcp-0.1.0/examples/mlx.lane.json +25 -0
  56. cli_bridge_mcp-0.1.0/pyproject.toml +59 -0
  57. cli_bridge_mcp-0.1.0/server.json +36 -0
  58. cli_bridge_mcp-0.1.0/site/index.html +134 -0
  59. cli_bridge_mcp-0.1.0/smithery.yaml +29 -0
  60. cli_bridge_mcp-0.1.0/src/cli_bridge/__init__.py +2 -0
  61. cli_bridge_mcp-0.1.0/src/cli_bridge/__main__.py +4 -0
  62. cli_bridge_mcp-0.1.0/src/cli_bridge/buildloop.py +379 -0
  63. cli_bridge_mcp-0.1.0/src/cli_bridge/cli.py +438 -0
  64. cli_bridge_mcp-0.1.0/src/cli_bridge/config.py +470 -0
  65. cli_bridge_mcp-0.1.0/src/cli_bridge/conversations.py +111 -0
  66. cli_bridge_mcp-0.1.0/src/cli_bridge/council.py +340 -0
  67. cli_bridge_mcp-0.1.0/src/cli_bridge/detect.py +17 -0
  68. cli_bridge_mcp-0.1.0/src/cli_bridge/eval.py +610 -0
  69. cli_bridge_mcp-0.1.0/src/cli_bridge/findings.py +316 -0
  70. cli_bridge_mcp-0.1.0/src/cli_bridge/guards.py +98 -0
  71. cli_bridge_mcp-0.1.0/src/cli_bridge/jobs.py +167 -0
  72. cli_bridge_mcp-0.1.0/src/cli_bridge/lanes.py +669 -0
  73. cli_bridge_mcp-0.1.0/src/cli_bridge/orchestrate.py +587 -0
  74. cli_bridge_mcp-0.1.0/src/cli_bridge/preamble.py +99 -0
  75. cli_bridge_mcp-0.1.0/src/cli_bridge/router.py +158 -0
  76. cli_bridge_mcp-0.1.0/src/cli_bridge/runner.py +371 -0
  77. cli_bridge_mcp-0.1.0/src/cli_bridge/server.py +2414 -0
  78. cli_bridge_mcp-0.1.0/src/cli_bridge/telemetry.py +745 -0
  79. cli_bridge_mcp-0.1.0/src/cli_bridge/workflows.py +1312 -0
  80. cli_bridge_mcp-0.1.0/src/cli_bridge/worktrees.py +480 -0
  81. cli_bridge_mcp-0.1.0/tests/conftest.py +9 -0
  82. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/auth_bypass_none_user/case.diff +10 -0
  83. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/auth_bypass_none_user/expected.json +25 -0
  84. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/auth_bypass_none_user/ideal.json +10 -0
  85. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/auth_debug_bypass/case.diff +8 -0
  86. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/auth_debug_bypass/expected.json +25 -0
  87. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/auth_debug_bypass/ideal.json +10 -0
  88. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/clean_rename/case.diff +12 -0
  89. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/clean_rename/expected.json +12 -0
  90. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/clean_rename/ideal.json +1 -0
  91. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/clean_reorder_imports/case.diff +10 -0
  92. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/clean_reorder_imports/expected.json +12 -0
  93. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/clean_reorder_imports/ideal.json +1 -0
  94. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/identity_compare_status/case.diff +8 -0
  95. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/identity_compare_status/expected.json +24 -0
  96. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/identity_compare_status/ideal.json +10 -0
  97. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/index_bounds_ring/case.diff +9 -0
  98. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/index_bounds_ring/expected.json +26 -0
  99. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/index_bounds_ring/ideal.json +10 -0
  100. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/index_plus_one_loop/case.diff +9 -0
  101. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/index_plus_one_loop/expected.json +24 -0
  102. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/index_plus_one_loop/ideal.json +10 -0
  103. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/logic_inversion_delete/case.diff +8 -0
  104. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/logic_inversion_delete/expected.json +25 -0
  105. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/logic_inversion_delete/ideal.json +10 -0
  106. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/logic_negation_flip/case.diff +10 -0
  107. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/logic_negation_flip/expected.json +25 -0
  108. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/logic_negation_flip/ideal.json +10 -0
  109. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/missing_return_total/case.diff +9 -0
  110. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/missing_return_total/expected.json +23 -0
  111. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/missing_return_total/ideal.json +10 -0
  112. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/multibug_bank/case.diff +15 -0
  113. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/multibug_bank/expected.json +35 -0
  114. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/multibug_bank/ideal.json +18 -0
  115. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/multibug_orders/case.diff +15 -0
  116. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/multibug_orders/expected.json +35 -0
  117. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/multibug_orders/ideal.json +18 -0
  118. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/none_config_subscript/case.diff +8 -0
  119. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/none_config_subscript/expected.json +24 -0
  120. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/none_config_subscript/ideal.json +10 -0
  121. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/null_deref_chained_get/case.diff +8 -0
  122. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/null_deref_chained_get/expected.json +22 -0
  123. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/null_deref_chained_get/ideal.json +10 -0
  124. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/null_deref_lookup/case.diff +9 -0
  125. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/null_deref_lookup/expected.json +22 -0
  126. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/null_deref_lookup/ideal.json +10 -0
  127. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/off_by_one_range_loop/case.diff +10 -0
  128. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/off_by_one_range_loop/expected.json +25 -0
  129. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/off_by_one_range_loop/ideal.json +10 -0
  130. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/off_by_one_slice/case.diff +11 -0
  131. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/off_by_one_slice/expected.json +25 -0
  132. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/off_by_one_slice/ideal.json +10 -0
  133. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/race_lazy_singleton/case.diff +11 -0
  134. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/race_lazy_singleton/expected.json +25 -0
  135. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/race_lazy_singleton/ideal.json +10 -0
  136. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/race_toctou_write/case.diff +11 -0
  137. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/race_toctou_write/expected.json +25 -0
  138. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/race_toctou_write/ideal.json +10 -0
  139. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/resource_leak_early_return/case.diff +12 -0
  140. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/resource_leak_early_return/expected.json +25 -0
  141. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/resource_leak_early_return/ideal.json +10 -0
  142. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/socket_leak_error_path/case.diff +15 -0
  143. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/socket_leak_error_path/expected.json +25 -0
  144. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/socket_leak_error_path/ideal.json +10 -0
  145. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/swallowed_exception_sync/case.diff +11 -0
  146. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/swallowed_exception_sync/expected.json +25 -0
  147. cli_bridge_mcp-0.1.0/tests/fixtures/evalset/swallowed_exception_sync/ideal.json +10 -0
  148. cli_bridge_mcp-0.1.0/tests/fixtures/replies/clean_array.json +6 -0
  149. cli_bridge_mcp-0.1.0/tests/fixtures/replies/fenced.txt +6 -0
  150. cli_bridge_mcp-0.1.0/tests/fixtures/replies/garbage.txt +2 -0
  151. cli_bridge_mcp-0.1.0/tests/fixtures/replies/no_issues.txt +1 -0
  152. cli_bridge_mcp-0.1.0/tests/fixtures/replies/prose_wrapped.txt +6 -0
  153. cli_bridge_mcp-0.1.0/tests/fixtures/reviews/clean.diff +11 -0
  154. cli_bridge_mcp-0.1.0/tests/fixtures/reviews/dangerous_shell.diff +10 -0
  155. cli_bridge_mcp-0.1.0/tests/fixtures/reviews/multi_issue.diff +22 -0
  156. cli_bridge_mcp-0.1.0/tests/fixtures/reviews/secret_leak.diff +10 -0
  157. cli_bridge_mcp-0.1.0/tests/test_build_direct.py +204 -0
  158. cli_bridge_mcp-0.1.0/tests/test_buildloop.py +242 -0
  159. cli_bridge_mcp-0.1.0/tests/test_byo_api.py +42 -0
  160. cli_bridge_mcp-0.1.0/tests/test_cache.py +79 -0
  161. cli_bridge_mcp-0.1.0/tests/test_challenge.py +54 -0
  162. cli_bridge_mcp-0.1.0/tests/test_cli.py +172 -0
  163. cli_bridge_mcp-0.1.0/tests/test_consensus.py +143 -0
  164. cli_bridge_mcp-0.1.0/tests/test_conversation_dispatch.py +73 -0
  165. cli_bridge_mcp-0.1.0/tests/test_conversations.py +92 -0
  166. cli_bridge_mcp-0.1.0/tests/test_cost_defaults.py +112 -0
  167. cli_bridge_mcp-0.1.0/tests/test_cost_truth.py +169 -0
  168. cli_bridge_mcp-0.1.0/tests/test_council_recap.py +110 -0
  169. cli_bridge_mcp-0.1.0/tests/test_debate_hardening.py +371 -0
  170. cli_bridge_mcp-0.1.0/tests/test_eval_scorer.py +289 -0
  171. cli_bridge_mcp-0.1.0/tests/test_evals.py +110 -0
  172. cli_bridge_mcp-0.1.0/tests/test_features.py +282 -0
  173. cli_bridge_mcp-0.1.0/tests/test_files_required.py +90 -0
  174. cli_bridge_mcp-0.1.0/tests/test_findings.py +207 -0
  175. cli_bridge_mcp-0.1.0/tests/test_git_tools.py +73 -0
  176. cli_bridge_mcp-0.1.0/tests/test_guards.py +132 -0
  177. cli_bridge_mcp-0.1.0/tests/test_host_sample.py +63 -0
  178. cli_bridge_mcp-0.1.0/tests/test_integration.py +120 -0
  179. cli_bridge_mcp-0.1.0/tests/test_isolation.py +51 -0
  180. cli_bridge_mcp-0.1.0/tests/test_jobs.py +141 -0
  181. cli_bridge_mcp-0.1.0/tests/test_lanes.py +324 -0
  182. cli_bridge_mcp-0.1.0/tests/test_live_e2e.py +30 -0
  183. cli_bridge_mcp-0.1.0/tests/test_local_recipes.py +48 -0
  184. cli_bridge_mcp-0.1.0/tests/test_model_discovery.py +83 -0
  185. cli_bridge_mcp-0.1.0/tests/test_nesting_env.py +43 -0
  186. cli_bridge_mcp-0.1.0/tests/test_opencode_cache.py +57 -0
  187. cli_bridge_mcp-0.1.0/tests/test_orchestrate.py +464 -0
  188. cli_bridge_mcp-0.1.0/tests/test_outcome_routing.py +145 -0
  189. cli_bridge_mcp-0.1.0/tests/test_pacing.py +91 -0
  190. cli_bridge_mcp-0.1.0/tests/test_preamble.py +70 -0
  191. cli_bridge_mcp-0.1.0/tests/test_profile.py +58 -0
  192. cli_bridge_mcp-0.1.0/tests/test_progress.py +47 -0
  193. cli_bridge_mcp-0.1.0/tests/test_resources.py +45 -0
  194. cli_bridge_mcp-0.1.0/tests/test_router.py +97 -0
  195. cli_bridge_mcp-0.1.0/tests/test_runner.py +211 -0
  196. cli_bridge_mcp-0.1.0/tests/test_server.py +399 -0
  197. cli_bridge_mcp-0.1.0/tests/test_severity_filter.py +33 -0
  198. cli_bridge_mcp-0.1.0/tests/test_stance_agreement.py +52 -0
  199. cli_bridge_mcp-0.1.0/tests/test_telemetry.py +192 -0
  200. cli_bridge_mcp-0.1.0/tests/test_workflows.py +275 -0
  201. cli_bridge_mcp-0.1.0/tests/test_worktrees.py +143 -0
@@ -0,0 +1,29 @@
1
+ # Code of Conduct
2
+
3
+ ## Our pledge
4
+
5
+ We — contributors and maintainers — pledge to make participation in this project a harassment-free
6
+ experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and
7
+ expression, level of experience, nationality, personal appearance, race, religion, or sexual
8
+ identity and orientation.
9
+
10
+ ## Our standards
11
+
12
+ Examples of behavior that contributes to a positive environment:
13
+
14
+ - Being respectful of differing viewpoints and experiences.
15
+ - Giving and gracefully accepting constructive feedback.
16
+ - Focusing on what is best for the community and the project.
17
+
18
+ Unacceptable behavior includes harassment, insulting or derogatory comments, personal or political
19
+ attacks, publishing others' private information, and other conduct that would reasonably be
20
+ considered inappropriate.
21
+
22
+ ## Enforcement
23
+
24
+ Instances of abusive or otherwise unacceptable behavior may be reported to the maintainer via a
25
+ GitHub private security advisory or the contact on the maintainer's profile. All complaints will be
26
+ reviewed and investigated and will result in a response appropriate to the circumstances.
27
+
28
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
29
+ version 2.1.
@@ -0,0 +1,49 @@
1
+ # Contributing to cli-bridge
2
+
3
+ Thanks for helping out. cli-bridge aims to stay small, dependency-light, and predictable, so a
4
+ few rules keep it that way.
5
+
6
+ ## Setup
7
+
8
+ ```bash
9
+ uv venv && uv pip install -e . pytest pytest-asyncio ruff
10
+ CLI_BRIDGE_STATE_DB=/tmp/t.sqlite pytest -q # keep tests off your real state db
11
+ ruff check src/ tests/
12
+ ```
13
+
14
+ No real AI CLI or network is needed to develop or test — lanes are faked with `echo`/`false`
15
+ and the state DB is a temp sqlite.
16
+
17
+ ## Ground rules
18
+
19
+ - **Stdlib + `mcp` only.** No new runtime dependencies. (Dev tools like `pytest`/`ruff` are fine.)
20
+ - **Keep `server.py` thin.** Business logic lives in `lanes`/`runner`/`router`/`workflows`/
21
+ `findings`/`telemetry`. The server routes; it doesn't decide.
22
+ - **Every change ships a test**, and `pytest -q` + `ruff check` must stay green. Tests must not
23
+ require a real CLI or network.
24
+ - **Portable**: macOS / Linux / Windows. No POSIX-only calls without a Windows branch
25
+ (see `runner._kill_tree`).
26
+ - **Telemetry is best-effort** — it must NEVER raise into a delegation path.
27
+ - **Cost safety**: a missing/empty model must never resolve to a paid model.
28
+ - **Surgical diffs.** Match the existing style; don't reformat unrelated code.
29
+
30
+ ## Adding a lane (a new CLI)
31
+
32
+ You usually don't need to fork: point `CLI_BRIDGE_LANES_FILE` at a JSON file
33
+ (see `examples/lanes.example.json`), or wrap an HTTP API with `curl`
34
+ (`examples/byo-api-lane.json`). To add a built-in lane, append a `LaneSpec` in `lanes.py` with
35
+ its argv builder and capabilities, and ship a test. See `docs/ARCHITECTURE.md` → "Extending it".
36
+
37
+ ## Adding a workflow
38
+
39
+ Add a function in `workflows.py` taking `(targets, args, run_lane)`, then register a tool +
40
+ dispatch in `server.py` (and a prompt in `_PROMPTS` if it deserves a slash command). Reuse the
41
+ injected `run_lane` so it's testable with fakes.
42
+
43
+ ## Commit / PR
44
+
45
+ - Conventional-commit-ish subjects (`feat(...)`, `fix(...)`, `docs(...)`) are appreciated.
46
+ - Describe the *why*, not just the *what*. Note any new env var or tool.
47
+ - Update `CHANGELOG.md` under "Unreleased".
48
+
49
+ By contributing you agree your work is licensed under the project's MIT license.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something in cli-bridge behaves incorrectly
4
+ title: "[bug] "
5
+ labels: bug
6
+ ---
7
+
8
+ **What happened**
9
+ A clear description of the bug.
10
+
11
+ **Steps to reproduce**
12
+ 1. Host (Claude Code / Codex / opencode / …) and version:
13
+ 2. Tool called and arguments:
14
+ 3. What you expected vs. what happened:
15
+
16
+ **`doctor` output**
17
+ Paste the output of the `doctor` tool (or `cli-bridge doctor`).
18
+
19
+ **Environment**
20
+ - cli-bridge version / commit:
21
+ - OS:
22
+ - Python:
23
+ - Relevant `CLI_BRIDGE_*` env vars (redact secrets):
24
+
25
+ **Logs**
26
+ If you can, set `CLI_BRIDGE_LOG=<path>` and attach the relevant lines (redact secrets).
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: CLI flag broken / drifted
3
+ about: A delegate CLI changed its flags and a lane no longer works
4
+ title: "[drift] "
5
+ labels: drift
6
+ ---
7
+
8
+ **Which lane / CLI?**
9
+ e.g. `gemini` (agy), `gpt` (codex), `opencode` …
10
+
11
+ **What broke**
12
+ The error or wrong behavior you see (paste the `[kind] message`, e.g. `[failed] … exit 2`).
13
+
14
+ **The CLI's current invocation**
15
+ What the CLI now expects (paste the relevant `--help` excerpt):
16
+
17
+ ```
18
+ <paste mycli --help here>
19
+ ```
20
+
21
+ **Version**
22
+ - CLI version:
23
+ - cli-bridge version / commit:
24
+
25
+ > The nightly `drift-check` workflow opens these automatically when the test suite breaks; feel
26
+ > free to file one manually if you hit it first.
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security report
4
+ url: https://github.com/JoaoBerne/cli-bridge-mcp/security/advisories/new
5
+ about: Please report vulnerabilities privately via a GitHub security advisory, not a public issue. See .github/SECURITY.md.
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: Lane request
3
+ about: Ask for a new built-in CLI lane
4
+ title: "[lane] "
5
+ labels: lane-request
6
+ ---
7
+
8
+ **Which CLI?**
9
+ Name + link to the official CLI.
10
+
11
+ **Install + auth**
12
+ How is it installed, and how does a user log in (subscription / free tier / API key)?
13
+
14
+ **Invocation**
15
+ The exact non-interactive command to send one prompt and get an answer, e.g.:
16
+
17
+ ```
18
+ mycli --print "the prompt"
19
+ ```
20
+
21
+ - Model selection flag (if any):
22
+ - Reasoning/effort flag (if any):
23
+ - Write/build mode flag (if any):
24
+ - How to list models (if any):
25
+
26
+ **Cost**
27
+ Is it free, quota-limited, or paid/credits for a typical user?
28
+
29
+ > Tip: you may not need a built-in lane — you can add any CLI yourself via
30
+ > `CLI_BRIDGE_LANES_FILE` (see `examples/lanes.example.json`).
@@ -0,0 +1,17 @@
1
+ <!-- Thanks for contributing! Keep diffs surgical and tests green. -->
2
+
3
+ ## What & why
4
+ <!-- What does this change, and why? Link any issue. -->
5
+
6
+ ## Checklist
7
+ - [ ] `pytest -q` is green (tests don't need a real CLI or network)
8
+ - [ ] `ruff check src/ tests/` is clean
9
+ - [ ] No new runtime dependency (stdlib + `mcp` only)
10
+ - [ ] `server.py` stays thin (logic lives in lanes/runner/router/workflows/findings/telemetry)
11
+ - [ ] Telemetry stays best-effort (never raises into a delegation)
12
+ - [ ] Cost safety preserved (empty model never resolves to paid)
13
+ - [ ] `CHANGELOG.md` updated under "Unreleased" (if user-facing)
14
+ - [ ] New env var / tool documented (README / ARCHITECTURE)
15
+
16
+ ## Notes
17
+ <!-- Anything reviewers should know: new env vars, behavior changes, follow-ups. -->
@@ -0,0 +1,73 @@
1
+ # Security
2
+
3
+ cli-bridge spawns official AI CLIs as subprocesses and returns their output to your host
4
+ assistant. That puts it between two trust boundaries, so it's worth being precise about what it
5
+ defends against and what it does not.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please **do not** open a public issue for a security problem. Instead, open a
10
+ [GitHub security advisory](https://github.com/JoaoBerne/cli-bridge-mcp/security/advisories/new)
11
+ (or email the maintainer listed on the GitHub profile). Include repro steps and the affected
12
+ version/commit. You'll get an acknowledgement within a few days.
13
+
14
+ ## Threat model
15
+
16
+ cli-bridge handles two kinds of untrusted data:
17
+
18
+ 1. **Delegate output** — text produced by another model/CLI, returned to your host assistant.
19
+ It can contain prompt-injection ("ignore previous instructions"), requests to exfiltrate
20
+ secrets, hidden instructions in HTML comments, or shell commands disguised as guidance.
21
+ 2. **The task/diff you pass in** — may itself contain secrets or hostile content.
22
+
23
+ ### What cli-bridge does about it
24
+
25
+ - **Ban-safe by construction.** It only ever spawns the official CLI you already run. It never
26
+ extracts tokens, reads credential files, or sends your API keys anywhere. (Test: `test_isolation.py`.)
27
+ - **No pollution of your CLI config.** The only things it writes are an overflow temp file, the
28
+ local telemetry sqlite, and an optional log. Never to `~/.gemini`, `~/.codex`, etc.
29
+ - **Secret redaction.** Known secret shapes (bearer tokens, `sk-…`, `ghp_…`, `AIza…`,
30
+ `api_key=…`) are redacted from output **before** anything is returned or logged
31
+ (`runner.redact`). The review prechecks redact a secret's value even while flagging it.
32
+ - **Output guard.** `CLI_BRIDGE_GUARD=off|warn|strict` (default `warn`) scans delegate output for
33
+ injection / tool-poisoning signals and, in `warn`, prepends a banner telling the host to treat
34
+ the text as **data, not instructions**; in `strict`, it withholds the body. Runs after redaction.
35
+ - **Read-only by default.** A delegate can only edit files with an explicit `agent: build`. The
36
+ recommended way to use write mode is **`ask_build_isolated`**, which runs the agent in a
37
+ throwaway git worktree and returns a diff — your real repository is never modified.
38
+ - **Cost safety.** A missing/empty model never resolves to a paid model; `ask_all`/`ask_cascade`
39
+ exclude limited/paid lanes by default.
40
+ - **Telemetry is local and minimal.** A task **hash + short preview** only (never the full
41
+ prompt/output unless you set `CLI_BRIDGE_STORE_TRANSCRIPTS=true`), in a local sqlite DB that
42
+ never leaves your machine. Disable with `CLI_BRIDGE_TELEMETRY=off`.
43
+
44
+ ### What it does NOT protect against
45
+
46
+ - **It is not a sandbox.** A delegate CLI runs with your user's permissions. In `agent: build`
47
+ (outside `ask_build_isolated`) it can modify files; only run write mode on code you trust.
48
+ - **The guard is heuristic.** It catches high-signal patterns, not every possible injection. In
49
+ `warn` mode the text still reaches the host — treat delegated output as untrusted input.
50
+ - **It can't vet the models themselves.** A compromised or malicious model could emit harmful
51
+ content; that's why output is annotated and, for writes, isolated.
52
+ - **`cwd`/path arguments are not jailed.** A delegate sees whatever directory you point it at.
53
+ - **Delegates inherit your full environment.** Each spawned CLI gets the host process's complete
54
+ `os.environ` — deliberately, because official CLIs need their own `PATH`, auth caches and
55
+ config to work. The flip side: every secret in that environment (cloud creds, unrelated API
56
+ keys) is readable by any delegate process, exactly as if you ran that CLI by hand. cli-bridge
57
+ redacts known secret shapes from *output*, but it cannot stop a malicious CLI from reading the
58
+ env it was born with. If that matters, launch your MCP host from a scoped environment (e.g.
59
+ `env -i PATH=… HOME=…` or a shell profile without the sensitive exports).
60
+ - **BYO-API (curl) lanes: keep the key OUT of argv.** A lane that substitutes a `${ENV}` key into
61
+ a `curl` command line puts that key in this machine's process list for the duration of the call
62
+ (it is never logged — traces redact it, and it never leaves your machine otherwise). The shipped
63
+ examples use the secret-safe pattern instead — `--variable %MY_KEY` + `--expand-header
64
+ "Authorization: Bearer {{MY_KEY}}"` (curl ≥ 8.3) imports the key *inside* curl, so `ps` only
65
+ ever shows the variable's name. `doctor` warns about any custom lane that still expands a
66
+ secret into a credential-bearing argv part.
67
+
68
+ ## Hardening checklist for sensitive use
69
+
70
+ - Set `CLI_BRIDGE_GUARD=strict`.
71
+ - Use `ask_build_isolated` instead of raw `agent: build`.
72
+ - Keep `CLI_BRIDGE_STORE_TRANSCRIPTS` unset.
73
+ - Run from a directory that contains only what the delegate should see.
@@ -0,0 +1,47 @@
1
+ # Nightly "does it still import / do the lane builders still hold" check.
2
+ # CLIs change their flags without warning; this catches obvious breakage early and opens
3
+ # an issue so the lane builders can be updated before users hit it.
4
+ name: drift-check
5
+
6
+ on:
7
+ schedule:
8
+ - cron: "0 6 * * *" # daily 06:00 UTC
9
+ workflow_dispatch: {}
10
+
11
+ permissions:
12
+ contents: read
13
+ issues: write
14
+
15
+ jobs:
16
+ smoke:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v5
20
+ - uses: actions/setup-python@v6
21
+ with:
22
+ python-version: "3.12"
23
+ - run: |
24
+ python -m pip install --upgrade pip
25
+ pip install -e . pytest pytest-asyncio
26
+ - name: Import + unit tests
27
+ id: check
28
+ run: pytest -q
29
+ - name: Open an issue on failure
30
+ if: failure()
31
+ uses: actions/github-script@v7
32
+ with:
33
+ script: |
34
+ const title = "drift-check failed — a CLI lane may be broken";
35
+ const body = "The nightly drift-check run failed. A delegate CLI may have changed its " +
36
+ "flags, or a dependency broke. See the failing run: " +
37
+ `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
38
+ const existing = await github.rest.issues.listForRepo({
39
+ owner: context.repo.owner, repo: context.repo.repo,
40
+ state: "open", labels: "drift",
41
+ });
42
+ if (existing.data.length === 0) {
43
+ await github.rest.issues.create({
44
+ owner: context.repo.owner, repo: context.repo.repo,
45
+ title, body, labels: ["drift"],
46
+ });
47
+ }
@@ -0,0 +1,35 @@
1
+ # GitHub Pages — landing page (site/index.html + assets/).
2
+ # Manual trigger only: Pages on the free plan needs the repo public, so this is armed for
3
+ # launch day (run it once from the Actions tab after going public + enabling Pages → Actions).
4
+ name: pages
5
+
6
+ on:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+ pages: write
12
+ id-token: write
13
+
14
+ concurrency:
15
+ group: pages
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ deploy:
20
+ environment:
21
+ name: github-pages
22
+ url: ${{ steps.deployment.outputs.page_url }}
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v5
26
+ - name: Assemble site
27
+ run: |
28
+ mkdir -p _site
29
+ cp site/index.html _site/
30
+ cp -r assets _site/assets
31
+ - uses: actions/upload-pages-artifact@v3
32
+ with:
33
+ path: _site
34
+ - id: deployment
35
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,47 @@
1
+ # Publish to PyPI on a version tag, via Trusted Publishing (OIDC — no API token stored).
2
+ # One-time setup on PyPI: add a "pending publisher" for project `cli-bridge-mcp`, repo
3
+ # JoaoBerne/cli-bridge-mcp, workflow `release.yml`, environment `pypi`. Then `git tag v0.1.0 &&
4
+ # git push --tags` builds + publishes automatically.
5
+ name: release
6
+
7
+ on:
8
+ push:
9
+ tags: ["v*"]
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ build:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v5
19
+ - uses: actions/setup-python@v6
20
+ with:
21
+ python-version: "3.12"
22
+ - name: Build sdist + wheel
23
+ run: |
24
+ python -m pip install --upgrade pip build
25
+ python -m build
26
+ - name: Smoke-check the wheel imports + entry points
27
+ run: |
28
+ python -m pip install dist/*.whl
29
+ python -c "import cli_bridge, cli_bridge.cli, cli_bridge.server; print('import ok')"
30
+ cli-bridge --help >/dev/null && echo "cli-bridge entry ok"
31
+ - uses: actions/upload-artifact@v4
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+
36
+ publish:
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ environment: pypi
40
+ permissions:
41
+ id-token: write # required for Trusted Publishing
42
+ steps:
43
+ - uses: actions/download-artifact@v4
44
+ with:
45
+ name: dist
46
+ path: dist/
47
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,92 @@
1
+ name: tests
2
+
3
+ on:
4
+ # PR-only: a rebase-merge lands the exact commits the PR already tested, so a separate
5
+ # push-on-main run would re-test identical commits — pure duplication. Dropped to halve CI cost.
6
+ pull_request:
7
+ branches: [main, master]
8
+ workflow_dispatch: # manual full-matrix run on main when you want one (e.g. before a release)
9
+
10
+ jobs:
11
+ lint:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v5
15
+ - uses: actions/setup-python@v6
16
+ with:
17
+ python-version: "3.12"
18
+ - name: Install ruff
19
+ run: python -m pip install --upgrade pip ruff
20
+ - name: Lint
21
+ run: ruff check src/ tests/
22
+
23
+ typecheck:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v5
27
+ - uses: actions/setup-python@v6
28
+ with:
29
+ python-version: "3.12"
30
+ - name: Install
31
+ # mypy pinned so the gate can't pass on one version and break on another; install the
32
+ # package so mypy resolves mcp's own types.
33
+ run: |
34
+ python -m pip install --upgrade pip
35
+ pip install -e . mypy==2.1.0
36
+ - name: Type check
37
+ run: mypy src/cli_bridge
38
+
39
+ test:
40
+ runs-on: ${{ matrix.os }}
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ os: [ubuntu-latest]
45
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
46
+ include:
47
+ # prove portability (a stated invariant). macOS minutes bill at 10× on GitHub-hosted
48
+ # runners, so we keep a single macOS job (newest Python) and cover both ends of the
49
+ # version range on Windows (2×) instead. Full cross-product on demand via workflow_dispatch.
50
+ - os: macos-latest
51
+ python-version: "3.13"
52
+ - os: windows-latest
53
+ python-version: "3.10"
54
+ - os: windows-latest
55
+ python-version: "3.13"
56
+ steps:
57
+ - uses: actions/checkout@v5
58
+ - name: Set up Python ${{ matrix.python-version }}
59
+ uses: actions/setup-python@v6
60
+ with:
61
+ python-version: ${{ matrix.python-version }}
62
+ - name: Install
63
+ run: |
64
+ python -m pip install --upgrade pip
65
+ pip install -e . pytest pytest-asyncio
66
+ - name: Run tests
67
+ run: pytest -q
68
+
69
+ security:
70
+ runs-on: ubuntu-latest
71
+ permissions:
72
+ contents: read
73
+ pull-requests: read # gitleaks-action lists the PR's commits via the API in PR mode
74
+ steps:
75
+ - uses: actions/checkout@v5
76
+ with:
77
+ fetch-depth: 0 # gitleaks scans full history; dep-review diffs the PR base/head
78
+ # Fail a PR that ADDS a dependency carrying a high+ CVE. PR-scoped, native to GitHub, free,
79
+ # zero runtime cost — right-sized for a stdlib + `mcp` project (no Trivy: it would find ~0
80
+ # on a one-dependency tree and just burn CI minutes). Hard gate now that the repo is public
81
+ # (the dependency-graph API is on by default for public repos): a PR adding a high+ CVE dep fails.
82
+ - name: Dependency review
83
+ if: github.event_name == 'pull_request'
84
+ uses: actions/dependency-review-action@v4
85
+ with:
86
+ fail-on-severity: high
87
+ # Secret scan — the real risk here: the whole pitch is "no token leak, no key extraction".
88
+ # gitleaks-action is free for personal-account repos (no GITLEAKS_LICENSE needed).
89
+ - name: Secret scan (gitleaks)
90
+ uses: gitleaks/gitleaks-action@v2
91
+ env:
92
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+
11
+ # Secrets / local state (never commit)
12
+ .env
13
+ .env.*
14
+ *.sqlite
15
+ *.sqlite-wal
16
+ *.sqlite-shm
17
+
18
+ # Test / tooling
19
+ .pytest_cache/
20
+ .coverage
21
+ htmlcov/
22
+ .ruff_cache/
23
+ .mypy_cache/
24
+
25
+ # OS / editor
26
+ .DS_Store
27
+ *.swp
28
+ .idea/
29
+ .vscode/
30
+ TESTING.md
@@ -0,0 +1,14 @@
1
+ # gitleaks configuration — extends the default ruleset.
2
+ #
3
+ # The test tree carries INTENTIONAL synthetic secrets (fake `ghp_…`, `sk-…`, Slack-webhook
4
+ # strings) used as fixtures to verify cli-bridge's OWN secret redaction + precheck detection.
5
+ # They are not real credentials — policy is that tests never use real keys (see AGENTS.md/CLAUDE.md).
6
+ # Allowlist the test tree so gitleaks doesn't flag its own bait; `src/` stays fully scanned.
7
+ [extend]
8
+ useDefault = true
9
+
10
+ [allowlist]
11
+ description = "Synthetic secrets in the test suite (redaction/precheck fixtures, not real credentials)"
12
+ paths = [
13
+ '''^tests/''',
14
+ ]
@@ -0,0 +1,124 @@
1
+ # Agent guide — cli-bridge
2
+
3
+ Guidance for AI coding agents (Claude Code, Codex, Gemini CLI, opencode…) working on this
4
+ repo. `CLAUDE.md` is a symlink to this file.
5
+
6
+ ## What this is
7
+
8
+ An MCP server that lets the host AI consult **other** AI CLIs as a council. Each lane spawns
9
+ the official CLI as a subprocess (ban-safe: no token extraction, no API keys). Read-only by
10
+ default. Pure-stdlib + `mcp` only.
11
+
12
+ ## Layout
13
+
14
+ ```
15
+ src/cli_bridge/
16
+ server.py # MCP surface: tool list, dispatch, doctor/setup. Keep thin.
17
+ lanes.py # LaneSpec registry + argv builders + custom-lane JSON loader
18
+ runner.py # subprocess exec, redaction, process-tree kill, error classification
19
+ config.py # env parsing, cost profile, timeouts, onboarding text
20
+ telemetry.py # sqlite3 run log + lane health/cooldown (best-effort, privacy-first)
21
+ router.py # deterministic cascade ordering (pure)
22
+ council.py # ask_all/ask_cascade/ask_best/synthesize fan-out (injected run_lane — like workflows)
23
+ jobs.py # in-process async jobs (ask_all_async) + sqlite persistence
24
+ workflows.py # review_diff/security_review/debate + prechecks + council recap
25
+ orchestrate.py # batch_run durable fan-out + presets (refine_plan/verify_repair/fanout_compare/…)
26
+ findings.py # parse/merge/render structured review findings (pure)
27
+ guards.py # injection/tool-poisoning output guard (CLI_BRIDGE_GUARD)
28
+ worktrees.py # ask_build (isolated worktree diff | direct zone-guarded write + artifact return)
29
+ buildloop.py # steerable multi-turn builds: job_tail/build_steer, executable DoD gate
30
+ conversations.py # round-table threads: sqlite persistence + recipient-aware replay
31
+ preamble.py # terse response-style preamble prepended to delegate prompts
32
+ eval.py # quality eval: council vs single + self-consistency, permutation test, scorer
33
+ cli.py # human/CI entry point (cli-bridge ...) over the same internals
34
+ detect.py # PATH detection
35
+ tests/ # pytest; unit + cross-host integration (no real CLI needed)
36
+ docs/ # COSTS.md, BENCHMARKS.md, ARCHITECTURE.md, i18n/ READMEs
37
+ assets/ # README banner/mark/social SVGs + demo.gif (generated, do not hand-edit)
38
+ site/ # GitHub Pages landing (deployed by .github/workflows/pages.yml)
39
+ examples/ # custom-lane JSON recipes + GitHub Action
40
+ ```
41
+
42
+ ## Rules for changes
43
+
44
+ - **Keep `server.py` thin** — business logic belongs in lanes/runner/router/telemetry.
45
+ - **No new runtime deps** beyond `mcp`. Stdlib only.
46
+ - **Every change ships tests.** `pytest -q` must stay green. Tests must not need a real AI
47
+ CLI or network (fake lanes via `echo`/`false`, temp sqlite via `CLI_BRIDGE_STATE_DB`).
48
+ - **Portability**: must run on macOS/Linux/Windows. No POSIX-only calls without a Windows
49
+ branch (see `runner._kill_tree`).
50
+ - **Telemetry is best-effort** — it must NEVER raise into a delegation path.
51
+ - **Cost safety**: a missing/empty model must never resolve to a paid model. `ask_all`/
52
+ `ask_cascade` exclude limited/paid by default.
53
+ - Match existing style; surgical diffs.
54
+
55
+ ## Commands
56
+
57
+ ```
58
+ uv venv && uv pip install -e . pytest pytest-asyncio ruff
59
+ pytest -q
60
+ CLI_BRIDGE_STATE_DB=/tmp/t.sqlite pytest -q # keep tests off your real state db
61
+ ruff check src/ tests/ # lint (CI enforces this)
62
+ CLI_BRIDGE_LIVE_E2E=1 pytest tests/test_live_e2e.py -q # opt-in live checks
63
+ ```
64
+
65
+ ## Roadmap
66
+
67
+ See `CHANGELOG.md` for the shipped history. Done: config extraction, telemetry+cooldown, cascade router,
68
+ terse preamble (+min-chars skip), response cache, trace fields, workflow tools (review_diff/
69
+ security_review/debate), council recap, MCP prompts, opt-in write/build mode (all lanes),
70
+ sibling-model self-consultation, in-process async jobs (ask_all_async), structured findings
71
+ JSON + deterministic merge + prechecks + residual_risk, output guard (injection/poisoning),
72
+ worktree-isolated write mode (ask_build_isolated), ask_best mode router + estimated token/
73
+ credit accounting (usage_report/usage_budget), human CLI (cli-bridge), MCP resources,
74
+ premortem/test_plan workflows, eval fixtures + no-network evaluator, ruff lint + CI lint job,
75
+ modular tool loading (DISABLED_TOOLS/ENABLED_TOOLS), quality eval (`cli-bridge eval`: council vs
76
+ single-model + self-consistency, deterministic scorer + calibration gate), architect/editor build
77
+ split, debate VOTE footer + convergence early-stop, files_required grounding gate, anti-burst
78
+ spawn pacing (per-lane MIN_INTERVAL_S), trace-footer toggle, i18n READMEs (docs/i18n/), Pages
79
+ landing (site/), opt-in streaming runner (arun on_line/log_path + stall guard), direct builds
80
+ (ask_build mode=isolated|direct — zone contract + per-zone lock + post-turn zone-violation check +
81
+ greenfield init), steerable multi-turn builds (buildloop: job_tail/build_steer/interrupt, executable
82
+ DoD gate, plan-leak warning), durable journaled fan-out (batch_run + resume_id across restart) with
83
+ workflow presets (council_review/map_review/research_verify/refine_plan), guard NFKC/zero-width
84
+ normalization, runtime paid-model warning, **council module extraction** (`council.py`, injected
85
+ run_lane), **mypy gate in CI** (typed `_ann()` helper for the SDK-stub noise), **eval v3** (seeded
86
+ permutation test replacing the 1-sigma heuristic + multi-bug fixtures + in-fixture decoys),
87
+ **build artifact-return** (non-text files surfaced by path — capability-borrowing), **cross-model
88
+ `verify_repair`** + **`fanout_compare`** workflow presets. **Dynamic orchestration engine (Phase 1):**
89
+ typed result envelope + provenance, `findings.extract_json` contract, per-invocation budget caps +
90
+ `dry_run` cost envelope, **cross-vendor `jury`** (author≠reviewer family, k-of-N fail-closed) +
91
+ `lanes.family_of`, **disagreement-as-uncertainty** score on `ask_all`, opt-in **confidence-escalate**
92
+ cascade, **`BRIDGE_DEPTH` re-entry guard**, **`CLI_BRIDGE_LEAN`** core surface, `role=` personas,
93
+ Gemini `images=` vision (experimental). **Local + council quality + quota resilience:** **Ollama lane**
94
+ (`ask_ollama`/`list_ollama_models` — local, $0, offline, read-only) + local-model custom-lane recipes
95
+ (`examples/`), **peer-anonymized debate/council** (neutral Reviewer/Debater labels so no model favours
96
+ a known rival), **`seat_report`** earn-their-seat (`jury_outcomes` telemetry benches dead-weight lanes
97
+ on evidence), **discrete calibration binning** (eval bins on emitted confidences, N≥50 gate),
98
+ **quota-empty cooldown with capped exponential backoff** (never infinite, success-resets).
99
+
100
+ ### Considered & deferred (rationale — not just "not yet")
101
+ - **forced-pacing engine** — contradicts the model (cli-bridge delegates investigation to the
102
+ council; it doesn't force the host to slow down), big effort, low value, and only helps if the
103
+ host respects the gate. Dropped.
104
+ - **warm pool** — no lane offers a daemon/server mode (the lanes are spawn-per-call), so there's
105
+ nothing to keep warm. Infeasible cleanly.
106
+ - **chars/token calibration per lane** — would need real provider token counts = ban-risk fishing,
107
+ against the no-extraction ethos. The chars/4 figure stays honestly labeled "estimated".
108
+ - **native build resume (`--session-id`)** — no lane exposes a reliable session id; filesystem
109
+ continuity (the delegate re-reads its own files each turn) already covers it. Revisit if a CLI
110
+ ships a stable resume handle.
111
+ - **Big orchestration architecture** (recursive spawn trees, shared state bus, inter-agent mailbox,
112
+ capability passthrough hub, a wire-protocol "bus between AIs") — real directions, but vaporware-
113
+ prone and vendor-hostile (we build on CLIs we don't control). Roadmap only; positioned honestly
114
+ as a direction, never sold as a shipped protocol. See `docs/ARCHITECTURE.md` for the framing.
115
+
116
+ ### Next candidates (small — after real-usage soak of the engine; council-trimmed)
117
+ - **early-stop `ask_all`** (`agree_stop`) — stop spawning once K lanes agree (reuses the agreement
118
+ score). Deferred: needs ask_all restructured from gather-all to incremental + cancellation, and
119
+ the agreement heuristic validated on real outputs first.
120
+ - **architect/editor split** for `ask_build` (plan on a strong lane, edit on a cheap diff-precise one).
121
+ - GATED (build on real demand, not speculatively): **planner → plan_build**, **precommit** (≈
122
+ `review_diff role=strict`), **MoA** preset. CUT: **debug**, **conversation_resume**, generic
123
+ chaining **DSL** / **recursive spawn** (the host already orchestrates; see deferred above).
124
+ - Release track: opt-in real-CLI contract job in CI, history secrets scan, PyPI publish (GO-gated).