Description
In role or project mode the root skills/ is the tag catalog and is not delivered by default (design doc, "Skills keep one difference"; pinned by still does not deliver root skills by default in role mode). That part is intended. What is wrong is how a member finds out: they don't. When a member picks a role or project, pull deletes the root skills it installed earlier. It does the same when an admin just adds manifest/projects.yaml, and then it hits members who never ran --project too. The only record is a debug line that calls the skills "excluded", and the summary says No resources to sync.
pullForScope src/pull.ts
resolveResourceNamespaces src/resource-namespaces.ts:57
team has projects.yaml → project mode, even with no active project
resolveDesiredSkills src/resources/desired.ts:242
scanRoleAwareSkills: active namespaces only src/resources/desired.ts:198 (root = tag catalog, by design)
Step 3b: installed skill not in the desired set src/pull.ts:1296
remove(skillDir)
log.debug(`Removed excluded skill …`) only visible with --verbose, and wrong: nothing was excluded
"No resources to sync"
Two doc passages say the opposite, which makes the removal look like a bug:
docs/designs/multi-project-management.md:229: <type>/ root, shared with everyone. The skills exception is 40 lines later.
docs/usage-guide.md:239 (docs/usage-guide.zh-CN.md:223): a member with no project "still get[s] common". They don't, unless a role lists common. With projects.yaml present and no role, pull delivers no skills at all.
Other types are fine: root rules, agents, CLAUDE.md fragments and docs are delivered with a project active.
Expected: pull names the skills it removes and says how to get a root skill back.
Proposed fix, in Step 3b:
if (!options.dryRun && desiredSkillNames && knownRepoSkillNames) {
const baseDir = resolveBaseDir(localConfig);
+ const removedSkills = new Set<string>();
…
await remove(skillDir);
- log.debug(`Removed excluded skill ${dir} from ${tool}`);
+ removedSkills.add(dir);
+ log.debug(`Removed skill ${dir} from ${tool}: no longer delivered here`);
…
+ if (removedSkills.size > 0) {
+ const hint = roleContext ? ' While the team uses roles or projects, root skills arrive only through a tag: `teamai tags subscribe <tag>`.' : '';
+ log.info(`[${scopeLabel}] Removed ${removedSkills.size} skill(s) no longer delivered here: ${[...removedSkills].join(', ')}.${hint}`);
+ }
}
Plus a pull-namespace-override test: install lonely with no role, pull as frontend, and assert that the skill is gone and an info line names it and teamai tags subscribe. Fix the two doc lines above, and add a bullet to the usage guide's multi-project section, in both languages. cleanupInactiveNamespaceSkills (src/pull.ts:270) removes namespace skills just as quietly; the same one-line summary would cover it.
Not proposed here: delivering root skills by default in role/project mode, or at least to members with no project. That would change the design, so it is for the maintainers to decide.
Reproduction
- Team repo with
teamai.yaml and skills/shared-skill/SKILL.md. A member runs teamai init <url>, then teamai pull: new: shared-skill.
- Add
manifest/projects.yaml with one project (id: svc-a, resources: { skills: [svc-a] }) and push it.
- The member runs
teamai pull again, with no --project:
✔ [project] Team repo: 1 file(s) changed
ℹ [project] No resources to sync
.claude/skills/shared-skill is gone. teamai pull --verbose shows [debug] Removed excluded skill shared-skill from claude. init --project svc-a on a fresh machine gives Synced 1 skills … new: svc-a-skill and no shared-skill.
Environment
- OS: macOS 27.0
- Node.js: v24.21.0
- teamai: 0.22.0 (repro); fix and test on
main at 417e704
- Provider: git
- AI tool(s): Claude Code
Logs
Where it was found
Seen in three separate sandbox setups while testing multi-project layouts for #908. Reproduced with the real CLI in a sandbox with a bare git team repo. The proposed fix went red then green in pull-namespace-override.test.ts. The pull suites pass (23 files, 304 tests), and a real-CLI run of step 3 prints Removed 1 skill(s) no longer delivered here: shared-skill. ….
Description
In role or project mode the root
skills/is the tag catalog and is not delivered by default (design doc, "Skills keep one difference"; pinned bystill does not deliver root skills by default in role mode). That part is intended. What is wrong is how a member finds out: they don't. When a member picks a role or project,pulldeletes the root skills it installed earlier. It does the same when an admin just addsmanifest/projects.yaml, and then it hits members who never ran--projecttoo. The only record is adebugline that calls the skills "excluded", and the summary saysNo resources to sync.Two doc passages say the opposite, which makes the removal look like a bug:
docs/designs/multi-project-management.md:229:<type>/ root, shared with everyone. The skills exception is 40 lines later.docs/usage-guide.md:239(docs/usage-guide.zh-CN.md:223): a member with no project "still get[s]common". They don't, unless a role listscommon. Withprojects.yamlpresent and no role,pulldelivers no skills at all.Other types are fine: root rules, agents, CLAUDE.md fragments and docs are delivered with a project active.
Expected:
pullnames the skills it removes and says how to get a root skill back.Proposed fix, in Step 3b:
if (!options.dryRun && desiredSkillNames && knownRepoSkillNames) { const baseDir = resolveBaseDir(localConfig); + const removedSkills = new Set<string>(); … await remove(skillDir); - log.debug(`Removed excluded skill ${dir} from ${tool}`); + removedSkills.add(dir); + log.debug(`Removed skill ${dir} from ${tool}: no longer delivered here`); … + if (removedSkills.size > 0) { + const hint = roleContext ? ' While the team uses roles or projects, root skills arrive only through a tag: `teamai tags subscribe <tag>`.' : ''; + log.info(`[${scopeLabel}] Removed ${removedSkills.size} skill(s) no longer delivered here: ${[...removedSkills].join(', ')}.${hint}`); + } }Plus a
pull-namespace-overridetest: installlonelywith no role, pull asfrontend, and assert that the skill is gone and an info line names it andteamai tags subscribe. Fix the two doc lines above, and add a bullet to the usage guide's multi-project section, in both languages.cleanupInactiveNamespaceSkills(src/pull.ts:270) removes namespace skills just as quietly; the same one-line summary would cover it.Not proposed here: delivering root skills by default in role/project mode, or at least to members with no project. That would change the design, so it is for the maintainers to decide.
Reproduction
teamai.yamlandskills/shared-skill/SKILL.md. A member runsteamai init <url>, thenteamai pull:new: shared-skill.manifest/projects.yamlwith one project (id: svc-a,resources: { skills: [svc-a] }) and push it.teamai pullagain, with no--project:.claude/skills/shared-skillis gone.teamai pull --verboseshows[debug] Removed excluded skill shared-skill from claude.init --project svc-aon a fresh machine givesSynced 1 skills … new: svc-a-skilland noshared-skill.Environment
mainat 417e704Logs
Where it was found
Seen in three separate sandbox setups while testing multi-project layouts for #908. Reproduced with the real CLI in a sandbox with a bare git team repo. The proposed fix went red then green in
pull-namespace-override.test.ts. The pull suites pass (23 files, 304 tests), and a real-CLI run of step 3 printsRemoved 1 skill(s) no longer delivered here: shared-skill. ….