Repository navigation
Description
Relocated from dezren39/darwin-nix#5 on 2026-10-28 (placement audit): mcpx's single source lives in developing-today/code (pkgs/mcpx); re-home tracked at #309. Original body below; issue references inside it are historical (dezren39/nix numbering).
Parent: #181
Problem
paths.config is declared in the settings registry but nothing reads it. The
config search path is still the hardcoded upward walk in config.SearchPath().
Still true at 05c78b2 (#171 left it open on purpose). paths.config appears
in Go only at its declaration (internal/settings/registry.go:270) and in the
#171 guard's allowlist (internal/settings/consumed_test.go:67-70).
SearchPathFrom (internal/config/config.go:542-579) reads MCPX_CONFIG,
XDG_CONFIG_HOME and the home directory, nothing else.
One correction to what #171 recorded: the allowlist reason and
docs/declared-but-unread.md:93-96 both say config.SearchPath reads
MCPX_PATHS_CONFIG directly. It does not -- MCPX_PATHS_CONFIG occurs nowhere in
Go code outside that string. So the setting is inert through all three
channels, and docs/configuration.md:336 advertises --paths-config and
MCPX_PATHS_CONFIG, both of which parse and do nothing. The allowlist entry is
defending a mechanism that does not exist.
That is the same advertised-but-inert failure fixed for paths.scripts,
pool.* and the logging group in #4, left in one place because the fix there
is genuinely harder.
Why it is harder
Circular. To know where to look for config files you would read a setting —
which comes from a config file.
Approaches
A -- delete the setting. Honest and immediate: a knob that parses and does
nothing is the #177 bug class. Loses the "a repo config can say also look here"
capability, which nobody can use today anyway.
B -- environment and flag only. Read MCPX_PATHS_CONFIG / --paths-config
before discovery and prepend (or splice) them into the search path; ignore the
key in files. Not circular, small, and it makes the allowlist sentence true. It
does not let a file extend the chain, which is the part the rest of this issue
is about.
C -- recommended: the two-pass resolution below, with B as its first input.
The environment/flag value seeds pass 1; files found then extend the chain in
pass 2. Recommended because it is the only option where the declared setting
means the same thing from all three channels, which is the registry's promise.
Proposed resolution (Approach C)
Two passes, with the boundary stated rather than implied.
- Discovery pass. Walk the default locations. Read only
paths.config
from whatever is found, honouring the null splice. - Load pass. Resolve that list and load everything on it, nearest last.
A file's paths.config therefore governs the rest of the chain from that
point, not the search that found the file itself. So a repo config can say
"also look here", and a parent cannot be redirected by a child it has never
read.
Rules worth pinning
- A
paths.configfound in pass 2 that differs from pass 1 is reported,
not silently applied. Applying it means re-running discovery with different
roots, which can not terminate. - A cycle (A adds B, B adds A) is refused by identity, the way the launcher
refuses placeholder cycles. MCPX_CONFIGcontinues to win outright and skip both passes, because "this
file, nothing else" has to stay expressible.
Done when
paths.configfrom a discovered file changes which files load afterwards- a cycle is refused, naming the path that closed it
mcpx config --sourcesshows both passes distinctlyMCPX_CONFIGstill bypasses everything
Ease · Impact · Related
Ease S-M · Impact med -- small, and #103 assumes it; also the gate on what
a project config may add to the chain before hooks (#81) and plugin directories
(#80) make that a larger grant.
Related: #103 (assumes it), #81 and #80 (a project config that declares hooks or
a plugin search path is an escalation this rule has to allow for; #173's
warnings), #177 / #129 (the inert-setting class and the guard whose allowlist
reason is wrong here).
Security/auth deferred; see tracker.
Activity
developing-today commentedon Oct 28, 2026
CODE-770
dezren39 commentedon Oct 28, 2026
History carried over from dezren39/darwin-nix#5 (verbatim, oldest first):
@dezren39 · 2026-09-30T07:28:35Z
Integration pass. This issue has no category tracker -- it predates the build-out and is a dependency of several parts of it. Placed in the proposed order at #181.
@dezren39 · 2026-09-30T12:11:57Z
Issues pass (2026-09-30, at 05c78b2).
Parent: #181, a footer (Ease S-M, Impact med, matching Phase 3: sync, blob gate, and relays #181) and Related links.paths.configunread on purpose. It appears only atinternal/settings/registry.go:270and in the guard allowlist.internal/settings/consumed_test.go:67-70) anddocs/declared-but-unread.md:93-96sayconfig.SearchPathreadsMCPX_PATHS_CONFIGdirectly. It does not.SearchPathFrom(internal/config/config.go:542-579) reads onlyMCPX_CONFIG,XDG_CONFIG_HOMEand the home dir, andMCPX_PATHS_CONFIGappears nowhere in Go. The setting is inert through all three channels, yetdocs/configuration.md:336advertises the flag and the variable.designlabel.@dezren39 · 2026-10-28T19:01:27Z
Triage verdict (task 2025): CONFIRMED, with one update since filing.
Verified at current mains — the mcpx Go source now lives only in developing-today/code
pkgs/mcpx(dezren39/nix main efd3161 has no mcpx Go source; onlymcpx.config.nix,.github/workflows/mcpx-nixbuild.yml,planning/plans/mcpx-extraction.md), so citations are at developing-today/code main35726e8e:internal/settings/registry.go:349still declarespaths.config(KindPathList, Repeatable).internal/config/config.goSearchPathFrom(713–776) is still the hardcoded upward walk: it readsMCPX_CONFIG(730) andXDG_CONFIG_HOME(752) and the home dir — nopaths.config, noMCPX_PATHS_CONFIG.MCPX_PATHS_CONFIGoccurs in zero Go files (code search: onlydocs/configuration.md:431anddocs/declared-but-unread.md).--paths-config/MCPX_PATHS_CONFIGstill parse and do nothing, anddocs/declared-but-unread.mdstill falsely claims "config.SearchPath reads MCPX_PATHS_CONFIG directly".paths.configdoes not change which files load afterwards, there is no cycle refusal, andconfig --sourcesshows no two passes. (MCPX_CONFIGbypass does hold.)Update: the setting is no longer wholly unread.
internal/settings/consumed_test.go:75–82removed it from the unread allowlist becausecli.adoptSettingsreads it — but that read iscli/root.go:211warnPathsConfigFile(#278), which only warns when an entry names a file. It adds nothing to the search/load chain, so the issue's core claim stands.Routing: follow-up fix packet enqueued to queue
repo-health-nix-pilot(deduperepo-health:v1:fix:dezren39/nix:issue:5, kind small_fix) scoped to Approach C (B as pass-1 input) in developing-today/codepkgs/mcpx, with the cycle-refusal, pass-2-divergence-report,--sources, andMCPX_CONFIG-bypass acceptance items from this issue. This issue stays the single tracking issue for the set — no per-repo code issue filed.dezren39 commentedon Oct 29, 2026
🤖 Agent note · picked up
paths.configscope against current pkgs/mcpx main, enqueue the implementation follow-up with acceptance criteria intact. No implementation in this task.dezren39 commentedon Oct 29, 2026
🤖 Agent note · triage verdict — CONFIRMED, implementation follow-up enqueued
paths.configshould govern the rest of the config chainVerdict: CONFIRMED at current main
82b019a0. Scope stands as written, with the issue's own recommended Approach C (two-pass resolution, env/flag as its first input) as the implementation direction. No duplicate exists.Verified fresh (2026-10-29 ~04:15Z):
pkgs/mcpx/internal/settings/registry.go~L349 declarespaths.config(KindPathList, Repeatable). Nothing consumes it to build the chain:SearchPathFrom(pkgs/mcpx/internal/config/config.go~L713-763) honours onlyMCPX_CONFIGoutright, then the upward walk, XDG/home fallbacks and/etc/mcpx/config.json. Code search:MCPX_PATHS_CONFIGoccurs in no Go file — onlydocs/configuration.mdanddocs/declared-but-unread.md, both of which advertise a mechanism that does not exist; theconsumed_test.goallowlist reason repeats the same false claim. (One nuance for the implementer: the comment atconfig.go~L728 says "paths.configFile. Read by name because it decides which files the settings are resolved from" — that names the internal constant for theMCPX_CONFIGenv var, not thepaths.configsetting; do not mistake it for consumption. AwarnPathsConfigFilehelper ininternal/cli/root.go~L211-230 does exist — it warns when an entry names a file — but warning is not governing.)paths.config/ the config chain returns this issue as the only one scoped to it. The other hits are trackers that reference it (mcpx: extensibility -- plugins, hooks, tool sources, embedding (tracker) #1885, mcpx: a promise and a behaviour that disagree — every declared surface needs a guard that walks it (tracker) #1893, mcpx: the backlog build-out — every theme, in one order, with the disagreements between them (super tracker) #1900, mcpx testing: guard tests that close a whole bug class #1971, mcpx docs: level-2 page map, and the configuration, modes and transport pages #1848, mcpx: the sources the reference would be generated from are incomplete, and several docs say what the code does not #1883) or different work (mcpx: where a script's packages come from -- npm/deno/bun dependency configuration chain #1913 dependency chain; closed mcpx daemons: dead records listed forever, custom-state daemons missed, paths.config file entry silently ignored #278 was the daemon-side "file entry silently ignored" bug, a different defect). Nothing to close as a duplicate; no competing PR or branch owns this.paths.configfrom the default locations, honouring the null splice; load pass resolves that list, nearest last), with Approach B's env/flag value (MCPX_PATHS_CONFIG/--paths-config) seeding pass 1. That makes the declared setting mean the same thing from file, env and flag — the registry's promise. Rules pinned by the issue and carried into the follow-up intact: a differingpaths.configfound in pass 2 is reported, not applied; a cycle is refused by identity, naming the path that closed it;MCPX_CONFIGkeeps winning outright and skips both passes.Follow-up: implementation packet enqueued to repo-health-code-pilot (small_fix) with the issue's four "Done when" bullets as its acceptance criteria, plus the allowlist/docs truth-up (
consumed_test.goallowlist reason,docs/declared-but-unread.md,docs/configuration.md) so the guard stops defending a mechanism that does not exist. Task ID recorded in the completion note below / queue.dezren39 commentedon Oct 29, 2026
🤖 Agent note · triage complete
small_fix, dedupe_keyrepo-health:v1:fix:developing-today/code:issue:1842) with the issue's four "Done when" bullets intact plus the allowlist/docs truth-up. This issue now carriesqueue/queuedfor task 3059.21 remaining items
dezren39 commentedon Oct 30, 2026
agent-note:v1
event: parked
task: 3059 (queue repo-health-code-pilot, lane D)
worker: repo-worker-code
summary: Implemented Approach C and opened PR #2477 (branch queue/3059-1842-paths-config-chain): config.ResolveChainFrom two-pass resolution, env/global-flag seeding, cycle refusal naming the closing path, pass-2 divergence reported via mcpx config --sources, MCPX_CONFIG bypass, consumed_test/docs truth-ups. 6 new tests in internal/config/chain_test.go; config, settings and (isolated) cli packages pass on the laptop; go vet clean.
next: Parked for CI on PR #2477 and the merge-queue gate #2403. Next lane: read PR checks (incl. a clean internal/daemon verdict — one termination was seen under parallel-suite contention and did not reproduce isolated) and Codex findings, merge when green and #2403 clears, then complete task 3059.
pr: #2477
mcpx: declare MCPX_PATHS_CONFIG as a bootstrap raw read (#1842)
dezren39 commentedon Oct 30, 2026
🤖 Agent note · parked
dezren39 commentedon Oct 30, 2026
🤖 Agent note · handed off
dezren39 commentedon Oct 30, 2026
🤖 Agent note · done
awaiting_ci)0b06b277, 01:09:11Z by Drew) and this issue is closed (01:16:05Z).pkgs/mcpx/internal/config/chain.go+chain_test.goare onmainvia merge0b06b277; CI was green at heade013229f. Task 3059 completed asfixed_merged; this shift created no branch and no PR.queue/parked,status/parkedandwork/assignedlabels now that the task is terminal.0b06b277· follow-up paths.config two-pass chain: disposition 6 Codex P2 findings from merged PR #2477 #2507