You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Codex does not appear to support project-scoped plugin installation: codex plugin add and codex plugin marketplace add expose no project
or --scope option. However, plugin scope should not prevent installation
when --skills-only explicitly requests raw skill files.
The Codex registry entry does not set SupportsProjectScope or ProjectConfigDir, so SupportsProjectScope defaults to false.
This may correctly reflect the lack of project-scoped Codex plugin
installation, but it also blocks project-scoped raw skills when --skills-only is used.
The capabilities may need to be distinguished by delivery method, for
example:
Project-scoped plugin installation
Project-scoped raw-skill installation
For Codex, raw-skill project scope should be enabled with a project
configuration directory of .agents, producing:
<project>/.agents/skills
Environment
Databricks CLI v1.12.1
Codex CLI 0.147.0
Related issue
Related to #6037, which proposes installing skills into the
vendor-neutral .agents/skills directory. This report specifically
concerns --skills-only being rejected because Codex plugin and
raw-skill scope capabilities appear to be treated as one capability.
I looked into this and your diagnosis is right — but the fix is wider than the Codex registry entry, so I would rather agree on the shape before sending a PR.
Why the one-line fix does not work. Adding SupportsProjectScope: true + ProjectConfigDir: ".agents" to the Codex entry would also enable the plugin path, and codex plugin add has no project scope. The single field is read in ~12 branches across installer.go, update.go and uninstall.go (filterProjectAgents, incompatibleAgentNames, and the uninstall/update equivalents), and none of them distinguish delivery method — exactly the split you suggested.
Proposed shape. Replace Agent.SupportsProjectScope with two capabilities:
SupportsProjectSkills — raw skill files can be written under the project root
SupportsProjectPlugin — the agent's plugin can be installed project-scoped
Codex gets SupportsProjectSkills: true with ProjectConfigDir: ".agents", and no project plugin support. Claude Code, Pi, Gemini and Goose get both true, so their behaviour is unchanged.
The part that needs threading. The scope gating in installer.go runs on InstallOptions, which does not carry the skills-only flag today — skillsOnly currently stops at cmd/aitools/install.go (selectAgents, buildPlan, planItemFor). So filterProjectAgents cannot tell which capability to check. It needs either a new InstallOptions field or an extra parameter. I would add the field, since update.go and uninstall.go need the same information.
One design question I would rather you answer than guess at.<repo>/.agents/skills is not Codex-specific — this repository has its own .agents/{prompts,rules,skills} at the root, and other agents read that convention too. Installing there means the Databricks skills become visible to every agent honouring .agents, not just Codex, and aitools uninstall --scope project would remove a directory that is not exclusively ours. Is that acceptable, or would you want the project-scoped skills directory to stay namespaced per agent?
Happy to send the PR once you confirm the split and the .agents question. If you would rather keep SupportsProjectScope and add a narrower ProjectSkillsDir-only capability, that is fine too — I just want to avoid guessing at a public capability model that spans eight agents.
Codex should have SupportsProjectSkills: true, ProjectConfigDir: ".agents", and no project plugin support. Adding the delivery mode to InstallOptions gives the install path enough context to apply the correct capability, and update/uninstall can use the recorded delivery state when deciding which paths to manage.
.agents/skills should be treated as a shared discovery path, not a Codex owned directory.
The existing Databricks layout already provides a clean ownership boundary.
The entries in agent discovery directories can be per skill symlinks to the canonical Databricks files. Uninstall should only remove entries that it can verify are Databricks managed. It should never remove .agents/skills in its entirety or unrelated content.
I checked how skills.sh handles this. It uses .agents/skills/<skill> as canonical storage. During targeted uninstall, it scans the install paths of other currently detected agents and retains the canonical skill when another path still exists. This protects active symlinks, but skills.sh does not persist which agents each skill was installed for. As a result, its decisions depend on which agents are detected at uninstall time rather than the original installation intent.
From reading the current call order, I think hasRemainingSkillExposure is also effectively path based too. It appears to work when agents have distinct exposure paths pointing to the same canonical skill. After one exposure is removed, another path still exists. I do not think it preserves a shared exposure when multiple agents resolve to the same physical path. For example, if Codex and Cursor both use .agents/skills/databricks-core, targeted Codex uninstall appears to remove that entry first. The later check for Cursor would resolve to the same now missing path and therefore would not know that Cursor was another logical consumer.
This is where an explicit exposure state could be beneficial, although not sure if its worth the overhead.. Databricks can extend the existing .state.json with skill exposure records that associate each physical path with the agents for which it was installed.
With that record, targeted Codex uninstall removes codex from the agent list but keeps the shared symlink while cursor remains. This is information that cannot be recovered reliably from the filesystem because one symlink does not reveal how many agents requested it.
A targeted uninstall would then,
Remove the requested agent from the matching exposure record.
Remove the exposure when no recorded agents remain for that physical path.
Remove the canonical skill when it has no remaining exposures.
Update or remove the corresponding skill, file-provenance, and exposure records from .state.json.
The state records installation intent. Before removing an exposure, the CLI should verify that a symlink points into .databricks/aitools/skills, or that a copied directory still matches the existing file provenance records.
User modified or unrelated content should be preserved.
If a skill is removed from the upstream manifest, the same rules apply. Update can remove its managed exposures, canonical files, and state records when everything is still unmodified. If the skill or one of its exposures has been modified, it should be retained with a warning. This is consistent with the existing skillPrunable and exposureRemovable behavior.
There is one unavoidable case when agents share .agents/skills cannot be isolated from one another. If that exposure remains for another recorded agent, Codex can still discover it. That is inherent to the shared discovery path, but recording exposures in .state.json makes installation and cleanup behavior predictable.
My thought is to use with the capability split, use .agents/skills as the shared project path, retain canonical files under .databricks/aitools/skills, and track skill exposures in .state.json.
Thanks — agreed on the capability split, and that answers my .agents question.
Two corrections/observations after reading the code, so nobody rebuilds what is already there:
The canonical + exposure layout already exists.agents.CanonicalSkillsDir is already .databricks/aitools/skills (libs/aitools/agents/skills.go:17), agent skills dirs already hold symlinks into it, and exposureRemovable / cleanup.go already refuse to delete anything that is not a symlink into the canonical dir or a byte-identical copy. So the ownership boundary you describe is the current design, not something to add.
Your shared-path concern is real, but it is created by this change, not pre-existing.hasRemainingSkillExposure (libs/aitools/installer/uninstall.go:215) walks the registry and tests filepath.Join(agentDir, skillName) per agent. That works today only because every project-scoped agent has a distinct ProjectConfigDir (.claude, .pi, .gemini, .goose) — no two agents can collide. Pointing Codex at the shared .agents is the first time two agents could resolve to one physical path, and then removing it for one agent makes the check report "gone" for the other. Worth noting that function is itself one of the ~12 SupportsProjectScope call sites the split has to touch (line 221).
On scoping. I would rather not put the exposure-tracking redesign in the same PR as the bug fix — AGENTS.md asks for one change per PR, and .state.json is persisted user state, so changing its shape deserves its own review. My suggestion:
Capability split + Codex entry + delivery mode in InstallOptions. Fixes the reported bug.
Exposure records in .state.json, if maintainers want it.
But (1) alone makes Codex and Claude Code share .agents/skills only if a second agent is later pointed there — with just Codex on .agents, no collision exists yet, so (1) is safe to land on its own and (2) becomes required before any second agent moves to .agents.
We are both outside contributors, so our agreeing does not settle it. Could a maintainer confirm the split and whether Codex should use the shared .agents/skills at all? I have the (1)-shaped change ready to write once someone signs off.
Activity
TangoEnSkai commentedon Aug 18, 2026
I looked into this and your diagnosis is right — but the fix is wider than the Codex registry entry, so I would rather agree on the shape before sending a PR.
Why the one-line fix does not work. Adding
SupportsProjectScope: true+ProjectConfigDir: ".agents"to the Codex entry would also enable the plugin path, andcodex plugin addhas no project scope. The single field is read in ~12 branches acrossinstaller.go,update.goanduninstall.go(filterProjectAgents,incompatibleAgentNames, and the uninstall/update equivalents), and none of them distinguish delivery method — exactly the split you suggested.Proposed shape. Replace
Agent.SupportsProjectScopewith two capabilities:SupportsProjectSkills— raw skill files can be written under the project rootSupportsProjectPlugin— the agent's plugin can be installed project-scopedCodex gets
SupportsProjectSkills: truewithProjectConfigDir: ".agents", and no project plugin support. Claude Code, Pi, Gemini and Goose get bothtrue, so their behaviour is unchanged.The part that needs threading. The scope gating in
installer.goruns onInstallOptions, which does not carry the skills-only flag today —skillsOnlycurrently stops atcmd/aitools/install.go(selectAgents,buildPlan,planItemFor). SofilterProjectAgentscannot tell which capability to check. It needs either a newInstallOptionsfield or an extra parameter. I would add the field, sinceupdate.goanduninstall.goneed the same information.One design question I would rather you answer than guess at.
<repo>/.agents/skillsis not Codex-specific — this repository has its own.agents/{prompts,rules,skills}at the root, and other agents read that convention too. Installing there means the Databricks skills become visible to every agent honouring.agents, not just Codex, andaitools uninstall --scope projectwould remove a directory that is not exclusively ours. Is that acceptable, or would you want the project-scoped skills directory to stay namespaced per agent?Happy to send the PR once you confirm the split and the
.agentsquestion. If you would rather keepSupportsProjectScopeand add a narrowerProjectSkillsDir-only capability, that is fine too — I just want to avoid guessing at a public capability model that spans eight agents.rob7thousand commentedon Aug 19, 2026
I agree that the capability split is probably the right shape.
SupportsProjectSkillscontrols project-scoped skill delivery.SupportsProjectPlugincontrols project-scoped plugin installation.Codex should have
SupportsProjectSkills: true,ProjectConfigDir: ".agents", and no project plugin support. Adding the delivery mode toInstallOptionsgives the install path enough context to apply the correct capability, and update/uninstall can use the recorded delivery state when deciding which paths to manage..agents/skillsshould be treated as a shared discovery path, not a Codex owned directory.The existing Databricks layout already provides a clean ownership boundary.
The entries in agent discovery directories can be per skill symlinks to the canonical Databricks files. Uninstall should only remove entries that it can verify are Databricks managed. It should never remove
.agents/skillsin its entirety or unrelated content.I checked how skills.sh handles this. It uses
.agents/skills/<skill>as canonical storage. During targeted uninstall, it scans the install paths of other currently detected agents and retains the canonical skill when another path still exists. This protects active symlinks, but skills.sh does not persist which agents each skill was installed for. As a result, its decisions depend on which agents are detected at uninstall time rather than the original installation intent.From reading the current call order, I think
hasRemainingSkillExposureis also effectively path based too. It appears to work when agents have distinct exposure paths pointing to the same canonical skill. After one exposure is removed, another path still exists. I do not think it preserves a shared exposure when multiple agents resolve to the same physical path. For example, if Codex and Cursor both use.agents/skills/databricks-core, targeted Codex uninstall appears to remove that entry first. The later check for Cursor would resolve to the same now missing path and therefore would not know that Cursor was another logical consumer.This is where an explicit exposure state could be beneficial, although not sure if its worth the overhead.. Databricks can extend the existing
.state.jsonwith skill exposure records that associate each physical path with the agents for which it was installed.For example:
{ "skill_exposures": { "databricks-core": [ { "path": ".agents/skills/databricks-core", "agents": ["codex"] }, { "path": ".claude/skills/databricks-core", "agents": ["claude-code"] } ] } }When multiple agents resolve to the same physical path, they share the same exposure entry.
{ "path": ".agents/skills/databricks-core", "agents": ["codex", "cursor"] }With that record, targeted Codex uninstall removes
codexfrom the agent list but keeps the shared symlink whilecursorremains. This is information that cannot be recovered reliably from the filesystem because one symlink does not reveal how many agents requested it.A targeted uninstall would then,
.state.json.The state records installation intent. Before removing an exposure, the CLI should verify that a symlink points into
.databricks/aitools/skills, or that a copied directory still matches the existing file provenance records.User modified or unrelated content should be preserved.
If a skill is removed from the upstream manifest, the same rules apply. Update can remove its managed exposures, canonical files, and state records when everything is still unmodified. If the skill or one of its exposures has been modified, it should be retained with a warning. This is consistent with the existing
skillPrunableandexposureRemovablebehavior.There is one unavoidable case when agents share
.agents/skillscannot be isolated from one another. If that exposure remains for another recorded agent, Codex can still discover it. That is inherent to the shared discovery path, but recording exposures in.state.jsonmakes installation and cleanup behavior predictable.My thought is to use with the capability split, use
.agents/skillsas the shared project path, retain canonical files under.databricks/aitools/skills, and track skill exposures in.state.json.TangoEnSkai commentedon Aug 22, 2026
Thanks — agreed on the capability split, and that answers my
.agentsquestion.Two corrections/observations after reading the code, so nobody rebuilds what is already there:
The canonical + exposure layout already exists.
agents.CanonicalSkillsDiris already.databricks/aitools/skills(libs/aitools/agents/skills.go:17), agent skills dirs already hold symlinks into it, andexposureRemovable/cleanup.goalready refuse to delete anything that is not a symlink into the canonical dir or a byte-identical copy. So the ownership boundary you describe is the current design, not something to add.Your shared-path concern is real, but it is created by this change, not pre-existing.
hasRemainingSkillExposure(libs/aitools/installer/uninstall.go:215) walks the registry and testsfilepath.Join(agentDir, skillName)per agent. That works today only because every project-scoped agent has a distinctProjectConfigDir(.claude,.pi,.gemini,.goose) — no two agents can collide. Pointing Codex at the shared.agentsis the first time two agents could resolve to one physical path, and then removing it for one agent makes the check report "gone" for the other. Worth noting that function is itself one of the ~12SupportsProjectScopecall sites the split has to touch (line 221).On scoping. I would rather not put the exposure-tracking redesign in the same PR as the bug fix —
AGENTS.mdasks for one change per PR, and.state.jsonis persisted user state, so changing its shape deserves its own review. My suggestion:InstallOptions. Fixes the reported bug..state.json, if maintainers want it.But (1) alone makes Codex and Claude Code share
.agents/skillsonly if a second agent is later pointed there — with just Codex on.agents, no collision exists yet, so (1) is safe to land on its own and (2) becomes required before any second agent moves to.agents.We are both outside contributors, so our agreeing does not settle it. Could a maintainer confirm the split and whether Codex should use the shared
.agents/skillsat all? I have the (1)-shaped change ready to write once someone signs off.github-actions commentedon Oct 21, 2026
This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.