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:

  1. Storage: AgentVaultStorage in src/core/storage/AgentVaultStorage.ts handles persistence, writing files to .claude/agents/<name>.md
  2. Serialization: src/utils/agent.ts provides serializeAgent and parseAgentFile to convert between AgentDefinition objects and Markdown format
  3. Permission Enforcement: ApprovalManager in src/core/security/ApprovalManager.ts validates tool calls against agent-specific allow/deny lists using matchesRulePattern and buildPermissionUpdates
  4. Model Resolution: src/core/types/models.ts exports normalizeVisibleModelVariant to 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 like sonnet, opus, or haiku, or inherit to 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 use
  • acceptEdits: Automatically approves file modification tools (Write, Edit, NotebookEdit) but prompts for others
  • dontAsk: Silently approves all whitelisted tools
  • bypassPermissions: Skips all permission dialogs entirely
  • plan: Requires explicit plan approval before execution
  • delegate: 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:

  1. Pattern Extraction: getActionPattern extracts identifiers like file paths from tool inputs
  2. Rule Matching: matchesRulePattern compares the pattern against allowed tools, supporting:
    • Exact matches or wildcards for Bash commands (e.g., git *, npm:*)
    • Path-prefix matching for file tools (Read, Write, Edit)
    • Simple prefix matching for other tools
  3. Permission Updates: If the user chooses "allow always", buildPermissionUpdates creates addRules entries 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:

  1. Navigate to Agent Settings: Open Settings → "Sub-agents" → Click +

  2. 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
  1. Add the System Prompt: "You are a concise web summarizer. Fetch the target URL, extract key points, and provide a 3-bullet summary."

  2. Save the Agent: The file writes to .claude/agents/web-summarizer.md with 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) and disallowedTools (blacklist) fields, enforced at runtime by ApprovalManager via matchesRulePattern and buildPermissionUpdates
  • Model overrides specify sonnet, opus, haiku, or inherit in the model field, processed by normalizeVisibleModelVariant in src/core/types/models.ts
  • Permission modes (acceptEdits, bypassPermissions, etc.) control UI approval behavior without modifying tool lists
  • Serialization logic in src/utils/agent.ts handles conversion between AgentDefinition objects and Markdown via serializeAgent and parseAgentFile

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →