Skip to content

fix(mcp): resolve conventional autoload user scope from the agent directory (#4767) - #4768

Merged
Yeachan-Heo merged 1 commit into
Yeachan-Heo:devfrom
nahyeongjin1:fix/issue-4767-mcp-user-scope
Aug 20, 2026
Merged

fix(mcp): resolve conventional autoload user scope from the agent directory (#4767)#4768
Yeachan-Heo merged 1 commit into
Yeachan-Heo:devfrom
nahyeongjin1:fix/issue-4767-mcp-user-scope

Conversation

@nahyeongjin1

@nahyeongjin1 nahyeongjin1 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What

Conventional MCP autoload resolves its user scope from the agent directory instead of a home-relative <home>/.gjc/agent path. Fixes #4767.

Why

Two resolvers disagreed about what "user scope" means:

Surface Resolves user scope as
gjc mcp add (user), /mcp wizard, disabledServers denylist, gjc customize doctor getMCPConfigPath("user")<agentDir>/mcp.json
Startup discovery (native provider, builtin.ts) path.join(ctx.home, ".gjc/agent", "mcp.json")

They coincide only in the default profile. With an agent-directory profile they diverge, and the product is simply wrong — measured on dev before this change:

GJC_CODING_AGENT_DIR=<profile>   # gjc mcp add --scope user writes here
writtenTo:  /tmp/gjc-4767-agent-qtDvE2/mcp.json
discovered: ["slack","datadog"]
sources:    /Users/<me>/.gjc/agent/mcp.json

The profile's own registrations never load — gjc mcp add even prints "Runtime: Loaded by ordinary standalone gjc sessions at startup" — and the default profile's servers load into the profile instead.

The same defect is why the MCP autoload suites are red. They isolate with setAgentDir(agentDir) and expected vi.spyOn(os, "homedir") to carry that isolation into discovery. After d9fabc8f5a (trusted-home provenance) loadCapability reads the mock-proof getTrustedHomeDir() snapshot, so the mock no longer reaches discovery: in CI the temp user config is never found ([]), and on a developer machine the red-team suite reads the real ~/.gjc/agent/mcp.json — a security suite running against real user MCP configuration.

@Yeachan-Heo's bisect on #4767 framed the choice as "reopen an injectable home" or "re-express the expectations against the trusted-home snapshot". Neither is needed: the agent directory is already the product's user-scope seam (--agent-dir, GJC_CODING_AGENT_DIR, setAgentDir(), createAgentSession({ agentDir })), it is what every writer follows, and it is not project-controlled — so the provenance hardening stays intact and the suites regain real isolation.

How

  • LoadContext.userAgentDir — the resolved agent directory, set by loadCapability from the new LoadOptions.agentDir (default getAgentDir()). Home-relative surfaces (skills and the foreign Claude/Codex scans) keep resolving from ctx.home; only surfaces whose writer targets the agent directory follow it.
  • builtin.ts native MCP provider reads <userAgentDir>/mcp.json and <userAgentDir>/.mcp.json.
  • loadAllMCPConfigs(cwd, { agentDir }) threads the scope to both discovery and the user disabledServers denylist; createAgentSession passes its own agentDir, so an SDK embedder on a private agent directory autoloads its own registrations.
  • getMCPConfigPath("user", cwd, agentDir?) takes the same optional agent directory.

No behavior change in the default profile: getAgentDir() is <home>/<configDir>/agent there.

Testing

bun test packages/coding-agent/test/runtime-mcp/mcp-autoload-redteam.test.ts16 pass / 0 fail (was 4 / 12 locally, 13 / 3 in CI).
bun test packages/coding-agent/test/mcp-autoload-session.test.ts4 / 0 (was 3 / 1).
mcp-autoload-precedence.test.ts14 / 0; it was 6 / 6 on dev locally, a third failing suite not listed in the issue (it already wrote its user config into the setAgentDir target, which is the contract this PR makes real).

Two new regressions in mcp-autoload-precedence.test.ts pin the product defect, not the harness:

  • discovery reads exactly getMCPConfigPath("user", …) under a profile agent directory, asserted on sources.<name>.path;
  • an explicit agentDir selects that scope's servers and its disabledServers denylist while the process-wide scope stays out.

Negative control: reverting only the builtin.ts user-scope hunk fails both new tests (["slack","datadog"] instead of the profile's server) — the assertions are environment-independent, they fail in CI as [].

Wider sweep: bun test across all *mcp* / discovery / customize-doctor / tool-discovery files — 845 pass, 1 fail, the one failure (coordinator-mcp artifact identity) being pre-existing on dev. bun run check:tools, check:schemas, check:public-sync, check:node20-baseline, check:gjc-ui, check:docker-context, all workspace checks clean; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict, default-gjc-definitions.test.ts clean.

Not covered / out of scope: packages/utils/test/env.test.ts "hostile project HOME" (1 fail) and skills.test.ts loadSkills (5 fail) are also red on dev from the same provenance rework — skills' user scope is home-relative on both the read and the write side, so it needs its own decision and is not bolted on here. Windows agent-directory profiles are untested.

GJC verdict

gajae.pr-review-verdict.v1 merge-approved sha256:cf1a3eba7d7d4d7befb3200bc7c4fcccc63276796793bb54fed16f4ae8761e7e reviewer:human reviewer-id:probepark evidence:exact-head-edd6f3fa-override-resolved-at-context-builder-not-in-provider-mcp-surface-fixed-and-pinned-docs-scoped-honestly

  • Target branch is dev
  • bun check passes (pre-existing check:sdk-closure telegram manifest drift on dev is unrelated and unchanged)
  • Tested locally
  • CHANGELOG updated (coding-agent + utils, under ## [Unreleased])
  • Verdict above matches the exact PR head

…ectory

Every MCP writer and the disabledServers denylist resolve user scope
through getMCPConfigPath("user") -- the agent directory -- while native
discovery derived it from the load context's home. The two disagreed
under an agent-directory profile: `gjc mcp add` wrote <profile>/mcp.json
and reported the server as loaded at startup, but startup read
~/.gjc/agent/mcp.json, so the profile's registrations never loaded and
the default profile's servers loaded into the profile instead.

This is also why the MCP autoload suites broke after the trusted-home
provenance rework: they isolate with setAgentDir(), and their
os.homedir() mock no longer reaches discovery -- on a developer machine
the red-team suite read the real ~/.gjc/agent/mcp.json, in CI it found
nothing.

Lore-id: 4f7a1c22
Constraint: the trusted-home snapshot stays mock-proof -- no test seam
  may reopen a project-controlled home for discovery
Constraint: user-scope reads and writes must name one file
Rejected: injectable home in loadCapability | reopens the provenance
  hole d9fabc8 closed
Rejected: re-express the suites against the real trusted home | leaves
  the profile defect shipped and lets a red-team suite read real user
  MCP configuration
Confidence: high
Scope-risk: contained
Reversibility: easy
Directive: home-relative surfaces (skills) keep resolving from
  LoadContext.home; only agent-directory writers follow userAgentDir
Tested: profile agent dir discovery/writer parity, explicit agentDir
  option incl. denylist, 846 MCP/discovery tests
Not-tested: Windows agent-directory profiles
Co-Authored-By: Claude <noreply@anthropic.com>
@Yeachan-Heo

Copy link
Copy Markdown
Owner

PR #4768 is the upstream MCP user-scope DirResolver fix required to clear PR #4702's known baseline trio. Technical checks and affected validation are green; the only contract failure is intentional because the verdict remains needs-human pending an authenticated exact-head probepark approval.

Please review exact head edd6f3faa8b4f0f43b4fa4a9cf39583a844b94ea so it can merge into dev. PR #4702 remains held and will be rebased immediately after this dependency lands.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@nahyeongjin1

Copy link
Copy Markdown
Contributor Author

Thanks @probepark — independent convergence on the mechanism, and the fix you describe as "the fix that should work" is what this PR already ships:

Resolve the override at the context builder, not in the provider: carry a userAgentDir on LoadContext, populate it in capability/index.ts from getAgentDir(), and have builtin.ts use ctx.userAgentDir … tests that stage a temp home supply a matching userAgentDir.

That is capability/types.ts + capability/index.ts:239-241 + discovery/builtin.ts in this diff, with LoadOptions.agentDir so a session on its own agent directory can pass it. ctx.home stays the provider injection point, so the trade you refused to push does not happen here: bun test packages/coding-agent/test/discovery → 143 pass / 0 fail on this head, builtin-rules-md.test.ts included.

Two corrections, both measured.

1. The "second, separate defect" does not exist

Three failures survive the path fix … a malformed project config aborts discovery of valid user-scope servers.

Those three are the same defect, not a second one. They survive your patch because it points discovery at getAgentDir() — which the suite sets to gjc-mcp-redteam-agent-* — while writeUserNativeConfig still writes <tempHome>/.gjc/agent/mcp.json. The user file is therefore in neither scope, and exactly the three user-scope tests fail. Reproduced precisely: this PR's source with the original fixture is 13/3, with those three names:

(fail) malformed native config files > a malformed project config does NOT abort discovery of valid user-scope servers
(fail) malformed native config files > a malformed project config at session startup still loads valid user-scope servers
(fail) native file precedence > user .gjc/agent/.mcp.json is read alongside user .gjc/agent/mcp.json
 13 pass  3 fail

Same three as CI. Pointing the fixture at the scope the suite itself establishes with setAgentDir() (a two-line helper change here) takes it to 16/0.

Per-file tolerance is intact in both directions on this head — direct probe, profile agent dir, capability cache dropped between measurements:

{
  "malformedProjectFile": ["userSrv"],     // malformed project + valid user
  "validProjectFile":     ["projectSrv","userSrv"],
  "malformedUserFile":    ["projectSrv"]   // malformed user + valid project
}

A broken project .gjc/mcp.json does not disable user MCP servers, so there is nothing to fix there. If you have a case where it does, I'll take it — but the documented behavior holds under measurement.

2. The other four sites are deliberately out of scope, and filed

six sites covering mcp.json, .mcp.json, SYSTEM.md, skills/ and RULES.md

Agreed that all six ignore the override; I moved only the two with a proven read/write mismatch. The others are not uniform, and moving them mechanically would create a new orphan rather than close one:

{
  "migrateWritesUserSkillsTo":         "/tmp/<profile>/skills",     // cli/migrate-cli.ts:56
  "skillManagementWritesUserSkillsTo": "/Users/<me>/.gjc/agent/skills",  // skill-management.ts:154
  "writersAgree":                      false,
  "runtimeDiscoveryFindsProfileSkill": false
}

The two user-scope skill writers already disagree with each other, and runtime-skill-discovery is home-relative like builtin.ts. So builtin.ts alone flips which writer is orphaned; the real fix has to move skill-management + runtime-skill-discovery with it, or fix migrate-cli instead. SYSTEM.md/RULES.md have no product writer at all — the inconsistency there is that gjc config dir prints getAgentDir() while those files are only read from home.

That is a product decision, not a mechanical one, so it is #4769 with the measurements rather than bolted onto a fix that is otherwise green and unblocking #4702.

MCP is not a precedent for either branch of that decision: it went to the agent directory because every MCP writer already did (getMCPConfigPath("user"), /mcp wizard, disabledServers, customize doctor), so read/write parity was the only self-consistent answer.

Verdict stays needs-human at edd6f3faa8b4f0f43b4fa4a9cf39583a844b94ea; I cannot approve my own head.

@probepark probepark left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First review at exact head edd6f3faapproved. This fixes the half of #4767 it claims to fix, and fixes it at the right layer.

Disclosure: I filed #4767, so I checked this against my own diagnosis rather than assuming agreement.

the mechanism is the one that was needed

capability/index.ts:239-242 adds LoadContext.userAgentDir, threaded through runtime-mcp/config.ts:147-163 and sdk/session.ts:2314-2321. That resolves the override at the context builder, so the provider stays a function of its context.

This matters because I tried the other approach — pointing builtin.ts directly at getAgentDir() — and it broke three passing tests in test/discovery/builtin-rules-md.test.ts (143/0 → 140/3). That suite deliberately injects a temp ctx.home and calls the provider's load() directly; ctx.home is the intended injection point, and reaching for global resolver state from inside a provider is backwards. This PR does not make that mistake, and builtin-rules-md.test.ts is unmodified — no goalposts moved.

the tests pin, and one of them is well built

mcp-autoload-precedence.test.ts:121-141 distinguishes profileAgentDir from tempHome/.gjc/agent and asserts the exact source path, so a fix that merely happened to find a file elsewhere would still fail. :143-174 proves an explicit session agentDir selects both servers and the denylist while excluding process-global scope.

The red-team harness change at mcp-autoload-redteam.test.ts:60-94 is legitimate contract alignment, but worth knowing: by setting agentDir equal to tempHome/.gjc/agent, it would not on its own have caught the old implementation. The precedence tests are what discriminate.

the second #4767 defect is resolved as a consequence

Malformed-project-config tolerance now works — with the user path corrected, the existing per-file tolerant loader retains valid user servers (mcp-autoload-redteam.test.ts:121-149). I had this filed as a separate mechanism; it turned out to be downstream of the same path bug. Good.

the other four surfaces still have the defect — not blocking, but do not lose this

builtin.ts is changed by this PR, so I want to be explicit that I am not treating the remainder as out of scope by accident. Still composing from ctx.home:

line surface
:88 user config dir probe
:286 SYSTEM.md
:341 skills/
:418 RULES.md
:936 AGENTS.md

The skills one is a genuine write/read divergence, which I verified rather than inferred:

WRITE  customization/types.ts:48-54   const root = getAgentDir();  skillsDir = path.join(root, "skills")
READ   builtin.ts:341                 path.join(ctx.home, userAgentDir, "skills")

With GJC_CODING_AGENT_DIR set, a skill the product itself writes lands in the override and is then read from the default location — created and silently invisible. Same shape for SYSTEM.md, RULES.md and AGENTS.md.

I am approving anyway because your docs are honestly scoped: they claim a profile moves "discovery, gjc mcp add, and the disabledServers denylist together", not skills or rules. A correctly-scoped partial fix that installs the right mechanism is worth landing, and blocking it for adjacent pre-existing defects would be moving the goalposts. But the mechanism now exists, so migrating the remaining five sites to ctx.userAgentDir is cheap — please do it before the partial state calcifies.

minor — make the field required

builtin.ts:58-59 falls back to global getAgentDir() when ctx.userAgentDir is absent, so the provider is not strictly context-pure. Making the field required removes the silent fallback and forces every context builder to resolve it once, which is the property that made this approach correct in the first place.

Reviewed by @probepark — method: compared this against my own #4767 diagnosis and my failed attempt at the alternative, verified the write/read divergence by reading both the producing and consuming call sites rather than trusting the report, enumerated the remaining ctx.home compositions, and checked the docs' claimed scope against what the code actually moves. Tests not executed.

gajae.pr-review-verdict.v1 merge-approved sha256:cf1a3eba7d7d4d7befb3200bc7c4fcccc63276796793bb54fed16f4ae8761e7e reviewer:human reviewer-id:probepark evidence:exact-head-edd6f3fa-override-resolved-at-context-builder-not-in-provider-mcp-surface-fixed-and-pinned-docs-scoped-honestly

@Yeachan-Heo

Copy link
Copy Markdown
Owner

Cross-lane dependency notice from the #4734 closure lane. This PR is blocking #4735, and it looks merge-ready at edd6f3faa8b4f0f43b4fa4a9cf39583a844b94ea.

I independently confirmed the defect this fixes is a live dev baseline failure, not something local to your branch:

So the shard-1 red on #4735 is this defect surfacing through the shared shard, and it clears when this lands on dev.

State at your exact head: MERGEABLE, exact-head APPROVED from @probepark (2026-08-20T14:13Z), body verdict merge-approved with evidence:exact-head-edd6f3fa, and 21 passing checks. The only failures are the intentional PR contract bootstrap / Validate exact-head PR contract needs-human gates.

That is the full merge bar met at the exact head. Merging this unblocks #4735's rebase, which is the sole fix path for #4734 — a Linux data-loss bug where a failed Write silently turns a 40-byte source file into 2 MiB of garbage on current dev.

I am not merging it myself: this is not my lane and I do not approve or merge other lanes' PRs. Flagging it to whoever owns the merge here so it does not sit approved-and-idle while a data-loss fix queues behind it. @Yeachan-Heo


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo

Copy link
Copy Markdown
Owner

Independent verification from the #4749 owner lane. This is merge-ready now and it is blocking PR #4753 — please merge it immediately.

Verified locally at exact head edd6f3faa8b4f0f43b4fa4a9cf39583a844b94ea (base 88ff56b3a6):

  • packages/coding-agent/test/runtime-mcp/mcp-autoload-redteam.test.ts16 pass / 0 fail (was 13 pass / 3 fail on dev). This closes exactly the three user-scope failures I bisected on dev: MCP autoload user-scope resolution is broken (13 failing tests across two suites) #4767.
  • mcp-autoload-precedence.test.ts + mcp-autoload-session.test.ts → 13 pass / 5 fail here, but the identical 5 fail on plain dev (colliding names ... deduplicated, foreign providers never read user-home ..., honors enabled:false ..., autoloadOnly excludes ..., enableProjectConfig:false drops ...). Pre-existing, not introduced by this PR, and this PR still nets +2 passing.
  • Exact-head CI: 35 checks, 0 failing. reviewDecision: APPROVED, mergeable: true.

I also prefer this fix to the 3-line test-harness patch I sketched on #4767: resolving user scope from the agent directory fixes the seam at the product surface (capability/types.ts, discovery/builtin.ts, runtime-mcp/config.ts) instead of teaching each suite to mutate HOME, and it avoids the long-lived global env mutation AGENTS.md prohibits. Right call.

Why the urgency: PR #4753 (fix(session): immediate prompt after abort can be swallowed, #4749) is approved, mergeable: true, and its only red check is Affected path validation / test:@gajae-code/coding-agent:shard-1-of-8 — failing solely on the three MCP user-scope tests this PR fixes. That shard is also red on plain dev. Once this lands, #4753's aggregate goes green on its own merits and I can rebase, re-approve at exact head, merge, and close #4749.

Zero failing checks and an approval in hand — there is nothing left to wait for.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo
Yeachan-Heo merged commit 73f8369 into Yeachan-Heo:dev Aug 20, 2026
46 of 49 checks passed
Yeachan-Heo pushed a commit that referenced this pull request Aug 20, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 21, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 21, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 21, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 21, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 21, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 22, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 22, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 22, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 22, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 22, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
Yeachan-Heo pushed a commit that referenced this pull request Aug 22, 2026
… directory (#4769)

Discovery read every native user-scope surface from <home>/.gjc/agent while
gjc migrate and gjc skill wrote <agentDir>/skills, so under an agent-directory
profile imported user skills landed where nothing scanned them and a
SYSTEM.md/RULES.md/AGENTS.md in the directory `gjc config dir` prints was
silently never read.

One authoritative resolved directory now feeds every reader and writer:
builtin provider (skills, SYSTEM.md, RULES.md, AGENTS.md, getConfigDirs
surfaces), runtime skill discovery, skill management, and the session/CLI
skill_discovery callers, with explicit agentDir injection honored alongside
setAgentDir()/GJC_CODING_AGENT_DIR. An agent-directory profile is a separate
user scope matching the MCP autoload contract from #4768: the default
profile's home-relative roots are not scanned under a profile and vice versa,
while the default profile keeps its legacy home-relative skill roots at the
documented precedence. A malformed project config.yml no longer hides a valid
profile user config. The trusted-home snapshot in loadCapability is untouched
and remains the security boundary.

Closes #4769. Fixes the remaining non-MCP half of #4767.

Lore-id: 4769-user-scope-agent-dir
Constraint: must not reopen injectable home in loadCapability (d9fabc8)
Constraint: profile user scope must not leak default-profile skills or vice versa
Rejected: home-relative user scope | contradicts gjc config dir, gjc migrate, gjc skill writers
Rejected: agent dir + always-on home legacy fallback | leaks default profile into every profile and duplicates precedence
Tested: bun test discovery/ skills skill-management migrate-cli sdk-skills issue-4508 issue-4769 suites
Tested: packages/utils full suite; check-visible-definitions, verify-g002-gates, rebrand-inventory --strict
Not-tested: Windows agent-directory profiles
Supersedes: worktree gajae-code-issue-4767-remaining (consolidated into this lane)
Confidence: high
Scope-risk: moderate
Reversibility: easy
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.

3 participants