fix(claude.sh): forward a claude-bound -- to the CLI instead of consuming it #27

Merged
claudiomaradonna merged 2 commits from fix/forward-locked-double-dash into main 2026-08-25 12:53:01 +02:00

Problem

claude mcp add localrecall --env K=V -- /usr/local/bin/localrecall-mcp fails inside
the jail with:

error: missing required argument 'commandOrUrl'

The wrapper consumes the first -- in argv unconditionally as its wrapper/claude
boundary — even here, where mcp has already locked the workspace slot and everything
after it belongs to claude. The container's CLI receives the command without its --,
the variadic --env <env...> swallows the binary path as another env entry, and
commandOrUrl comes up missing. Reproduced with --dry-run before the fix: the
forwarded tail shows the -- dropped.

Fix

A -- can only be the wrapper boundary while the wrapper is still parsing its own
arguments. Once the slot is locked, no boundary is possible any more, so the -- is
appended to claude_args instead of dropped. Passthrough still begins there, so server
arguments spelled like wrapper flags (--image, --network, …) reach claude verbatim.

Unchanged: claude . -- --model sonnet (boundary consumed as before) and the
claude . -- -- foo doubling idiom.

Changes

  • claude.sh — the -- case forwards the token when _workspace_locked=1; Phase 1
    header comment and _print_help updated
  • tests/test_arg_parsing.sh — two new tests, written first and watched fail on
    exactly the dropped --: a locked -- reaches claude; passthrough still applies
    after it
  • docs/superpowers/specs/2026-07-28-argument-parsing-design.md — contract table split
    into unlocked/locked -- rows, amendment dated 2026-08-25
  • README.md — one paragraph on when -- is forwarded rather than consumed

Verification

  • tests/run.sh → ALL TESTS PASSED (72 tests; arg-parsing file went 17 → 19)
  • Dry-run of the failing invocation now ends with
    … claude-code mcp add --scope user localrecall --env … -- /usr/local/bin/localrecall-mcp
## Problem `claude mcp add localrecall --env K=V -- /usr/local/bin/localrecall-mcp` fails inside the jail with: error: missing required argument 'commandOrUrl' The wrapper consumes the first `--` in argv unconditionally as its wrapper/claude boundary — even here, where `mcp` has already locked the workspace slot and everything after it belongs to claude. The container's CLI receives the command without its `--`, the variadic `--env <env...>` swallows the binary path as another env entry, and `commandOrUrl` comes up missing. Reproduced with `--dry-run` before the fix: the forwarded tail shows the `--` dropped. ## Fix A `--` can only be the wrapper boundary while the wrapper is still parsing its own arguments. Once the slot is locked, no boundary is possible any more, so the `--` is appended to `claude_args` instead of dropped. Passthrough still begins there, so server arguments spelled like wrapper flags (`--image`, `--network`, …) reach claude verbatim. Unchanged: `claude . -- --model sonnet` (boundary consumed as before) and the `claude . -- -- foo` doubling idiom. ## Changes - `claude.sh` — the `--` case forwards the token when `_workspace_locked=1`; Phase 1 header comment and `_print_help` updated - `tests/test_arg_parsing.sh` — two new tests, written first and watched fail on exactly the dropped `--`: a locked `--` reaches claude; passthrough still applies after it - `docs/superpowers/specs/2026-07-28-argument-parsing-design.md` — contract table split into unlocked/locked `--` rows, amendment dated 2026-08-25 - `README.md` — one paragraph on when `--` is forwarded rather than consumed ## Verification - `tests/run.sh` → ALL TESTS PASSED (72 tests; arg-parsing file went 17 → 19) - Dry-run of the failing invocation now ends with `… claude-code mcp add --scope user localrecall --env … -- /usr/local/bin/localrecall-mcp`
The contract had the wrapper consume the first -- unconditionally, assuming
it could only ever be the wrapper/claude boundary. But once the workspace
slot is locked, claude's argv has already started and no boundary is
possible any more, so that -- is claude's own. Consuming it broke
'claude mcp add <name> --env K=V -- <cmd>': the CLI's variadic --env
swallowed the command and claude failed with "missing required argument
'commandOrUrl'".

Amended: a -- seen while the slot is open is consumed as the boundary, as
before; a -- seen after the slot is locked is forwarded, and passthrough
still begins there so server arguments spelled like wrapper flags reach
claude verbatim.

Claude-Session: https://claude.ai/code/session_01VZEEdm4K6oExgudCeC6MmT
'claude mcp add localrecall --env K=V -- /usr/local/bin/localrecall-mcp'
reached the container without its --: the parser consumed the first --
unconditionally as the wrapper boundary, even though 'mcp' had already
locked the slot and everything from there on belongs to claude. Inside
the container the variadic --env then swallowed the binary path, and
claude failed with "missing required argument 'commandOrUrl'".

A -- can only be the boundary while the wrapper is still parsing its own
arguments. Once the slot is locked it is appended to claude_args instead
of dropped; passthrough begins either way, so server arguments spelled
like wrapper flags (--image, --network) still reach claude verbatim.

Tests written first and watched fail on exactly the dropped --. Help
text and README updated alongside.

Claude-Session: https://claude.ai/code/session_01VZEEdm4K6oExgudCeC6MmT
claudiomaradonna deleted branch fix/forward-locked-double-dash 2026-08-25 12:53:04 +02:00
Commenting is not possible because the repository is archived.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
claudiomaradonna/claude-jail!27
No description provided.