Skip to content

fix(opencode): update skill handling in context and permissions - #29738

Closed
OpeOginni wants to merge 3 commits into
anomalyco:devfrom
OpeOginni:fix/skill-permissions
Closed

OpeOginni wants to merge 3 commits into
anomalyco:devfrom
OpeOginni:fix/skill-permissions

Conversation

@OpeOginni

@OpeOginni OpeOginni commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #29727
Closes #21793

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

  • Filter /skills list by permissions: The app.skills HTTP endpoint now calls skill.available(defaultAgent) instead of skill.all(), so the /skills slash command only shows skills the current agent is allowed to use.

  • Hide the skill tool when globally disabled: ToolRegistry.tools() now checks Permission.disabled(["skill"], ...) and excludes the skill tool entirely when skill: "deny" or skill: { "*": "deny" } is configured, preventing the model from seeing or calling it.

  • Check permission before loading skill content: In the skill tool executor, ctx.ask() now runs before skill.require(). This ensures the permission gate is evaluated before reading the skill from the in-memory store.

How did you verify your code works?

  • Tested with a simple config that has the following permissions object
  "permission": {
    "skill": {
      "manager": "deny",
      "tester-*": "deny"
    }
  }

Now the skill doesnt show up in the registry, the model doesnt have knowledge of the skill from initial prompt, even when forced to use that skill, it gets denyed use of the skill.

Screenshots / recordings

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

One caveat: The /skills HTTP endpoint uses the default agent, not the currently active session agent, because the endpoint is instance-level and doesn't receive agent/session context. So if you switch to a subagent with stricter skill permissions, the /skills dialog might still show skills allowed for the default agent. But when that subagent actually runs, its own permissions will filter the tool description and block execution.

@kapilratnani

Copy link
Copy Markdown

I think this fix is needed. In the current version the permission.skill just doesn't work. I can see the denied skills as well as they can be triggered.

I am working on building this project https://github.com/kapilratnani/aienv to create isolated and task specific AI environments. With claude-code i am able to restrict the skills and mcp to the one selected while with OpenCode only mcp works.

If permissions is not the way what should we do ?

@OpeOginni

Copy link
Copy Markdown
Contributor Author

@kapilratnani Saw your other comment on the other issue.

I think the /skills command doesnt let the Agent load the skills on its own, it adds thw whole skill to the context, im thining that is more of a manual/deliberate action from the user forcing the skill text in the context.

But in the case of the agent "loading" the skill that seems to still work, if it doesnt for you lease share your config and maybe an example of the skill you are trying to deny and I can check it out and try to repod on my end

@kapilratnani

Copy link
Copy Markdown

i am using this config

{
  "$schema": "https://opencode.ai/config.json",
  "model": "claude-sonnet-4-5",
  "mcp": {
    "docker": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "@docker/mcp-server"
      ]
    },
    "github": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "@modelcontextprotocol/server-github"
      ],
      "env": {
        "GITHUB_TOKEN": "env:GITHUB_TOKEN"
      }
    },
    "postgres": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "@modelcontextprotocol/server-postgres",
        "postgresql://localhost/mydb"
      ]
    }
  },
  "instructions": [
  ],
  "permission": {
    "skill": {
      "*": "deny",
      "tdd": "allow",
      "vercel-react-best-practices": "allow"
    }
  }
}

I tried to trigger a grill-me skill which is installed globally.
Prompt : "start a grill me session" - did not trigger
Prompt : "/grill-me on this project" - Trigger.

Then i modified the config to allow the grill-me skill:

  "permission": {
    "skill": {
      "*": "deny",
     "grill-me": "allow", 
     "tdd": "allow",
      "vercel-react-best-practices": "allow"
    }
  }

Prompt : "start a grill me session" - skill loaded.

@OpeOginni

Copy link
Copy Markdown
Contributor Author

@kapilratnani This is what i get from you

  • Prompt : "start a grill me session" - did not trigger: This means the deny worked
  • Prompt : "/grill-me on this project" - Trigger: This is because when using /skill and specifing the skll exactly it adds the whole md into context, the model doesnt "load" it beacuse you already added it to the prompt, so like i said before its you manually forcing the skill in the context.

Second Case

  • Prompt : "start a grill me session" - skill loaded.: The skill loaded normally since its allowed now.

Hope you understand now. So there isnt any issue with the permissions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Permissions for skill not working as expected bug: permission.skill pattern rules are not fully enforced in skill exposure flow

2 participants