Skip to content

Agent Profiles as Markdown

Status: Draft Principles: [[guiding-design-principles]] (#1 files as source of truth, #9 simple interfaces) Related: [[vault]], [[memory-scoping]], [[specs/agent-profiles]], [[agent-coordination]]


1. Overview

Agent profiles are markdown files in the vault that serve as the source of truth for agent-type configuration. The database stores a synced copy for fast runtime access. This replaces the current DB-only profile model.


2. Hybrid Format

Profiles use a hybrid approach: freeform English for guidance that gets injected into the agent's prompt, and JSON code blocks for structured configuration that requires exact parsing. This avoids the fragility of LLM-parsing tool configurations while keeping behavioral guidance human-readable.

vault/agent-types/coding/profile.md:

---
id: coding
name: Coding Agent
tags: [profile, agent-type]
---

# Coding Agent

## Role
You are a software engineering agent. You write, modify, and debug code
within a project workspace. You follow project conventions, write tests,
and commit clean, working code.

## Config
```json
{
  "model": "claude-sonnet-4-6",
  "permission_mode": "auto",
  "max_tokens_per_task": 100000,
  "runtime": "claude_sdk"
}
```

The ``runtime`` field selects which Runtime implementation executes
tasks for this profile.  Supported values:

- ``"claude_sdk"`` (default; matches ``config.default_runtime``) —
  spawns a Claude Code subprocess via the Agent SDK.  Owns a per-task
  workspace.  The escape hatch when ACP doesn't expose a needed feature
  (SDK-internals reach for ``_resilient_query``, bespoke error
  classification, etc.).
- ``"acpx"`` — fans out to any ACP-compatible coding agent via the
  ``acpx`` CLI.  ``profile.agent_name`` selects the underlying agent
  (``"claude"`` / ``"codex"`` / ``"gemini"`` / ``"opencode"`` /
  ``"cursor"`` / etc. — see [[runtimes/acpx]]).  Workspace-based.
- ``"supervisor"`` — runs in-process via the daemon-wide
  :class:`Supervisor` singleton.  Tool-call-only, no workspace.
  Suitable for triage / classify / summarise / route / send-message
  work where the profile's ``allowed_tools`` defines a bounded surface.
  See ``vault/templates/example-supervisor-runtime-profile.md``.

## Tools
```json
{
  "allowed": ["shell", "file_read", "file_write", "git", "vibecop_scan", "vibecop_check"],
  "denied": []
}
```

## MCP Servers
```json
["github", "playwright"]
```

The values are **registry names**, not inline configs. Server definitions
live in `vault/mcp-servers/<name>.md` (system) or
`vault/projects/<pid>/mcp-servers/<name>.md` (project scope shadows system
by name). See [[specs/mcp-server]] for the registry format and CRUD.

## Rules
- Always run existing tests before committing
- Never commit secrets, .env files, or credentials
- Prefer small, focused commits over large ones
- If tests fail after your changes, fix them before moving on
- Check for and respect any project-specific overrides

## Reflection
After completing a task, consider:
- Did I encounter any surprising behavior worth remembering?
- Did I resolve an error that might recur? If so, save the pattern.
- Is there a convention in this project I should note for next time?

What gets parsed deterministically (JSON blocks): - ## Config → model, permission mode, token limits → DB fields - ## Tools → allowed/denied tool lists → DB fields - ## MCP Servers → list of registry names → DB field (mcp_servers: list[str])

What gets injected as prompt context (English sections): - ## Role → system prompt prefix - ## Rules → behavioral guidance in agent context - ## Reflection → post-task reflection instructions

This split means misconfigured MCP servers are caught by JSON parse errors (not LLM misinterpretation), while behavioral guidance stays natural and editable.


3. Sync Model

Human edits profile.md in Obsidian
       │                              Agent updates profile via chat command
       │                                       │
       ▼                                       ▼
  File watcher detects change          System writes to profile.md
       │                                       │
       ▼                                       ▼
  Parse profile ◄─────────────────────────────┘
       ├── Extract JSON code blocks → validate → structured DB fields
       ├── Extract English sections → store as prompt text
  Update DB row (agent_profiles table)
  Runtime picks up new config

All writes flow through the markdown file. The chat/dashboard interface writes to the file, not the DB. The file watcher handles sync in one direction only: markdown → DB. No bidirectional sync, no conflicts.

Validation on sync: - JSON blocks must parse successfully; if not, sync fails and the previous DB config remains active. An error notification is sent. - Tool names in ## Tools are validated against the tool registry. Unknown tools produce a warning (not a hard failure — the tool may not be loaded yet). - MCP server commands are validated for basic structure (command exists, args are strings). Server health is not checked at sync time.

Tool naming in ## Tools

allowed uses bare tool names (the form the supervisor's tool registry exposes — e.g. get_weather, create_task, send_message). The supervisor validates these directly against the registry; sandboxed playbooks rely on the same form.

The Claude CLI sees agent-queue tools through the MCP transport as mcp__agent-queue__<name>. The Claude adapter handles the translation automatically — bare names in allowed are mapped to their MCP-prefixed form when building --allowed-tools for the CLI subprocess. Profile authors do not write the mcp__agent-queue__ prefix.

Exceptions: - Claude built-ins (Read, Edit, Bash, Glob, Grep, WebSearch, WebFetch, Agent, etc.) keep their bare names — they live outside the embedded MCP server. - Third-party MCP servers (anything other than the embedded agent-queue server) use the full mcp__<server>__<tool> form in allowed. There's no unambiguous way to strip a prefix when multiple servers might define the same bare tool name.


4. Starter Knowledge Packs

New agent types start with no memory. To avoid a cold-start problem, the system ships starter knowledge packs in vault/templates/knowledge/:

vault/templates/knowledge/
  coding/
    common-pitfalls.md           # "Always check for async/sync mismatches..."
    git-conventions.md           # "Prefer small commits, meaningful messages..."
  code-review/
    review-checklist.md          # "Check for: error handling, edge cases..."
    review-process.md            # "Review order, giving feedback, scope..."
  qa/
    testing-patterns.md          # "Prefer integration tests for critical paths..."

When a new agent type is created (profile.md saved for the first time), the system copies matching starter knowledge from templates/knowledge/{type}/ to the agent type's memory/ folder if one exists. These starter files are tagged #starter and can be updated or removed as the agent accumulates real experience.