Skip to content

mcpx: ${mcpx.root} / ${mcpx.cwd} substitution at spawn + era identity on effective definition #960

Closed

Description

@dezren39

Slice 2 of decision record 0004 (pkgs/mcpx/docs/decisions/0004-scope-resolved-roots.md, PR #957). Design source: dezren39/darwin-nix#818 — this issue carries its acceptance criteria. Depends on slice 1 (#958, ResolvedScope plumbing).

What to build (spec §4)

  • At instance-spawn time only, substitute ${mcpx.root} (the instance's resolved root) and ${mcpx.cwd} (the creating CallContext's canonical cwd) in Args, every Env value, and Cwd.
  • Placeholder names validated at config load: an unknown ${mcpx.<name>} or a malformed ${mcpx. sequence is a config error naming the server and the field. Only the mcpx. namespace is touched; every other ${…} passes through verbatim.
  • Referencing ${mcpx.root} for an instance whose root is empty (e.g. a global-scoped server) fails the spawn loudly, naming server and field — never substitute an empty or daemon-cwd root.
  • pool.Identity (era cache) must hash the effective per-instance (substituted) spawn definition, not the static Resolved config.

Acceptance criteria (from nix#818, verbatim intent)

  • ${mcpx.root} and ${mcpx.cwd} in a server's Args, Env, or Cwd are replaced with the scope-resolved root / caller cwd when an instance spawns.
  • The stored/merged config on disk and in mcpx config output remains unsubstituted.
  • The era/instance identity reflects the substituted spawn definition (two instances differing only by substituted root do not collide).
  • An unknown ${mcpx.*} placeholder fails loudly with the server name and field.
  • Servers whose config contains no placeholders behave exactly as before.
  • Tests cover substitution in each of Args/Env/Cwd and the unknown-placeholder error.

Activity

  1. added
    kind/featureNew feature or capability request
    source/humanFiled directly by a human
    status/blockedQueue or user escalation state
    priority/normalOrdinary priority (the default)
    effort/mMedium: expected under 1 day of work
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 26, 2026
  2. dezren39 commented on Oct 26, 2026

    @dezren39
    MemberAuthor

    Intake review

    Still live (verified this run): no ${mcpx.root} / ${mcpx.cwd} substitution exists in pkgs/mcpx on main (grep clean), no ResolvedScope to source the root from, and no merged PR addresses it. Design record is in open PR #957.

    Related: #958 (slice 1, prerequisite) · PR #957 (decision 0004, open) · #961 (slice 4; does not require this slice) · design origin dezren39/darwin-nix#818.

    Notes / risks: Marked status/blocked at intake — depends on slice 1. Two easy-to-miss requirements: (1) substitution happens at spawn time only, never in the stored/merged config; (2) the era/instance identity must hash the substituted definition, or two instances differing only by root will collide in the pool cache. The empty-root loud failure (never substitute daemon cwd) is a safety property — keep it an error, not a warning.

    Suggested approach: After #958, add load-time placeholder validation (unknown/malformed ${mcpx.…} names the server + field), spawn-time substitution over Args/Env/Cwd, and switch pool.Identity to the effective definition; test each field plus the unknown-placeholder and empty-root errors.

    — Fleet monitor intake enrichment (acceptance criteria were already in the body; labels normalized, meta/enriched added).

  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    Duplicate link (from triage of #1991, task 2897): #1991 — the 2026-10-28 relocation of dezren39/darwin-nix#818 — duplicates this issue, which was filed 2026-10-26 as slice 2 of decision record 0004 and explicitly carries nix#818's acceptance criteria. #1991 is closed as a duplicate of this issue; nothing in #1991 goes beyond what is specified here (this issue's spec is the more precise one: load-time placeholder validation, loud spawn failure on an empty resolved root, pool.Identity hashing the effective definition). Implementation stays tracked here, gated on slice 1 (#958, still open).

  4. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  5. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    Triage verdict: CONFIRMED — not implemented; implementation gated on slice 1 (#958)

    Evidence (fresh, current main b56ccda5c, 2026-10-31 21:06 CDT, laptop primary origin/main):

    • grep -rn 'mcpx\.root\|mcpx\.cwd' pkgs/mcpx --include='*.go' → no matches: no spawn-time substitution exists.
    • grep -rn 'ResolvedScope' pkgs/mcpx --include='*.go' → no matches: slice 1's plumbing has not landed either.
    • pkgs/mcpx/docs/decisions/0004-scope-resolved-roots.md exists on main — the spec (§4) is merged and available to implement against.

    Dependency state: #958 (slice 1, ResolvedScope plumbing) is still OPEN and, at this check, carries queue/claimed + work/assigned — another worker holds it. This slice cannot be built before it: there is no resolved root to substitute.

    Route: follow-up fix enqueued as queue task 4874 (kind small_fix, packet packet-960-fix.json) with the gate pinned in the packet: at claim time re-check #958 — if it has not landed, block the task naming the dependency rather than improvising a parallel ResolvedScope. The packet pins the full scope: load-time placeholder validation (unknown/malformed ${mcpx.*} names server + field), spawn-time-only substitution over Args/Env/Cwd, loud spawn failure on an empty resolved root (never daemon cwd), and pool.Identity hashing the effective substituted definition.

    This issue stays open with status/blocked (dependency) until #958 lands; the duplicate #1991 remains closed against this tracker.

  6. 38 remaining items

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 3, 2026
  8. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

effort/mMedium: expected under 1 day of workkind/featureNew feature or capability requestmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/humanFiled directly by a humantask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions