How to Create and Use Custom Agents with Tool Restrictions and Model Overrides in Claudian
Claudian allows you to create custom agents as Markdown files with YAML front-matter that whitelist specific tools, blacklist others, and override the default Claude model, with restrictions enforced by the ApprovalManager at runtime.
Claudian, an open-source Obsidian plugin available at YishenTu/claudian, enables granular control over LLM behavior through custom agent definitions. These agents are stored as Markdown files in your vault and allow precise tool restrictions and model overrides. By configuring the AgentDefinition interface in src/core/types/agent.ts, you can constrain which actions the Claude SDK may perform and specify exactly which model variant handles each conversation.
Understanding Claudian's Agent Architecture
Claudian's agent system centers on the AgentDefinition interface defined in src/core/types/agent.ts. Each agent is a Markdown file containing YAML front-matter that describes its capabilities and constraints. The architecture follows a clear serialization and enforcement pipeline:
- Storage:
AgentVaultStorageinsrc/core/storage/AgentVaultStorage.tshandles persistence, writing files to.claude/agents/<name>.md - Serialization:
src/utils/agent.tsprovidesserializeAgentandparseAgentFileto convert betweenAgentDefinitionobjects and Markdown format - Permission Enforcement:
ApprovalManagerinsrc/core/security/ApprovalManager.tsvalidates tool calls against agent-specific allow/deny lists usingmatchesRulePatternandbuildPermissionUpdates - Model Resolution:
src/core/types/models.tsexportsnormalizeVisibleModelVariantto resolve agent-specific model overrides
Creating a Custom Agent with Tool Restrictions
Front-Matter Structure
Agent capabilities are defined in YAML front-matter between triple dashes. According to the AgentDefinition interface and serialization logic in src/utils/agent.ts, the following fields control tool access:
---
name: web-summarizer
description: Summarizes web articles safely
tools: [Read, Write, WebFetch] # whitelist - only these tools allowed
disallowedTools: [Bash, Grep] # blacklist - removed from inherited set
model: sonnet # overrides global model setting
permissionMode: acceptEdits # controls UI approval behavior
skills: [summarize] # passed directly to Claude SDK
hooks: {} # optional SDK hook configuration
---
Your custom system prompt goes here...
Key fields include:
tools: An explicit whitelist. If omitted, the agent inherits all tools from the global configuration or parent agent.disallowedTools: A blacklist that removes specific tools from the inherited set, useful for creating restricted variants of broad-capability agents.model: Accepts concrete values likesonnet,opus, orhaiku, orinheritto use the parent model.
File Location and Format
AgentVaultStorage.save writes agent files to <vault>/.claude/agents/<name>.md. When serializeAgent processes an AgentDefinition, it constructs the YAML block programmatically:
export function serializeAgent(agent: AgentDefinition): string {
const lines = ['---'];
lines.push(`name: ${agent.name}`);
lines.push(`description: ${yamlString(agent.description)}`);
pushYamlList(lines, 'tools', agent.tools);
pushYamlList(lines, 'disallowedTools', agent.disallowedTools);
if (agent.model && agent.model !== 'inherit') lines.push(`model: ${agent.model}`);
if (agent.permissionMode) lines.push(`permissionMode: ${agent.permissionMode}`);
pushYamlList(lines, 'skills', agent.skills);
if (agent.hooks !== undefined) lines.push(`hooks: ${JSON.stringify(agent.hooks)}`);
lines.push('---');
lines.push(agent.prompt);
return lines.join('\n');
}
The parseAgentFile function reverses this process, extracting the YAML front-matter and body to build an AgentDefinition via buildAgentFromFrontmatter.
Implementing Model Overrides
When an agent specifies a model field, the runtime overrides the global model selection. The UI in src/features/settings/ui/AgentSettings.ts presents a dropdown of valid choices: inherit, sonnet, opus, or haiku.
At execution time in src/utils/claudeCli.ts, the system calls normalizeVisibleModelVariant from src/core/types/models.ts to resolve the agent's model preference. This function maps the string identifier to the correct Claude SDK model configuration, respecting user flags like "enable 1M context" while prioritizing the agent-specific override over global settings.
Enforcing Tool Restrictions and Permissions
Permission Modes
The AGENT_PERMISSION_MODES constant in src/utils/agent.ts defines how the UI handles tool approval:
default: Standard permission prompts for each tool useacceptEdits: Automatically approves file modification tools (Write,Edit,NotebookEdit) but prompts for othersdontAsk: Silently approves all whitelisted toolsbypassPermissions: Skips all permission dialogs entirelyplan: Requires explicit plan approval before executiondelegate: Delegates permission decisions to a parent agent
Set the mode in front-matter: permissionMode: acceptEdits.
How ApprovalManager Enforces Rules
When the Claude SDK proposes a tool call, ApprovalManager validates it against the agent's restrictions:
- Pattern Extraction:
getActionPatternextracts identifiers like file paths from tool inputs - Rule Matching:
matchesRulePatterncompares the pattern against allowed tools, supporting:- Exact matches or wildcards for
Bashcommands (e.g.,git *,npm:*) - Path-prefix matching for file tools (
Read,Write,Edit) - Simple prefix matching for other tools
- Exact matches or wildcards for
- Permission Updates: If the user chooses "allow always",
buildPermissionUpdatescreatesaddRulesentries in the session or project settings
An agent with tools: [Read, WebFetch] will have all Bash, Write, and other non-whitelisted calls blocked by this validation layer.
Practical Example: Building a Web Summarizer Agent
Follow these steps to create a restricted agent for web content analysis:
-
Navigate to Agent Settings: Open Settings → "Sub-agents" → Click +
-
Configure the Definition:
| Field | Value |
|---|---|
| Name | web-summarizer |
| Description | Fetches and summarizes web content safely |
| Model | opus |
| Tools | WebFetch, Read |
| Disallowed Tools | Bash, Grep, Write |
| Permission Mode | acceptEdits |
-
Add the System Prompt: "You are a concise web summarizer. Fetch the target URL, extract key points, and provide a 3-bullet summary."
-
Save the Agent: The file writes to
.claude/agents/web-summarizer.mdwith this exact content:
---
name: web-summarizer
description: Fetches and summarizes web content safely
tools:
- WebFetch
- Read
disallowedTools:
- Bash
- Grep
- Write
model: opus
permissionMode: acceptEdits
---
You are a concise web summarizer. Fetch the target URL, extract key points, and provide a 3-bullet summary.
When selected, this agent runs exclusively on the opus model and cannot execute shell commands or modify files, regardless of the global tool configuration.
Advanced Configuration Techniques
Dynamic Tool Inheritance: Omit the tools field entirely to inherit the global whitelist, then use disallowedTools to prune only unsafe operations. This creates "global minus X" agents without maintaining full tool lists.
Custom SDK Hooks: Include a hooks object in front-matter to pass arbitrary configuration to the Claude SDK:
hooks: { "onMessage": "customHandler", "preProcess": "validateInput" }
Extra Front-Matter: Any unrecognized keys (e.g., customPriority: high) are stored in AgentDefinition.extraFrontmatter and round-tripped through serializeAgent, allowing plugins to extend agent metadata without breaking core functionality.
Programmatic Creation: Use AgentVaultStorage.save(agent) directly from plugin scripts, passing a fully formed AgentDefinition object to bypass the UI entirely.
Summary
- Custom agents in Claudian are Markdown files stored in
.claude/agents/with YAML front-matter defining capabilities - Tool restrictions use
tools(whitelist) anddisallowedTools(blacklist) fields, enforced at runtime byApprovalManagerviamatchesRulePatternandbuildPermissionUpdates - Model overrides specify
sonnet,opus,haiku, orinheritin themodelfield, processed bynormalizeVisibleModelVariantinsrc/core/types/models.ts - Permission modes (
acceptEdits,bypassPermissions, etc.) control UI approval behavior without modifying tool lists - Serialization logic in
src/utils/agent.tshandles conversion betweenAgentDefinitionobjects and Markdown viaserializeAgentandparseAgentFile
Frequently Asked Questions
How do I prevent an agent from executing shell commands?
Add Bash to the disallowedTools array in the agent's front-matter, or omit Bash from the tools whitelist. The ApprovalManager in src/core/security/ApprovalManager.ts validates all tool calls against these lists and will block unauthorized Bash execution attempts.
Can I override the model for a specific agent while keeping the global default for others?
Yes. Set the model field in the agent's front-matter to a concrete value like sonnet or opus. According to src/core/types/models.ts, the runtime resolves this via normalizeVisibleModelVariant, which prioritizes the agent-specific model over the global configuration unless the value is inherit.
What happens if I specify both tools and disallowedTools?
The system first applies the tools whitelist to determine the available set, then removes any tools listed in disallowedTools. If you omit tools entirely, the agent inherits all global tools, and disallowedTools acts as a subtraction filter—useful for creating slightly restricted versions of powerful agents.
How do I create an agent programmatically without using the UI?
Import AgentVaultStorage from src/core/storage/AgentVaultStorage.ts and call storage.save(agent) with a complete AgentDefinition object. This writes the serialized Markdown file directly to .claude/agents/, bypassing the AgentModal interface in src/features/settings/ui/AgentSettings.ts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →