Skip to content

chore(cli)!: drop --mcp-config-path argv flag (subsumed by host config + env var)#29

Merged
manojp99 merged 4 commits into
mainfrom
feat/drop-mcp-config-path-flag
Jun 3, 2026
Merged

chore(cli)!: drop --mcp-config-path argv flag (subsumed by host config + env var)#29
manojp99 merged 4 commits into
mainfrom
feat/drop-mcp-config-path-flag

Conversation

@manojp99

@manojp99 manojp99 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Drops the --mcp-config-path argv flag from amplifier-agent run and from both wrappers. Pure removal, no engine-side flag tolerance, lockstep update.

Why

Three equivalent paths to the same outcome existed after PR #27 (host config layer) merged on top of PR #24 (protocol-0.2.0 wire alignment):

  1. Host config mcp.configPath: <path> → engine sets AMPLIFIER_MCP_CONFIG env var (added in feat: host config layer + drop hostCapabilities surface #27 by 70121c3)
  2. $AMPLIFIER_MCP_CONFIG set directly in the host's process environment → tool-mcp reads natively
  3. --mcp-config-path <path> argv flag → engine sets AMPLIFIER_MCP_CONFIG env var (CLI-only path inherited from fix(wire): align all sites to protocol 0.2.0 (--mcp-config-path, schema rename, fixture bump) #24's rename of --mcp-servers)

Path 3 is the redundant survivor. The Mode A amendment §2.5 D9 and the host config design D10 both staked out "per-invocation flags stay argv, host policy moves to config." mcpConfigPath is host policy — where the MCP catalog lives is stable per install. So the argv flag should not exist by our own design principle. This PR removes it.

What's removed

Engine:

  • --mcp-config-path click option declaration and run() parameter
  • _TurnSpec.mcp_config_path field
  • _runtime.make_turn_handler(mcp_config_path=...) kwarg
  • _runtime.py §(5b) validation block + CLI-flag-only env var translation
  • _write_audit param + mcpConfigPathDigest audit field

Engine, preserved (replacement paths):

  • Host config mcp.configPath block in _runtime.py → still sets AMPLIFIER_MCP_CONFIG
  • Wire-protocol agent/initialize.params.mcpConfigPath field → still handled by _runtime.handle_initialize. The conformance fixture initialize-with-mcp-config-path.yaml is intentionally kept because it tests this wire-protocol surface, not the argv flag.

TypeScript wrapper (BREAKING):

  • AssembleArgvInput.mcpConfigPath field
  • argv emission of --mcp-config-path <path>
  • SessionHandle.makeIterable now injects AMPLIFIER_MCP_CONFIG=<spill-path> into the subprocess env instead

Python wrapper (BREAKING):

  • assemble_argv mcp_config_path kwarg + emission
  • SessionHandle._make_iterable now injects AMPLIFIER_MCP_CONFIG=<spill-path> into the subprocess env
  • Kwarg-rejection guardrail added

Migration

Old New
amplifier-agent run --mcp-config-path /etc/mcp.json "..." Set AMPLIFIER_MCP_CONFIG=/etc/mcp.json in process env (set once by host) — OR use host config: {"mcp": {"configPath": "/etc/mcp.json"}}
Wrapper SpawnAgentParams.mcpConfigPath / mcp_config_path Wrappers now compute the spill path internally and inject as env var; callers pass mcpServers (TS) / mcp_servers (Py) as before — the wrapper handles the spill+env wiring
--mcp-servers '<json or @path>' (already renamed by #24) Same migration; flag was already gone before this PR

Cross-repo follow-up

NC adapter (amplifier-nc-provider) currently emits --mcp-config-path (added in #24's rename). It will break against this engine after this PR merges. Same shape as Phase 1's hostCapabilities NC follow-up.

Migration for NC: inject AMPLIFIER_MCP_CONFIG=<spill_path> into the engine subprocess env instead of emitting the argv flag. This is the identical pattern this PR applied inside the Python/TS wrappers. Tracking issue should reference this PR.

Why strict (no engine-side flag tolerance)

Matches Phase 1's chosen posture. The migration paths are short (env var or host config), the in-repo wrappers are updated atomically alongside the engine, and the NC adapter is going to need a code change anyway (it never had MCP-config wiring against the env var, only against argv). Strict rejection makes that migration visible immediately rather than silent at first run and surprising the day a tool-mcp config is needed.

Tests

Suite Pass Fail
Engine (uv run pytest --ignore=wrappers) 486 + 3 skipped 4 (all pre-existing — reference --mcp-servers flag / initialize-with-mcpservers fixture name from PR #24's incomplete cleanup)
TypeScript wrapper 63/63 0
Python wrapper 48/48 0
Conformance TS 4 1 (pre-existing — runner expects initialize-with-mcpservers.yaml)
Conformance Py 4 1 (same baseline)

6 pre-existing failures total, zero new failures introduced. Loud-failure verification: amplifier-agent run --mcp-config-path /tmp/x.json "hi"Error: No such option '--mcp-config-path'. Did you mean '--config'?, exit 2. ✓

Commits

b4112bc chore(wrapper-ts)!: drop mcpConfigPath from AssembleArgvInput + argv emission
f710694 chore(wrapper-py)!: drop mcp_config_path from assemble_argv + spawn_agent
3fab58c chore(engine)!: drop --mcp-config-path argv flag
238ac88 test(engine): add removal guardrail for --mcp-config-path argv flag

All three breaking-change commits use ! per Conventional Commits with BREAKING CHANGE: footers.

Supersedes / amends

Manoj Prabhakar Paidiparthy and others added 4 commits June 2, 2026 18:52
Pure intent-capture commit (RED): the assertions in this test file FAIL
against the current source. The matching implementation drops in the next
commit (chore(engine)!: drop --mcp-config-path argv flag).

Mirrors the Phase 1 cleanup pattern from tests/cli/test_drop_host_capabilities.py:
each guardrail asserts an absence at a specific seam — click --help output,
click usage rejection, _TurnSpec dataclass fields, make_turn_handler signature,
and _runtime.py source — so future refactors that re-introduce the flag fail
loudly at this layer instead of via downstream regressions.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Pure removal, no flag tolerance — click rejects with `Error: No such
option '--mcp-config-path'` (exit 2). Mirrors Phase 1's hostCapabilities
removal posture.

After PR #27 merged the host config layer (commit 70121c3) and PR #24
renamed `--mcp-servers` to `--mcp-config-path`, three equivalent paths
set AMPLIFIER_MCP_CONFIG for tool-mcp:
  (1) host_config["mcp"]["configPath"]   — host policy via config file
  (2) AMPLIFIER_MCP_CONFIG env var       — read natively by tool-mcp
  (3) --mcp-config-path argv flag        — redundant survivor

Per Mode A amendment §2.5 D9 + host config D10, per-invocation flags stay
argv and host policy moves to config. `mcpConfigPath` is host policy.
This commit removes path (3); paths (1) and (2) remain.

Engine changes (src/amplifier_agent_cli/modes/single_turn.py):
 - Drop @click.option("--mcp-config-path") declaration and the matching
   `mcp_config_path` parameter on run().
 - Drop the §(5b) validation block that gated the flag value as a real
   file (mcp_config_path_invalid).
 - Drop `mcp_config_path` from the _TurnSpec dataclass and from the
   make_turn_handler kwargs in _execute_turn.
 - Drop `mcp_config_path` parameter on _write_audit and the
   `mcpConfigPathDigest` audit field. The field was only populated by
   the argv flag; no remaining surface feeds it. The envDigest
   precedent of preserving stable digests with empty placeholders
   does not apply here — the field carried no information once the
   source was gone, so dropping it cleanly is preferable.

Engine changes (src/amplifier_agent_lib/_runtime.py):
 - Drop the `mcp_config_path` parameter on make_turn_handler.
 - Drop the CLI-flag → AMPLIFIER_MCP_CONFIG translation block.
 - The host_config["mcp"]["configPath"] → AMPLIFIER_MCP_CONFIG block
   (added by 70121c3) remains; the `not mcp_config_path` precedence
   guard is dropped because the CLI path is gone.
 - The wire-side `handle_initialize` path (`params["mcpConfigPath"]` →
   `_wire_mcp_config_path` → AMPLIFIER_MCP_CONFIG) is untouched; it is
   protocol-0.2.0 surface, not argv surface.

Test updates:
 - tests/cli/test_drop_mcp_config_path_flag.py (added in the previous
   commit) now passes — all five guardrails green.
 - tests/cli/test_drop_host_capabilities.py: drop the obsolete
   mcp_config_path=None kwarg from the _write_audit call.
 - tests/cli/test_mode_a_audit_trail.py: rewrite to invoke `run`
   without the removed flag and assert mcpConfigPathDigest is absent
   from the audit (negative guardrail).
 - tests/test_runtime_config_merge.py: drop
   test_cli_mcp_config_path_takes_precedence_over_host (precedence
   semantics are gone with the CLI path). The host-config translation
   test stays.
 - tests/test_runtime_mcp_threading.py: drop the two make_turn_handler
   CLI-path tests; rename the surviving "no source" test to reflect
   host_config being the only engine-side translation site. The
   wire-side handle_initialize tests are untouched.

Cross-repo follow-up: amplifier-nc-provider's adapter currently passes
`--mcp-config-path` to the engine subprocess (this was set up by the
PR #24 rename). It will break against this engine. Same shape as
Phase 1's hostCapabilities NC issue — file a tracking issue in the
adapter repo to migrate the spilled path forwarding from the argv
flag to AMPLIFIER_MCP_CONFIG via the subprocess environment.

BREAKING CHANGE: The `--mcp-config-path` argv flag was removed from
`amplifier-agent run`. Callers must migrate to one of:
  (1) host config: `mcp.configPath: /path/to/mcp.json` in the file
      consumed by --config; the engine translates it to
      AMPLIFIER_MCP_CONFIG at make_turn_handler boot.
  (2) ambient env: set AMPLIFIER_MCP_CONFIG=/path in the engine's
      subprocess environment; tool-mcp reads it natively via its
      config-discovery priority chain.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…gent

Lockstep with the engine drop (chore(engine)!: drop --mcp-config-path
argv flag). The Python wrapper still spills the supplied mcp_servers
dict to a 0600 tmpfile (CR-A); the forwarding path changes from argv
flag to subprocess env var.

argv_builder.py:
 - Drop `mcp_config_path` parameter from `assemble_argv` and the
   `--mcp-config-path` emission block. Note the new path in the
   docstring (AMPLIFIER_MCP_CONFIG injected into subprocess env by
   SessionHandle._make_iterable, or set by the host directly).

session.py:
 - Drop the `mcp_config_path=spill["config_path"]` kwarg from the
   `assemble_argv` call in `_make_iterable`.
 - Build a fresh subprocess env dict per submit; when the spill
   produced a path, inject `AMPLIFIER_MCP_CONFIG=<path>` into it
   and pass that to `asyncio.create_subprocess_exec`. The
   SessionHandle's stored `subprocess_env` is never mutated.
 - Update the step-numbered comment block to reflect the env-var
   forwarding mechanism.

mcp_spill.py:
 - Docstring updates only — replace references to "engine receives
   the plain file path via --mcp-config-path" with the new "caller
   injects the spilled path into the engine's subprocess environment
   as AMPLIFIER_MCP_CONFIG" description.

__init__.py:
 - Update the spawn_agent() docstring for `mcp_servers` to describe
   the env-var forwarding mechanism.

tests/test_argv_builder.py:
 - Rename case (iv) from "threaded as bare path when caller
   pre-spilled" to "flag is not emitted".
 - Add case (v): asserts `assemble_argv(..., mcp_config_path=...)`
   raises TypeError so callers that still pass the obsolete kwarg
   fail loudly instead of silently no-opping.

BREAKING CHANGE: assemble_argv() no longer accepts the
`mcp_config_path` keyword argument. Callers using the public spawn_agent
API are unaffected — the wrapper handles the env-var injection
internally. Callers depending on the lower-level argv_builder must
remove the kwarg and inject AMPLIFIER_MCP_CONFIG into their
subprocess environment themselves.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…emission

Lockstep with the engine drop (chore(engine)!: drop --mcp-config-path
argv flag) and the Python wrapper drop (chore(wrapper-py)!: drop
mcp_config_path from assemble_argv + spawn_agent). The TypeScript
wrapper still spills the supplied mcpServers map to a 0600 tmpfile
(CR-A); the forwarding path changes from argv flag to subprocess env
var.

src/argv-builder.ts:
 - Drop `mcpConfigPath` field from `AssembleArgvInput`.
 - Drop the `--mcp-config-path` emission block in `assembleArgv`.
 - Document the new forwarding mechanism (AMPLIFIER_MCP_CONFIG injected
   into subprocess env by SessionHandle.makeIterable, or set by the
   host directly).

src/session.ts:
 - Drop the `mcpConfigPath: spill.configPath ?? undefined` field from
   the `assembleArgv` call in `makeIterable`.
 - Build a fresh `subprocessEnv` per submit; when the spill produced a
   path, inject `AMPLIFIER_MCP_CONFIG=<path>` into it and pass that
   object to `childSpawn`. The SessionHandle's stored
   `params.subprocessEnv` is never mutated.
 - Update the step-numbered JSDoc to reflect the env-var forwarding
   mechanism and the dropped argv flag.
 - Update the `mcpServers` field's JSDoc on `SessionHandleParams`.

src/mcp-spill.ts:
 - Docstring updates only — replace references to "engine receives the
   plain file path via --mcp-config-path" with the new description.

src/index.ts:
 - Update the JSDoc on `SpawnAgentParams.mcpServers` to describe
   env-var forwarding.

test/argv-builder.test.ts:
 - Rename case (iv) from "threaded as plain path" to "is not emitted
   (removed surface)".
 - Add case (v): a compile-time guardrail using `@ts-expect-error` to
   assert `AssembleArgvInput` no longer accepts `mcpConfigPath`; if a
   future refactor re-adds the field, the directive becomes a build
   error.

dist/*: regenerated by `npm run build` — these are committed artifacts
in this wrapper. Source-of-truth changes live in src/ and test/; the
dist/ delta is mechanical.

BREAKING CHANGE: `AssembleArgvInput` no longer exposes the
`mcpConfigPath` field. Callers using the public `spawnAgent` API are
unaffected — the wrapper handles env-var injection internally. Callers
depending on the lower-level `assembleArgv` must remove the field and
inject `AMPLIFIER_MCP_CONFIG` into their subprocess environment
themselves.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
@manojp99 manojp99 merged commit c893ace into main Jun 3, 2026
1 of 3 checks passed
manojp99 added a commit that referenced this pull request Jun 3, 2026
…from wrappers (sync with engine) (#31)

* chore(wrapper-ts)!: drop envAllowlist, envExtra, allowProtocolSkew from AssembleArgvInput + argv emission

The engine removed the --env-allowlist, --env-extra, and
--allow-protocol-skew argv flags in PR #27 (host config layer). The
TypeScript wrapper was still emitting them when the corresponding
AssembleArgvInput / SessionHandleParams / SpawnAgentParams fields
were set, which made engine click reject the invocation with UsageError
(exit 2) for any wrapper consumer that supplied them.

This commit removes:
- envAllowlist, envExtra, allowProtocolSkew from AssembleArgvInput
  and the three argv.push(...) blocks in assembleArgv()
- envAllowlist, envExtra, allowProtocolSkew from SessionHandleParams
  and the threading through to assembleArgv()
- allowProtocolSkew from SpawnAgentParams and the threading through to
  new SessionHandle(...)

SpawnAgentParams.env = { allowlist, extra } is preserved unchanged - the
wrapper still composes the subprocess environment via buildEnv(). Only
the FORWARDING of those values as argv flags to the engine is removed.

argv-builder tests are extended with @ts-expect-error compile-time
guardrails and runtime negative assertions for all three flags, mirroring
PR #29's removal pattern for --mcp-config-path.

NC follow-up: the NC adapter (amplifier-module-provider-nc) may pass
envAllowlist / envExtra / allowProtocolSkew to spawnAgent(); a follow-up
adapter PR will catch it up.

BREAKING CHANGE: SpawnAgentParams.allowProtocolSkew,
SessionHandleParams.envAllowlist / envExtra / allowProtocolSkew, and the
corresponding AssembleArgvInput fields are removed. Hosts that need the
skew override now set host_config.allowProtocolSkew: true in the JSON
config file. Hosts that need custom env composition either set
$AMPLIFIER_AGENT_CONFIG in the subprocess env or pass --config <path>
per turn.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(wrapper-py)!: drop env_allowlist, env_extra, allow_protocol_skew from spawn_agent + assemble_argv

The engine removed the --env-allowlist, --env-extra, and
--allow-protocol-skew argv flags in PR #27 (host config layer). The
Python wrapper was still emitting them when the corresponding kwargs were
set, which made engine click reject the invocation with UsageError
(exit 2) for any wrapper consumer that supplied them.

This commit removes:
- env_allowlist, env_extra, allow_protocol_skew kwargs from assemble_argv
  and the three argv.extend(...) / argv.append(...) blocks
- env_allowlist, env_extra, allow_protocol_skew fields from
  SessionHandleParams (and the unused `field` import that they required)
  plus the threading into assemble_argv
- allow_protocol_skew kwarg from spawn_agent and the threading into
  SessionHandleParams

spawn_agent(env={"allowlist": ..., "extra": ...}) is preserved unchanged
- the wrapper still composes the subprocess environment via build_env().
Only the FORWARDING of those values as argv flags to the engine is
removed.

test_argv_builder is extended with three TypeError-rejected kwarg tests
and three "flag not emitted" negative assertions, mirroring PR #29's
removal pattern for --mcp-config-path.

NC follow-up: the NC adapter (amplifier-module-provider-nc) may pass
env_allowlist / env_extra / allow_protocol_skew to spawn_agent(); a
follow-up adapter PR will catch it up.

BREAKING CHANGE: spawn_agent.allow_protocol_skew,
SessionHandleParams.env_allowlist / env_extra / allow_protocol_skew, and
the corresponding assemble_argv kwargs are removed. Hosts that need the
skew override now set host_config.allowProtocolSkew: true in the JSON
config file. Hosts that need custom env composition either set
$AMPLIFIER_AGENT_CONFIG in the subprocess env or pass --config <path>
per turn.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(wrapper-ts): rebuild dist after wrapper API removals

Regenerates wrappers/typescript/dist/ to reflect the source removals in
796f10d (drop envAllowlist, envExtra, allowProtocolSkew from
AssembleArgvInput / SessionHandleParams / SpawnAgentParams + argv
emission).

Mirrors PR #29's pattern of committing the rebuilt dist alongside the
source change so consumers using the published package see the API
narrowing immediately. No additional source changes.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

---------

Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
Co-authored-by: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
manojp99 added a commit that referenced this pull request Jun 3, 2026
…#27, #29, #31) (#32)

* fix(conformance): rename runner refs to initialize-with-mcp-config-path (post-#24)

PR #24 renamed the wire-shape fixture from
``initialize-with-mcpservers.yaml`` to
``initialize-with-mcp-config-path.yaml`` but left three hardcoded
references to the old name behind:

  * wrappers/conformance/test/runner-ts.test.ts (TS conformance suite)
  * wrappers/conformance/tests/test_runner_py.py (Py conformance suite)
  * tests/test_phase_2_1_exit_gate.py (engine-side fixture-set guard)

All three have been failing since PR #24. The conformance suites
showed up as "1 pre-existing failure each" in PRs #27, #29, and
#31, so wrapper/engine drift could land unseen during the entire
window in which we did most of the v0.3.0 argv cleanup -- the
exact class of bug the conformance suite is supposed to catch.

This commit restores the baseline to green by pointing each
reference at the surviving wire-protocol fixture name. No fixture
data changes, no engine logic changes.

Verification (this commit, host machine):
  * wrappers/conformance/ (TS): 5 passed (was 4 passed, 1 failed)
  * wrappers/conformance/ (Py): 5 passed (was 4 passed, 1 failed)
  * tests/test_phase_2_1_exit_gate.py: passes (was failing)

Out of scope (separate cleanup, noted for the PR body):
  * tests/cli/test_mode_a_v2_envelope.py still has 3 pre-existing
    failures referencing the removed ``--mcp-servers`` flag.
    Not touched here per the conformance-restore PR scope.

* chore(conformance): align version_skew remediation text with post-#27 host-config surface

PR #27 dropped the --allow-protocol-skew argv flag and moved protocol-skew opt-in into the host config file (allowProtocolSkew: true, surfaced through --config). The engine's real protocol_version_mismatch remediation string was updated in lockstep (src/amplifier_agent_lib/engine.py:160-163).

The version_skew wire-shape fixture's scripted server response still carried the old 'pass --allow-protocol-skew' remediation text, drifting it from current engine behavior even though no assertion in the fixture exercises the field directly. Update the scripted response to match the engine's current text so the fixture remains an honest exemplar of the wire-protocol surface post-#27/#29/#31.

Companion to PR #31 fixture sweep. No engine logic changes, no assertions changed, no test outcome changes.

* test(conformance): add baseline + protocol-skew-override wire-shape fixtures

Extend the conformance suite with two wire-protocol fixtures that lock in the post-cleanup surface and the previously-uncovered override branch of the version-skew contract:

* initialize-baseline.yaml -- canonical minimum init + turn/submit + result/final flow with only protocol-required params (no mcpConfigPath, no allowProtocolSkew, no hostCapabilities, no envAllowlist, no envExtra). Locks in the wire shape that survives PR #27 (host config + drop hostCapabilities), PR #29 (drop --mcp-config-path argv), and PR #31 (drop env-allowlist / env-extra / allow-protocol-skew from wrappers). Any future re-introduction of those legacy fields on the wire must be an intentional, reviewed addition rather than silent drift.

* initialize-with-protocol-skew-override.yaml -- the 'permits the handshake' branch of design §8 D6, companion to version_skew.yaml which covers only the strict-refuse branch. Client sends allowProtocolSkew=true (now sourced from the host config file, not from a --allow-protocol-skew argv flag) and a mismatched protocolVersion; server returns a successful sessionState instead of protocol_version_mismatch.

Both new fixtures are wired into the TS and Python conformance runners and acknowledged in the two fixture-set guard tests (tests/test_protocol_conformance_fixtures.py and tests/test_phase_2_1_exit_gate.py).

Scope note: the conformance runners use scripted JSON-RPC wire replay (ScriptedTransport) -- they do NOT spawn the engine subprocess. Argv-level 'loud failure' invariants for the dropped flags (--host-capabilities, --env-allowlist, --env-extra, --allow-protocol-skew, --mcp-config-path) are already locked in by the engine-side click-CliRunner tests at tests/cli/test_drop_host_capabilities.py and tests/cli/test_drop_mcp_config_path_flag.py. Extending the conformance runner to also exercise argv-level invariants would require subprocess invocation and changes to the loader at src/amplifier_agent_lib/protocol/conformance/loader.py (engine-internal, off limits per the PR scope) and is intentionally left for a future PR.

Verification (host machine):

* wrappers/conformance/ (TS): 7 passed (was 5 after rename commit)

* wrappers/conformance/ (Py): 7 passed (was 5 after rename commit)

* tests/test_protocol_conformance_fixtures.py: 17 passed (was 16; the new fixtures load and validate)

* tests/test_phase_2_1_exit_gate.py: passes (now acknowledges the new fixtures in the sorted-name guard)

* Engine suite (uv run pytest -q --ignore=wrappers): 519 passed, 3 pre-existing failures in tests/cli/test_mode_a_v2_envelope.py (unchanged from PR #31's pre-existing baseline -- they reference the long-removed --mcp-servers flag and are tracked for a separate cleanup).

* Wrappers/python: 48 passed; wrappers/typescript: 63 passed; manual smoke confirms --host-capabilities / --env-allowlist / --env-extra / --allow-protocol-skew / --mcp-config-path all reject with click UsageError ('no such option').

---------

Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
manojp99 pushed a commit that referenced this pull request Jun 3, 2026
Engine version bump for the host-config-layer release window. Pairs with
the wire PROTOCOL_VERSION bump (0.2.0 -> 0.3.0) and consolidates argv/wire
surface removals shipped in PRs #27, #29, #30, #31.

Verified:
  $ uv run amplifier-agent --version
  amplifier-agent, version 0.4.0

BREAKING CHANGE: Engine version 0.3.0 -> 0.4.0. Wire protocol 0.2.0 -> 0.3.0
shipped in the same release. Old wrappers fail handshake. See CHANGELOG.md
for the full argv/wire/API removal list.
manojp99 pushed a commit that referenced this pull request Jun 3, 2026
Python wrapper version bump to pair with the engine 0.4.0 release.
Same major.minor as engine — the two move together.

The wrapper's compiled PROTOCOL_VERSION (sourced from amplifier_agent_lib)
follows the engine bump 0.2.0 -> 0.3.0 transitively.

BREAKING CHANGE: SpawnAgentParams API removed envAllowlist, envExtra,
allowProtocolSkew, host, and mcpConfigPath fields across PRs #27, #29, #31.
Callers must migrate to host_config (JSON file passed via --config or
$AMPLIFIER_AGENT_CONFIG) or env var injection (AMPLIFIER_MCP_CONFIG).
manojp99 pushed a commit that referenced this pull request Jun 3, 2026
The TS wrapper jumps minor (0.4.0 -> 0.5.0) rather than tracking the
engine's major.minor (0.4.0) because of release-window history:

  - 0.4.0 was already published to npm (verified: 'npm view
    amplifier-agent-ts versions' lists 0.3.0, 0.3.1, 0.4.0)
  - 0.4.0 was published by PR #17 (path-based MCP config delivery,
    pre-#27/#29/#30/#31)
  - Since the 0.4.0 publish, PRs #27, #29, #30, #31 have all landed,
    removing breaking surface from the TS wrapper API:
      * SpawnAgentParams.host / HostCapabilities type (#27)
      * mcpConfigPath field + argv emission (#29)
      * envAllowlist / envExtra / allowProtocolSkew fields (#31)

We cannot republish 0.4.0 with different code, and the accumulated changes
are breaking (not a patch). Bumping to 0.5.0 puts the next npm release on
a fresh, unpublished version. If you have context I'm missing about a
prior decision to keep TS major.minor tied to engine major.minor, override
with a follow-up bump.

BREAKING CHANGE: TS wrapper API removed SpawnAgentParams.host,
HostCapabilities type, InitializeHostParams type (#27); mcpConfigPath field
+ argv emission (#29); envAllowlist, envExtra, allowProtocolSkew fields
(#31). Callers must migrate to AMPLIFIER_MCP_CONFIG env var and a
host_config JSON file passed via --config.
manojp99 pushed a commit that referenced this pull request Jun 3, 2026
, #32)

Replace the [Unreleased] section with a full [0.4.0] - 2026-06-03 entry
that consolidates the host-config-layer release window:

  PR #27 - Host config layer + drop hostCapabilities surface
  PR #29 - Drop --mcp-config-path argv (subsumed by host config + env var)
  PR #30 - host-config skills: block + tool-skills bundle composition
  PR #31 - Drop env-allowlist, env-extra, allow-protocol-skew from wrappers
  PR #32 - Restore conformance suite

Highlights:
  - 4 argv flags + 1 env var removed (subsumed by host config layer)
  - hostCapabilities fully removed from envelope, initialize, and wrapper API
  - 5th host-config block 'skills:' (D11/D12/D13)
  - Wire protocol 0.2.0 -> 0.3.0 (BREAKING)
  - Engine 0.3.0 -> 0.4.0, Python wrapper 0.3.0 -> 0.4.0, TS wrapper 0.4.0 -> 0.5.0

Also documents the cross-repo follow-ups that downstream consumers
(notably amplifier-module-provider-nc) must catch up on but are NOT
part of this release.
manojp99 pushed a commit that referenced this pull request Jun 3, 2026
Closes the last 4 Python CI failures on this release branch.

(1) tests/cli/test_config_show.py::test_config_show_reports_default_when_env_absent

Click's CliRunner.invoke(env=...) MERGES the env dict with os.environ instead
of replacing it. GitHub Actions runners set XDG_CONFIG_HOME by default, which
leaked into the test and made source='env:XDG_CONFIG_HOME' instead of the
'default' the test was asserting. Now uses monkeypatch.delenv() to explicitly
remove XDG_CONFIG_HOME / XDG_CACHE_HOME / XDG_STATE_HOME before invoking.

(2) tests/cli/test_mode_a_v2_envelope.py

The three test_mcp_servers_* tests (inline_json_parsed, at_path_form,
malformed_json_yields_argv_envelope) target the --mcp-servers argv flag.
That flag was renamed to --mcp-config-path by PR #24 and then fully removed
by PR #29. The tests have been failing as 'pre-existing baseline' through
PRs #27, #29, #31, #32, and #33's earlier baselines. They test removed
surface and should never have been kept.

Replaced with an inline comment naming the removal context and pointing at
the removal guardrail at tests/cli/test_drop_mcp_config_path_flag.py.

Local: 532 passed, 3 skipped, 0 failed (full pytest tests/).
manojp99 added a commit that referenced this pull request Jun 3, 2026
…ce restored (#33)

* chore(protocol)!: bump wire PROTOCOL_VERSION 0.2.0 -> 0.3.0

Bump the wire protocol version to reflect accumulated backward-incompatible
changes shipped under the 0.4.0 release window:

  - metadata.hostCapabilities removed from response envelope (#27)
  - InitializeParams.host removed (#27)
  - InitializeParams.mcpServers renamed to mcpConfigPath (#24)
  - skills field added (host config skills: block, #30)

Old wrappers pinned to '0.2.0' should hard-fail handshake with a typed
protocol_version_mismatch error and exit 2 — verified manually:

    $ uv run amplifier-agent run --protocol-version 0.2.0 --session-id sm 'hi'
    {... "code": "protocol_version_mismatch" ...}
    EXIT=2

    $ uv run amplifier-agent run --protocol-version 0.3.0 --session-id sm 'hi'
    {... "reply": "..." ...}
    EXIT=0

Updated sites (audited via 'git grep "0.2.0" src/ tests/'):

  - src/amplifier_agent_lib/protocol/methods.py — PROTOCOL_VERSION constant
  - src/amplifier_agent_lib/protocol/spec.md — regenerated artifact
  - 9 conformance fixtures' protocolVersion: literals (setup + initialize params)
  - version_skew.yaml — serverVersion in expected error.data
  - 6 test files pinning protocolVersion in wrapper-side InitializeParams

Left as historical references (per release-issue guidance):

  - loader.py docstring example (illustrative fixture shape)
  - test_protocol_conformance_fixtures.py's self-contained _VALID_FIXTURE
    (loader smoke test, not engine-compat)
  - serverInfo.version: "0.2.0" in fixture script result blocks
    (not asserted by conformance harness — engine emits __version__ at
    runtime; fixture scripts are descriptive, only the explicit
    assertions: block is verified)

BREAKING CHANGE: Wire protocol 0.2.0 -> 0.3.0. Old wrappers pinned to 0.2.0
will hard-fail handshake with protocol_version_mismatch (exit 2). Reinstall
both engine and wrapper, or set allowProtocolSkew: true in host config.

* chore(engine)!: bump amplifier-agent version 0.3.0 -> 0.4.0

Engine version bump for the host-config-layer release window. Pairs with
the wire PROTOCOL_VERSION bump (0.2.0 -> 0.3.0) and consolidates argv/wire
surface removals shipped in PRs #27, #29, #30, #31.

Verified:
  $ uv run amplifier-agent --version
  amplifier-agent, version 0.4.0

BREAKING CHANGE: Engine version 0.3.0 -> 0.4.0. Wire protocol 0.2.0 -> 0.3.0
shipped in the same release. Old wrappers fail handshake. See CHANGELOG.md
for the full argv/wire/API removal list.

* chore(wrapper-py)!: bump Python wrapper version 0.3.0 -> 0.4.0

Python wrapper version bump to pair with the engine 0.4.0 release.
Same major.minor as engine — the two move together.

The wrapper's compiled PROTOCOL_VERSION (sourced from amplifier_agent_lib)
follows the engine bump 0.2.0 -> 0.3.0 transitively.

BREAKING CHANGE: SpawnAgentParams API removed envAllowlist, envExtra,
allowProtocolSkew, host, and mcpConfigPath fields across PRs #27, #29, #31.
Callers must migrate to host_config (JSON file passed via --config or
$AMPLIFIER_AGENT_CONFIG) or env var injection (AMPLIFIER_MCP_CONFIG).

* chore(wrapper-ts)!: bump amplifier-agent-ts version 0.4.0 -> 0.5.0

The TS wrapper jumps minor (0.4.0 -> 0.5.0) rather than tracking the
engine's major.minor (0.4.0) because of release-window history:

  - 0.4.0 was already published to npm (verified: 'npm view
    amplifier-agent-ts versions' lists 0.3.0, 0.3.1, 0.4.0)
  - 0.4.0 was published by PR #17 (path-based MCP config delivery,
    pre-#27/#29/#30/#31)
  - Since the 0.4.0 publish, PRs #27, #29, #30, #31 have all landed,
    removing breaking surface from the TS wrapper API:
      * SpawnAgentParams.host / HostCapabilities type (#27)
      * mcpConfigPath field + argv emission (#29)
      * envAllowlist / envExtra / allowProtocolSkew fields (#31)

We cannot republish 0.4.0 with different code, and the accumulated changes
are breaking (not a patch). Bumping to 0.5.0 puts the next npm release on
a fresh, unpublished version. If you have context I'm missing about a
prior decision to keep TS major.minor tied to engine major.minor, override
with a follow-up bump.

BREAKING CHANGE: TS wrapper API removed SpawnAgentParams.host,
HostCapabilities type, InitializeHostParams type (#27); mcpConfigPath field
+ argv emission (#29); envAllowlist, envExtra, allowProtocolSkew fields
(#31). Callers must migrate to AMPLIFIER_MCP_CONFIG env var and a
host_config JSON file passed via --config.

* docs(changelog): consolidate 0.4.0 release notes (PRs #27, #29, #30, #31, #32)

Replace the [Unreleased] section with a full [0.4.0] - 2026-06-03 entry
that consolidates the host-config-layer release window:

  PR #27 - Host config layer + drop hostCapabilities surface
  PR #29 - Drop --mcp-config-path argv (subsumed by host config + env var)
  PR #30 - host-config skills: block + tool-skills bundle composition
  PR #31 - Drop env-allowlist, env-extra, allow-protocol-skew from wrappers
  PR #32 - Restore conformance suite

Highlights:
  - 4 argv flags + 1 env var removed (subsumed by host config layer)
  - hostCapabilities fully removed from envelope, initialize, and wrapper API
  - 5th host-config block 'skills:' (D11/D12/D13)
  - Wire protocol 0.2.0 -> 0.3.0 (BREAKING)
  - Engine 0.3.0 -> 0.4.0, Python wrapper 0.3.0 -> 0.4.0, TS wrapper 0.4.0 -> 0.5.0

Also documents the cross-repo follow-ups that downstream consumers
(notably amplifier-module-provider-nc) must catch up on but are NOT
part of this release.

* fix(ci): commit uv.lock for deterministic dependency resolution

The CI workflow uses astral-sh/setup-uv@v3 with enable-cache: true, which
defaults to globbing **/uv.lock to compute the cache key. With uv.lock
gitignored, every CI run failed at the install step with:

  No matches found for glob **/uv.lock

Committing uv.lock fixes CI and aligns with Astral's recommended practice
for reproducible builds. Catches reproducibility drift between contributors
and CI/DTU. The lock is ~150KB.

This was a pre-existing CI break on main (every recent CI run failing) that
this version-bump release is unblocking as part of release-readiness.

* fix(ci): install Node + pnpm for conformance parity tests

tests/test_conformance_parity.py::test_ts_and_py_runners_agree[*] shells
out to 'pnpm exec tsx runner_ts.ts' to cross-validate the TS runner against
the Python runner. The Python CI job had no Node.js or pnpm installed, so
all 10 parametrized cases failed with:

  FileNotFoundError: [Errno 2] No such file or directory: 'pnpm'

Adds setup-node@v4, pnpm/action-setup@v3, and a pnpm-install step in
wrappers/conformance/ before pytest runs. Pre-existing CI gap that this
release branch is closing as part of release-readiness.

* fix(ci): make XDG test hermetic + delete obsolete --mcp-servers tests

Closes the last 4 Python CI failures on this release branch.

(1) tests/cli/test_config_show.py::test_config_show_reports_default_when_env_absent

Click's CliRunner.invoke(env=...) MERGES the env dict with os.environ instead
of replacing it. GitHub Actions runners set XDG_CONFIG_HOME by default, which
leaked into the test and made source='env:XDG_CONFIG_HOME' instead of the
'default' the test was asserting. Now uses monkeypatch.delenv() to explicitly
remove XDG_CONFIG_HOME / XDG_CACHE_HOME / XDG_STATE_HOME before invoking.

(2) tests/cli/test_mode_a_v2_envelope.py

The three test_mcp_servers_* tests (inline_json_parsed, at_path_form,
malformed_json_yields_argv_envelope) target the --mcp-servers argv flag.
That flag was renamed to --mcp-config-path by PR #24 and then fully removed
by PR #29. The tests have been failing as 'pre-existing baseline' through
PRs #27, #29, #31, #32, and #33's earlier baselines. They test removed
surface and should never have been kept.

Replaced with an inline comment naming the removal context and pointing at
the removal guardrail at tests/cli/test_drop_mcp_config_path_flag.py.

Local: 532 passed, 3 skipped, 0 failed (full pytest tests/).

---------

Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
manojp99 pushed a commit that referenced this pull request Jun 3, 2026
Mirrors PR #29 / #31 pattern: dist/ is tracked so consumers installing
from the git tarball get the compiled artifacts without a build step.

Regenerated from npm run build after issues #1, #2, #3, #4, #5, #6, #7,
#9, #10 landed.
manojp99 added a commit that referenced this pull request Jun 3, 2026
…, approval, getEngineInfo, +5 more) (#36)

* feat(wrapper-ts): re-export internal helpers from index.ts (#5)

Adds named re-exports from the package entry point so consumers can
import internal helpers without reaching into private deep paths:

  assembleArgv, AssembleArgvInput
  resolveMcpConfigPath, cleanupSpillFile, McpSpillResult
  buildEnv, resolveBinaryPath, probeEngineVersion,
    DEFAULT_ALLOWLIST, BLOCKED_ENV_KEYS,
    ResolveBinaryPathOptions, BuildEnvOptions
  Transport, TransportOptions, ExitInfo
  checkProtocolVersion, VersionCheckResult, VersionCheckOk,
    VersionCheckFail, CheckProtocolVersionOptions
  parseRunOutput, STDERR_TAIL_BYTES, SubprocessOutcome
  makeApprovalHandler, ApprovalAdapter, ApprovalRequest,
    ApprovalHandler

Each export is annotated @public.

Closes #5.

* feat(wrapper-ts): wire checkProtocolVersion() into init path (#9)

spawnAgent() now probes the engine's protocol version once during
initialization (via amplifier-agent version --json) and runs
checkProtocolVersion() against PROTOCOL_VERSION_REQUIRED_BY_WRAPPER
BEFORE constructing a SessionHandle. Mismatch fails fast wrapper-side
with AaaError(protocol_version_mismatch), saving a full subprocess
roundtrip later.

Adds two new SpawnAgentParams fields:
  - allowProtocolSkew?: boolean — bypass the check (mirrors engine's
    host_config.allowProtocolSkew)
  - _engineVersionProbe?: () => Promise<EngineVersionPayload> —
    test-only injection point for the probe

Also bumps PROTOCOL_VERSION_REQUIRED_BY_WRAPPER from "0.2.0" to
"0.3.0" to match the engine's current wire protocol
(amplifier_agent_lib.protocol.methods.PROTOCOL_VERSION). The wrapper
was shipping with a stale pin; the new check would have surfaced this
at startup.

Closes #9.

* feat(wrapper-ts): add runChildProcess injection point (#3)

Adds SpawnAgentParams.runChildProcess?: ChildProcessFactory — a public
seam to substitute the subprocess factory used inside SessionHandle.
When set, the wrapper invokes the factory in place of
child_process.spawn, preserving the same options shape (detached, stdio,
env, optional cwd).

Useful for:
  - Sandboxing (e.g. wrapping the child in a container or namespace)
  - Test doubles (e.g. EventEmitter fakes that drive scripted outputs)
  - Harness wrapping (e.g. observing the subprocess from outside)

ChildProcessFactory is exported as a @public type from index.ts.

Closes #3.

* feat(wrapper-ts)!: wire Transport NDJSON pipeline + dispatch to display.onEvent (#2, #4, #6)

The engine emits one JSON object per line on the child subprocess's
stderr stream for each wire-protocol notification (progress,
result/delta, result/final, thinking/delta, thinking/final,
tool/started, tool/completed, approval/request, approval/timeout,
plus wire-level error). Before this change the wrapper buffered
stderr as raw text and silently dropped every event — the existing
Transport class implemented NDJSON parsing but was never wired
anywhere (dead code).

This change:

  - Adds parseNdjsonStream(stream, {onJson, onNonJson?}) — a
    standalone helper extracted from the parsing logic Transport
    already had. Resolves when the stream emits 'close'. Exported
    @public.

  - Wires parseNdjsonStream onto child.stderr inside
    SessionHandle.makeIterable(). JSON lines are parsed into
    'notification' DisplayEvents and dispatched to
    params.display?.onEvent. Non-JSON lines (and JSON lines, for
    completeness) are still accumulated into stderrBuf so the
    stderrTail surface on parseRunOutput remains diagnostically
    useful.

  - Extends the DisplayEvent discriminated union with a new
    {type: 'notification', method: string, params: unknown}
    variant. **BREAKING**: existing exhaustive switch statements
    on event.type will no longer be exhaustive without a
    notification branch.

  - Threads SpawnAgentParams.display through to SessionHandle so
    the callback that was previously silently dropped is now
    actually fired (Issue #4).

Closes #2, #4, #6.

BREAKING CHANGE: display.onEvent callbacks are now actually invoked
with wire-event notifications. Callers that registered onEvent
expecting it to be a no-op may observe new event flow. The
DisplayEvent union has a new 'notification' variant; exhaustive
switch statements need a corresponding branch.

* feat(wrapper-ts): surface --config flag via SpawnAgentParams.configPath (#1)

Engine PR #27 / v0.4.0 added the --config <path> flag and the
host_config layer (approval mode, MCP servers, provider defaults,
allowProtocolSkew, etc.). The wrapper had no surface to forward this,
so callers had to fall back to AMPLIFIER_AGENT_CONFIG in env.extra.

This change:

  - Adds SpawnAgentParams.configPath?: string (public, @public TSDoc).
  - Adds AssembleArgvInput.configPath?: string.
  - assembleArgv emits --config <path> when configPath is set.
  - Threads configPath through SessionHandleParams to the per-submit
    argv assembly.

Also drive-by adds approvalMode field to AssembleArgvInput (used by
#10's commit). The argv-builder now reads input.approvalMode and emits
-y / -n / nothing accordingly. Default remains -y for backward compat
with callers that haven't opted into the approval API.

Closes #1.

* feat(wrapper-ts)!: wire approval API to engine -y/-n + approval.mode (#10)

Previously, SpawnAgentParams.approval threw AaaError(
approval_not_supported_in_v1) whenever set because it required the
mid-turn onRequest callback that v1 doesn't support.

This change extends SpawnAgentParams.approval to also accept the
static-policy shape { mode: 'yes' | 'no' | 'prompt' }, which maps to
engine argv:

  - 'yes'    -> -y (auto-allow every tool call)
  - 'no'     -> -n (auto-deny every tool call)
  - 'prompt' -> emit no flag; engine falls back to
                host_config.approval.mode or the bundle's TTY-based
                default. This is how a host hands policy resolution
                back to the engine.

The legacy { onRequest, timeoutMs } form still throws
approval_not_supported_in_v1 — the Mode A wire has no mid-turn
channel. Mid-turn callbacks will return when WG-4 lands.

Engine compatibility: { mode: 'prompt' } requires
amplifier-agent >= 0.4.0 (PR #34 added host_config.approval.mode).

Closes #10.

BREAKING CHANGE: SpawnAgentParams.approval is now a union shape;
callers passing { mode } no longer hit approval_not_supported_in_v1.
Callers that defensively catch that error need to remove the try/catch
when migrating to the mode shape.

* feat(wrapper-ts): implement getEngineInfo() — engineVersion + bundleDigest (#7)

Closes the Task-9 TODO: getEngineInfo() now returns the values
captured during the engine version probe that spawnAgent() runs at
init (Issue #9). Previously both fields were hardcoded empty strings.

  - engineVersion populated from `amplifier-agent version --json`
    payload's `version` field.
  - bundleDigest populated from the probe payload's optional
    `bundleDigest` field. The engine's current `version --json`
    output (from admin/version_info.py) only emits {version,
    protocolVersion} — bundleDigest will be empty string until a
    future engine release exposes it. Forward-compatible: when the
    engine adds it, the wrapper picks it up automatically with no
    further changes.

DONE_WITH_CONCERNS for the bundleDigest follow-up: filed as an
engine-side ask for a future PR. The wrapper does what it can with
the data the engine surface exposes today; the contract is wired
so the field will populate the moment the engine emits it.

Closes #7.

* chore(wrapper-ts): rebuild dist after hardening release changes

Mirrors PR #29 / #31 pattern: dist/ is tracked so consumers installing
from the git tarball get the compiled artifacts without a build step.

Regenerated from npm run build after issues #1, #2, #3, #4, #5, #6, #7,
#9, #10 landed.

* chore(release): bump amplifier-agent-ts to 0.6.0 + CHANGELOG

Wrapper hardening release closing 8 consumer-reported gaps at 0.5.0:
  #1  configPath surface
  #2  stderr NDJSON parsing
  #3  runChildProcess injection
  #4  display.onEvent dispatch
  #5  public re-exports
  #6  Transport dead code (root cause of #2/#4)
  #7  getEngineInfo() implementation
  #9  checkProtocolVersion() wired into init path
  #10 approval API mapped to engine -y/-n + approval.mode

Issue #8 in the consumer report was a misread — InitializeParams.
mcpConfigPath is intentionally retained in protocol-0.3.0. No
type change needed; the schema is canonical and correct.

This is a minor bump per 0.x convention even though some changes
are BREAKING — the wrapper hasn't shipped a 1.0 yet, so breaking
changes ride minor bumps. See CHANGELOG for the BREAKING list.

Engine compatibility: requires amplifier-agent >= 0.4.0.
Pinned protocol: 0.3.0.

---------

Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant