Summary
Follow-up to #569 / #571 (shipped in v0.117.0). The sandbox carve-out for ~/.infer/skills and ./.infer/skills is currently conditional on c.Agent.Skills.Enabled being true at ValidatePathInSandbox time (config/config.go:1041). When that flag isn't set — running with default config, before infer config agent skills enable has run, or when the INFER_AGENT_SKILLS_ENABLED override hasn't reached the validator — the carve-out silently does not fire and reads of SKILL.md are denied with outside configured sandbox directories.
Skills directories are a well-known, read-only allowlist under ~/.infer/. Gating their sandbox visibility on a runtime feature flag re-introduces the failure mode #569 was meant to remove.
Proposed fix
Move the skills directories into the default Sandbox.Directories in DefaultConfig() (config/config.go:619-625), unconditionally:
// resolve user-scope skills dir at config-build time
homeDir, _ := os.UserHomeDir()
dirs := []string{".", "/tmp", ConfigDirName + "/tmp", ConfigDirName + "/skills"}
if homeDir != "" {
dirs = append(dirs, filepath.Join(homeDir, ConfigDirName, "skills"))
}
Sandbox: SandboxConfig{
Directories: dirs,
ProtectedPaths: []string{ConfigDirName + "/", ".git/", "*.env"},
},
Then drop the isWithinSkillsDir-gated branch of the carveOut expression in ValidatePathInSandbox (lines 1041-1050). Keep isWithinConfigSubdir(absPath, "tmp", "plans") — that's an orthogonal carve-out for project .infer/{tmp,plans} and unrelated to skills.
Protected-paths interaction
protected_paths: [.infer/] will currently match ~/.infer/skills/foo/SKILL.md via the substring/prefix logic in checkProtectedPaths (config/config.go:1127-1149). Two options:
- Recognize an explicit, more-specific
Sandbox.Directories entry (e.g. ~/.infer/skills) as an override of a broader protected_paths entry (.infer/). Generalizes today's carveOut-skip-.infer/ trick at line 1131 into something declarative.
- Add an
isWithinSkillsDir(absPath) short-circuit in checkProtectedPaths (always allow, no flag) — narrower but simpler than option 1.
Either way, the agent's Read of SKILL.md and references/*.md succeeds with default config; ~/.infer/config.yaml, ~/.infer/conversations.db, etc. remain protected because they're outside skills/.
Why this is better than the v0.117.0 carve-out
- One source of truth for what is readable:
Sandbox.Directories. No second runtime predicate to keep in sync.
agent.skills.enabled goes back to meaning exactly "load skill metadata into the prompt and offer them to the agent" — purely about discovery/loading, no sandbox semantics.
- No env-var plumbing required from
infer-action or any other consumer: INFER_AGENT_SKILLS_ENABLED=true becomes optional for reading (still useful for enabling skill loading).
- Behavior is identical across
chat, infer agent, channels, and heartbeat — no per-mode flag drift.
Repro
Failed run that prompted this: @infer on inference-gateway/adl (2026-06-02), CLI v0.116.0 via inference-gateway/.github@v0.4.1's pin. v0.116.0 has no carve-out at all, so this exact failure is also resolved by the centralized workflow bumping its cli-version to v0.117.0+ — but the conditional design means even after that bump the failure can re-appear if agent.skills.enabled isn't true at validation time.
Tests
Update config/config_test.go:
- New:
ValidatePathInSandbox of ~/.infer/skills/foo/SKILL.md succeeds with DefaultConfig() and Agent.Skills.Enabled = false.
- New: same for
./.infer/skills/foo/SKILL.md.
- New:
~/.infer/config.yaml and ~/.infer/conversations.db still rejected (protected-paths still applies).
- Remove or rewrite the existing
isWithinSkillsDir / agent.skills.enabled-gated cases.
Follow-up
Once this lands and a new CLI is cut:
inference-gateway/infer-action — bump inputs.version.default in action.yml to the new CLI release.
inference-gateway/.github — bump cli-version default in the centralized infer workflow (currently v0.116.0) so existing consumers like adl pick up the fix.
[DOCS] ticket: a one-line update to the skills/sandbox doc explaining that skills dirs are read-allowed by default (no flag required).
Summary
Follow-up to #569 / #571 (shipped in v0.117.0). The sandbox carve-out for
~/.infer/skillsand./.infer/skillsis currently conditional onc.Agent.Skills.Enabledbeing true atValidatePathInSandboxtime (config/config.go:1041). When that flag isn't set — running with default config, beforeinfer config agent skills enablehas run, or when theINFER_AGENT_SKILLS_ENABLEDoverride hasn't reached the validator — the carve-out silently does not fire and reads ofSKILL.mdare denied withoutside configured sandbox directories.Skills directories are a well-known, read-only allowlist under
~/.infer/. Gating their sandbox visibility on a runtime feature flag re-introduces the failure mode #569 was meant to remove.Proposed fix
Move the skills directories into the default
Sandbox.DirectoriesinDefaultConfig()(config/config.go:619-625), unconditionally:Then drop the
isWithinSkillsDir-gated branch of thecarveOutexpression inValidatePathInSandbox(lines 1041-1050). KeepisWithinConfigSubdir(absPath, "tmp", "plans")— that's an orthogonal carve-out for project.infer/{tmp,plans}and unrelated to skills.Protected-paths interaction
protected_paths: [.infer/]will currently match~/.infer/skills/foo/SKILL.mdvia the substring/prefix logic incheckProtectedPaths(config/config.go:1127-1149). Two options:Sandbox.Directoriesentry (e.g.~/.infer/skills) as an override of a broaderprotected_pathsentry (.infer/). Generalizes today'scarveOut-skip-.infer/trick at line 1131 into something declarative.isWithinSkillsDir(absPath)short-circuit incheckProtectedPaths(always allow, no flag) — narrower but simpler than option 1.Either way, the agent's
ReadofSKILL.mdandreferences/*.mdsucceeds with default config;~/.infer/config.yaml,~/.infer/conversations.db, etc. remain protected because they're outsideskills/.Why this is better than the v0.117.0 carve-out
Sandbox.Directories. No second runtime predicate to keep in sync.agent.skills.enabledgoes back to meaning exactly "load skill metadata into the prompt and offer them to the agent" — purely about discovery/loading, no sandbox semantics.infer-actionor any other consumer:INFER_AGENT_SKILLS_ENABLED=truebecomes optional for reading (still useful for enabling skill loading).chat,infer agent, channels, and heartbeat — no per-mode flag drift.Repro
Failed run that prompted this:
@inferoninference-gateway/adl(2026-06-02), CLI v0.116.0 viainference-gateway/.github@v0.4.1's pin. v0.116.0 has no carve-out at all, so this exact failure is also resolved by the centralized workflow bumping itscli-versionto v0.117.0+ — but the conditional design means even after that bump the failure can re-appear ifagent.skills.enabledisn't true at validation time.Tests
Update
config/config_test.go:ValidatePathInSandboxof~/.infer/skills/foo/SKILL.mdsucceeds withDefaultConfig()andAgent.Skills.Enabled = false../.infer/skills/foo/SKILL.md.~/.infer/config.yamland~/.infer/conversations.dbstill rejected (protected-paths still applies).isWithinSkillsDir/agent.skills.enabled-gated cases.Follow-up
Once this lands and a new CLI is cut:
inference-gateway/infer-action— bumpinputs.version.defaultinaction.ymlto the new CLI release.inference-gateway/.github— bumpcli-versiondefault in the centralized infer workflow (currently v0.116.0) so existing consumers like adl pick up the fix.[DOCS]ticket: a one-line update to the skills/sandbox doc explaining that skills dirs are read-allowed by default (no flag required).