# How to Create and Use Custom Agents with Tool Restrictions and Model Overrides in Claudian

> Learn to create and use custom Claudian agents with tool restrictions and model overrides. Define agent behavior using Markdown files and YAML front-matter for precise control.

- Repository: [YishenTu/claudian](https://github.com/YishenTu/claudian)
- Tags: how-to-guide
- Published: 2026-03-17

---

**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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/src/core/storage/AgentVaultStorage.ts) handles persistence, writing files to `.claude/agents/<name>.md`
2. **Serialization**: [`src/utils/agent.ts`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/src/utils/agent.ts), the following fields control tool access:

```yaml
---
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:

```typescript
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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/src/utils/claudeCli.ts), the system calls `normalizeVisibleModelVariant` from [`src/core/types/models.ts`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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` |

3. **Add the System Prompt**: "You are a concise web summarizer. Fetch the target URL, extract key points, and provide a 3-bullet summary."

4. **Save the Agent**: The file writes to [`.claude/agents/web-summarizer.md`](https://github.com/YishenTu/claudian/blob/main/.claude/agents/web-summarizer.md) with this exact content:

```markdown
---
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:

```yaml
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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/src/features/settings/ui/AgentSettings.ts).