Summary
Local skill discovery for repo-local .agents/skills is anchored to the nearest enclosing git root. In a layout where several independent git repositories are grouped under a non-git parent directory, a skill placed at the grouping-root's .agents/skills is only discovered when the agent's working directory is exactly that root. As soon as docker-agent runs from inside any sub-repo, the upward walk stops at the sub-repo's .git and never reaches the parent — so the grouping-level skill silently disappears.
Severity: low / latent. It does not bite when launching from the grouping root (so it's not the cause of #3054), but the behavior is surprising and undocumented.
Filesystem setup (anonymized)
A common "grouping" layout — a plain directory that is not a git repo, containing multiple independent clones, each its own repo:
~/work/dev/org/ <- grouping root, NOT a git repo (no .git)
├── .agents/
│ └── skills/
│ └── services/
│ └── SKILL.md <- skill name: "services" (grouping-level skill)
├── service-a/ <- independent repo
│ └── .git/
├── service-b/ <- independent repo
│ └── .git/
└── docker-agent/ <- independent repo
└── .git/
The intent: services is a cross-repo helper skill that should be available no matter which repo you're working in.
What works vs. what doesn't
| Working directory when docker-agent is launched |
projectSearchDirs walks |
Finds ~/work/dev/org/.agents/skills/services? |
~/work/dev/org (grouping root, no .git) |
no git marker found → returns just [cwd] |
✅ yes (cwd == grouping root) |
~/work/dev/org/docker-agent |
hits docker-agent/.git immediately → stops there |
❌ no (never reaches the parent) |
~/work/dev/org/docker-agent/pkg/skills |
walks up, hits docker-agent/.git → stops there |
❌ no |
~/work/dev/org/service-a |
hits service-a/.git → stops there |
❌ no |
So the grouping-level services skill is only visible from the one directory that is the grouping root itself; from inside any actual repo (the normal place to do work) it vanishes.
Root cause
projectSearchDirs (in pkg/skills/local.go) walks up from cwd and stops at the first .git marker:
for current := abs; ; {
dirs = append(dirs, current)
if hasGitMarker(current) { // stops at the nearest git root
gitRoot = current
break
}
parent := filepath.Dir(current)
if parent == current { break }
current = parent
}
if gitRoot == "" {
return []string{abs} // not in a git repo: only cwd
}
localSearchPaths then scans <dir>/.agents/skills for each returned dir. Because the walk terminates at the nearest git boundary, it can never cross above a repo into a non-git parent. A skill living in that non-git parent is therefore unreachable from inside any sub-repo.
Expected / discussion
At minimum the boundary behavior should be documented (it currently is not — see the doc comments below, which describe "from git root down to cwd" without noting the non-git-parent blind spot). Possible improvements for maintainers to weigh:
- Continue walking up past a git root to also include
.agents/skills in non-git ancestor directories (up to $HOME or a sane ceiling), so grouping-root skills are picked up; and/or
- Provide an explicit, configurable extra search root (env var or config) for "umbrella"/grouping layouts; and/or
- Document the git-root anchoring clearly so users know to place shared skills under
~/.agents/skills (the global recursive path), which is unaffected.
Affected code references
pkg/skills/local.go — projectSearchDirs (the upward walk that stops at the nearest .git) and localSearchPaths (which builds .agents/skills paths only from projectSearchDirs' result).
pkg/skills/local.go — localSearchPaths doc comment: ".agents/skills` from the git root down to cwd (closest wins)".
pkg/skills/skills.go — Load doc comment: ".agents/skills/` (flat, scanned from git root to cwd)".
Note
Distinct from #3054 (that issue is a slash-command dispatch loop; this one is about discovery reachability in grouping layouts).
Summary
Local skill discovery for repo-local
.agents/skillsis anchored to the nearest enclosing git root. In a layout where several independent git repositories are grouped under a non-git parent directory, a skill placed at the grouping-root's.agents/skillsis only discovered when the agent's working directory is exactly that root. As soon as docker-agent runs from inside any sub-repo, the upward walk stops at the sub-repo's.gitand never reaches the parent — so the grouping-level skill silently disappears.Severity: low / latent. It does not bite when launching from the grouping root (so it's not the cause of #3054), but the behavior is surprising and undocumented.
Filesystem setup (anonymized)
A common "grouping" layout — a plain directory that is not a git repo, containing multiple independent clones, each its own repo:
The intent:
servicesis a cross-repo helper skill that should be available no matter which repo you're working in.What works vs. what doesn't
projectSearchDirswalks~/work/dev/org/.agents/skills/services?~/work/dev/org(grouping root, no.git)[cwd]~/work/dev/org/docker-agentdocker-agent/.gitimmediately → stops there~/work/dev/org/docker-agent/pkg/skillsdocker-agent/.git→ stops there~/work/dev/org/service-aservice-a/.git→ stops thereSo the grouping-level
servicesskill is only visible from the one directory that is the grouping root itself; from inside any actual repo (the normal place to do work) it vanishes.Root cause
projectSearchDirs(inpkg/skills/local.go) walks up from cwd and stops at the first.gitmarker:localSearchPathsthen scans<dir>/.agents/skillsfor each returneddir. Because the walk terminates at the nearest git boundary, it can never cross above a repo into a non-git parent. A skill living in that non-git parent is therefore unreachable from inside any sub-repo.Expected / discussion
At minimum the boundary behavior should be documented (it currently is not — see the doc comments below, which describe "from git root down to cwd" without noting the non-git-parent blind spot). Possible improvements for maintainers to weigh:
.agents/skillsin non-git ancestor directories (up to$HOMEor a sane ceiling), so grouping-root skills are picked up; and/or~/.agents/skills(the global recursive path), which is unaffected.Affected code references
pkg/skills/local.go—projectSearchDirs(the upward walk that stops at the nearest.git) andlocalSearchPaths(which builds.agents/skillspaths only fromprojectSearchDirs' result).pkg/skills/local.go—localSearchPathsdoc comment: ".agents/skills` from the git root down to cwd (closest wins)".pkg/skills/skills.go—Loaddoc comment: ".agents/skills/` (flat, scanned from git root to cwd)".Note
Distinct from #3054 (that issue is a slash-command dispatch loop; this one is about discovery reachability in grouping layouts).