The tool filtering system in SuperCode/OpenCode provides fine-grained control over which tools are available during AI agent execution. This allows you to restrict or expand tool access based on security requirements, specific workflows, or custom configurations.
The system uses a hierarchical configuration approach with four levels of control:
- Agent Configuration - Base tool configuration from agent definitions
- Command Configuration - Tool overrides from custom commands
- Flag Configuration - Tool modifications from flags
- Input Configuration - Direct user overrides (highest precedence)
Input > Flags > Commands > Agent
Higher precedence levels can override or modify lower levels.
Agents define their base tool configuration in opencode.json or through the agent system:
{
"agent": {
"my-agent": {
"tools": {
"read": true,
"write": true,
"bash": false
},
"allowedTools": ["grep", "glob"],
"denyTools": ["patch"]
}
}
}Fields:
tools: Explicit tool enable/disable configurationallowedTools: Additional tools to enable (additive)denyTools: Tools to explicitly disable (subtractive)
Custom commands in .opencode/commands/ can specify tool configurations in their YAML frontmatter:
---
description: Security audit command
allowed-tools: read, grep, glob
deny-tools: write, bash, edit
---
Perform a security audit...Behavior: Commands with allowed-tools create a restrictive allowlist - ONLY the specified tools are enabled.
Flags in .opencode/flags/ can modify tool availability through their frontmatter:
---
description: Safe mode flag
allowed-tools: read, grep
deny-tools: write, edit, bash
placement: before
---
Enable safe mode with restricted tool access...Flag Modes:
- Additive Mode: Only
allowed-toolsspecified → adds tools to existing configuration - Restrictive Mode:
deny-tools: "*"withallowed-tools→ ONLY allows specified tools - Subtractive Mode: Specific
deny-tools→ removes specific tools from existing configuration
Direct tool configuration can be passed programmatically (primarily for internal use):
const input = {
tools: {
read: true,
write: false
}
}When only allowedTools is specified, tools are ADDED to the existing configuration:
# Flag or Agent config
allowed-tools: bash, grepResult: Existing tools remain enabled, bash and grep are added.
When denyTools: ["*"] is combined with allowedTools, ONLY the allowed tools are enabled:
# Flag config
deny-tools: "*"
allowed-tools: read, grepResult: Only read and grep are enabled, all others are disabled.
When specific tools are listed in denyTools, they are removed from the configuration:
# Flag or Agent config
deny-tools: write, bashResult: write and bash are disabled, other tools remain as configured.
Create a flag .opencode/flags/readonly.md:
---
description: Read-only mode for safe operations
deny-tools: write, edit, multiedit, patch, bash
allowed-tools: read, grep, glob, ls
---
Restricts to read-only operations for safety.Usage: --readonly Analyze this codebase
Create a command .opencode/commands/dev.md:
---
description: Full development access
allowed-tools:
- read
- write
- edit
- multiedit
- bash
- grep
- glob
deny-tools: []
---
Full development access with all tools enabled.Usage: /dev implement this feature
Create an agent configuration:
{
"agent": {
"security": {
"tools": {
"read": true,
"grep": true,
"glob": true
},
"allowedTools": ["ls"],
"denyTools": ["write", "edit", "bash", "patch"]
}
}
}.opencode/
├── flags/
│ ├── safe-mode.md # Flag with tool restrictions
│ └── verbose.md # Flag without tool config
├── commands/
│ ├── security.md # Command with tool config
│ └── analyze.md # Regular command
└── agents/
└── custom-agent.json # Agent configurations
Both flags and commands use YAML frontmatter with consistent fields:
---
# For flags (uses camelCase internally after parsing)
allowed-tools: tool1, tool2, tool3
deny-tools: tool4, tool5
# For commands (uses hyphenated keys)
allowed-tools:
- tool1
- tool2
deny-tools: tool3, tool4
# Both support string or array format
---Available tools include:
read- Read fileswrite- Write filesedit- Edit filesmultiedit- Multiple editspatch- Apply patchesbash- Execute bash commandsgrep- Search in filesglob- File pattern matchingls- List directorieswebfetch- Fetch web resourcestodoread- Read todo items (always allowed)todowrite- Write todo items (always allowed)
Some tools are ALWAYS allowed regardless of configuration:
todoreadtodowrite
These ensure basic task management functionality is always available.
-
flags/flags.ts- Uses
gray-matterfor YAML parsing - Converts hyphenated keys to camelCase
extractFlagToolConfig()extracts tool configurations
- Uses
-
commands/custom.ts- Uses
gray-matterfor YAML parsing - Maintains hyphenated keys
executeCommand()returns tool configurations
- Uses
-
agent/agent.ts- Extended schema with
allowedToolsanddenyTools - Loads configurations from files
- Extended schema with
-
tool/filter.tsresolveToolConfig()- Combines all configurationsisToolEnabled()- Checks if a tool is allowed- Handles precedence and mode logic
-
session/index.ts- Builds complete tool configuration
- Applies filtering during tool registration
// Simplified resolution logic
function resolveToolConfig(config) {
// 1. Start with agent base configuration
let result = { ...agent.tools, ...agent.allowedTools }
// 2. Apply agent deny list
for (tool of agent.denyTools) {
result[tool] = false
}
// 3. If command has allowedTools, replace with restrictive set
if (command?.allowedTools) {
result = onlyThese(command.allowedTools)
}
// 4. Apply flag modifications based on mode
if (flags?.denyTools?.includes("*")) {
// Restrictive mode
result = onlyThese(flags.allowedTools)
} else if (flags?.allowedTools) {
// Additive mode
result = { ...result, ...toEnabled(flags.allowedTools) }
}
// 5. Apply flag deny list
for (tool of flags?.denyTools || []) {
result[tool] = false
}
// 6. Input overrides everything
if (input) {
result = { ...result, ...input }
}
return result
}-
Use Flags for Temporary Restrictions
- Create flags for temporary safety modes
- Apply restrictions during sensitive operations
-
Use Commands for Workflow-Specific Tools
- Define command-specific tool sets
- Ensure commands have appropriate access
-
Configure Agents for Base Behavior
- Set reasonable defaults in agent configuration
- Use agent-level restrictions for security
-
Test Tool Configurations
- Verify tool availability with test commands
- Check that restrictions work as expected
- Check if a command is overriding with
allowed-tools - Verify no flags are applying
deny-tools: "*" - Check agent configuration for base restrictions
- Ensure flag/command files have correct frontmatter format
- Verify the flag/command is being triggered
- Check precedence - input overrides everything
To debug tool filtering:
- Check
input.flagToolsandinput.commandToolsin session - Verify
agent.allowedToolsandagent.denyToolsare populated - Use
ToolFilter.resolveToolConfig()to see resolution - Test with
ToolFilter.isToolEnabled()for specific tools
- Default Deny Strategy: Consider using restrictive mode for sensitive operations
- Audit Tool Access: Regularly review which tools are available
- Principle of Least Privilege: Only enable tools necessary for the task
- Command Isolation: Use commands to isolate different security contexts
If upgrading from an older version:
- Update flag files to use
allowed-toolsanddeny-tools(hyphenated) - Update command files similarly
- Agent configurations now support
allowedToolsanddenyToolsarrays - The system now uses
gray-matterfor robust YAML parsing