@bridge_gpt/mcp-server 0.2.53 → 0.2.55

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 (103) hide show
  1. package/README.md +116 -56
  2. package/build/agent-guidance.generated.js +3 -0
  3. package/build/agent-launchers/claude-executor-adapter.js +3 -0
  4. package/build/agent-launchers/claude.js +3 -3
  5. package/build/agent-launchers/prompt.js +8 -11
  6. package/build/agent-notes.js +178 -0
  7. package/build/agent-registry.js +5 -2
  8. package/build/agent-utils.js +58 -0
  9. package/build/agents.generated.js +1 -1
  10. package/build/base-ref.js +33 -9
  11. package/build/bounded-wait.js +174 -0
  12. package/build/codex-skill-adapter.js +55 -0
  13. package/build/commands.generated.js +6 -5
  14. package/build/conductor/bridge-api-client.js +235 -14
  15. package/build/conductor/bring-up-facts.js +187 -0
  16. package/build/conductor/claude-hook.js +7 -5
  17. package/build/conductor/cli.js +28 -0
  18. package/build/conductor/doctor.js +80 -9
  19. package/build/conductor/epic-implementer-cli.js +1298 -0
  20. package/build/conductor/epic-runtime.js +134 -98
  21. package/build/conductor/errors.js +2 -2
  22. package/build/conductor/git-ci-types.js +1 -1
  23. package/build/conductor/git-hooks.js +28 -14
  24. package/build/conductor/install-doctor.js +11 -5
  25. package/build/conductor/readiness-cli.js +10 -10
  26. package/build/conductor/readiness-sections.js +58 -9
  27. package/build/conductor/readiness.js +120 -4
  28. package/build/conductor/recovery-cli.js +289 -10
  29. package/build/conductor/recovery-operations.js +125 -2
  30. package/build/conductor/repair-contract.js +58 -0
  31. package/build/conductor/run-branch.js +137 -0
  32. package/build/conductor/store.js +2 -2
  33. package/build/conductor/supervisor-runtime.js +1 -1
  34. package/build/conductor/test-run-branch-vectors.js +165 -0
  35. package/build/conductor-bin.js +2 -139
  36. package/build/conductor-claude-hook-bin.js +2 -2
  37. package/build/conductor-claude-hook-removed-stub-bin.js +31 -0
  38. package/build/conductor-removed-stub-bin.js +30 -0
  39. package/build/docs.generated.js +1 -1
  40. package/build/doctor.js +145 -18
  41. package/build/drive-epic.js +752 -90
  42. package/build/epic-implementer-bin.js +145 -0
  43. package/build/epic-implementer-bundle-cli.js +264 -0
  44. package/build/epic-implementer-claude-hook-bin.js +3 -0
  45. package/build/epic-integration-pr.js +5 -3
  46. package/build/executor/claim-scope.js +104 -0
  47. package/build/executor/cli.js +14 -25
  48. package/build/executor/env-file-guard.js +82 -3
  49. package/build/executor/env.js +6 -0
  50. package/build/executor/interrupted-worktree.js +60 -0
  51. package/build/executor/job-errors.js +45 -0
  52. package/build/executor/job-runner.js +334 -9
  53. package/build/executor/job-types.js +25 -9
  54. package/build/executor/merge-tree-classifier.js +171 -0
  55. package/build/executor/reconcile-overlap-governance.js +129 -0
  56. package/build/executor/reconcile-overlap-job.js +989 -0
  57. package/build/executor/reconcile-overlap-types.js +14 -0
  58. package/build/executor/spawn-job-driver.js +1 -0
  59. package/build/executor/types.js +2 -0
  60. package/build/executor/worker-finalization.js +25 -2
  61. package/build/executor/worker-guard-hook.js +15 -7
  62. package/build/implement-epic/bridge-client.js +773 -0
  63. package/build/implement-epic/checkpoint-store.js +542 -0
  64. package/build/implement-epic/cli.js +3158 -0
  65. package/build/implement-epic/cut-protocol.js +392 -0
  66. package/build/implement-epic/lock.js +302 -0
  67. package/build/implement-epic/pr-state.js +286 -0
  68. package/build/implement-epic/spawn.js +113 -0
  69. package/build/index.js +657 -481
  70. package/build/init.js +72 -8
  71. package/build/install-bridge-conductor.js +5 -5
  72. package/build/install-bridge.js +403 -70
  73. package/build/local-artifact-storage.js +130 -0
  74. package/build/mcp-host-config.js +22 -60
  75. package/build/mcp-host-entry-adapter.js +18 -0
  76. package/build/mcp-host-targets.js +1 -21
  77. package/build/merge-pull-request.js +1 -1
  78. package/build/pipelines.generated.js +23 -16
  79. package/build/plan-epic-conductor-eligibility.js +1 -1
  80. package/build/plane/cli.js +321 -41
  81. package/build/plane/manifest.js +209 -1
  82. package/build/plane/member-roster.js +70 -0
  83. package/build/plane/preflight.js +128 -12
  84. package/build/plane/shutdown.js +18 -5
  85. package/build/plane/status.js +35 -1
  86. package/build/plane/supervisor.js +546 -164
  87. package/build/plane/types.js +25 -2
  88. package/build/polling-policy.js +72 -0
  89. package/build/readiness-check.js +3 -3
  90. package/build/readme.generated.js +1 -1
  91. package/build/review-generation.js +219 -0
  92. package/build/run-unit-tests-launcher.js +6 -1
  93. package/build/setup-epic.js +567 -38
  94. package/build/start-tickets-conductor.js +8 -7
  95. package/build/ticket-key-utils.js +4 -3
  96. package/build/ticket-review-artifact-gate.js +461 -0
  97. package/build/upgrade-cli.js +5 -26
  98. package/build/version.generated.js +3 -3
  99. package/build/worker-guard-hook-bin.js +1 -1
  100. package/docs/CONDUCTOR.md +8 -6
  101. package/docs/install/mcp-tool-integrations.md +23 -1
  102. package/package.json +5 -3
  103. package/pipelines/review-ticket.json +17 -4
package/README.md CHANGED
@@ -32,8 +32,7 @@ account — it will ask.
32
32
  `--api-key` or `BAPI_API_KEY` — the installer writes that store, it does not read
33
33
  it back.
34
34
  - Writes outside your project root only when you pick a host whose configuration is
35
- global: OpenAI Codex (`~/.codex/config.toml`) and GitHub Copilot CLI
36
- (`~/.copilot/mcp-config.json`).
35
+ global: OpenAI Codex (`~/.codex/config.toml`).
37
36
 
38
37
  **Prerequisites**
39
38
 
@@ -41,8 +40,8 @@ account — it will ask.
41
40
  - **A project directory** — run the command from the folder your editor opens: your
42
41
  repository root, the one containing `.git`. No `package.json` is required — SFCC
43
42
  cartridge repos, Python, Go, Rust, and other non-Node projects work the same way.
44
- - **An MCP-capable editor or CLI**: Claude Code, GitHub Copilot in VS Code, GitHub
45
- Copilot CLI, Cursor, Windsurf, or OpenAI Codex.
43
+ - **An MCP-capable editor or CLI**: Claude Code, GitHub Copilot in VS Code, Cursor,
44
+ Windsurf, or OpenAI Codex.
46
45
  - **No Bridge account needed.** The installer can create one for you from just an
47
46
  email address.
48
47
 
@@ -87,13 +86,13 @@ npx -y @bridge_gpt/mcp-server install
87
86
  a token:
88
87
 
89
88
  ```
90
- 1. Yes, I have received a token
91
- 2. No, I need one
89
+ 1. I need a token
90
+ 2. I already have a token
92
91
  ```
93
92
 
94
- - Choose **2** if you have nothing yet. It asks for your email address and a name
93
+ - Choose **1** if you have nothing yet. It asks for your email address and a name
95
94
  for your new Bridge project, then creates both for you.
96
- - Choose **1** if someone gave you a token — either a Bridge API key or an invite
95
+ - Choose **2** if someone gave you a token — either a Bridge API key or an invite
97
96
  code. Paste it at the hidden prompt; you do not have to say which kind it is,
98
97
  because the installer recognizes it. Nothing is echoed as you type.
99
98
 
@@ -120,8 +119,8 @@ include a host the installer can launch, the run has to be on an interactive
120
119
  terminal, and you have to accept the consent prompt (*"Bridge can configure and set
121
120
  up this project for you automatically. Open a `<tool>` session to do that now?
122
121
  (Y/n)"*). Claude Code is the only selection that launches on its own. A
123
- Cursor-only, Copilot, Copilot CLI, Codex, or Windsurf selection, a non-interactive
124
- run, or a declined prompt all print the command to continue by hand instead. Pass
122
+ Cursor-only, Copilot, Codex, or Windsurf selection, a non-interactive run, or a
123
+ declined prompt all print the command to continue by hand instead. Pass
125
124
  `--agent claude` or `--agent cursor-agent` to override the decision outright.
126
125
 
127
126
  **7. Follow the next step the session shows you, if it shows one.** The installer
@@ -143,7 +142,7 @@ Want to see what would happen without changing anything? Add `--dry-run`.
143
142
 
144
143
  | Path | What it is | Commit it? |
145
144
  |---|---|---|
146
- | `.claude/commands/`, `.cursor/commands/` | The slash commands your editor runs | Yes |
145
+ | `.claude/commands/`, `.cursor/commands/`, `.github/prompts/`, `.github/skills/` | The generated workflow commands for supported agent hosts | Yes |
147
146
  | `.claude/agents/` and editor equivalents | Agent definitions used by those commands | Yes |
148
147
  | `.bridge/config` | Your project manifest — the repository name and which MCP targets to provision. Deliberately secret-free | Yes |
149
148
  | `.bridge/pipelines/`, `.bridge/instructions/` | Editable pipeline definitions | Yes |
@@ -173,8 +172,8 @@ Cursor's agent instead of Claude Code.
173
172
 
174
173
  **Selecting Windsurf prints instructions instead of writing config.** Windsurf's
175
174
  global `mcp_config.json` is never modified automatically; the installer reports the
176
- entry for you to paste yourself. Codex and Copilot CLI *are* written automatically,
177
- even though their files are global too.
175
+ entry for you to paste yourself. Codex *is* written automatically, even though its
176
+ file is global too.
178
177
 
179
178
  **Your key is stored for the tools that read the store.** The MCP server and the
180
179
  shell-spawned tooling (`start-tickets` and its model routing) resolve it from
@@ -261,7 +260,7 @@ Creates a brand-new Bridge project for that address and your first admin key in
261
260
  command. No account, no key, and no invite needed beforehand. The address labels
262
261
  your new workspace and may receive a setup message; delivery is best-effort, so
263
262
  nothing waits on it. The email is visible as you type (it is not a secret) and is
264
- never written to a log. This is the same route as answering **2** at the prompt.
263
+ never written to a log. This is the same route as answering **1** at the prompt.
265
264
 
266
265
  **You were sent an invite code.**
267
266
 
@@ -300,7 +299,7 @@ created or spent.
300
299
  | `--invite [code]` | Redeem an invite code. Omit the value for the hidden prompt (recommended) |
301
300
  | `--api-key <key>` | Use an existing Bridge API key |
302
301
  | `--repo <name>` | Name the registered repository instead of resolving or asking for it |
303
- | `--tools <list>` | Configure specific MCP hosts without the picker. Accepted IDs are exactly `claude-code`, `cursor`, `copilot-vscode`, `copilot-cli`, `codex`, and `windsurf` (e.g. `claude-code,cursor`); any other value is a parse error |
302
+ | `--tools <list>` | Configure specific MCP hosts without the picker. Accepted IDs are exactly `claude-code`, `cursor`, `copilot-vscode`, `codex`, and `windsurf` (e.g. `claude-code,cursor`); any other value is a parse error |
304
303
  | `--agent claude\|cursor-agent` | Which agent to open for the final configuration step. **No default** — without this flag the agent is derived from the hosts you selected, and an explicit value always wins, including for a host you did not select |
305
304
  | `--dry-run` | Preview every step without writing, contacting Bridge, resolving or prompting for a credential, or opening anything. Genuinely inert: it returns before the project-root prompt, before the repository is resolved, and before any tool-selection prompt, so a value it cannot know locally (an unresolved repository name, an unselected tool) is shown as **not yet known** rather than guessed |
306
305
  | `--force` | Overwrite an existing stored key without asking |
@@ -352,7 +351,7 @@ later boot.
352
351
  "mcpServers": {
353
352
  "bridge": {
354
353
  "command": "npx",
355
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.53", "serve"],
354
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
356
355
  "env": {
357
356
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
358
357
  "BAPI_REPO_NAME": "your-repo",
@@ -366,7 +365,7 @@ later boot.
366
365
  </details>
367
366
 
368
367
  <details>
369
- <summary><strong>VS Code / Copilot (.vscode/mcp.json)</strong></summary>
368
+ <summary><strong>GitHub Copilot (.vscode/mcp.json)</strong></summary>
370
369
 
371
370
  ```json
372
371
  {
@@ -374,7 +373,7 @@ later boot.
374
373
  "bridge": {
375
374
  "type": "stdio",
376
375
  "command": "npx",
377
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.53", "serve"],
376
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
378
377
  "env": {
379
378
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
380
379
  "BAPI_REPO_NAME": "your-repo",
@@ -396,33 +395,7 @@ later boot.
396
395
  "bridge": {
397
396
  "type": "stdio",
398
397
  "command": "npx",
399
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.53", "serve"],
400
- "env": {
401
- "BAPI_BASE_URL": "https://bridgegpt-api.com",
402
- "BAPI_REPO_NAME": "your-repo",
403
- "BAPI_API_KEY": "your-api-key",
404
- "BAPI_DOCS_DIR": "docs/tmp"
405
- }
406
- }
407
- }
408
- }
409
- ```
410
- </details>
411
-
412
- <details>
413
- <summary><strong>GitHub Copilot CLI (~/.copilot/mcp-config.json)</strong></summary>
414
-
415
- Copilot CLI reads a single global file. The installer writes this one for you when
416
- you select `copilot-cli`; the shape below is what it produces.
417
-
418
- ```json
419
- {
420
- "mcpServers": {
421
- "bridge": {
422
- "type": "local",
423
- "command": "npx",
424
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.53", "serve"],
425
- "tools": ["*"],
398
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
426
399
  "env": {
427
400
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
428
401
  "BAPI_REPO_NAME": "your-repo",
@@ -445,7 +418,7 @@ Windsurf only supports global MCP configuration.
445
418
  "mcpServers": {
446
419
  "bridge": {
447
420
  "command": "npx",
448
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.53", "serve"],
421
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
449
422
  "env": {
450
423
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
451
424
  "BAPI_REPO_NAME": "your-repo",
@@ -464,7 +437,7 @@ Windsurf only supports global MCP configuration.
464
437
  ```toml
465
438
  [mcp_servers.bridge]
466
439
  command = "npx"
467
- args = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.53", "serve"]
440
+ args = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"]
468
441
 
469
442
  [mcp_servers.bridge.env]
470
443
  BAPI_BASE_URL = "https://bridgegpt-api.com"
@@ -802,7 +775,16 @@ Repository and ticket housekeeping commands, beyond the tiers above. Implementat
802
775
  | `/parse-repository` | Queue a background job to index the repository for Bridge AI agents |
803
776
  | `/scan-tickets` | Sync recently-updated Jira tickets and backfill workflow timestamps |
804
777
 
805
- > Commands are designed for Claude Code. Other editors may support slash commands differently — check your editor's documentation for how to invoke prompt files.
778
+ > **GitHub Copilot modes.** On VS Code's Local agent, Bridge provisions one
779
+ > `.github/prompts/<command>.prompt.md` prompt per packaged command, including
780
+ > `/explore-ticket`. On VS Code Agent Host, prompt files are not loaded, so the
781
+ > installer provisions the same canonical command as a project skill at
782
+ > `.github/skills/<command>/SKILL.md`; invoke that skill by its slash-command
783
+ > name. Bridge does not claim Copilot CLI or cloud-agent workflow support from
784
+ > this scaffold alone. If either artifact is not discovered, use VS Code's Chat
785
+ > Customizations diagnostics, confirm the workspace is trusted, and invoke the
786
+ > workflow manually with its full instructions rather than assuming the slash
787
+ > command is available.
806
788
 
807
789
  ### Extra Capabilities
808
790
 
@@ -1090,12 +1072,54 @@ all, because an unknown owner is not the same as a not-ready one. No branch,
1090
1072
  including every error path, ever offers you two paths.
1091
1073
 
1092
1074
  `drive-epic` owns no branch behavior of its own — it forwards `--feature-branch
1093
- <name>` and `--into-base` verbatim to `setup-epic`, which decides the strategy (see
1094
- below). With neither flag, a multi-ticket epic runs on `epic/<KEY>`.
1075
+ <name>`, `--into-base`, and `--attended` verbatim to `setup-epic`, which decides
1076
+ the strategy and the posture (see below). With none of them, a multi-ticket epic
1077
+ runs on `epic/<KEY>`, unattended.
1078
+
1079
+ **The composed bring-up is two-phase (BAPI-1102).** With `--plan-file` on a
1080
+ repository whose readiness is missing only the runtime facts, one invocation runs,
1081
+ in order: the **control plane** (Bridge API server + reconciler, each gated on its
1082
+ own readiness), then `setup-epic` to create and approve the run, then **executor
1083
+ lanes scoped to that run** with `--epic-run-id <run>`, then the **dead-man
1084
+ observer** last, then the ready banner. The order is forced: an executor lane must
1085
+ carry an explicit claim scope, and the run it is scoped to does not exist until the
1086
+ server is up and `setup-epic` has run.
1087
+
1088
+ A composed plane serves **exactly one** run; start a second plane for a second
1089
+ epic. If `setup-epic` fails, the control plane is left running and **no executor
1090
+ lane is spawned**. If the lanes fail to become ready, the control plane and the
1091
+ committed run are both left intact and the observer is not started — nothing is
1092
+ rolled back, because a local process that failed to start says nothing about
1093
+ whether the run is valid.
1094
+
1095
+ "Plane ready" reports **processes**, not dispatchability: if the run cuts an epic
1096
+ branch, the reconciler holds ticket dispatch until that branch's index scope
1097
+ finishes preparing.
1095
1098
 
1096
1099
  Two conductors is a transitional state. When one is eliminated, `drive-epic` is
1097
1100
  the only thing that changes.
1098
1101
 
1102
+ ### `plane up` — claim scope is required
1103
+
1104
+ `plane up` starts the runtime on its own, and every executor lane it starts needs
1105
+ an explicit claim scope:
1106
+
1107
+ ```
1108
+ npx -y @bridge_gpt/mcp-server plane up --epic-run-id <run-id> # repeatable
1109
+ npx -y @bridge_gpt/mcp-server plane up --repo-wide # or repository-wide
1110
+ ```
1111
+
1112
+ The two are mutually exclusive. Asked to start lanes with neither, `plane up`
1113
+ **refuses before spawning anything**, in the executor's own words. That is not a
1114
+ new restriction — an executor started with no claim scope has refused to start
1115
+ since BAPI-1026 — it is that refusal moved to where it is actionable, instead of
1116
+ surfacing as a member crash and a full plane rollback.
1117
+
1118
+ `plane status` reports the lifecycle phase (control plane starting/ready, lanes
1119
+ starting/ready, observer active, plane ready) and the epic run the plane is bound
1120
+ to. `plane down` handles every intermediate phase: it stops the bound run first,
1121
+ then signals the recorded process group.
1122
+
1099
1123
  ### `setup-epic`
1100
1124
 
1101
1125
  Bootstraps an Epic Conductor v2 run in one command — creates the epic run, stores the plan DAG, and approves it:
@@ -1118,21 +1142,56 @@ branch, matching plain `start-tickets`.
1118
1142
  > name, or to force a branch for a single-node plan. Passing both is a parse error,
1119
1143
  > refused before any file read, credential resolution, or network call.
1120
1144
 
1145
+ **A run that selects an epic branch is created UNATTENDED (BAPI-1102).** Its
1146
+ `policy_json` carries `posture: "unattended"` and `v2_auto_merge_enabled: true`, so
1147
+ child PRs merge into the epic branch without parking for a human at every gate. The
1148
+ **integration PR into the repository base branch stays human-gated.** The run's CI
1149
+ gate is stamped **server-side at first approval** — from your repository's declared
1150
+ default, or, when it declares none, as an explicit recorded `no_ci_gate` mode.
1151
+
1152
+ > **Behavior change (BAPI-1102).** Pass `--attended` to restore the previous
1153
+ > composition: `base_branch` plus an explicitly requested `--review-policy`, with no
1154
+ > posture and no auto-merge authorization. `--into-base`, single-node plans, and
1155
+ > branch-silent invocations are **unchanged** — they send no `policy_json` at all,
1156
+ > byte for byte as before. A `--policy-file` still supersedes composition entirely;
1157
+ > combining `--attended` with a file that declares `posture: "unattended"` is a named
1158
+ > refusal rather than a silent winner.
1159
+
1160
+ An unattended run has two one-time **repository** prerequisites — consent
1161
+ (`unattended_epic_implementer_allowed`) and a verified notify webhook default — plus
1162
+ confirmed default-branch review/CI workflows. Each is refused by name **before any
1163
+ run row is created** (`target_not_allowed`, `webhook_unverified`,
1164
+ `repository_readiness_unconfirmed`), and `drive-epic` readiness and `doctor` both
1165
+ list them with their current state. `notify.local_sink` does not satisfy the webhook
1166
+ prerequisite.
1167
+
1168
+ > **Rollout note.** The client-side default and the server-side admission,
1169
+ > stamping, and readiness changes must be released as **one compatible unit**. The
1170
+ > new default's shape (`v2_auto_merge_enabled: true` with no `required_checks`) is
1171
+ > exactly what the create route refused before BAPI-1102, so shipping the client
1172
+ > half alone would 422 every unattended run at `POST /jira/epic-runs/runs`.
1173
+ > Deploying only the server half is safe and inert: it narrows two refusals and adds
1174
+ > a first-approval stamp, and **rewrites no existing run**. No database migration and
1175
+ > no new environment variable is introduced — `config_projects.unattended_epic_implementer_allowed`
1176
+ > and `epic_supervisor_setup.done_gate_config` already exist and are read as-is.
1177
+
1121
1178
  Once the plan is approved, the **server-side reconciler** picks the run up within ~30s. To execute claimed jobs on your machine, run `executor`:
1122
1179
 
1123
1180
  ```
1124
1181
  npx -y @bridge_gpt/mcp-server executor --repo <name>
1125
1182
  ```
1126
1183
 
1127
- ### `conduct-epic`
1184
+ ### `implement-epic`
1128
1185
 
1129
1186
  The deterministic half of the `/conduct-epic` loop: it owns the epic branch, a
1130
1187
  versioned local checkpoint, a per-epic lock, and the read-only probes the loop
1131
1188
  decides on. It never creates or mutates an `epic_run` — that is the server-side
1132
1189
  v2 reconciler's job, and `init` refuses to start when one is already active.
1190
+ This is EPIC-LEVEL orchestration, distinct from the ticket-level
1191
+ `implement-ticket` command.
1133
1192
 
1134
1193
  ```
1135
- npx -y @bridge_gpt/mcp-server conduct-epic <verb> [flags]
1194
+ npx -y @bridge_gpt/mcp-server implement-epic <verb> [flags]
1136
1195
  ```
1137
1196
 
1138
1197
  **Verbs**
@@ -1198,9 +1257,9 @@ appear in a command argument, in stdout/stderr, or in a journal line.
1198
1257
 
1199
1258
  ### Conductor (epic & multi-agent orchestration)
1200
1259
 
1201
- Conductor is an **opt-in, off-by-default** layer for epic supervision, inter-agent messaging, done-gate evaluation, local git-hook event producers, and conditional auto-merge. Its full reference — the v2 architecture (server-side reconciler + local executor), `setup-epic`, `conductor install-git-hooks`, the supervisor `done_gate_config` / `auto_merge_enabled` settings, and the observability stream — lives in **[CONDUCTOR.md](./docs/CONDUCTOR.md)**.
1260
+ Conductor is an **opt-in, off-by-default** layer for epic supervision, inter-agent messaging, done-gate evaluation, local git-hook event producers, and conditional auto-merge. Its full reference — the v2 architecture (server-side reconciler + local executor), `setup-epic`, `epic-implementer install-git-hooks`, the supervisor `done_gate_config` / `auto_merge_enabled` settings, and the observability stream — lives in **[CONDUCTOR.md](./docs/CONDUCTOR.md)**. (The event-ledger CLI was renamed from `conductor` to `epic-implementer`; the retained `conductor` bin name is now a fixed migration pointer.)
1202
1261
 
1203
- > The v1 `conductor epic-tick` command is **frozen** — it throws on every invocation. There is nothing to schedule locally, and `conductor doctor` flags any epic-tick schedule left over from an earlier release so you can cancel it.
1262
+ > The v1 `epic-implementer epic-tick` command is **frozen** — it throws on every invocation. There is nothing to schedule locally, and `epic-implementer doctor` flags any epic-tick schedule left over from an earlier release so you can cancel it.
1204
1263
 
1205
1264
  ## Custom Pipelines
1206
1265
 
@@ -1487,17 +1546,18 @@ The full surface, for when you need the complete enumeration. Day-to-day, use [U
1487
1546
 
1488
1547
  ### MCP tools
1489
1548
 
1490
- The authoritative tool catalog covers **73 tools** (enumerated below). What's actually registered in a session depends on `BRIDGE_MCP_PROFILE`: the default `core` profile loads a trimmed subset, and the conductor/pipeline-authoring/SFCC tools are added only under their respective profiles (see [Environment Variables](#environment-variables)). Async AI tools follow a request/get pattern: call the `request_*` tool to kick off generation, then the matching `get_*` tool to retrieve the result (or pass `wait_for_result: true` to poll automatically).
1549
+ The authoritative tool catalog covers **75 tools** (enumerated below). What's actually registered in a session depends on `BRIDGE_MCP_PROFILE`: the default `core` profile loads a trimmed subset, and the conductor/pipeline-authoring/SFCC tools are added only under their respective profiles (see [Environment Variables](#environment-variables)). Async AI tools follow a request/get pattern: call the `request_*` tool to kick off generation, then the matching `get_*` tool to retrieve the result (or pass `wait_for_result: true` to poll automatically).
1491
1550
 
1492
1551
  - **Connectivity & identity** — `ping` (its JSON also carries `docs_dir`, `role`, and `customer_type`)
1493
1552
  - **Team & access** — `invite_member` (admin-only; mints a scoped access key for a teammate on an already-configured project — the plaintext key is shown exactly once)
1494
1553
  - **Jira tickets** — `get_tickets`, `get_ticket`, `create_ticket`, `update_ticket_description`, `add_comment`, `get_comments`
1495
1554
  - **Attachments** — `attachment` (operations: `upload`, `download`, `list`)
1496
1555
  - **AI generation (request/get)** — `request_plan_generation`/`get_plan`, `create_doc`/`get_doc` (design docs by `doc_type`: tdd/architecture/fsd/prd, where `architecture` is an alias of `tdd`), `request_ticket_review` (writes both `get_clarifying_questions` and `get_ticket_critique`), `request_reimplement_context`/`get_reimplement_context`, `request_council`/`get_council`, `request_deep_research`/`get_deep_research`
1556
+ - **Bounded waits** — `wait_for_ticket_review`, `wait_for_ci_checks`. Each call waits at most 240 s and returns `state: "ready" | "pending" | "error"`; `pending` is a normal, resumable result you call again on, never a failure. They exist so an agent can wait without a foreground `sleep` and without binding a long server-side operation to the 900 s MCP client deadline. `wait_for_ci_checks` reports only that checks are **terminal** — deciding pass or fail stays with the caller.
1497
1557
  - **Other AI** — `second_opinion`, `generate_image`, `generate_decision_page`, `visual_diff` (deterministic pixel diff of a rendered URL vs a design comp)
1498
1558
  - **Ticket lifecycle** — `track_ticket`, `update_ticket_state`, `get_ticket_state`, `get_ticket_state_tree` (live repo-wide lifecycle + dependency tree; read-only, no mutation parameter)
1499
1559
  - **Jira status** — `update_jira_status` (pass `status: "auto"` to resolve the configured post-PR status server-side)
1500
- - **Repository & CI** — `parse_repository` (`action`: `start`, `status`), `regenerate_directory_map`, `create_pull_request`, `merge_pull_request`, `resolve_ci_checks`, `poll_ci_checks`
1560
+ - **Repository & CI** — `parse_repository` (`action`: `start`, `status`), `regenerate_directory_map`, `create_pull_request`, `merge_pull_request`, `resolve_ci_checks`, `poll_ci_checks`, `wait_for_ci_checks` (the last two are hidden until `ci_check_config` resolves, and share one visibility gate)
1501
1561
  - **Pipelines & automation** — `get_pipeline_recipe` (returns a fully resolved recipe the agent executes step-by-step)
1502
1562
  - **Config** — `get_project_standards`, `config_field` (operations: `get`, `update`, `list`)
1503
1563
 
@@ -0,0 +1,3 @@
1
+ // AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
2
+ // This file is produced by scripts/bundle-agent-guidance.js from mcp_server/agent-guidance.md
3
+ export const AGENT_GUIDANCE = "### Get Project Standards (`get_project_standards`)\n\n**When to use it:** (Implementation | Refinement) Before writing or reviewing code, so the agent applies this project's recorded coding standards instead of generic defaults.\n\n**How to use it:** Call the `get_project_standards` MCP tool directly — it takes no required input and returns the project's recorded standards text.\n\n### Second Opinion (`second_opinion`)\n\n**When to use it:** (Architecture | Refinement | Implementation) Any time you want a quick sanity check on a plan, draft, or decision from a fresh perspective.\n\n**How to use it:** Ask your agent — \"Get a second opinion from Gemini on whether the BAPI-123 plan's migration step is safe to run against production.\"\n\n### Council (`request_council`)\n\n**When to use it:** (Architecture | Refinement) Early, when you want a spread of approaches — technical for how to build it, design for how it should look, discovery for what still needs figuring out before a real ticket exists, general for a quick brief-driven pass before the repository is indexed.\n\n**How to use it:** `/council <question>`\n\n### Review Ticket (`request_ticket_review`)\n\n**When to use it:** (Refinement) Right after a ticket is drafted, before anyone starts building — to surface gaps and tighten it.\n\n**How to use it:** `/review-tickets BAPI-123` (command only — \"review\" as free text is easily mistaken for a freehand agent review). A single key reviews inline in the current session — no terminal tab, no worktree. For several tickets at once, `/review-tickets BAPI-123 BAPI-456` opens one terminal tab per ticket and reviews them in parallel with no worktrees; every review flag applies, and `--review KEY=auto,rounds=N` sets per-ticket overrides.";
@@ -345,6 +345,9 @@ export function createClaudeExecutorAdapter(spec, deps = {}) {
345
345
  if (input.workerBranch !== undefined) {
346
346
  envOptions.workerBranch = input.workerBranch;
347
347
  }
348
+ if (input.declaredTouchedFiles !== undefined) {
349
+ envOptions.declaredTouchedFiles = input.declaredTouchedFiles;
350
+ }
348
351
  return {
349
352
  executable: spec.command,
350
353
  argv: buildClaudeArgv(input.prompt, input.modelAlias, input.mcpConfigPath, input.posture),
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Resolves the `claude` binary against the *explicitly supplied PATH* (not the
5
5
  * ambient process default) and builds the launched-run invocation by delegating
6
- * to the shared `renderScheduledPrompt` renderer (no hard-coded `/full-automation`
6
+ * to the shared `renderScheduledPrompt` renderer (no hard-coded per-command
7
7
  * prompt). It emits `{ exe, args: ["-p", prompt] }`. Claude Code has no
8
8
  * working-directory flag, so the cwd is always set by the launching unit — this
9
9
  * adapter must never add a working-directory argument to the invocation.
@@ -41,8 +41,8 @@ export async function resolveCommandOnPath(command, envPath, deps) {
41
41
  return pathApi.normalize(candidate);
42
42
  }
43
43
  /**
44
- * Backward-compatibility shim for callers that quoted an idea-file path for a
45
- * `/full-automation` prompt. Generalized prompt-token quoting now lives in
44
+ * Backward-compatibility shim for callers that quoted an idea-file path for the
45
+ * pre-rename automation prompt. Generalized prompt-token quoting now lives in
46
46
  * `quotePromptToken`; this preserves the original quote semantics (always wrap in
47
47
  * double quotes, escape embedded quotes) for any remaining path callers.
48
48
  */
@@ -32,15 +32,14 @@ function schemaSupportsAutoFlag(schema) {
32
32
  * the normalized `input.args`, plus (only where the command can parse them)
33
33
  * `--scheduled-at <ISO>` and `--auto`.
34
34
  *
35
- * `--scheduled-at` is appended for `full-automation` (legacy) and `epic-tick`
36
- * (BAPI-418), both of whose parsers accept it as a first-class argument. Every
37
- * other command rejects unrecognized flags and halts (e.g. `start-tickets` stops
38
- * on any unsupported flag), and the shared late-fire gate already embeds the
39
- * scheduled time so injecting `--scheduled-at` into their argv would break an
40
- * otherwise launchable command for no benefit.
35
+ * `--scheduled-at` is appended for `epic-tick` (BAPI-418), whose parser accepts
36
+ * it as a first-class argument. Every other command rejects unrecognized flags
37
+ * and halts (e.g. `start-tickets` stops on any unsupported flag), and the shared
38
+ * late-fire gate already embeds the scheduled time so injecting `--scheduled-at`
39
+ * into their argv would break an otherwise launchable command for no benefit.
41
40
  *
42
41
  * `--auto` is appended when auto-approve is set AND the command supports it (its
43
- * schema declares a boolean `--auto` flag, or it is `full-automation` / `epic-tick`).
42
+ * schema declares a boolean `--auto` flag, or it is `epic-tick`).
44
43
  * It is never duplicated if already present in `input.args`.
45
44
  *
46
45
  * This is the SINGLE source of the delegated argv: both the rendered target
@@ -54,12 +53,10 @@ function buildAugmentedArgs(input) {
54
53
  // epic-tick already accepts --scheduled-at (parseEpicTickArgs, cli.ts) so it
55
54
  // receives the scheduled time as a structured arg for the late-fire decision,
56
55
  // not just via the embedded gate text.
57
- if (input.commandName === "full-automation" || input.commandName === "epic-tick") {
56
+ if (input.commandName === "epic-tick") {
58
57
  args.push("--scheduled-at", input.runAtIso);
59
58
  }
60
- const supportsAuto = schemaSupportsAutoFlag(input.schema) ||
61
- input.commandName === "full-automation" ||
62
- input.commandName === "epic-tick";
59
+ const supportsAuto = schemaSupportsAutoFlag(input.schema) || input.commandName === "epic-tick";
63
60
  const alreadyHasAuto = input.args.includes("--auto");
64
61
  if (input.autoApprove && supportsAuto && !alreadyHasAuto) {
65
62
  args.push("--auto");
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Marker-scoped, opt-in cross-platform agent notes writer (BAPI-1207).
3
+ *
4
+ * Creates or refreshes a Bridge-owned region inside a consumer project's
5
+ * `AGENTS.md` (shared by Cursor, Copilot VS Code, Codex, and Claude Code) and,
6
+ * for Claude Code specifically, a pointer region inside `CLAUDE.md` — so a
7
+ * Claude-only selection never leaves a dangling `@AGENTS.md` reference. Every
8
+ * other byte in either file — content a person wrote by hand outside the
9
+ * marker pair — is preserved exactly.
10
+ *
11
+ * This module performs I/O only through the injected `readFile`/`writeFile`/
12
+ * `mkdir` seams, mirroring the rest of the install-flow dependency-injection
13
+ * convention (see `InstallBridgeDeps` in `install-bridge.ts`), and does no
14
+ * platform detection, credential handling, `.gitignore` mutation, or scaffold
15
+ * bookkeeping of its own — those stay the caller's responsibility.
16
+ */
17
+ import path from "path";
18
+ /** The runtime marker pair this module owns inside a target notes file. */
19
+ export const BRIDGE_MCP_GUIDANCE_BEGIN_MARKER = "<!-- BEGIN BRIDGE MCP GUIDANCE -->";
20
+ export const BRIDGE_MCP_GUIDANCE_END_MARKER = "<!-- END BRIDGE MCP GUIDANCE -->";
21
+ /** Platforms whose shared notes file is AGENTS.md. Claude Code also gets CLAUDE.md. */
22
+ const AGENTS_MD_PLATFORMS = new Set([
23
+ "cursor",
24
+ "copilot-vscode",
25
+ "codex",
26
+ "claude-code",
27
+ ]);
28
+ /**
29
+ * Pure projection from a selected-platform set to the physical notes files
30
+ * that selection implies. Never touches the filesystem or re-detects
31
+ * platforms — the caller supplies the already-selected set.
32
+ */
33
+ export function resolveAgentNotesTargets(selectedPlatforms) {
34
+ const targets = new Set();
35
+ const unsupported = new Set();
36
+ for (const platform of selectedPlatforms) {
37
+ if (platform === "windsurf") {
38
+ unsupported.add(platform);
39
+ continue;
40
+ }
41
+ if (AGENTS_MD_PLATFORMS.has(platform)) {
42
+ targets.add("AGENTS.md");
43
+ }
44
+ // Claude Code additionally gets a CLAUDE.md pointer — never a substitute
45
+ // for AGENTS.md, since @AGENTS.md would otherwise dangle.
46
+ if (platform === "claude-code") {
47
+ targets.add("CLAUDE.md");
48
+ }
49
+ }
50
+ const ordered = [];
51
+ if (targets.has("AGENTS.md"))
52
+ ordered.push("AGENTS.md");
53
+ if (targets.has("CLAUDE.md"))
54
+ ordered.push("CLAUDE.md");
55
+ return { targets: ordered, unsupportedPlatforms: [...unsupported] };
56
+ }
57
+ /** The one-line pointer note CLAUDE.md's owned region carries (BAPI-1207). */
58
+ const CLAUDE_NOTES_POINTER_NOTE = "Bridge MCP usage guidance is maintained in AGENTS.md — see the section above.";
59
+ function buildClaudeOwnedBody() {
60
+ return `@AGENTS.md\n\n${CLAUDE_NOTES_POINTER_NOTE}`;
61
+ }
62
+ function countOccurrences(text, marker) {
63
+ return text.split(marker).length - 1;
64
+ }
65
+ /**
66
+ * Locate the existing owned region in *text*, or classify why it cannot be
67
+ * located safely. A malformed topology (a missing half, a duplicate, reversed
68
+ * order, or a marker not on its own line) is reported rather than repaired —
69
+ * this module never appends a second region next to one it cannot parse.
70
+ */
71
+ function scanMarkers(text) {
72
+ const beginCount = countOccurrences(text, BRIDGE_MCP_GUIDANCE_BEGIN_MARKER);
73
+ const endCount = countOccurrences(text, BRIDGE_MCP_GUIDANCE_END_MARKER);
74
+ if (beginCount === 0 && endCount === 0)
75
+ return { kind: "absent" };
76
+ if (beginCount === 0 || endCount === 0) {
77
+ return { kind: "malformed", reason: "missing half of the marker pair" };
78
+ }
79
+ if (beginCount > 1)
80
+ return { kind: "malformed", reason: "duplicate BEGIN marker" };
81
+ if (endCount > 1)
82
+ return { kind: "malformed", reason: "duplicate END marker" };
83
+ const beginIndex = text.indexOf(BRIDGE_MCP_GUIDANCE_BEGIN_MARKER);
84
+ const endIndex = text.indexOf(BRIDGE_MCP_GUIDANCE_END_MARKER);
85
+ if (endIndex < beginIndex)
86
+ return { kind: "malformed", reason: "markers are reversed" };
87
+ const afterBegin = beginIndex + BRIDGE_MCP_GUIDANCE_BEGIN_MARKER.length;
88
+ if (text[afterBegin] !== "\n") {
89
+ return { kind: "malformed", reason: "BEGIN marker is not on its own line" };
90
+ }
91
+ const contentStart = afterBegin + 1;
92
+ const lineStart = text.lastIndexOf("\n", endIndex - 1) + 1;
93
+ if (text.slice(lineStart, endIndex).trim().length > 0) {
94
+ return { kind: "malformed", reason: "END marker is not on its own line" };
95
+ }
96
+ return { kind: "present", contentStart, contentEnd: endIndex };
97
+ }
98
+ /** Replace only the bytes between valid existing markers; preserve everything else. */
99
+ function replaceRegion(text, contentStart, contentEnd, ownedBody) {
100
+ const normalized = ownedBody.trim() + "\n";
101
+ return text.slice(0, contentStart) + normalized + text.slice(contentEnd);
102
+ }
103
+ /**
104
+ * Append one fresh owned region at EOF, using the minimal separator needed
105
+ * for a clean markdown boundary. The existing prefix is never normalized —
106
+ * only the amount of new whitespace inserted before the region varies.
107
+ */
108
+ function appendRegion(existingText, ownedBody) {
109
+ const region = `${BRIDGE_MCP_GUIDANCE_BEGIN_MARKER}\n${ownedBody.trim()}\n${BRIDGE_MCP_GUIDANCE_END_MARKER}\n`;
110
+ if (existingText.length === 0)
111
+ return region;
112
+ if (existingText.endsWith("\n\n"))
113
+ return existingText + region;
114
+ if (existingText.endsWith("\n"))
115
+ return existingText + "\n" + region;
116
+ return existingText + "\n\n" + region;
117
+ }
118
+ function isEnoent(err) {
119
+ return (typeof err === "object" &&
120
+ err !== null &&
121
+ "code" in err &&
122
+ err.code === "ENOENT");
123
+ }
124
+ async function writeOneTarget(target, options) {
125
+ const filePath = path.join(options.cwd, target);
126
+ let existing;
127
+ try {
128
+ existing = await options.readFile(filePath);
129
+ }
130
+ catch (err) {
131
+ if (isEnoent(err)) {
132
+ existing = "";
133
+ }
134
+ else {
135
+ return { target, status: "failed", reason: "could not read the existing file" };
136
+ }
137
+ }
138
+ const ownedBody = target === "AGENTS.md" ? options.guidance : buildClaudeOwnedBody();
139
+ const scan = scanMarkers(existing);
140
+ let merged;
141
+ if (scan.kind === "malformed") {
142
+ return {
143
+ target,
144
+ status: "failed",
145
+ reason: `existing marker region is malformed (${scan.reason})`,
146
+ };
147
+ }
148
+ else if (scan.kind === "present") {
149
+ merged = replaceRegion(existing, scan.contentStart, scan.contentEnd, ownedBody);
150
+ }
151
+ else {
152
+ merged = appendRegion(existing, ownedBody);
153
+ }
154
+ if (merged === existing) {
155
+ return { target, status: "skipped", reason: "content already up to date" };
156
+ }
157
+ try {
158
+ await options.mkdir(path.dirname(filePath), { recursive: true });
159
+ await options.writeFile(filePath, merged, { encoding: "utf-8" });
160
+ }
161
+ catch {
162
+ return { target, status: "failed", reason: "could not write the file" };
163
+ }
164
+ return { target, status: "written" };
165
+ }
166
+ /**
167
+ * Create or refresh the Bridge-owned notes region in every target the
168
+ * selected platforms resolve to. Each target is handled independently — a
169
+ * failure on one never rolls back or blocks a write already made to another.
170
+ */
171
+ export async function writeAgentNotes(options) {
172
+ const { targets, unsupportedPlatforms } = resolveAgentNotesTargets(options.selectedPlatforms);
173
+ const files = [];
174
+ for (const target of targets) {
175
+ files.push(await writeOneTarget(target, options));
176
+ }
177
+ return { files, unsupportedPlatforms };
178
+ }
@@ -44,8 +44,11 @@ export const AGENT_REGISTRY = {
44
44
  supportsModelOverride: true,
45
45
  modelFlag: "--model",
46
46
  // Claude family aliases float to the latest release and never drift, so they
47
- // can be validated against a static allowlist.
48
- tierModels: { cheap: "haiku", basic: "sonnet", premium: "opus" },
47
+ // can be validated against a static allowlist. The `cheap` tier deliberately
48
+ // maps to `sonnet` (not `haiku`): even the lowest-difficulty tickets route to
49
+ // sonnet. `haiku` stays in the allowlist so a per-repo
50
+ // `difficulty_model_tier_overrides` may still opt back into it.
51
+ tierModels: { cheap: "sonnet", basic: "sonnet", premium: "opus" },
49
52
  staticModelAliasAllowlist: ["haiku", "sonnet", "opus"],
50
53
  // BAPI-781: the reference executor adapter. `managedCarriers` is EMPTY and
51
54
  // `passthroughs` names only the operator's own OAuth variable — Bridge