RimZ

Markdown definitions

RimZ reads machine agent, subagent, and team definitions directly from Markdown with YAML frontmatter.

RimZ reads machine agent, subagent, and team definitions directly from Markdown with YAML frontmatter. Edit the source, then run rimz agents validate; there is no generation step. Machine preferences and command shortcuts remain in config.toml. Trusted project .rimz/config.toml keeps its TOML schema and trust rules.

Trees and format

The definitions root is the RimZ home, ~/.rimz by default, which RIMZ_HOME relocates; RIMZ_AGENTS_HOME overrides it for these trees and the skill library alone:

agents/<name>.md       direct profiles and kind bases
subagents/<name>.md    supervised-child profiles
teams/<name>.md        team roster and pipeline
traits/<name>.md       plain Markdown fragments
skills/<name>/SKILL.md shared skill library

The three definition trees are scanned non-recursively for .md files, in sorted order. Subdirectories and AGENTS.md, CLAUDE.md, and README.md are skipped. A missing tree is empty. Traits are read when referenced. Symlinked trees work too.

The first line must be exactly ---; another exact --- line closes a YAML mapping. Unknown keys and wrong value types fail. The remaining Markdown is the prompt body, trimmed at its edges. String-list keys accept YAML lists; an explicit null list means [], not inheritance. Signals have their own rules below.

For example, agents/planner.md:

---
description: Plan changes without editing files
agent: claude
model: fable
tools: [Bash, Read, Grep, Glob, AskUserQuestion]
subagents: []
---
Read the surrounding code and propose a bounded plan before implementation.

Because this example has a body, it also needs agents/claude.md:

---
description: Shared Claude instructions
---
Follow the project's instructions and report what you verified.

Agent and subagent keys

KeyMeaning
nameOptional public name; defaults to the filename stem.
descriptionRequired nonempty, single-line listing description; not inherited.
agentRegistered kind (a family preference for tiers) or another definition in the same tree. May be omitted with tier or when model identifies a kind.
modelConcrete model alias or provider model ID. Tier names are refused; use tier: instead.
tierModel tier: intern, junior, senior, or principal. Mutually exclusive with model.
modeask, auto, plan, or yolo.
isolationhost or sandbox; overrides machine policy unless --isolation is recorded. Inherited through definitions, unavailable on team roles or repository profiles.
empty-dirBoolean opting a solo agent or subagent into its own empty working directory. Inherited through agent: chains; false clears it. Also accepted in repository TOML [profiles] and [subagents.profiles]; machine profiles remain Markdown definitions. Team roles refuse it, including through a selected definition or profile, because teams share the worktree.
effortProvider-specific absolute effort (YAML integer or string), or omit for the selected model's default. Relative +N / -N values are refused.
fastBoolean requesting the provider's fast mode. Off by default; refused at load on a kind with no fast switch.
auto-compactNative compaction window: integer or string token count from 100k through 1M, inclusive; no percentages or decimals.
budgetDollar cap as string or number; a string such as 20/day selects a daily cap.
keep-warmPrompt-cache keep-warm horizon for a solo seat: off or a duration such as 2h.
model-reminderBoolean controlling the model identity in the launch reminder for solo agents and subagents. Defaults on; team members never show model names.
traitsTrait names substituted into this definition's body.
toolsTool-name list, translated to provider arguments below.
subagentsDirect profiles only: allowed RimZ child profiles; [] permits none.
skillsBare skill-directory names allowed for model invocation. Claude also adds exact invocation permissions for listed names without *, in both isolations and independently of allow-routine-rimz. Sandbox views and host Claude keep unlisted skills user-only; host Codex hides them. Other host providers warn and run unrestricted. [] lists none.
allowed-toolsPermission rules such as ["Bash(git *)", Read]. Claude pre-approves matching calls in both isolations, independently of allow-routine-rimz; other kinds warn and do not apply them. Available only in Markdown definitions, not repository TOML. [] or null clears inherited rules.

Names must match [A-Za-z0-9_-]+ and be unique across both definition trees. Registered kinds are reserved for kind bases. general and model aliases are not reserved by the definition parser. The final namespace checks also reject command-verb and address collisions, such as all, kind ordinals, or a profile colliding with a team.

Chains and defaults

The nearest definition setting tier:, model:, or a registered agent: kind decides the runtime. A tier: needs no agent:. A concrete model listed in the machine tier table has that tier and prefers the exact entry first; membership compares the configured text, so an alias and a full model ID are distinct entries. A model outside the table runs without tier routing. An explicit kind on the deciding definition prefers that family's entries first. Resolution tries the requested tier's remaining entries in list order, then higher tiers with the preferred family first, never lower. Families unable to render the definition's tools, skills, supported fields, or kind base are excluded with reasons reported by rimz agents validate. No eligible entry at or above the requested tier is an error.

tier and model inherit as one setting: setting either inherits neither. A child still inherits its parent's absolute effort if present; otherwise the chosen model's default applies. Relative effort is refused even when inherited, with the source named. Project TOML profiles and roles cannot set tier or tier-named model: define the tiered profile in Markdown or name a concrete model in TOML. Project models run exactly, even when listed in the table. For tier selection guidance, see choosing a model tier.

agent: follows only definitions in its own namespace: an agent cannot inherit a subagent or vice versa. Without agent:, a recognized model alias, model ID, or prefix determines the kind: Claude's roster and claude- prefix, and Codex's roster and gpt- prefix. Unknown models use the chain's kind or require agent: when none exists. A model implying a different kind from a registered agent: in the same definition is an error; a child model may change its ancestor's kind.

Children inherit tier or model, mode, isolation, empty-dir, effort, fast, auto-compact, budget, keep-warm, tools, allowed-tools, skills, subagents, and model-reminder. An explicit child field replaces the inherited value; lists never concatenate. Descriptions and trait lists are local. Parent prompt bodies are retained in order before the child's body. A bodyless definition adds no craft, so it can serve as a model-only preset on its kind base.

Defaults apply after inheritance: Claude uses mode auto and effort xhigh, except fable defaults to high; Codex and Pi default to effort xhigh. Codex aliases astra, sol, luna, and terra follow their account catalog's newest family model at fresh launch, subject to effort support; definitions retain the requested alias. Machine model alias pins take precedence. Resume and fork keep the session's recorded model for alias postures. A kind whose adapter declares native auto-compaction support uses the machine [harness] auto_compact default (272k built in, "off" passes none); other kinds have no default window. Definitions are rejected at load if their resolved kind cannot render a supplied or inherited model, effort, fast: true, or auto-compact field. Defaults are filled only when supported.

Kind bases

agents/<registered-kind>.md is a special base, not an ordinary definition. It accepts only description, requires a nonempty body, and supplies the replacement system prompt in both namespaces. It cannot pin a model or tools. Every team seat, every definition with a craft, and every definition of a kind that takes a system prompt (claude, codex, pi, qwen, and plugins that declare one) requires the base of the kind it runs on, body or not; a home with no definitions needs no base.

Traits

traits: [careful, concise] reads traits/careful.md then traits/concise.md, deduplicating first-seen names. Names cannot be empty, . or .., or contain path separators. These files are plain Markdown: their complete trimmed contents are joined with blank lines and replace the first ${traits} in the body. Later tokens collapse to a blank line. With no traits, the token disappears. Naming traits without a token is an error. Other ${...} placeholders survive unchanged; the team pipeline is not trait-substituted.

Tools to provider arguments

Tool entries use Claude-style names. The base before ( is trimmed and deduplicated in first-seen order; it must begin with an ASCII letter and contain only ASCII letters, digits, or underscores. Parentheses must balance without nesting. Only Agent(...) interprets its suffix, as a comma-separated native child-type allowlist. Other suffixes are discarded; this is not a permission-pattern language.

Quote entries containing commas in a YAML flow list: tools: ["Agent(Explore, Plan)", Bash].

tools decides which tools exist; allowed-tools pre-approves calls to them. Rules are trimmed and deduplicated, keeping the first occurrence. A rule starts with an ASCII letter, followed by ASCII letters, digits, _, *, or -, optionally followed by a nonempty (specifier) closing the rule. Control characters are refused. MCP names such as mcp__my-server__* are accepted. Claude auto mode drops some broad rules, including Bash, Bash(*), wildcarded interpreters, package-manager run commands, Agent, and Monitor; use narrow rules such as Bash(git *). Claude's drop list is best-effort and may change.

KindRendering
ClaudeRequires tools, even if empty. Emits --strict-mcp-config, then optional --disallowedTools, then --tools with comma-joined bases. A nonempty Agent(...) allowlist denies every unnamed type from Explore, Plan, general-purpose, statusline-setup, fork, in that order. Unknown native types fail. Bare Agent adds no type restriction.
CodexRequires tools, even if empty. Emits --strict-config and the ordered -c settings below. Native Agent(...) type names do not restrict Codex child types.
PiAccepts or omits tools; generates no tool arguments.
Other kindsOmit tools; a supplied list is unsupported.

Codex emits these settings in order. Boolean values are unquoted; web_search is a quoted string.

SettingValue
web_search"cached" with WebSearch or WebFetch, otherwise "disabled"
agents.enabledWhether Agent is present
features.goalsfalse
features.multi_agent, features.multi_agent_v2Whether Agent is present
features.shell_snapshot, features.shell_toolWhether Bash is present
features.skill_mcp_dependency_install, features.tool_call_mcp_elicitationfalse
features.browser_use, features.browser_use_external, features.computer_use, features.in_app_browserfalse
features.image_generation, features.tool_suggest, features.memoriesfalse
features.default_mode_request_user_input, tools.experimental_request_user_input.enabledWhether AskUserQuestion is present
skills.include_instructionsWhether Skill is present

Other tool bases do not toggle Codex settings. Markdown definitions do not accept raw args, system-prompt-file, or append-system-prompt-files: tools generate arguments and bodies supply prompt pieces. Project TOML and launch flags retain their separate surfaces.

Delegation and skills

Omitting subagents leaves RimZ delegation unrestricted; a list replaces that policy with named children, and [] denies all. Names are trimmed and deduplicated, must be nonempty, and must name a subagent definition that loads, an [agents.commands] entry, a registered kind, or the built-in general fallback. Naming a subagent that failed to load fails the listing definition. A subagent definition cannot set or inherit this field. A direct profile cannot combine any subagents list with the native Agent tool: choose the RimZ doorway or native delegation.

A skills list requires the Skill tool except on Pi. Entries are trimmed and deduplicated bare directory names, never paths, whitespace, or <name>:<mode> strings. At config load from a host process, a list is checked only when the definition resolves to sandbox isolation or to a host provider with a skill switch (Claude or Codex). For a checked list, each skill must have a readable <name>/SKILL.md in the provider's skill root or the RimZ skill library, searched in that order, the same roots and precedence as the sandbox skill view; the first copy found is the one whose marker is checked, and a name in neither root fails naming both paths. A skill marked user-only for the selected provider is rejected: frontmatter disable-model-invocation: true for frontmatter-based providers, or policy.allow_implicit_invocation: false in agents/openai.yaml for Codex. The error names the marked file and both fixes: drop the skill from skills: or remove the marker. Invalid marker metadata or unreadable files also fail.

Host isolation enforces the list through Claude's or Codex's per-launch switch; providers without a switch warn and run unrestricted. The load-time decision uses the inherited profile isolation default, then machine policy; host definitions without a switch skip both skill lookup and marker checks. The check reads the host's skill roots, so it runs only from a host process: inside a sandboxed pane, where an agent's own unlisted skills appear as RimZ's user-only copies, config loading and rimz agents validate skip it (validate says so on stderr). Validation resolves the provider root from the ambient environment; a named account whose login home holds a different skill set is checked when that account launches. Sandbox launch also requires provider support for skill views. See configuration: skills and host switch limits.

Teams and seats

teams/<name>.md contains YAML roster metadata and a required Markdown pipeline body. Roles select successful ordinary definitions from agents/, not subagents or bare kinds. Each seat becomes a resolved <team>.<role> profile, launchable alone or with the team.

Team keyMeaning
nameOptional name, default filename stem; [A-Za-z0-9_-]+, unique among teams.
descriptionOptional string, accepted as metadata.
layoutOptional layout using role names and roleless cells; comma columns, plus tiled rows, slash stacked rows (tiled on tmux).
leaderRequired declared role handle; receives the initial task and retains AskUserQuestion.
stagesRequired nonempty ordered list of unique, nonblank stage names.
traitsTraits added to every seat's leaf craft.
rolesRequired nonempty list of role mappings.
Role keyMeaning
agentRequired direct definition name.
roleOptional handle, defaulting to agent; unique within the team.
ownsStages owned by this role; omitted or null means none.
tier, model, mode, effort, fast, auto-compact, budget, model-reminder, tools, allowed-tools, subagents, skillsOverrides with the same types and inheritance as agent fields, including mutually exclusive tier and model, and absolute effort only.
traitsAdditional traits for this seat's leaf craft.
signalsOptional nonempty signal-binding list.
flip-compactStage-handoff compaction threshold or off.
idle-compactIdle team compaction: off, on, or a duration; inherits the machine setting when omitted.
keep-warmPrompt-cache keep-warm horizon for this seat: off or a duration; not inherited from the definition.

Role fields override inherited definition fields. Unlike standalone chains, a seat's recognized model may select a different runtime kind; an unrecognized model keeps the original kind. That kind needs its own base. Tools are rendered again for the selected kind. Traits combine leaf-definition → role → team, deduplicated; ancestor crafts remain unchanged. Added traits require ${traits} in the leaf body. Nonleaders lose AskUserQuestion. Every nonempty seat skill list gains reflect, which must pass the same library checks. Empty and omitted skill lists stay unchanged.

Prompt order is kind base → ancestor crafts → seat craft → built-in consensus → team pipeline, separated by blank lines. Markdown teams do not expose custom consensus or scratch-file keys. Their staged workflow uses /blackboard.md and /*-notes.md as default ephemeral-memory patterns; see teams.

The built-in consensus copy

RimZ writes a read-only copy of the built-in consensus to teams/consensus.md under the definitions root, for reading and linking. rimz setup writes or refreshes it, and launching a team seat that runs under the built-in consensus refreshes it too, so an upgrade replaces a stale copy at the next team launch. A header line names the RimZ version that wrote it. RimZ never reads the file back: teams always run under the text compiled into the binary, and an edit to the copy changes nothing and is overwritten at the next refresh. To change a team's consensus, set consensus-file in a project TOML team.

Because the definitions loader skips it, teams/consensus.md is never a team definition, and consensus is not available as a Markdown team file name.

Stages and handles

Every declared stage must have exactly one owner. Ownership of an undeclared stage or duplicate ownership fails. Implement and Review, when both present, must have different owners. Done is implicit and cannot appear in stages or owns. Stage names match exactly; declaration order is not an enforced transition order.

The leader must name a declared handle. Handles must satisfy the shared address grammar and cannot shadow broadcast, reserved sender, kind, or kind-ordinal addresses. A layout must place every declared role exactly once. The pipeline and built-in consensus are scanned for @ mentions beginning with an ASCII letter; each must name a declared role, all, rimz, or a registered kind. See addresses.

Signals

Signals belong on roles, never standalone definitions or the team root:

signals:
  - ci.failed
  - signal: agent.idle
    match: {handle: reviewer}
    prompt: Read the review and continue the plan.

A selector is family.event or family.*: the family begins with a lowercase ASCII letter, and words contain only lowercase ASCII letters, digits, _, or -. No multi-dot or partial-wildcard selectors are accepted. Mapping entries accept only signal, match, and prompt. match maps payload field names to nonempty strings; all fields must match. An agent.* binding requires handle or session. A supplied prompt must be nonblank and is trimmed. An omitted signals field has no bindings; a supplied field must be a nonempty list, so null and [] are refused. Launch also validates event scope. See team signal delivery.

Idle compaction

idle-compact accepts off, on, or a duration such as 25m (units s, m, h, d). YAML booleans false and true mean off and on; integers without units are refused. Omission inherits harness.idle_compact, whose default is on. An explicit role value overrides it, including a machine opt-out.

on uses the configured provider prompt-cache lifetime minus one minute; a duration supplies the threshold directly. Unknown or disabled lifetimes skip the role under on, and an adapter without a native compact command always skips. See idle compaction for the provider defaults, overrides, and eligibility.

This field is valid only on a team role. A standalone definition is rejected because a solo seat is never idle-compacted.

Keep-warm

keep-warm accepts off or a positive duration such as 2h (units s, m, h, d). A bare YAML off (the boolean false) means off; true, numbers, and unitless text are refused. Omission means off.

On a standalone definition it sets the horizon for a solo agent launched from that profile and is inherited through agent; a TOML profile inherits it through its agent base the same way. On a team role it sets the seat's horizon; a seat reads only its role, never the definition behind it. The horizon holds only when the provider's prompt-cache lifetime is known and at least harness.keep_warm_min_ttl; rimz agents validate warns at the definition when it will not: the lifetime is unknown or under the floor, or harness.cache_keepalive is off; it also notes a horizon longer than harness.cache_keepalive_max, which the pings stop at. A subagents definition may carry the field but no seat reads it, and validate says so. See keep-warm for what a horizon does and costs.

Flip compaction

flip-compact accepts nonnegative integer token counts, strings such as 120k or 1m, percentages from 0% through 100%, or case-insensitive off; decimals, repeated suffixes, and overflowing counts fail. Omission inherits harness.flip_compact; when that is unset, a seat owning Plan gets 120k and other seats get 180k. An explicit role value overrides both, including a machine off. A provider without a manual compact command requires off on the role or machine-wide.

flip-compact: off

YAML boolean false is also accepted as off; true is refused.

This is separate from native auto-compact. A role leaving its stage for another owner's stage compacts at its next turn boundary only when occupied context reaches the threshold. Flips to Done, user flips, same-stage re-fires, and moves between self-owned stages do not compact. See stage handoff.

Validation and failures

rimz agents validate
rimz agents validate --json

Validation reads the definition trees without launching agents or writing generated files. Human output groups agents, subagents, and teams; team rows include stages and leader, followed by seats. Errors appear last as path: message. Warnings for unenforced host lists follow the errors and do not change the exit status. JSON returns {rows, errors, warnings}; rows carry namespace, name, kind, model, effort, source, and team-seat metadata where applicable. Any error makes the exit status nonzero. From a host shell, listed skills are checked against the provider's skill root and the skill library in every isolation mode; an absent library is simply one empty root. Inside a sandboxed pane the check is skipped and validate says so on stderr. It also reports every error the launch path's config load records (commands from config.toml included), so a set that passes validation is a set that launches.

The loader collects independent errors rather than stopping at the first file, and one broken definition never fails the config load. Every command keeps the definitions that loaded; only a launch that selects a failed name refuses, with that definition's path: message, instead of silently substituting another profile. That covers rimz agents launch, resume, restart, and fork, rimz subagents, rimz teams launch and flip, loop tasks, and the exec wrapper. A definition that selects a failed one (an agent allowing a failed subagent, a team with a failed seat) fails too. A failure no single definition owns, such as a team named like an [agents.commands] entry, still refuses every launch until it is fixed. Resuming a lane degrades a member whose recorded profile failed to a bare resume with a warning, as it does for a deleted profile. rimz doctor and startup notices direct you here.

Failure classWhat to fix
Files and YAMLUnreadable trees/files, missing or unclosed frontmatter, malformed or nonmapping YAML, unknown keys, or wrong types. Traits and skill metadata can also be unreadable or malformed.
Retired or misplaced fieldsReplace soul with body text and meka with agent; role meka is invalid because the model selects runtime. Move signals, flip-compact, and idle-compact onto roles. Raw prompt-path/argv keys are not Markdown fields.
IdentityUnsafe, duplicate, reserved, or address-shadowing names; cross-namespace duplicates; team/profile/command collisions.
Required contentMissing or multiline definition/base description, empty kind base, missing team pipeline, roster, stages, or leader. Ordinary definition bodies may be empty.
ResolutionMissing kind inference, unknown or failed parent, cross-namespace inheritance, cycles, excessive shared chain depth, model/kind mismatch, missing kind base, or an unknown/failed seat definition.
Model tiersBoth tier and model set, a tier name in model, an unknown tier (with a suggestion), relative effort, or no eligible model at or above the requested tier. Exclusions identify each family's reason. Configure ordered lists in machine config.toml; project TOML cannot set [tiers], tier, or tier-valued models.
TraitsInvalid names, unreadable fragments, or named traits without a substitution token.
ToolsRequired list missing, malformed entry, unsupported kind, unknown Claude native child type, or an argument that cannot be rendered.
DelegationEmpty/unknown child names, delegation on a child, native Agent combined with a RimZ child list, or a child reference rejected by final namespace validation.
SkillsInvalid names or missing Skill tool; for enforced lists, a listed skill in neither the provider root nor the library, invalid policy metadata, or a listed user-only skill (including automatically added reflect).
Compaction and presetsInvalid native token count or handoff threshold; shared validation/launch rejects unsupported provider capabilities and invalid provider-specific values.
Team topologyDuplicate/missing/invalid role handles; unknown leader; missing, duplicate, unknown, blank, or reserved stages/owners; same Implement/Review owner; undeclared prompt handle; invalid layout, missing or repeated role placement.
SignalsEmpty list, invalid selector or map, blank match value/prompt, unscoped agent selector, or a binding rejected by the shared signal-selector checks. Worktree-dependent scope is checked at launch.

To check a definition by hand without touching your own home, validate it in a scratch one. Point RIMZ_HOME and RIMZ_AGENTS_HOME at a temporary directory, write nonempty kind bases agents/claude.md and agents/codex.md, and give every Claude or Codex definition a tools: list such as tools: [Bash]:

export RIMZ_HOME=$(mktemp -d) RIMZ_AGENTS_HOME=$RIMZ_HOME
mkdir -p "$RIMZ_HOME/agents"
printf -- '---\ndescription: Claude base\n---\nBase prompt.\n' > "$RIMZ_HOME/agents/claude.md"
printf -- '---\ndescription: Codex base\n---\nBase prompt.\n' > "$RIMZ_HOME/agents/codex.md"
printf -- '---\ndescription: Scratch seat\nagent: claude\ntier: senior\ntools: [Bash]\n---\n' > "$RIMZ_HOME/agents/scratch.md"
rimz agents validate

Validation does not prove that provider executables, accounts, sandbox preconditions, or a particular live launch will work. Those remain launch checks.

Moving existing machine configuration

Move agent launch preferences, [agents.commands], [agents.worktree], attention settings, and [agents.subagents] timeout into config.toml. Put direct profiles, children, teams, and traits in the trees above. Old agents.toml, profiles/*/agent.toml, and teams/*/team.toml are no longer read; setup does not convert or delete them. agents.d/*/agent.toml plugin manifests are a separate, unchanged format. Project .rimz/config.toml remains TOML. Validate the Markdown sources before launching.

On this page