Perseus Directives Reference

August 9, 2026 · View on GitHub

Full directive system for Perseus context documents. All directives are resolved at render time — the assistant sees only verified facts, never directive syntax.

Directive Protocol Version

Source documents start with @perseus v1.0.8 on line 1. The value after @perseus is the directive protocol version (the syntax revision Perseus parses). Existing v0.4/v0.8 context files remain supported for backward compatibility.

Directive Table

DirectiveWhat it does
@query "shell cmd" [fallback="text"] [schema="name"]Runs a shell command, embeds stdout as a fenced block; requires render.allow_query_shell=true and PERSEUS_ALLOW_DANGEROUS=1; fallback= emits literal text on failure or empty output; schema= validates YAML stdout
@read <file> [path="key"] [schema="name"]Reads a file; dot-notation path for JSON/YAML/TOML; key= for .env files; schema= validates full or extracted output
@env VAR [fallback="x"] [schema="name"]Injects an environment variable; required=true emits a visible warning if unset; schema= validates the value or fallback
@include <file> [last=N] [since=14d] [mode=reference]Embeds a file inline; markdown raw, structured files fenced. last=N keeps only the final N lines; since=14d/2w/24h keeps only dated sections (markdown headings containing an ISO date) within the window — both bound an appended log so the rendered file does not grow unbounded. Do not @include files the host agent already ingests natively (its own memory files, ~/AGENTS.md discovery chains): the content lands in model context 2-4×. Use mode=reference to emit a one-line pointer instead, or list such files once in render.host_loaded_paths so every @include of them refuses to inline (#715)
@if <cond> / @else / @endifConditional blocks: file.exists/missing, env.set/unset/eq/neq, query("cmd") [not] matches /regex/[i]
@constraint id="..." severity="..."Machine-readable rules rendered as a | ID | Severity | Rule | table
@skills [flag_stale=true] [category=comma,list]Scans the assistant's skills dir, reads frontmatter, flags stale entries; category= filters to specific skill categories (e.g. category=devops,github). Use this to keep the skills table focused — omit category= to list all skills.
@skill-candidates [status=pending] [limit=N]Renders mined procedural-skill candidates (from session transcripts, #932): name, description, trigger, evidence sessions, token cost. Candidates are staged, never activeperseus skills approve <name> is the only activation path (review gate). Opt-in surfacing: place this directive in your context source; the mining pipeline never writes AGENTS.md/CLAUDE.md itself. `status=all
@services (YAML block or @services ... @end)HTTP health checks (url:), Docker container status (docker:), or optional shell exit check (command:); command checks also require PERSEUS_ALLOW_DANGEROUS=1
@session [count=N] [topic="..."]Recent session digest from the sessions directory
@date format="YYYY-MM-DD HH:mm z"Live date/time, inline or standalone
@waypoint [ttl=N]Latest checkpoint rendered inline; ttl= skips it if too old
@prompt...@endAI instruction callout — visible to the assistant, attributed to Perseus
@validate schema="name"...@endRenders a block, validates the payload, and emits a visible warning instead of invalid context
@agora [status=...] [scope=...]Live task board from tasks/ — markdown table by status/scope
@memory [focus="..."] [ttl=N]Perseus Vault narrative for the workspace; focus= slices a single section (arc, decisions, recent, patterns, history)
@memory mode=search query="terms" [k=5] [scope=...] [type=...]Perseus Vault v2 FTS5 BM25 search over the vault (~/.perseus/memory/vault/*.md). Returns ranked results with snippet highlights. Use single-word queries for best recall — multi-word queries are matched as exact FTS5 phrases.
@vault query="terms" [k=5] [scope=...] [type=...]Canonical Perseus Vault FTS5 recall directive. It uses the same backend as @memory mode=search without narrative or federation modes.
@capture [limit=N]Write side of the memory loop (#713): pushes up to N recent session checkpoints for this workspace to Perseus Vault as durable, provenance-tagged memories. Idempotent (keyed per checkpoint — re-renders upsert, never duplicate). Automatic capture at session boundaries (checkpoint write, memory update) is opt-in via perseus_vault.capture.enabled
@healthMaintenance suggestions (stale checkpoints, near-duplicates, large context, old completed tasks)
@list <path> [type] [depth] [path] [columns] [as]Directory listing OR structured-file table from path="dot.key" of JSON/YAML
@tree <path> [depth] [match] [exclude]Fenced directory tree with plain indentation
@agent "command" [timeout=N] [strip=true] [fallback="text"]Run a local subprocess, embed stdout inline; requires render.allow_agent_shell=true and PERSEUS_ALLOW_DANGEROUS=1
@inbox [unread=true] [limit=N]Render pending point-to-point messages from perseus inbox send
@memory federation [alias=name]Render digest of subscribed cross-workspace narratives (see perseus memory federation)
@memory include_federation=trueLocal narrative + appended ## Federated Context digest
@vault query=\"topic\"Recall persistent memories via Perseus Vault (entities, journal, state). Category-filtered, FTS5 keyword search with LIKE fallback.
@driftDaedalus drift report — acceptance rate, recommendation Jaccard, confidence proxy (see perseus oracle drift)
@context-diff [reset=true]Compact "Since last session" delta (#714): git branch/commits, Agora task-board changes, new inbox messages, new checkpoints, and new vault session memories since the last recorded snapshot. Put it at the top of a context document so the assistant spends zero turns re-orienting on unchanged state. Baseline refresh is debounced by render.context_diff_min_age_s (default 300s); reset=true forces a new baseline
@tool "\"<path>\"" [args...]Run an allowlisted external tool. Unlike @agent (ad-hoc), @tool requires explicit approval in tools.allowlist per path, with argument restrictions, timeouts, and output size caps. Accepts @cache ttl=N.
@synthesize question="..." source="file" [label="..."]Optional curated synthesis section. Requires generation.enabled: true in config. LLM-powered summarization with provenance claims — every assertion traces back to a cited source.
@perseus <url>Fetch rendered context from a remote Perseus serve instance. Gated by foreign_resolver.allowlist and render.allow_remote_services_health. Accepts @cache ttl=N.

Cache Modifiers

Any directive accepts a @cache modifier:

@query "git log --oneline -5" @cache session      ← run once per render, reuse after
@services @cache mock="(stubbed in CI)"           ← bypass execution entirely
@skills flag_stale=true @cache persist             ← survives across processes
@skills flag_stale=true @cache ttl=3600            ← cache to disk for 1 hour
@read config.yaml @cache fingerprint               ← auto-invalidates when config.yaml changes
@read archive.json @cache nofingerprint ttl=86400  ← opt-out: pure TTL, ignores file changes

New in v1.0.5+: @cache ttl=N and @cache persist now include a dependency fingerprint by default. When a directive reads a file (e.g., @read data.txt), the cache key includes a hash of that file's content. If the file changes, the cache invalidates automatically — no need to wait for TTL expiry. Use @cache nofingerprint to opt out and keep pure TTL-based caching.

ModifierBehavior
@cache sessionIn-memory only, this process. No fingerprint.
@cache ttl=NDisk cache, N seconds TTL. Includes fingerprint for @read/@include.
@cache persistDisk cache with persist_cache_ttl_s TTL. Includes fingerprint.
@cache fingerprintExplicit opt-in (same as ttl/persist default).
@cache nofingerprint [ttl=N]Opt out of fingerprinting. Pure TTL-based expiry.

Safety Gates

Shell-backed features can be gated in ~/.perseus/config.yaml:

render:
  allow_query_shell: true
  allow_agent_shell: false
  allow_services_command: false
  allow_outside_workspace: false
  • allow_query_shell: enables or disables @query command execution
  • allow_agent_shell: enables or disables @agent command execution
  • allow_services_command: enables or disables command: checks inside @services
  • allow_outside_workspace: controls whether @read / @include may escape the workspace

Even when the config enables ad-hoc shell execution, @query, @agent, and @services command: require PERSEUS_ALLOW_DANGEROUS=1 in the process environment. This second gate is intentional friction for copied configs and automation profiles.


See also: CLI Reference, Quickstart, Integration Guide