Skip to main content
ChatCLI lets you create Customizable Agents (also called Personas) that define specific behaviors for the AI. This system transforms ChatCLI from a tool with a static “System Prompt” into a polymorphic platform.

Core Concept

The central idea is prompt composition:
  • Agents define “who” the AI is (personality, specialization, tone).
  • Skills define “what” it must know/obey (rules, knowledge, compliance).
An Agent can import multiple Skills, creating a “Super System Prompt” composed automatically. Both Skills and Agents support per-turn model and effort preferences, honored automatically by the dispatcher when they activate.

Benefits

Reuse

Skills can be shared across multiple agents.

Versioning

.md files can be versioned in Git.

Collaboration

Teams can share agents and skills.

Consistency

Coding style rules applied automatically.

Specialization

Create agents for Go, Python, DevOps, etc.

Dispatch as Worker

Custom agents are automatically registered in the multi-agent system and can be dispatched via agent_call by the LLM orchestrator.

Skill Auto-activation

Skills with triggers: or paths: in their frontmatter are automatically injected into the system prompt when detected in the user’s message.

Per-Agent Model & Effort

Each skill and each agent can declare ideal model: and effort: — the dispatcher routes correctly without changing the user’s active choice.

Directory Structure

Files live under ~/.chatcli/:
~/.chatcli/
|-- agents/            # Agent files
|   |-- go-expert.md
|   |-- devops-senior.md
|   |-- security-auditor.md
|   +-- python-data-scientist.md
+-- skills/            # Skill files (.md or V2 directories)
    |-- clean-code/    # Skill V2 (package with subskills + scripts)
    |   |-- SKILL.md
    |   |-- naming-rules.md
    |   +-- scripts/
    |       +-- lint_check.py
    |-- error-handling.md  # Skill V1 (single file)
    |-- docker-master.md
    +-- clean-scripts.md

Agent File Format

Agents are Markdown files with YAML frontmatter:
---
name: "devops-senior"
description: "Senior DevOps focused on CI/CD and infrastructure"
tools: Read, Grep, Glob, Bash, Write, Edit   # Tools this agent can use as worker
skills:                    # Skills to import
  - clean-code
  - bash-linux
  - architecture
plugins:                   # Enabled plugins (optional)
  - "@coder"

# LLM preferences (optional) — applied when this agent runs as a worker
model: "claude-opus-4-6"   # Ideal model; transparent swap if user is on another
effort: "high"             # low | medium | high | max

# Optional metadata
category: "devops"
version: "2.1.0"
author: "Edilson Freitas"
tags: devops, cicd, k8s
---
# Base Personality

You are a Senior DevOps Engineer, expert in CI/CD, containers,
infrastructure as code, and observability.

tools Field — Multi-Agent Integration

The tools field in the YAML frontmatter is the key to integration with the multi-agent orchestration system. It defines which commands the agent can use when dispatched as a worker by the LLM orchestrator.
Tool in YAML@coder Command(s)Description
ReadreadRead file contents
GrepsearchSearch patterns in files
GlobtreeList directories
Bashexec, test, git-status, git-diff, git-log, git-changed, git-branchCommand execution and git operations
WritewriteCreate/overwrite files
EditpatchPrecise edits (search/replace)
MultiEditmultipatchTransactional multi-file edit with all-or-nothing rollback
Agents without a tools field automatically receive read, search, tree and are marked as read-only. Agents with Write, Edit, MultiEdit, or Bash have write/execution access. The 12 built-in agent names (file, coder, shell, git, search, planner, reviewer, tester, refactor, diagnostics, formatter, deps) are protected and cannot be overridden.

Example without tools

---
name: "go-expert"
description: "Go/Golang expert focused on clean code"
skills:
  - clean-code
  - error-handling
plugins:
  - "@coder"
---
# Base Personality

You are a Senior Software Engineer, expert in Go/Golang.

## Core Principles

1. **Simplicity**: Prefer simple, readable code.
2. **Composition**: Use small interfaces and composition over inheritance.
3. **Errors**: Handle errors explicitly, never ignore.
4. **Tests**: Write table-driven tests.
This agent will be registered as read-only in the multi-agent system (only read, search, tree).

Advanced Agent Frontmatter

Recent releases bring full parity between agents and skills for LLM preference fields. Both are optional and backwards compatible — agents without these fields keep working exactly as before.
FieldTypeDefaultDescription
modelstringPreferred model when this agent runs as a worker. If the user is on a different model/provider, the dispatcher attempts a transparent swap (same provider → catalog → family; cross-provider when available).
effortstringEffort level: low, medium, high, max. Maps to extended thinking (Anthropic) / reasoning_effort (OpenAI) on supported providers.
categorystringCategory for organization (e.g., devops, security, review).
versionstringAgent version (SemVer recommended).
authorstringAgent author.
tagslist|stringTags for search and classification. Accepts YAML list or comma-separated string.

How the Dispatcher Applies Model/Effort

When the orchestrator LLM dispatches an agent via <agent_call>, the dispatcher:
1

Reads `agent.Model()` and `agent.Effort()`

For custom agents these come from the frontmatter. For built-ins they come from BuiltinAgentMeta (defaults + env var override).
2

If `Model()` is non-empty, runs the Model Router

The resolver tries, in order: API cache of the active provider → static catalog → family heuristic (claude-*, gpt-*, gemini-*, etc.) → optimistic fallback on the user’s provider. If the target provider is not configured (no API key), it gracefully falls back to the user’s client and logs a clear warning.
3

If `Effort()` is non-empty, attaches to the worker `ctx`

Providers read the hint via client.EffortFromContext(ctx) inside SendPrompt and inject thinking.budget_tokens (Anthropic) or reasoning.effort / reasoning_effort (OpenAI) into the request body — only on models that support it.
4

`cli.Client`, `cli.Provider` and `cli.Model` are **not** mutated

Swaps are worker-turn scoped. When the worker finishes, the next agent dispatch or chat turn uses the user’s original choice.

Example: Custom Agent with Ideal Model

---
name: "my-strict-reviewer"
description: "Critical reviewer focused on subtle bugs and design issues"
tools: Read, Grep, Glob
skills:
  - go-testing
  - golangci
model: "claude-opus-4-6"   # always runs in Opus, even if user is on Sonnet
effort: "high"             # enables extended thinking
category: "review"
version: "1.0.0"
author: "Edilson Freitas"
---
# Personality

You are an extremely strict reviewer. Focus on subtle bugs, design issues,
SOLID violations, and high-cyclomatic-complexity hotspots. Avoid nit-picky
formatting comments.
If the user has CLAUDEAI configured but is on claude-sonnet-4-6, this agent runs in claude-opus-4-6 automatically. If the user is on OPENAI with gpt-5 and does not have ANTHROPIC_API_KEY, the dispatcher falls back gracefully to the user’s model and prints a clear notice explaining why.

Skill File Format

Skills contain pure knowledge or compliance rules:
---
name: "clean-code"
description: "Clean Code principles and best practices"
---
# Clean Code Rules

## Naming

1. **Meaningful names**: Variables and functions must reveal their purpose.
2. **Avoid misinformation**: Do not use names that may confuse.
3. **Pronounceable names**: Use names that can be discussed verbally.

## Functions

1. **Small**: Functions should do one thing only.
2. **Few arguments**: Ideally 0–2 arguments, max 3.
3. **No side effects**: Functions should do only what they promise.

Skills V2 — Packages with Subskills and Scripts

Beyond V1 skills (single .md file), ChatCLI supports V2 Skills: directories with multiple documents and executable scripts.

V2 Skill Structure

skills/
+-- clean-code/
    |-- SKILL.md            # Main content (frontmatter + body)
    |-- naming-rules.md     # Subskill: naming rules
    |-- formatting.md       # Subskill: formatting rules
    +-- scripts/
        +-- lint_check.py   # Executable script

Subskills

.md files inside the skill directory (except SKILL.md) are registered as subskills. When the agent is dispatched as a worker, subskill paths appear in the worker’s system prompt, which can read them as needed.

Scripts

Files in scripts/ are registered as executable skills on the worker. The system automatically infers the run command from the extension:
ExtensionInferred Command
.shbash script.sh
.pypython3 script.py
.jsnode script.js
.tsnpx ts-node script.ts
.rbruby script.rb
Others./script (direct execution)
Scripts run via the @coder exec command and their results return to the worker.

Advanced Skill Frontmatter

Beyond the basic fields (name, description, allowed-tools), skills support advanced frontmatter for fine-grained behavior control. All advanced fields are optional and backwards compatible — existing skills keep working unchanged.
---
name: "go-testing"
description: "Go testing patterns and best practices"
allowed-tools: Read, Grep, Glob, Bash

# LLM preferences (propagated to the turn that activates the skill)
model: "sonnet"                        # Preferred model
effort: "high"                         # Effort level: low, medium, high, max

# Metadata
category: "testing"
version: "1.2.0"
author: "Edilson Freitas"
tags: testing, go, unit-tests, tdd

# Automatic activation
triggers: test, testing, tdd, unittest # Keywords that auto-activate
paths: ["*_test.go", "test/**"]        # Globs that auto-activate per-file

# Invocation control
user-invocable: true                   # Can be invoked via /skill-name
disable-model-invocation: false        # If true, manual-only
argument-hint: "<package>"             # Hint shown in autocomplete
---

## Go Testing Patterns
...

Automatic Activation: triggers

Keywords that activate the skill automatically when detected in the user message. Case-insensitive, substring match.
triggers: test, testing, tdd
If the user types “how do I write tests for this handler?”, the skill is automatically injected into the turn’s system prompt — together with the descriptive and full content of the skill. The LLM then follows the instructions automatically. Implemented in pkg/persona/manager.go#FindTriggeredSkills. Detection runs on every chat turn and once at the start of agent/coder mode.

Automatic Activation: paths

File globs that activate the skill when matching files are being discussed. Supports *, ** (recursive doublestar), and ?.
paths: ["*_test.go", "test/**", "src/**/*.ts"]
ChatCLI extracts file-path-looking tokens from the user input (@file path/..., @path/to/file.go, or bare tokens like pkg/foo/bar_test.go and main.go) and matches each against the paths: patterns of every installed skill. Examples that trigger *_test.go:
  • "run the tests in pkg/foo/bar_test.go"
  • "@file pkg/foo/bar_test.go"
  • "@pkg/foo/bar_test.go"
Implemented in pkg/persona/types.go#MatchesPath (with a custom doublestar matcher, zero external deps) and pkg/persona/manager.go#FindPathMatchedSkills. Path extraction from input is in cli/skill_activation.go#extractFilePaths.
When the same skill matches via both triggers and paths, it is injected only once (deduplicated by name).

model and effort Propagation

When a skill auto-activates (via triggers or paths), is pinned (/skill pin), or is manually invoked, its model: and effort: are propagated to the current turn:
  • model: — the dispatcher/resolver swaps the LLM client for this turn. Works within the same provider (e.g., sonnetopus on Claude) or cross-provider (e.g., user on Claude, skill wants gpt-5 on OpenAI). If the target provider is not configured, it falls back to the user’s client with a visible notice.
  • effort: — mapped to thinking.budget_tokens (Anthropic, Opus 4.x / Sonnet 4.x / 3.7 models) or reasoning_effort / reasoning.effort (OpenAI, o1/o3/o4/gpt-5 models). Unsupported models silently ignore.
Precedence when multiple modes fire in the same turn:
manual /<skill-name>  >  /skill pin  >  auto-activation (triggers/paths)
The first non-empty model: in this order wins; subsequent conflicts are logged as warnings but don’t force additional swaps.

Manual Invocation via /<skill-name>

Skills with user-invocable: true are available as direct slash commands:
/go-testing generate tests for Handler{}
ChatCLI intercepts /<skill-name> ahead of the default router, validates that the skill exists with user-invocable: true, loads its content, displays the argument-hint (when args are empty), and fires the turn with the skill injected as a ”# Manually Invoked Skill” block in the system prompt — taking precedence over auto-activated skills. The protected command list (/agent, /coder, /run, /switch, /help, /skill, etc.) can never be shadowed by a skill — even a skill named agent won’t shadow the built-in command. Slash command autocomplete also includes all user-invocable: true skills, showing description and argument-hint side by side.

Invocation Control

FieldTypeDefaultDescription
user-invocableboolfalseEnables invocation via /skill-name
disable-model-invocationboolfalseBlocks automatic activation via triggers/paths (user can still invoke manually if user-invocable: true)
argument-hintstringText shown in autocomplete and as a hint when invoked without args
disable-model-invocation: true together with user-invocable: true = the skill only runs when the user types /skill-name, never through automatic detection. Useful for destructive or highly specific skills.

Pin a Skill for the Session (/skill pin)

When you need a skill to apply to every turn of the session — not only those that match triggers:/paths: — pin it:
/skill pin go-testing      # Pin
/skill pinned              # List pinned
/skill unpin go-testing    # Unpin
Pin is a session-scoped intent (doesn’t persist across runs) and lives in its own # Pinned Skills block in the system prompt, cacheable via cache_control: ephemeral. On hint conflicts, pinned beats auto-activation but loses to a manual /<skill-name> invocation. Skills with disable-model-invocation: true cannot be pinned — the flag exists precisely to forbid automatic injection. Use manual /<skill-name> for those. Full details, examples, and the precedence table: Pin Skills in Skill Registry.

/agent Without Context

Before: typing /agent alone entered agent mode immediately and sent an empty message to the LLM. Now: typing /agent (or /run) without an inline task prints the persona handler help plus a usage hint and does not start the ReAct loop. Same applies to /coder. This avoids token burn on empty messages and makes the UX more predictable.
/agent
# 📋 persona handler help + examples
# 💡 Usage: /agent <task>  (e.g., /agent investigate 500 error)
To enter agent mode with context, pass the task inline:
/agent refactor the auth module

Skills from Remote Registries

Besides creating skills manually, you can search and install skills from remote registries via the /skill command:
# Search kubernetes skills
/skill search kubernetes

# Install a skill
/skill install k8s-ops

# Verify it shows up in the available skills
/agent skills
Skills installed via registry are saved in ~/.chatcli/skills/<name>/SKILL.md as V2 packages and are immediately available for agents. ChatCLI supports multiple registries simultaneously (ChatCLI.dev, ClawHub, corporate registries) with fan-out parallel search. See Skill Registry for full details.

Dispatch as Worker (Multi-Agent)

When starting /coder or /agent, all custom agents are automatically registered in the multi-agent orchestration system. The LLM orchestrator can then dispatch them via <agent_call>:
<agent_call agent="devops-senior" task="Configure CI/CD pipeline with GitHub Actions" />
<agent_call agent="my-strict-reviewer" task="Audit the authentication module for OWASP" />

What the worker gets

When dispatched, CustomAgent runs with:
1

Personalized system prompt

Includes agent content (markdown body), loaded skills, subskill paths, script commands, and tool_call instructions.
2

Mini ReAct loop

The same ReAct loop as built-in agents, with reasoning, action, and observation.
3

Permitted commands

Based on the tools field of the frontmatter.
4

Per-turn resolved client

If the agent declares model:, the dispatcher calls ResolveModelRouting to obtain the correct client before each mini-ReAct turn.
5

Effort applied to ctx

If the agent declares effort:, the worker’s ctx receives WithEffortHint, read by the provider inside SendPrompt.
6

Parallel reads

Read-only tool calls run in parallel goroutines.
7

File locks

Writes use per-filepath mutex for anti-race safety.
8

Error recovery

The orchestrator can use direct tool_call to diagnose and fix failures.

End-to-End Example

# 1. Create the agent in ~/.chatcli/agents/devops-senior.md (with model/effort)
# 2. Start coder mode
/coder configure the deployment pipeline and monitoring

# The LLM orchestrator can dispatch:
# <agent_call agent="devops-senior" task="Set up CI/CD with GitHub Actions" />
# <agent_call agent="file" task="Read current Dockerfile and docker-compose.yml" />
#
# Both run in parallel with their own ReAct loops.
# devops-senior can run on opus-4-6 with effort=high while file runs on
# sonnet with effort=low — respecting each agent's preferences.

Management Commands

All management commands are integrated under /agent:
CommandDescription
/agentShows active agent status and help (does not enter agent mode without a task)
/agent listLists all available agents
/agent statusLists only attached agents (short) — alias: attached, list-attached
/agent load <name>Loads a specific agent
/agent attach <name>Attaches an additional agent to the session
/agent detach <name>Removes an attached agent
/agent skillsLists all available skills
/agent show [--full]Shows the active agent with example prompts (use --full for everything)
/agent offDeactivates all currently active agents
/agent <task>Executes a task in agent mode

Prompt Assembly Order

When an agent is loaded, the system prompt is assembled in this order:
1

[ROLE]

Agent identity (name, description)
2

[PERSONALITY]

Agent base content (markdown body)
3

[SKILLS]

Imported skill knowledge (numbered)
4

[AUTO-LOADED SKILLS]

Skills auto-activated via triggers: or paths: on the current message
5

[MANUAL SKILL]

Extra block when the message was invoked via /<skill-name>
6

[PLUGINS]

Enabled plugin hints
7

[REMINDER]

Anchor with application instructions
This ordering ensures the AI receives context in a structured way, with explicit user intent (manual) taking precedence over auto-activation.

Full Practical Example

1. Create an agent

Create the file ~/.chatcli/agents/python-data.md:
---
name: "python-data"
description: "Python Data Scientist specialist"
skills:
  - clean-code
plugins:
  - "@coder"
model: "claude-opus-4-6"     # always runs in Opus
effort: "medium"
category: "data-science"
tags: python, ml, data
---
# Base Personality

You are a Senior Data Scientist, expert in Python.

## Preferred Tools

- Pandas for data manipulation
- NumPy for numeric computation
- Matplotlib/Seaborn for visualization
- Scikit-learn for classic ML
- PyTorch for deep learning

2. Use the agent

# List agents
/agent list

# Available Agents:
#   go-expert - Go/Golang specialist [2 skills]
#   python-data - Data Scientist [1 skills]

# Load the agent
/agent load python-data

# Agent 'python-data' loaded successfully!
#    Python Data Scientist specialist
#    Attached skills:
#     - clean-code

# Use in agent mode
/agent analyze this dataset and create visualizations

# Or in coder mode
/coder build a classification ML pipeline

Agent and Skill Precedence (Project > Global)

Both agents and skills support per-project directories with precedence over the globals. ChatCLI auto-detects the project root by looking for a .agent/ or .git/ directory upward from the current directory.

Search Order

Resource1. Project (priority)2. Global (fallback)
Agents./.agent/agents/*.md~/.chatcli/agents/*.md
Skills./.agent/skills/~/.chatcli/skills/
If an agent or skill with the same name exists in both directories, the project version wins.

Project Structure

my-project/
|-- .agent/                  # Marks the project root for ChatCLI
|   |-- agents/              # Project-specific agents
|   |   +-- backend.md       # Overrides ~/.chatcli/agents/backend.md
|   +-- skills/              # Project-specific skills
|       +-- team-rules.md    # Team-specific rules
|-- src/
+-- ...
If your project already has .git/, ChatCLI uses that directory as the project root automatically. .agent/ is optional — use it when you want project-local agents/skills without depending on Git.

Integration with /coder

When an agent is loaded:
  • /agent <task> — Uses the agent’s persona.
  • /coder <task> — Combines the agent’s persona with the coder prompt.
This lets you have a Go-expert agent using @coder tools to edit files, run tests, etc. The agent’s model: and effort: preferences are honored in both modes.

Tips

Start Simple

Create agents with a few skills and add more as needed.

Version on Git

Keep your agents and skills in a repo.

Share with the Team

Coding-style skills enforce consistency.

Use Clear Descriptions

Helps understand each agent/skill’s purpose.

Test the Prompt

Use /agent show to inspect the assembled prompt.

Assign `effort` Carefully

effort: high costs more tokens. Reserve it for agents that truly need deep reasoning (reviewers, planners, diagnostics).

Useful Skill Examples

  • clean-code — Clean code principles
  • error-handling — Error handling patterns
  • testing-patterns — Automated testing patterns
  • docker-master — Dockerfile best practices
  • clean-scripts — Safe Bash scripting patterns
  • aws-security — AWS security rules
  • team-conventions — Team-specific conventions

Remote Agents and Skills

When connected to a ChatCLI server via chatcli connect, the client automatically discovers agents and skills available on the server. They are transferred to the client and composed locally, allowing merge with local resources. Since the recent update, the gRPC wire (pb.AgentInfo) carries all the advanced fields — model, effort, category, version, author, tags — so remote agents behave exactly like local ones for routing purposes.
# On connect, the client shows available resources
Connected to ChatCLI server (version: 1.3.0, provider: CLAUDEAI, model: claude-sonnet-4-6)
 Server has 3 plugins, 2 agents, 4 skills available

# Remote agents appear in the listing
/agent list

# Available Agents:
#   go-expert       - Go/Golang specialist              [local]
#   devops-senior   - Senior DevOps focused on K8s      [remote]

# Loading a remote agent works the same way
/agent load devops-senior

Provisioning via Kubernetes

# Helm: inline agents and skills
helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
  --set agents.enabled=true \
  --set-file agents.definitions.devops-senior\\.md=agents/devops-senior.md \
  --set skills.enabled=true \
  --set-file skills.definitions.k8s-best-practices\\.md=skills/k8s-best-practices.md
ConfigMaps are mounted at /home/chatcli/.chatcli/agents/ and /home/chatcli/.chatcli/skills/, and are available for remote discovery automatically. Advanced frontmatter fields (model, effort, category, etc.) are read by the chatcli binary inside the pod — the CRD and operator do not need changes to support them.

Next steps

Multi-Agent Orchestration

How multiple custom agents run in parallel via <agent_call>.

Skill Registry

Publish and discover skills shared across teams.

Subagent Delegation

Focused delegation for concentrated analysis over a large payload.

Server Mode

Distribute agents via ConfigMap to the entire team.