@bridge_gpt/mcp-server 0.2.12 → 0.2.14

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.
package/CONDUCTOR.md ADDED
@@ -0,0 +1,131 @@
1
+ # Conductor — epic & multi-agent orchestration
2
+
3
+ Conductor is the **opt-in, off-by-default** coordination layer for running many
4
+ agent sessions together (epic supervision, inter-agent messaging, done-gate
5
+ evaluation, and conditional auto-merge). A normal `start-tickets` run does **not**
6
+ involve Conductor — you opt in per run with `--conductor`, and epic-tick dispatch
7
+ enables it internally.
8
+
9
+ This document is the reference for Conductor's observability stream, local git
10
+ hooks, and the per-repo done-gate / auto-merge config. For the everyday
11
+ `start-tickets` flags and cross-platform behavior, see
12
+ [README → CLI Subcommands](./README.md#cli-subcommands).
13
+
14
+ ## Conductor observability (opt-in via `--conductor`, BAPI-394)
15
+
16
+ Conductor is **off by default** — without `--conductor` no `BAPI_CONDUCTOR_*` env,
17
+ supervisor tab, or message-relay prompt is produced. With `--conductor`, a run mints
18
+ a single conductor `run_id` and emits one canonical `run.started` event into the
19
+ local conductor ledger (`~/.config/bridge/events.db`), attributing each worker by
20
+ `worker_id`, ticket key, and worktree path, and opens a supervisor peer tab. When
21
+ the selected agent is **Claude Code**, the CLI also injects a conductor lifecycle
22
+ hook into each created worktree's `.claude/settings.local.json` (preserving any
23
+ existing hooks) so the spawned session streams local `run.started` / `run.stopped` /
24
+ `agent.notification` (and, with `BAPI_CONDUCTOR_ENABLE_PRE_TOOL_USE=1`,
25
+ `tool.intent`) events. Per-worker conductor identity is passed only via secret-free
26
+ environment scoped to that one terminal/tab/session — no credentials are ever placed
27
+ in the env, hook command, or run metadata. Override the gate/supervisor labels with
28
+ `BAPI_CONDUCTOR_GATE_NAME` / `BAPI_CONDUCTOR_SUPERVISOR_MODE`. Inspect the stream
29
+ with `conductor doctor`. Observability is best-effort: a conductor failure never
30
+ blocks or aborts a spawn, and `--dry-run` performs no conductor side effects.
31
+ (Epic-tick dispatch always enables conductor internally, independent of this flag.)
32
+
33
+ When `--conductor` is set, the spawn boundary also injects
34
+ `BRIDGE_MCP_PROFILE=conductor` so each worker registers the 8 conductor/event/
35
+ supervisor MCP tools (a plain `start-tickets` run stays on the default `core`
36
+ profile). See [README → Environment Variables](./README.md#environment-variables).
37
+
38
+ ## `conductor install-git-hooks` (BAPI-395)
39
+
40
+ Installs local git hooks that opportunistically emit conductor git/PR/CI events into
41
+ the local ledger:
42
+
43
+ ```
44
+ conductor install-git-hooks [--json]
45
+ ```
46
+
47
+ The installed hooks are **local, unversioned, opportunistic, and bypassable**: they
48
+ live in the worktree's git hooks directory (resolved via
49
+ `git rev-parse --git-common-dir`), insert only a clearly-delimited managed block
50
+ (preserving any existing user hook content), launch the producer **detached in the
51
+ background** so a commit or ref update is never blocked, and tolerate every failure
52
+ (`|| true`). A directory that is not a git worktree, or an existing hook that looks
53
+ binary/unsafe, is left untouched and reported as a **degraded optional capability** —
54
+ never a fatal error. The hooks installed are `post-commit` (emits
55
+ `git.commit_created`) and `reference-transaction` (emits `worktree.changed` for
56
+ committed ref updates).
57
+
58
+ Missing hooks do **not** prevent PR/CI gate evaluation — `conductor doctor` reads
59
+ hook presence and managed-snippet status **read-only** (a new `git hooks` section /
60
+ `git_hooks` JSON object alongside the ledger report), and the `wait_for_done_gate`
61
+ MCP tool drives CI polling and gate evaluation regardless of whether hooks are
62
+ installed.
63
+
64
+ ## `conductor_done_gate` config
65
+
66
+ The per-repo `conductor_done_gate` config field (read through the existing
67
+ config-field route) defines the v1 done gate. It supports exactly one condition,
68
+ `required_ci_checks_green`:
69
+
70
+ ```json
71
+ {
72
+ "enabled": true,
73
+ "conditions": [
74
+ { "type": "required_ci_checks_green", "required_checks": ["build", "test"] }
75
+ ]
76
+ }
77
+ ```
78
+
79
+ `gate.met` is emitted (exactly once per `repo + pr_number + head_sha + effective
80
+ config`) only when every listed required check is present, complete, and green for
81
+ the bound PR head SHA. The gate **fails closed**: an unset, disabled (`enabled` not
82
+ strictly `true`), malformed, empty, or unsupported config emits no `gate.met`.
83
+
84
+ ## `conductor_auto_merge_enabled` config (C6 conditional auto-merge)
85
+
86
+ When a worker's PR meets the done gate (`gate.met`), the supervisor can autonomously
87
+ merge it — but **only** when the repo has explicitly opted in. The per-repo
88
+ `conductor_auto_merge_enabled` config field (read through the same config-field route
89
+ as `conductor_done_gate`) is the opt-in switch:
90
+
91
+ ```json
92
+ { "enabled": true }
93
+ ```
94
+
95
+ A bare JSON boolean (`true`) is also accepted. **Auto-merge is disabled by default.**
96
+ Behavior:
97
+
98
+ - **Disabled / unset / malformed → dry-run.** Anything other than `true` or
99
+ `{"enabled": true}` — including unset, `false`, `{"enabled": false}`, or any
100
+ malformed value — fails **closed**: the supervisor records a `merge.dry_run` event
101
+ and **no PR is ever merged**.
102
+ - **Enabled → autonomous merge** when the gate is met and the deterministic guards
103
+ pass.
104
+ - **Kill-switch.** Set `conductor_auto_merge_enabled` to `false` or remove the field
105
+ to immediately stop autonomous merges. The protected merge endpoint
106
+ **independently re-enforces** the flag, so even a conductor that calls it cannot
107
+ merge while the flag is off.
108
+
109
+ Merge authority is **deterministic code, never an LLM**. The deterministic guards,
110
+ all bound to **PR number + expected head SHA (never a branch name)**:
111
+
112
+ - the per-repo enablement flag (off → dry-run),
113
+ - the PR is still open,
114
+ - the merge is bound to the PR number plus the expected head SHA — **head-SHA drift
115
+ between gate evaluation and merge aborts the merge**,
116
+ - required CI checks are **revalidated green immediately before merge**.
117
+
118
+ Idempotency is crash-safe and race-safe: a TTL lease keyed by the deterministic
119
+ action key `merge:{repo}:{pr}:{head_sha}:{gate}` is claimed before acting, and an
120
+ existing `merge.succeeded` for that key is terminal — the supervisor never
121
+ double-merges across a crash/restart or two racing instances. The conductor never
122
+ holds VCS write credentials: it calls the protected Bridge API endpoint
123
+ `POST /vcs/pull-requests/{pr_number}/merge`, which owns the privileged merge, and
124
+ records the returned `merge.dry_run` / `merge.attempted` / `merge.succeeded` /
125
+ `merge.failed` / `merge.pending_approval` events into the local ledger.
126
+ `merge.failed` is **retryable** (a drifted head SHA produces a new action key);
127
+ `merge.pending_approval` is **nonterminal** — the worker remains active until a human
128
+ redeems the approval token and the server returns `merge.succeeded`.
129
+ **`merge.succeeded` is the only terminal merge event.** The local SQLite conductor
130
+ store uses schema version 5 (BAPI-413) to accommodate the `merge.pending_approval`
131
+ type in the `events.type` CHECK constraint.
package/README.md CHANGED
@@ -1,19 +1,58 @@
1
1
  # @bridge_gpt/mcp-server
2
2
 
3
- MCP server for [Bridge API](https://bridgegpt-api.com) — exposes Jira integration endpoints as MCP tools for AI coding agents. Works with Claude Code, VS Code/Copilot, Cursor, Windsurf, and OpenAI Codex.
4
-
5
- > **New here?** Jump to [Usage Documentation](#usage-documentation) for what you can actually do with Bridge, grouped by how often you'll reach for it.
3
+ The Bridge MCP is an end-to-end accelerator for shipping code within SFCC, powered by [Bridge API](https://bridgegpt-api.com). Works with Claude Code, Github Copilot, Cursor, Windsurf, and OpenAI Codex.
4
+
5
+ ## Contents
6
+
7
+ - [Getting Started](#getting-started)
8
+ - [Usage Documentation](#usage-documentation)
9
+ - [Tier 1 — Regularly useful](#tier-1--regularly-useful)
10
+ - [Tier 2 — Occasionally useful](#tier-2--occasionally-useful)
11
+ - [Tier 3 — Now and then](#tier-3--now-and-then)
12
+ - [Operational commands](#operational-commands)
13
+ - [Extra Capabilities](#extra-capabilities)
14
+ - [Salesforce B2C Commerce (SFCC) Tools](#salesforce-b2c-commerce-sfcc-tools)
15
+ - [CLI Subcommands](#cli-subcommands)
16
+ - [Custom Pipelines](#custom-pipelines)
17
+ - [Environment Variables](#environment-variables)
18
+ - [Worktree credentials and the `mcp-invoke` shim](#worktree-credentials-and-the-mcp-invoke-shim)
19
+ - [Reference](#reference)
20
+
21
+ For advanced epic/multi-agent orchestration, see [CONDUCTOR.md](./CONDUCTOR.md).
6
22
 
7
23
  ## Getting Started
8
24
 
9
- ### Quick start (one command)
25
+ ### Quick start
10
26
 
11
- From your **project root**, run:
27
+ From your **project root**, install and connect in one command:
12
28
 
13
29
  ```bash
14
30
  npx -y @bridge_gpt/mcp-server@latest install-bridge
15
31
  ```
16
32
 
33
+ `install-bridge` scaffolds the project, writes your editor's MCP config with real
34
+ values, verifies connectivity, persists your API key to the user-scoped credential
35
+ store, and opens a fresh agent session to finish setup (`/install-bridge` then
36
+ `/learn-repository`). The only inputs are an **API key** (generate one on the Bridge
37
+ API web UI **Security** page) and a **repo name** — everything else is derived. Add
38
+ `--dry-run` to preview every step without writing, pinging, or spawning anything.
39
+
40
+ To upgrade later, run:
41
+
42
+ ```bash
43
+ npx -y @bridge_gpt/mcp-server upgrade
44
+ ```
45
+
46
+ `upgrade` re-execs from `@latest`, refreshes all scaffolded artifacts (slash
47
+ commands, agents, pipelines), rewrites the version pin, and reconnects — also
48
+ available as the `/upgrade-bridge` slash command. (The legacy `--upgrade` flag still
49
+ works as a fallback.)
50
+
51
+ <details>
52
+ <summary><strong>Installation Instructions</strong></summary>
53
+
54
+ #### What `install-bridge` does
55
+
17
56
  `install-bridge` collapses the whole setup into a single command. It:
18
57
 
19
58
  1. **Scaffolds** the project (the same artifacts `--init` writes: slash commands,
@@ -55,9 +94,9 @@ That's it — once `install-bridge` finishes you're connected. If you prefer to
55
94
  it by hand (or just want to understand each step), the manual flow below does the
56
95
  same thing.
57
96
 
58
- ### Manual Setup (Alternative)
97
+ #### Manual Setup (Alternative)
59
98
 
60
- #### 1. Install the Package
99
+ ##### 1. Install the Package
61
100
 
62
101
  From your **project root**, install the MCP server and scaffold slash commands:
63
102
 
@@ -74,7 +113,7 @@ npx -y @bridge_gpt/mcp-server --init
74
113
 
75
114
  Re-run `--init` after upgrading the package to get updated commands.
76
115
 
77
- #### 2. Generate an API Key
116
+ ##### 2. Generate an API Key
78
117
 
79
118
  1. Log in to [Bridge API](https://bridgegpt-api.com) and navigate to your project's **Security** page
80
119
  2. Click **Create New Key**
@@ -82,7 +121,7 @@ Re-run `--init` after upgrading the package to get updated commands.
82
121
  4. Click **Create Key**
83
122
  5. **Copy the key immediately** — it will not be shown again
84
123
 
85
- #### 3. Configure the MCP Server
124
+ ##### 3. Configure the MCP Server
86
125
 
87
126
  Add the following to your editor's MCP configuration file, pasting in the API key from step 2:
88
127
 
@@ -196,28 +235,30 @@ BAPI_DOCS_DIR = "docs/tmp"
196
235
 
197
236
  After saving the config, restart your editor or reload the MCP server connection. Verify connectivity by asking your AI assistant to call the `ping` tool.
198
237
 
199
- #### 4. First-Time Setup: Teach Bridge Your Codebase
238
+ ##### 4. First-Time Setup: Teach Bridge Your Codebase
200
239
 
201
240
  If you're the first person to install Bridge API on your project, run the `/learn-repository` slash command after completing setup. This analyzes your codebase's architecture, testing patterns, code review standards, and documentation conventions, then uploads the findings to Bridge API. This gives Bridge the context it needs to generate implementation plans, ticket critiques, and code reviews that are consistent with your project's actual architecture and conventions.
202
241
 
203
242
  You only need to do this once per project — the learned standards persist for all team members.
204
243
 
205
- ### Upgrading
244
+ ##### Upgrading (details)
206
245
 
207
- To upgrade to the latest version and refresh all scaffolded artifacts in one step:
208
-
209
- ```bash
210
- npx -y @bridge_gpt/mcp-server --upgrade
211
- ```
212
-
213
- This runs `npm i @bridge_gpt/mcp-server@latest`, prints a before/after version summary, then re-runs the full `--init` scaffolding flow to update your slash commands, agents, and pipeline definitions.
246
+ The one-command `npx -y @bridge_gpt/mcp-server upgrade` (shown above) is the
247
+ recommended path. The legacy flag `npx -y @bridge_gpt/mcp-server --upgrade` still
248
+ works: it runs `npm i @bridge_gpt/mcp-server@latest`, prints a before/after version
249
+ summary, then re-runs the full `--init` scaffolding flow to update your slash
250
+ commands, agents, and pipeline definitions.
214
251
 
215
252
  The MCP server also checks for updates automatically on startup. If a newer version is available, you'll see a notice in your editor's MCP output logs with the upgrade command to run. This check is cached for 24 hours and never blocks server startup.
216
253
 
254
+ </details>
255
+
217
256
  ## Usage Documentation
218
257
 
219
258
  This is the Bridge API tooling worth knowing about as a software engineer — the things you'd ask an agent to do — grouped by how often you would use them. Each entry covers **what it does**, **when it's useful** and **how to use it**. The behind-the-scenes plumbing is summarized at the end under [Extra Capabilities](#extra-capabilities), and a full enumeration lives in [Reference](#reference).
220
259
 
260
+ Working in a Salesforce B2C Commerce codebase? Bridge also ships read-only SFCC platform-introspection tools — see [Salesforce B2C Commerce (SFCC) Tools](#salesforce-b2c-commerce-sfcc-tools).
261
+
221
262
  For invocation, prefer the slash command — it's deterministic. A free-text example is shown only where natural-language phrasing reliably maps to the right automation; high-consequence or easily-misread automations show only the slash command on purpose.
222
263
 
223
264
  ### Tier 1 — Regularly useful
@@ -401,6 +442,66 @@ Behind-the-scenes capabilities an agent gains from the MCP tools — mostly invo
401
442
  - **Retrieve any generated artifact** (`get_*` for plans, critiques, questions, brainstorms, research, architecture) without regenerating it.
402
443
  - **Tiered-section execution telemetry** recording (internal measurement).
403
444
 
445
+ ## Salesforce B2C Commerce (SFCC) Tools
446
+
447
+ Salesforce's official MCP server, `@salesforce/b2c-dx-mcp`, covers developer-experience tasks — cartridge deploy, step debugging, docs search, logs/MRT, and SCAPI Custom API scaffolding. As of its current toolset it has no way to *read* the platform's object model, custom objects, or site configuration — exactly the context an AI coding agent needs to write correct Commerce code and to inspect a sandbox before touching it. Bridge's SFCC tools install side-by-side with `b2c-dx-mcp` (they don't duplicate its surface) and close that gap with **read-only OCAPI Data API introspection** of system objects, custom object definitions, and site preferences.
448
+
449
+ **v1 is read-only and developer-sandbox-only** — no writes, and non-sandbox instances are rejected. Credentials stay local (in `dw.json` or `SFCC_*` env vars) and are never sent to Bridge.
450
+
451
+ <details>
452
+ <summary><strong>Setup</strong></summary>
453
+
454
+ The two diagnostic tools (`sfcc_setup_status`, `check_permissions`) are always available. The seven read tools must be enabled with a profile (step 3).
455
+
456
+ **Prerequisites:** a running SFCC **sandbox** and its hostname, plus an Account Manager API client (`client-id` + `client-secret`).
457
+
458
+ **1. Set the repo `version` config field** to your SFCC project type — one of `sfra | pwakit | sitegenesis | storefrontnext | hybrid`. The call-time gate reads this; a non-SFCC value blocks every SFCC tool except `sfcc_setup_status`. Set it via your normal config path, the `config_field` MCP tool (operation `update`, field `version`), or the `/teach-bridge` skill.
459
+
460
+ **2. Provide SFCC credentials.** Create a `dw.json` in your project root:
461
+
462
+ ```json
463
+ {
464
+ "hostname": "zzzz-001.sandbox.us01.dx.commercecloud.salesforce.com",
465
+ "client-id": "<account-manager-client-id>",
466
+ "client-secret": "<account-manager-client-secret>"
467
+ }
468
+ ```
469
+
470
+ Accepted key spellings: `hostname`/`host`, `client-id`/`clientId`/`client_id`, `client-secret`/`clientSecret`/`client_secret`. Prefer a single config — a multi-entry `configs[]` array forces you to pass an explicit `instance` on every call. `dw.json` is auto-added to git exclude and must never be committed. Alternatively, export `SFCC_HOSTNAME` / `SFCC_CLIENT_ID` / `SFCC_CLIENT_SECRET` in the MCP server environment.
471
+
472
+ **3. Enable the read tools.** Add `sfcc` to `BRIDGE_MCP_PROFILE` in the MCP server `env` block (it is comma-separated; `full` also works), then **restart the MCP client**:
473
+
474
+ ```json
475
+ "env": { "BRIDGE_MCP_PROFILE": "sfcc" }
476
+ ```
477
+
478
+ Without this, only the diagnostic tools are registered.
479
+
480
+ **4. Verify and grant OCAPI access.** Ask your agent to run `sfcc_setup_status` (expect all checks ✓), then `check_permissions`. If it reports HTTP 401/403, it prints the exact OCAPI Settings JSON to paste in Business Manager (**Administration → Site Development → Open Commerce API Settings → Data API** tab); save it there and re-run. Restart the MCP client after any credential or env change — a running session does not pick them up.
481
+
482
+ </details>
483
+
484
+ ### Tools
485
+
486
+ All SFCC tools are read-only and target a developer sandbox. Oversized responses are automatically saved to `BAPI_DOCS_DIR/sfcc/` and previewed inline.
487
+
488
+ **Diagnostics** (always available, no profile needed)
489
+ - `sfcc_setup_status` — report on every prerequisite: Bridge API key, repo name, `version` config, `dw.json` presence/uniqueness, and AM token acquisition.
490
+ - `check_permissions` — probe OCAPI access via `GET /system_object_definitions`; on 401/403, print the exact OCAPI Settings JSON to paste in Business Manager (split read-only vs. write/import grants).
491
+
492
+ **System object model** (needs the `sfcc` profile)
493
+ - `system_object_list` — list system object types (Product, Order, Customer, …).
494
+ - `system_object_get` — fetch one type's definition, optionally with its full attribute definitions (`expand_attribute_definitions`).
495
+ - `system_object_attribute_search` — search a type's attribute definitions; prefer this over a full dump when hunting a specific `c_` custom attribute.
496
+
497
+ **Custom object definitions** (needs the `sfcc` profile)
498
+ - `custom_object_definition_list` — list custom object type definitions.
499
+ - `custom_object_definition_get` — fetch an existing custom type with its key definition and attribute definitions/groups. Read-only — creating a custom object *type* isn't possible via OCAPI; that's a future v2 metadata-import capability.
500
+
501
+ **Site preferences** (needs the `sfcc` profile; sandbox only)
502
+ - `site_preference_get` — read a preference group's effective preferences.
503
+ - `site_preference_search` — search/filter preferences within a group.
504
+
404
505
  ## CLI Subcommands
405
506
 
406
507
  Beyond `--init` / `--upgrade`, the package ships operational subcommands of the **single `bridge-api-mcp-server` bin** (not separate binaries) — so they travel with the package to every consumer. See [Usage Documentation → Start Tickets](#tier-1--regularly-useful) for *when* to use `start-tickets`; this section is the full CLI reference.
@@ -433,7 +534,7 @@ npx -y @bridge_gpt/mcp-server start-tickets --agent cursor-agent BAPI-248
433
534
 
434
535
  **Difficulty-based model routing.** Before launching each agent, the CLI selects an implementation **model tier** from the ticket's `difficulty` (1-2 → cheap, 3-5 → basic, 6+ → premium) and injects it as a `--model` flag at the spawn boundary. The Python backend returns only the coarse tier (`GET /jira/tickets/{KEY}/model-tier`, computing + caching difficulty on demand); this CLI alone maps a tier to the agent-specific alias (`claude`: `haiku`/`sonnet`/`opus`; `cursor-agent`: version-suffixed strings validated against `cursor-agent --list-models`). It is gated per repo by `difficulty_model_routing_enabled` (default **ON**) with an optional `difficulty_model_tier_overrides` JSON map (tier → alias). Routing is **fail-open**: missing credentials, an evaluation failure/timeout, a backend `fallback`, an invalid/unavailable alias, an unadvertised Cursor model, or an agent without `--model` support all omit `--model` (the agent uses its default) and surface a per-ticket warning rather than failing the spawn. `--dry-run` does **not** fetch tiers or inject `--model`.
435
536
 
436
- **Conductor observability (opt-in via `--conductor`, BAPI-394).** Conductor is **off by default** — without `--conductor` no `BAPI_CONDUCTOR_*` env, supervisor tab, or message-relay prompt is produced. With `--conductor`, a run mints a single conductor `run_id` and emits one canonical `run.started` event into the local conductor ledger (`~/.config/bridge/events.db`), attributing each worker by `worker_id`, ticket key, and worktree path, and opens a supervisor peer tab. When the selected agent is **Claude Code**, the CLI also injects a conductor lifecycle hook into each created worktree's `.claude/settings.local.json` (preserving any existing hooks) so the spawned session streams local `run.started` / `run.stopped` / `agent.notification` (and, with `BAPI_CONDUCTOR_ENABLE_PRE_TOOL_USE=1`, `tool.intent`) events. Per-worker conductor identity is passed only via secret-free environment scoped to that one terminal/tab/session — no credentials are ever placed in the env, hook command, or run metadata. Override the gate/supervisor labels with `BAPI_CONDUCTOR_GATE_NAME` / `BAPI_CONDUCTOR_SUPERVISOR_MODE`. Inspect the stream with `conductor doctor`. Observability is best-effort: a conductor failure never blocks or aborts a spawn, and `--dry-run` performs no conductor side effects. (Epic-tick dispatch always enables conductor internally, independent of this flag.)
537
+ **Conductor observability (opt-in via `--conductor`, BAPI-394).** Conductor is **off by default**. With `--conductor`, a run mints a conductor `run_id`, emits events into the local ledger (`~/.config/bridge/events.db`), opens a supervisor peer tab, and (for Claude Code) injects a secret-free lifecycle hook into each worktree; it also sets `BRIDGE_MCP_PROFILE=conductor` so workers get the conductor MCP tools. Observability is best-effort a conductor failure never blocks a spawn, and `--dry-run` performs no conductor side effects. (Epic-tick dispatch always enables conductor internally.) See **[CONDUCTOR.md](./CONDUCTOR.md)** for the full observability, git-hook, done-gate, and auto-merge reference.
437
538
 
438
539
  **Cross-platform spawning.** The CLI routes spawning per platform; `--dry-run` previews the platform-correct command form on any OS. An unsupported `process.platform` (not `darwin`/`win32`/`linux`) fails fast with a clear "unsupported platform" message.
439
540
 
@@ -453,55 +554,9 @@ npx -y @bridge_gpt/mcp-server doctor [--agent <name>]
453
554
 
454
555
  It is **read-only**: it never installs anything, modifies your system, adds an npm `postinstall`, spawns a terminal, or starts the MCP server, and there is no `--fix`. For each prerequisite it prints found/missing and, when missing, the exact per-OS install command **as a manual instruction you run yourself**. The checked set is the `start-tickets` preflight prerequisites **plus `uv`** **plus the selected agent's command** (`claude` by default, or `cursor-agent` with `--agent cursor-agent`). The Worktrunk binary is probed via the resolved name (honoring `BAPI_WORKTRUNK_BIN`), not a hard-coded one. **Exit code:** `0` when all required prerequisites are present, non-zero when any is missing or the platform is unsupported. A failing `start-tickets` preflight now hints you to run `doctor` for an actionable diagnostics report.
455
556
 
456
- ### `conductor install-git-hooks` (BAPI-395)
457
-
458
- Installs local git hooks that opportunistically emit conductor git/PR/CI events into the local ledger:
459
-
460
- ```
461
- conductor install-git-hooks [--json]
462
- ```
463
-
464
- The installed hooks are **local, unversioned, opportunistic, and bypassable**: they live in the worktree's git hooks directory (resolved via `git rev-parse --git-common-dir`), insert only a clearly-delimited managed block (preserving any existing user hook content), launch the producer **detached in the background** so a commit or ref update is never blocked, and tolerate every failure (`|| true`). A directory that is not a git worktree, or an existing hook that looks binary/unsafe, is left untouched and reported as a **degraded optional capability** — never a fatal error. The hooks installed are `post-commit` (emits `git.commit_created`) and `reference-transaction` (emits `worktree.changed` for committed ref updates).
465
-
466
- Missing hooks do **not** prevent PR/CI gate evaluation — `conductor doctor` reads hook presence and managed-snippet status **read-only** (a new `git hooks` section / `git_hooks` JSON object alongside the ledger report), and the `wait_for_done_gate` MCP tool drives CI polling and gate evaluation regardless of whether hooks are installed.
467
-
468
- #### `conductor_done_gate` config
469
-
470
- The per-repo `conductor_done_gate` config field (read through the existing config-field route) defines the v1 done gate. It supports exactly one condition, `required_ci_checks_green`:
471
-
472
- ```json
473
- {
474
- "enabled": true,
475
- "conditions": [
476
- { "type": "required_ci_checks_green", "required_checks": ["build", "test"] }
477
- ]
478
- }
479
- ```
557
+ ### Conductor (epic & multi-agent orchestration)
480
558
 
481
- `gate.met` is emitted (exactly once per `repo + pr_number + head_sha + effective config`) only when every listed required check is present, complete, and green for the bound PR head SHA. The gate **fails closed**: an unset, disabled (`enabled` not strictly `true`), malformed, empty, or unsupported config emits no `gate.met`.
482
-
483
- #### `conductor_auto_merge_enabled` config (C6 conditional auto-merge)
484
-
485
- When a worker's PR meets the done gate (`gate.met`), the supervisor can autonomously merge it — but **only** when the repo has explicitly opted in. The per-repo `conductor_auto_merge_enabled` config field (read through the same config-field route as `conductor_done_gate`) is the opt-in switch:
486
-
487
- ```json
488
- { "enabled": true }
489
- ```
490
-
491
- A bare JSON boolean (`true`) is also accepted. **Auto-merge is disabled by default.** Behavior:
492
-
493
- - **Disabled / unset / malformed → dry-run.** Anything other than `true` or `{"enabled": true}` — including unset, `false`, `{"enabled": false}`, or any malformed value — fails **closed**: the supervisor records a `merge.dry_run` event and **no PR is ever merged**.
494
- - **Enabled → autonomous merge** when the gate is met and the deterministic guards pass.
495
- - **Kill-switch.** Set `conductor_auto_merge_enabled` to `false` or remove the field to immediately stop autonomous merges. The protected merge endpoint **independently re-enforces** the flag, so even a conductor that calls it cannot merge while the flag is off.
496
-
497
- Merge authority is **deterministic code, never an LLM**. The deterministic guards, all bound to **PR number + expected head SHA (never a branch name)**:
498
-
499
- - the per-repo enablement flag (off → dry-run),
500
- - the PR is still open,
501
- - the merge is bound to the PR number plus the expected head SHA — **head-SHA drift between gate evaluation and merge aborts the merge**,
502
- - required CI checks are **revalidated green immediately before merge**.
503
-
504
- Idempotency is crash-safe and race-safe: a TTL lease keyed by the deterministic action key `merge:{repo}:{pr}:{head_sha}:{gate}` is claimed before acting, and an existing `merge.succeeded` for that key is terminal — the supervisor never double-merges across a crash/restart or two racing instances. The conductor never holds VCS write credentials: it calls the protected Bridge API endpoint `POST /vcs/pull-requests/{pr_number}/merge`, which owns the privileged merge, and records the returned `merge.dry_run` / `merge.attempted` / `merge.succeeded` / `merge.failed` / `merge.pending_approval` events into the local ledger. `merge.failed` is **retryable** (a drifted head SHA produces a new action key); `merge.pending_approval` is **nonterminal** — the worker remains active until a human redeems the approval token and the server returns `merge.succeeded`. **`merge.succeeded` is the only terminal merge event.** The local SQLite conductor store uses schema version 5 (BAPI-413) to accommodate the `merge.pending_approval` type in the `events.type` CHECK constraint.
559
+ 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 `conductor install-git-hooks`, the `conductor_done_gate` and `conductor_auto_merge_enabled` config fields, and the observability stream lives in **[CONDUCTOR.md](./CONDUCTOR.md)**.
505
560
 
506
561
  ## Custom Pipelines
507
562
 
@@ -544,40 +599,6 @@ See `.bridge/pipelines/README.md` for the full schema reference.
544
599
 
545
600
  If a custom pipeline has the same key as a built-in pipeline, the custom version takes precedence (a warning is logged at startup).
546
601
 
547
- ## Smoke testing
548
-
549
- The package ships a canonical, **opt-in** in-host smoke-test runbook at
550
- `smoke-test/SMOKE-TEST.md`. An AI agent running inside your host (Claude Code,
551
- Cursor, Codex, Windsurf, or VS Code/Copilot) executes it to verify that the MCP
552
- server actually works end-to-end *inside that host* — it calls the real tools and
553
- records a PASS/FAIL verdict for each one in a markdown report.
554
-
555
- - `smoke-test/SMOKE-TEST.md` **ships with the npm package** and is the
556
- **canonical** source of truth for the smoke test.
557
- - The smoke test **adds no MCP tool** and **does not change the registered
558
- tool surface** (the server still registers its existing 62 tools).
559
- - It is **opt-in**: default `--init` **does not scaffold `/smoke-test-mcp`**, so
560
- consumer command palettes are not polluted.
561
-
562
- ### Running it
563
-
564
- You have two options:
565
-
566
- 1. **Copy the opt-in command manually.** Copy the packaged command stub into your
567
- host's command directory, then invoke `/smoke-test-mcp`:
568
-
569
- ```bash
570
- # Claude Code
571
- cp node_modules/@bridge_gpt/mcp-server/smoke-test/smoke-test-mcp.md .claude/commands/smoke-test-mcp.md
572
- # Cursor
573
- cp node_modules/@bridge_gpt/mcp-server/smoke-test/smoke-test-mcp.md .cursor/commands/smoke-test-mcp.md
574
- ```
575
-
576
- 2. **Open the runbook directly.** Alternatively, open
577
- `smoke-test/SMOKE-TEST.md` and ask the host agent to execute it.
578
-
579
- Reports are written to `<BAPI_DOCS_DIR>/smoke-test/REPORT-<host>-<timestamp>.md`.
580
-
581
602
  ## Environment Variables
582
603
 
583
604
  | Variable | Required | Default | Description |
@@ -591,7 +612,8 @@ Reports are written to `<BAPI_DOCS_DIR>/smoke-test/REPORT-<host>-<timestamp>.md`
591
612
  | `BAPI_WORKTRUNK_BIN` | No | `wt` (`git-wt` on Windows) | Override the Worktrunk executable name/path used by `start-tickets` for nonstandard installs |
592
613
  | `BAPI_TMUX_SESSION` | No | `bridge-start-tickets` | Override the tmux session-name prefix used by `start-tickets` on Linux |
593
614
  | `BAPI_MCP_UPGRADE_ADVICE_ENABLED` | No | _(enabled)_ | MCP-local opt-out for proactively surfacing upgrade advice in pipeline recipe preambles. Set to `false`/`0`/`no`/`off`/`disabled` to suppress. Disabling it does **not** change the `/jira/ping` response or server-side upgrade computation — it only gates the recipe-preamble convention |
594
- | `BRIDGE_MCP_PROFILE` | No | `core` | Startup-time tool registration profile. Controls which tool groups are registered when the server starts. Valid values: `core` (default — normal coding tools only), `conductor` (core + 8 conductor/event/supervisor tools), `pipeline-authoring` (core + 5 pipeline run/admin tools — `get_pipeline_recipe` is NOT gated; it stays in `core` because the recipe-driven slash commands depend on it), `full` (all tools, equivalent to the legacy unconditional registration). Unknown, blank, or malformed values fail safe to `core`. Dynamic mid-session switching via `tools/list_changed` is unsupported — the profile is resolved once at process startup. **Phase 2b note:** epic/conductor sessions launched via `start-tickets` will automatically inject `BRIDGE_MCP_PROFILE=conductor`; that injection is handled at the spawn boundary and is out of scope for this phase. |
615
+ | `CURSOR_API_KEY` | No | _(none)_ | API key used to authenticate `cursor-agent` when launching `start-tickets`/scheduled runs with `--agent cursor-agent`. Not needed for the default Claude Code agent |
616
+ | `BRIDGE_MCP_PROFILE` | No | `core` | Startup-time tool registration profile — a **comma-separated** list of groups controlling which tool groups are registered when the server starts. `core` is always implicitly included. Valid groups: `core` (default — normal coding tools only), `conductor` (+ 8 conductor/event/supervisor tools), `pipeline-authoring` (+ 5 pipeline run/admin tools — `get_pipeline_recipe` is NOT gated; it stays in `core` because the recipe-driven slash commands depend on it), `sfcc` (+ the 7 heavy SFCC read tools — see [Salesforce B2C Commerce (SFCC) Tools](#salesforce-b2c-commerce-sfcc-tools); the `sfcc_setup_status`/`check_permissions` diagnostics are always registered regardless), and `full` (shortcut that expands to every group). Example: `sfcc,conductor`. Unknown, blank, or malformed tokens are dropped (falling back to `core`). Dynamic mid-session switching via `tools/list_changed` is unsupported — groups are resolved once at process startup. Conductor/epic sessions launched via `start-tickets --conductor` automatically inject `BRIDGE_MCP_PROFILE=conductor` at the spawn boundary; a normal `start-tickets` run stays on `core`. |
595
617
 
596
618
  ## Worktree credentials and the `mcp-invoke` shim
597
619
 
@@ -666,7 +688,7 @@ The full surface, for when you need the complete enumeration. Day-to-day, use [U
666
688
 
667
689
  ### MCP tools
668
690
 
669
- The server registers **58 tools**. 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).
691
+ The server exposes **58 documented 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).
670
692
 
671
693
  - **Connectivity & identity** — `ping`, `get_my_role`, `get_docs_dir`
672
694
  - **Jira tickets** — `get_tickets`, `get_ticket`, `create_ticket`, `update_ticket_description`, `add_comment`, `get_comments`
@@ -7,6 +7,7 @@
7
7
  * failure. This module performs NO writes: no hook installation, no schema
8
8
  * migration, no event emission, and no scheduler unit creation.
9
9
  */
10
+ import { spawnSync } from "node:child_process";
10
11
  import { doctorConductorLedger } from "./store.js";
11
12
  import { inspectConductorGitHooks } from "./git-hooks.js";
12
13
  /**
@@ -105,6 +106,65 @@ export function inspectMcpProfile(env, epicTick) {
105
106
  }
106
107
  return { resolved_profile, conductor_context_detected, degraded, warnings };
107
108
  }
109
+ /**
110
+ * Read-only probe of the local-merge (F4) capability. Runs `gh --version` and
111
+ * `gh auth status` (no writes, no merge) and reports whether the host could merge
112
+ * a PR locally if `policy_json.local_merge.enabled` were set. Never throws.
113
+ */
114
+ export function inspectLocalMerge(runCommand) {
115
+ const run = runCommand ??
116
+ ((cmd, args) => {
117
+ try {
118
+ // Static ESM import (this package is "type": "module"): a lazy
119
+ // require("child_process") throws ReferenceError under ESM, which the
120
+ // catch swallowed — making `gh` always look unavailable (false negative).
121
+ //
122
+ // `gh auth status` hits api.github.com; with no timeout a network stall
123
+ // (expired token, DNS hiccup, partition) blocks the doctor process until
124
+ // the OS TCP timeout fires (30s–2min). Bound it to 10s — a hung health
125
+ // check then simply reports `gh` unavailable. GH_PROMPT_DISABLED keeps an
126
+ // interactive prompt from holding the process past the timeout.
127
+ const r = spawnSync(cmd, args, {
128
+ encoding: "utf8",
129
+ timeout: 10_000,
130
+ env: { ...process.env, GH_PROMPT_DISABLED: "1" },
131
+ });
132
+ return { status: r.status };
133
+ }
134
+ catch {
135
+ return { status: null };
136
+ }
137
+ });
138
+ let gh_available = false;
139
+ let gh_authed = false;
140
+ try {
141
+ gh_available = run("gh", ["--version"]).status === 0;
142
+ }
143
+ catch {
144
+ gh_available = false;
145
+ }
146
+ if (gh_available) {
147
+ try {
148
+ gh_authed = run("gh", ["auth", "status"]).status === 0;
149
+ }
150
+ catch {
151
+ gh_authed = false;
152
+ }
153
+ }
154
+ const warnings = [];
155
+ if (!gh_available) {
156
+ warnings.push("`gh` is not installed or not on PATH. Local merge (policy_json.local_merge.enabled) " +
157
+ "cannot run; install the GitHub CLI to enable conductor-driven merges.");
158
+ }
159
+ else if (!gh_authed) {
160
+ warnings.push("`gh` is installed but not authenticated (`gh auth status` failed). Run `gh auth login` " +
161
+ "to grant the conductor merge permission; otherwise local merge will emit merge.failed/skip.");
162
+ }
163
+ // Capability gap only — local merge is opt-in, so an unauthed host is not a hard
164
+ // failure unless the operator enabled it. Reported as degraded for visibility.
165
+ const degraded = !gh_available || !gh_authed;
166
+ return { gh_available, gh_authed, degraded, warnings };
167
+ }
108
168
  /**
109
169
  * Build the combined read-only doctor report. Composes the existing ledger
110
170
  * doctor, git hook inspection, and the epic-tick schedule enablement check.
@@ -120,6 +180,7 @@ export async function buildConductorDoctorReport(deps = {}) {
120
180
  git_hooks: inspectHooks(deps.hooksDeps),
121
181
  epic_tick: epicTick,
122
182
  mcp_profile,
183
+ local_merge: inspectLocalMerge(deps.runCommand),
123
184
  };
124
185
  }
125
186
  /**
@@ -128,7 +189,7 @@ export async function buildConductorDoctorReport(deps = {}) {
128
189
  * status tags consistent with the git hooks section's visual hierarchy.
129
190
  */
130
191
  export function formatConductorDoctorReport(report) {
131
- const { ledger, git_hooks, epic_tick, mcp_profile } = report;
192
+ const { ledger, git_hooks, epic_tick, mcp_profile, local_merge } = report;
132
193
  const lines = [
133
194
  "Conductor ledger doctor",
134
195
  "───────────────────────",
@@ -193,5 +254,21 @@ export function formatConductorDoctorReport(report) {
193
254
  for (const w of mcp_profile.warnings)
194
255
  lines.push(` - ${w}`);
195
256
  }
257
+ lines.push("");
258
+ lines.push("Local merge capability (optional, opt-in)");
259
+ lines.push("─────────────────────────────────────────");
260
+ const ghTag = local_merge.gh_available
261
+ ? local_merge.gh_authed
262
+ ? "[OK]"
263
+ : "[WARNING] not authenticated"
264
+ : "[WARNING] not installed";
265
+ lines.push(`gh available: ${local_merge.gh_available} ${ghTag}`);
266
+ lines.push(`gh authenticated: ${local_merge.gh_authed}`);
267
+ lines.push(`degraded: ${local_merge.degraded}`);
268
+ if (local_merge.warnings.length > 0) {
269
+ lines.push("local merge warnings:");
270
+ for (const w of local_merge.warnings)
271
+ lines.push(` - ${w}`);
272
+ }
196
273
  return lines.join("\n");
197
274
  }