Package: internal/agent/
Agents define behavioral presets: system prompts, tool permissions, and model parameters. Every session runs under an agent.
type Info struct {
Name string // unique identifier (registry key is filename stem; Name may differ via frontmatter)
Description string // human-readable description
Mode Mode // "primary", "subagent", "all"
Native bool // true for hardcoded agents
Hidden bool // hidden from user lists
Disabled bool // soft-disabled; Get/List skip these
TopP *float64 // LLM sampling parameter
Temperature *float64 // LLM sampling parameter
Color string // TUI display color (hex)
Permission permission.Ruleset // tool permission rules
Prompt string // system prompt text
Compact bool // true when compact variant is active
Steps *int // max steps for this agent
Options map[string]any // agent-specific options
Model *ModelRef // preferred model override
Variant string // model variant
}| Mode | Constant | Description |
|---|---|---|
| Primary | ModePrimary |
Can be the main session agent |
| Subagent | ModeSubagent |
Only available for delegation |
| All | ModeAll |
Available in both roles |
- Native agents — Hardcoded in
registerNativeAgents()with specific permissions (prompts fromdefaults/*.txt, exceptexplorewhich prefersexplore.mdbody) - Bundled agents — Loaded from
defaults/*.mdvia embedded filesystem (embed.FS); skipped when a native agent already owns the name - User agents —
LoadUserAgents:~/.config/tinycode/agents/*.mdthen~/.config/tinycode/agent/*.md(compat) - Project agents —
.tinycode/agent/*.md(loaded after user; overwrites non-native) - Config overrides — Applied from
config.Info.AgentsviaApplyConfigOverrides()
User/project .md agents may replace bundled (non-native) agents. Native agents are never overwritten by directory loads.
| Agent | Mode | Description | Key Permissions |
|---|---|---|---|
build |
Primary | Default agent, full tool access | question:allow, plan_enter:allow |
plan |
Primary | Planning mode — interviews, researches, writes plans; edits scoped to plans/*/drafts/* |
read:allow, task:allow, plan_exit:allow, edit "plans/*":allow, edit "drafts/*":allow, edit:deny elsewhere |
general |
Subagent | Plain assistant. Answers directly and uses a tool only when needed. On the default Tab cycle | todowrite:deny |
explore |
Subagent | Fast codebase search | Only: grep, glob, bash, webfetch, websearch, read |
scout |
Subagent | Upstream dependency source. Official docs go to document-specialist | Only: grep, glob, webfetch, websearch, read |
compaction |
Primary (hidden) | Context summarization | All denied |
title |
Primary (hidden) | Session title generation | All denied, temp=0.5 |
summary |
Primary (hidden) | Session summary | All denied |
Loaded from embedded markdown files with YAML frontmatter. Actual set in Go internal/agent/defaults/:
| Agent | Description |
|---|---|
analyst |
Requirements and acceptance criteria before planning |
architect |
Code design and architecture review (read-only). Known failures go to debugger |
code-reviewer |
Severity-rated code review with SOLID checks |
code-simplifier |
Refactoring for clarity (archived: disabled by default) |
critic |
Plan and gap review. Code defects go to code-reviewer |
debugger |
Root-cause analysis and bug fixing |
designer |
UI implementation with framework-aware visual design |
document-specialist |
External SDK docs, API references, changelogs, and integration guides |
executor |
Focused implementation of scoped tasks |
git-master |
Git history, rebasing, atomic commits |
ops |
Cluster and host administration. Primary. Read-only first; mutating shell commands ask |
qa-tester |
Interactive CLI testing (archived: disabled by default) |
scientist |
Data analysis and research (archived: disabled by default) |
security-reviewer |
Security vulnerability detection |
test-engineer |
Test strategy and TDD workflows |
tracer |
Competing-hypothesis causal tracing |
verifier |
Completion verification |
writer |
Technical documentation |
explore.md / explore.compact.md also live under defaults; the native explore agent uses the explore.md body as its prompt (permissions stay native). Compact peers of archived agents are disabled alongside the base agent.
The default Tab cycle is build, general, ops, plan, architect, code-reviewer. ops is primary. It allows read-only shell commands and asks for destructive-shell and secret-shell. It does not edit source. /incident, /change, and /host expand into checklists. An ambiguous cause goes to tracer, product docs to document-specialist, repo config to explore, source exposure to security-reviewer, file edits to executor, and application bugs to debugger.
The former standalone planner bundled agent was merged into the native plan agent (its methodology now lives in defaults/plan.txt). Switching between build and plan mid-session goes through the plan_enter / plan_exit tools (see 08-tools.md) rather than the /ask or Tab mechanisms alone — both tools require permission.Ask approval, and an approved call updates the session's active agent (Processor.applyPendingAgentSwitch), taking full effect (new system prompt, new permission set) starting with the next turn.
Agent .md files use YAML frontmatter. Shared parsing via applyFrontmatter:
---
name: optional-display-name
description: Human-readable description
mode: primary | subagent | all # omitted → subagent (bundled/user .md defaults)
hidden: true | false
color: "#ff0000"
steps: 10
temperature: 0.7
top_p: 0.9
model: ollama/qwen3:8b
permission:
edit: deny
read: allow
bash:
"*": allow
"/etc/*": deny
---
System prompt content here...The registry map key is always the filename stem. If name is set in frontmatter, it updates Info.Name only. Omitted mode defaults to ModeSubagent (not ModeAll).
Permissions support two formats:
Simple (applies to all patterns):
permission:
edit: deny
read: allowPattern-specific (nested maps):
permission:
bash:
"*": allow
"/etc/*": denyWhen a model's parameter count is ≤8B (detected from model name), the registry returns a compact variant if available and not disabled:
func (r *Registry) Get(name string, modelSizeB *float64) *Info {
if modelSizeB != nil && *modelSizeB <= 8 {
compact := r.agents[name+".compact"]
if compact != nil && !compact.Disabled {
result := *compact
result.Name = name // requested base name, not "*.compact"
result.Compact = true
return &result
}
}
// ... return standard agent (nil if missing or Disabled)
}Compact variants are agent files named <agent>.compact.md with simplified prompts optimized for smaller models. Get never serves disabled agents (base or compact).
Agent permissions are built by merging multiple rulesets:
DefaultRules → agentPerm → userPerms
For native agents, additional rules are inserted between default and user:
DefaultRules → nativeAgentRules → userPerms
For config overrides:
existingAgentPermission → configPermission
See 12-permissions.md for the full evaluation chain.
Users can modify agents via config:
{
"agents": {
"build": {
"temperature": 0.7,
"model": "ollama/qwen3:8b"
},
"my-agent": {
"prompt": "You are a custom agent...",
"description": "Custom agent",
"mode": "primary",
"permission": {
"edit": "allow",
"bash": "ask"
}
},
"debugger": {
"disable": true
}
}
}Override fields: model, variant, prompt, description, temperature, top_p, mode, color, hidden, name, steps, options, permission, disable.
Setting disable: true sets Disabled on the agent (soft disable). It does not remove the agent from the registry. Native agents cannot be disabled. Get and List skip disabled agents; ListAll includes them.
DefaultAgent(configDefault) resolves the default agent:
- If
configDefaultis set in config, validate it exists and is a primary, visible, non-disabled agent - Otherwise, use
"build"if not disabled - Fallback: first registered non-subagent, non-hidden, non-disabled agent
Agents can specify a preferred model:
type ModelRef struct {
ProviderID string
ModelID string
}ParseModel("ollama/qwen3:8b") → {ProviderID: "ollama", ModelID: "qwen3:8b"}
When an agent has a Model set, the session manager uses that model instead of the session's default.
Source: internal/agent/loader.go
LoadUserAgents(configDir, projectDir) loads user-defined agents from:
- User config:
~/.config/tinycode/agents/*.md - User compat:
~/.config/tinycode/agent/*.md - Project:
.tinycode/agent/*.md
Files are parsed identically to bundled agents (frontmatter + body via applyFrontmatter). Non-native agents already in the registry may be overwritten (project wins over user over bundled). Native agents are never overwritten. Load errors are logged, not silently discarded.
Compact variants (*.compact.md) are loaded alongside their full counterparts.
The /ask <agent> <prompt> command delegates a prompt to a specific agent:
parseAskCommand()extracts the agent name and prompt textisKnownAgent()validates against the loaded agent list- Sent as
agentfield onPromptInputto the session handler - Prompt autocomplete filters
/asksuggestions to non-primary agents only