Teams CLI
rimz teams lists, inspects, launches, resumes, and drives named teams, hands a team's board from stage to stage, and installs team bundles.
rimz teams lists, inspects, launches, resumes, and drives named teams, hands a team's board from stage to stage, and installs team bundles.
Bare rimz teams exits 2 with the list command first, followed by the same orientation as rimz teams --help: See (list show wait), Drive (focus stop restart flip record), Start (launch resume profiles), and Define (install). Launch flags live under rimz teams launch --help.
A positional word that is neither a command nor a configured team exits 2 and lists both. A lone prompt matching a teams command or alias is also refused with exit 2: rimz teams forge stop suggests rimz teams stop forge. To send the literal prompt instead, use rimz teams launch forge "stop". Explicit launch keeps exit 1 for an unknown team.
A team is a configured set of roles and a layout. Each role keeps its own model, prompt, and @role handle, and every member of one launch shares one lane; that group of live members is a cohort, addressed as team#lane (for example forge#feat-rate-limits). The teams guide explains how to design and run a team, configuration → teams covers where the definition files live, and the definition reference owns every field (roles, leader, layout, stages, scratch-files, consensus-file, append-system-prompt-files, and each role's owns, signals, and flip-compact). This page owns the command forms.
| Command | Does |
|---|---|
rimz teams list, ls | List teams and their live cohorts. |
rimz teams show, inspect | Inspect one team, or every team live in a lane. |
rimz teams profiles | List team role profiles. |
rimz teams <team>, launch | Launch a team. |
rimz teams resume | Resume a team's closed cohort. |
rimz teams focus, stop, restart | Drive a live team. |
rimz teams wait | Wait for a cohort to finish. |
rimz teams flip | Flip the board to the next stage. |
rimz teams record | Record an entry on the board. |
rimz teams install | Install a team bundle. |
rimz teams sets where a cohort runs, whether it resumes, and what each member may spend. Per-agent shaping (model, effort, prompts, permission mode, name, pane placement, supervised runs) stays on rimz agents, which also launches one role of a team as rimz agents forge.reviewer. Every form takes the global flags.
List teams
rimz teams list
rimz teams ls --jsonBare rimz teams, with no verb and no team name (an empty name counts as none), refuses with exit 2 and prints the list command to run. list and ls open with cohort counts and a needs you block using the same attention rule and age columns as agents list. A missing stage owner adds a not live attention row unless the board is at Done; it does not change the cohort's state. With no recorded flip, that row's age falls back to the newest member activity. Definitions with no live cohort collapse into a trailing no live cohort: … line.
| Column | Live cohort |
|---|---|
TEAM | Team name. |
LANE | #<lane>. |
STAGE | The board stage and owner, with not live for an absent owner, followed by the time since its recorded flip. No age when no flip is recorded. |
STATUS | The cohort state, followed by the time since the newest member activity. |
PR | #<number> from the room's cached PR facts, followed by the CI glyph unless the PR is closed; - when no pull request is cached. |
Cohorts needing attention sort first, then blocked, paused, idle, working, and sleeping cohorts; Done cohorts sort last. Within each group, the longest time since member activity comes first. The summary omits zero counts and counts attention rows, not blocked cohorts, as need(s) you.
A broken definition keeps a row at the top, with STATUS replaced by broken: <error>. A live cohort whose team is no longer defined keeps its state with · not defined appended. Resolved roles and models appear in show.
The catalogue merges machine Markdown definitions under <agents_home>/teams/<name>.md with the repository's .rimz/config.toml when trusted. Invalid definitions fail with their source errors; unknown frontmatter keys are errors, not ignored settings. Run rimz agents validate to inspect the complete library. The built-in roleless peer team remains unless replaced. With no user teams, the listing includes an install hint.
--json prints an array of team records. --json works only on the list forms and show: rimz teams forge --json is refused with a pointer to rimz teams show forge --json.
List team role profiles
Tiered role listings and show rosters display the tier beside the concrete model and mark a fallback. JSON adds tier and tier_fallback only for tiered roles; model remains the resolved provider model.
rimz teams profiles
rimz teams profiles --path # add each profile's defining file
rimz teams profiles --json --pathrimz teams profiles lists the resolved seat profiles named <team>.<role> for a configured team, such as forge.coder, as the same cards and JSON as rimz agents profiles. The launch grammar resolves those names as team roles, so rimz agents profiles leaves them out unless it gets --teams. The listing reads the machine configuration; with none configured it prints No team profiles configured. and the install command.
Inspect one team
rimz teams show forge # the definition, then one row per live cohort
rimz teams show forge#feat-rate-limits # one cohort's status, then the definition
rimz teams show '#feat-rate-limits' # every team live in that lane
rimz teams show forge --jsonshow (alias inspect) takes one target:
| Target | Reports |
|---|---|
<team> | The definition, then a table of the team's live cohorts. The team must be defined: a removed team's live cohort shows only in the list and in lane-only forms. |
<team>#<lane>, or <team> -w <lane> | The lane block of the cohort whose lane is <lane> or whose members run in worktree <lane>, then the definition. With no match it exits 1 and names the live lanes, or the resume command when none are live. Root aliases print as #main. |
'#<lane>', or -w <lane> alone | For every team live in that lane, defined or not, its lane block then its definition. With none it prints no live team in #<lane> and exits 0. |
Give the lane once: the fused form and -w together are refused. Quote '#lane' so the shell does not read it as a comment.
Each form leads with what it is asked for. A lane form, here rimz teams show forge#feat-x, checks on a run:
forge#feat-x · idle 48s
stage: Implement (@coder) for 28m
pipeline: Explore → Plan → [Implement] → Review → Submit → Reflect → Done
pr: #412 · open · ci pending · https://github.com/acme/api/pull/412
MEMBER STATUS AGE ACTIVITY CTX COST
@planner success 28m - 61% $1.84
@coder success 48s editing ingest.rs 42% $0.95
@reviewer idle 31m - 8% $0.12
signals: ci.failed → @coder · never fired · team-forge-feat-x-coder-ci-failed
worktree: /repo-worktrees/feat-x
isolation: host · shared ~/.rimz/ws/repo-3f2a/shared
memory: blackboard.md 41 lines · 2m ago
plan-notes.md 120 lines · 18m ago
forge
source: ~/.rimz/teams/forge.md
layout: planner,coder+reviewer
@planner claude fable <- leader
@coder codex gpt-6-astra
@reviewer claude opus
signals ci.failed → @coder
(prompt stack: rimz teams show forge --json)The team form, rimz teams show forge, describes the team and lists its cohorts:
forge
source: ~/.rimz/teams/forge.md
layout: planner,coder+reviewer
@planner claude fable <- leader
@coder codex gpt-6-astra
@reviewer claude opus
signals ci.failed → @coder
(prompt stack: rimz teams show forge --json)
LANE STAGE PR STATUS
#feat-x Implement (@coder) for 28m #412 · open · ci pending idle 48s
#feat-y Plan (@planner) for 4m - workingThe definition block names source and layout, and adds an error line only when the definition is broken. The roster lists each role's handle, provider, and model (- when unset), marks the leader with <- leader, and ends with a signals line when roles declare signal bindings, each shown as signal (match filters) → @role and clipped to the terminal width. When any role has system-prompt files, a pointer to --json follows, since the JSON carries the resolved prompt stack.
The cohort table's STAGE and STATUS cells carry the same text as a lane block's stage line (- when there is none) and header state; PR is the pr line without the URL.
A lane block reads top to bottom:
| Line | Shows |
|---|---|
| Header | <team>#<lane> · <state>, the cohort state followed by the time since any member's last activity, except while working. |
stage | Always present. The board stage with (@owner) when the board names one, then for <age>, the time since the flip into that stage; Done for <age> once the board is flipped to Done; none without a board stage. The age is omitted when no recorded flip matches (a hand-edited board, or a flip rotated out of the event log). |
pipeline | The declared stages with the implicit Done last, bracketing the board stage when it matches a name exactly. Omitted when the team declares no stages. |
pr | The cached pull request: number, state (open, merged, closed), its ci passing, ci pending, or ci failing verdict, and URL, as far as known; none when no pull request is cached. A trunk lane has no pull request, so it reads none however its branch CI stands; that verdict shows on the sidebar. |
| Member table | MEMBER STATUS AGE ACTIVITY CTX COST, members in the team's declared role order. Absent declared roles show not live and dashes. STATUS uses the agent status words, AGE is the time since the member's last activity, and COST is each role's lifetime spend in this worktree. |
signals | One line per subscription RimZ armed for a member from its role bindings: <signal> → @<member> · <fire> · <loop task name>. <fire> is fired <age> ago when the last fire delivered, or the loop run result with its age; ×<n> gives the fire count once it has fired more than once. A subscription that has not fired reads heard <signal> <age> ago when it has heard another signal of its family, otherwise never fired. Heard signals are never counted as fires. Omitted when nothing is armed. The roster's signals line shows what is declared; this one shows what is armed now and whether it fired. |
worktree | The members' absolute checkout path, with · branch <name> when the branch differs from the directory name; - when members disagree. |
isolation | host · shared <dir> or sandbox · shared <dir>: the room's shared directory ($RIMZ_SHARED, the same host path in both isolations), and where each member ran: the isolation its launch enforced, else the --isolation recorded at launch or replaced on resume, else the machine's agents.isolation. The enforced isolation already folds in a profile isolation default. Members that disagree show the machine setting. |
memory | Files matching the team's effective scratch patterns (defaults or explicit scratch-files), relative to the worktree, with line counts and modification ages. Omitted when none exist. |
When the stage owner is absent, its stage label reads Implement (@coder, not live) for <age>.
A script that blocks until the work is done runs rimz teams wait rather than polling .stage.name from --json. The report ends with the definition, with no launch, resume, or focus hints.
The definition includes a (prompt stack: rimz teams show <team> --json) hint when roles have prompt files or the team has a consensus.
Cohort state
A cohort's state is the first rule that matches its members' projected card statuses, including the sidebar's attention lift when a provider-native child waits or fails:
| State | When |
|---|---|
blocked | Any member is waiting or failed. |
paused | Any member is paused. |
working | Any member is running. |
sleeping | Any member is sleeping: at rest with a one-shot wait or delivery armed. Standing subscriptions do not count. |
idle | Otherwise, including members whose last turn succeeded. Whether the pipeline finished is the board stage, never member status. |
Board stage
The stage comes from the first line starting Stage: in <worktree>/blackboard.md, for example Stage: Implement (@coder). Only a final (@owner) splits off as the owner; other parenthesized text stays part of the stage name. A missing or unreadable board shows no stage, even when the team declares a pipeline. flip writes this line, and a hand-edited board parses the same way. The stage is advisory: RimZ never infers it from member status, and it is not proof that work finished.
PR and CI facts come from the room's sidebar cache. rimz teams list and show never contact the forge, so pr none means no pull request is cached, not that no PR exists. Before the room publishes its first snapshot, live cohorts still appear without PR facts or activity.
JSON report
rimz teams list --json prints an array of team records, show <team> --json one record, and lane-only show --json an array (empty when no team is live there). Fields marked optional are omitted when unset; the rest are always present, with null where a value is unavailable.
| Field | Meaning |
|---|---|
name, defined, valid | Team name; whether a definition exists; whether it resolves and validates. |
source, layout, leader, error | Optional. Definition file (built-in for peer), layout spec, effective leader role, validation error. |
consensus | Staged teams only: "builtin" or the absolute replacement-file path. RimZ keeps a read-only copy of the built-in text on disk. |
append_system_prompt_files | Team-level files composed after the consensus, as absolute paths. Omitted when empty. |
roles[] | role, profile, and signals, plus optional kind, model, effort, tier, tier_fallback, mode, system_prompt_file, and append_system_prompt_files. |
roles[].append_system_prompt_files | The role's own resolved profile-chain and role fragments, excluding the team layer. Omitted when empty. |
roles[].signals[] | Declared bindings: signal, match (an object), and prompt (nullable). |
instances[] | One record per live cohort, below. |
| Instance field | Meaning |
|---|---|
channel, state | Lane name without #, and the cohort state. |
status_counts | Object mapping each member status to its count. |
last_activity_at | The newest member last_activity_at (UTC timestamp). |
worktree, branch | Absolute checkout path and branch; null when unavailable or when members disagree. |
isolation, shared_dir | host or sandbox; the absolute host path of the room's shared directory. |
stages | Declared stage names in order; [] when undeclared or the team is no longer defined. |
stage | { "name": "Implement", "owner": "coder", "owner_live": true, "since": "2026-09-15T08:33:23Z" }; null when the board has no stage. name is Done once the board is flipped to Done, so .stage.name is the field to script against. owner is without @ and nullable; owner_live is true or false by the same role-holder rule as flip delivery, and null when no owner is named. since is the UTC time of the flip into this stage, null when no recorded flip matches. |
pr | number, state (open, merged, closed), ci (passing, pending, failing), and url, each nullable; null when no pull request is cached. |
memory[] | path (absolute), lines, and modified_at (UTC timestamp or null). |
members[] | In declared role order: role (nullable), handle, kind, status, phase, activity (nullable), last_activity_at (UTC timestamp), signals, and optional context_fill_pct and cost_usd. |
members[].signals[] | Armed subscriptions: name (the loop task name), selector, matches, optional fired, the task's latest fire: at (UTC timestamp), result (the snake_case run result, delivered for a delivered firing), and runs (the fire count), and optional heard, the newest sibling signal heard without firing: signal and at. A subscription that only heard siblings has heard and no fired. These keys differ from the declared roles[].signals[]. |
Launch a team
In both the bare and launch forms, PROMPT may start with -; a value that is itself one of the command's flags (--isolation, --isolation=…, -h, --help, etc.) needs -- before it. A prompt starting with -w is refused, even after --, to avoid mistaking an attached worktree option for a prompt; use -w NAME with a space.
rimz teams forge -w feat-rate-limits "add rate limiting"
rimz teams forge#feat-rate-limits "add rate limiting"
rimz teams forge#feat-rate-limits --fresh
rimz teams forge --from-pr 91 --bg
rimz teams peer --channel triage
rimz teams launch forge -w feat-rate-limitsA checkout holding another team (a live member, or team history with a board stage other than Done) refuses a fresh launch; rimz teams flip <team>#<lane> Done "<note>" releases a stopped run without removing its checkout. A channel held at a different checkout also refuses a fresh launch, even for the same team, whether the channel is explicit or derived from the checkout.
rimz teams <team> [PROMPT] and rimz teams launch <team> [PROMPT] launch a configured team and send the optional prompt to its leader: the leader role, else the first declared role. The team's tab selects the leader's pane internally; whether the client enters it follows the agent launch focus rule. Both run the same launch as rimz agents <team>: worktree creation, channel placement, pull-request checkout, and reconciliation with an existing cohort. A live cohort receives the prompt through its leader, or is just focused when no prompt is supplied; an agent caller or --bg preserves focus. A missing leader refuses with exit 1 and commands to message live members. A closed cohort prompts to resume, start fresh, or remove; cancellation and non-terminal refusals exit 1 with prompt-preserving next commands. A name that is not a defined team is refused with the list of configured teams, and forge.reviewer is refused with a pointer to rimz agents forge.reviewer. A team launched by an agent is a top-level cohort, not a child of that agent.
| Flag | Effect |
|---|---|
-w, --worktree [NAME] | Reuse or create the RimZ-owned worktree NAME, on lane #NAME; bare -w generates a name. New trees branch from the remote default branch, fetched at launch, unless agents.worktree.base selects head or a literal ref. A configured fresh also fetches. The fetch never prompts and gives up after 60 seconds, so an ssh origin whose key needs a passphrase with no agent running waits out that budget. A failed fetch warns and uses the last-fetched tip, or local HEAD if none exists; with no origin, an unset base uses local HEAD. Reuse and --from-pr do not fetch. team#NAME is the same selection; give one or the other. Name rules and prompts are on rimz agents. |
--channel NAME | Launch into the durable named lane NAME in the room root. Conflicts with -w and team#worktree. |
--from-pr PR | Create or reuse a worktree from a pull-request number or URL. |
--description TEXT | Seed the member cards' description until the agents name their sessions. |
--continue | Resume the matching closed cohort instead of launching; the same as rimz teams resume. |
--fresh | Start new sessions in an existing named worktree instead of resuming its closed cohort, keeping the checkout and its files. Needs -w NAME or team#NAME. |
--budget AMOUNT[/day] | Cap each member's spend for the session (5) or the local day (20/day). Each member is capped separately; there is no pooled team cap. See rimz budget. |
--isolation host|sandbox | Run every member under this isolation instead of the machine's agents.isolation, recorded per member. |
--bg | Keep focus where it is, as agent callers always do. See the focus rule. |
--new-tab | Open the launch in a new tab or tmux window. |
--detach | Launch the prompt without a team report and without holding the launching agent. Refused without a prompt and with --continue. |
--continue accepts --isolation host|sandbox, replacing each member's recorded isolation while keeping its conversation, and queues PROMPT to the leader after reopening. For model, effort, agent-base, tier, or permission overrides, use the resume verb below. --from-pr, --channel, --description, and --budget still conflict with resume. --fresh conflicts with --continue and --from-pr. Without --continue or --fresh, a launch into a named worktree whose cohort has closed offers the choice only at a terminal: run unattended (stdin not a terminal), it prints the resume and fresh commands to stderr and exits 1 without launching. Launch flags without a team name are refused with team launch options require a team name.
A launch that opens new panes prints a receipt:
launched forge in worktree #feat-rate-limits
path /repo-worktrees/feat-rate-limits
board blackboard.md
prompt → @planner "add rate limiting"
@planner (stable-haven) claude fable <- leader
@coder (round-binder) codex gpt-6-astra
@reviewer (quiet-otter) claude opus
signals ci.failed → @coderThe header names the lane as in worktree #<lane>, for a --channel lane too. path is the absolute checkout, and board is blackboard.md relative to it, whether or not the file exists yet. The prompt line appears only when you gave one: whitespace collapsed, quotes escaped, clipped to the terminal width. Member rows show the handle rimz agents list gives the member, its pet name beside it when the two differ, then provider and model (- when unset), and a signals line closes them when roles declare bindings. The receipt has no command hints and no JSON form; an agent's prompted launch adds the team report lines.
The receipt records what was launched. Members start asynchronously and may not yet appear in rimz teams show, which is the source of live status. To block until the board reaches Done, run rimz teams wait forge#feat-rate-limits; the cohort is resolvable as soon as the launch command returns. To be told when the cohort next goes idle instead, arm a one-shot signal subscription:
rimz loop add team-idle --wait @me --signal team.idle --match instance=forge#feat-rate-limits --onceIt fires on the next transition to idle only. Signals never replay, so a cohort that was already idle when you armed it does not wake you; check show as well. Idle does not mean the task is done.
Signal bindings at launch
A role's declared signals become live subscriptions when its member registers: at launch, resume, restart, and when the role is re-added. Subagents do not inherit them. Ending, losing, or stopping the session removes its subscriptions, and signals missed in between are not replayed. The binding list is part of project trust.
A launch from the root checkout with no named worktree (-w NAME or team#NAME) and no --from-pr refuses any ci.* or pr.* binding that lacks match.branch or match.path, before it creates panes or worktrees: the root checkout requires an explicit scope. Launch with -w NAME, launch from a linked worktree, or add an explicit branch or path match. match.branch = "*" accepts every checkout RimZ watches; see signal matching.
Resume a team
rimz teams resume forge
rimz teams resume forge#feat-rate-limits
rimz teams resume forge -w --bgresume reopens the newest closed cohort of the team, with the identity, directory, and lane recorded in the store and each role's saved launch record over its current profile. team#worktree or -w NAME limits the match to that worktree. Bare -w, or no flag while you stand in a linked worktree, scopes to the current worktree; from the root checkout the newest match anywhere in the room wins. A matched member that is still live refuses the command. Matching rules are on rimz agents → Continue a cohort.
--model MODEL, --effort LEVEL, --fast or --no-fast, --agent PROFILE|KIND, --tier TIER, --ask or --yolo, and --isolation host|sandbox become the saved launch settings, with the same provider and tier restrictions as rimz agents forge --continue. A positional PROMPT is queued to the team's leader as a user message after reopening. Omitting isolation preserves each member's recorded override; a member with none recorded takes its profile's isolation default, then machine policy. The replacement survives restart, rebirth, and child launches.
--bg and agent callers keep focus where it is under the focus rule. resume prints one line per member, resumed <kind>:<name> (<session id>) or started fresh <member> for a member with nothing to resume, followed by Check:, Reach:, and Wait: command hints for the cohort.
Drive a live team
rimz teams focus forge
rimz teams restart forge
rimz teams stop forge#feat-rate-limits
rimz teams stop forge -w feat-rate-limits| Verb | Does | Prints |
|---|---|---|
focus | Jumps to the member that most needs attention, else the declared leader, else the first member. | Nothing on success. |
stop | Closes every live member, stopping each member's own subagents first. | stopped TEAM#LANE (N members), then stopped @<handle> per member it stopped, error @<handle>: <reason> per failure. |
restart | Relaunches every live member in declared role order, resuming each provider session where supported. | restarted TEAM#LANE (N members), then one restart line per member, error @<handle>: <reason> per failure. |
stop and restart continue past a failed member and exit 1 when any member failed. A member whose account fails the account check is one such restart failure; a team launch and rimz teams resume refuse whole on it.
After a successful stop, a pending board keeps an existing checkout held. The receipt names its stage and prints the addressed resume and flip ... Done release commands. Stopping does not finish the board; ordinary worktree cleanup still applies.
Each verb acts on one live cohort. Without a lane, RimZ takes the cohort in your current lane, or the only live cohort; when several are live elsewhere it refuses and lists their lanes. team#worktree or -w NAME selects by lane or worktree name. With no live cohort, the error suggests rimz teams resume <team>.
Wait for a cohort to finish
rimz teams wait forge#feat-rate-limits
rimz teams wait forge -w feat-rate-limits --timeout 4h
rimz teams wait forge#feat-a forge#feat-b --json
rimz teams wait forge#feat-a forge#feat-b --anyrimz teams wait <NAME>... [-w NAME] [--any] [--timeout DURATION] [--json] blocks until each named cohort's board reaches the Done stage. Each NAME selects one live cohort the way the drive verbs do, once, when the command starts; -w NAME is accepted only with a single NAME. The team must be configured.
The wait reads the board stage every 500 ms and settles a cohort when:
| Outcome | When | Exit |
|---|---|---|
| completed | The board's stage is exactly Done (Done (delta) is not). A board already at Done settles at once. | 0 |
| failed | Every member has ended while the board is not at Done. | 1 |
A missing board, or a member waiting on you or failed, keeps the wait blocked: only the board says the work is done. With several names the wait settles when all of them have, exiting 0 when all completed and otherwise with the code of the first name, in argument order, that did not. --any settles on the first cohort to finish and exits with its code. --timeout caps the whole wait and exits 124, leaving the cohorts running. The wait changes no durable state.
With one name, a completed wait prints the board's ## Result section on stdout and nothing else; a board without one prints a note on stderr instead, and a failed wait prints rimz: <team>#<lane>: cohort ended before Done (stage: <stage>) on stderr. With several names, or --any, each cohort prints as it settles under a --- <team>#<lane> --- header, suffixed with its status when it did not complete.
In both human and --json modes, stderr reports each cohort's stage, owner, and state at the start, then changes to the stage, owner availability, or set of members needing you. A missing owner reads @<owner> not live, with no focus command, since focusing the cohort does not reach an absent owner; attention changes include a rimz teams focus command. Age changes alone print nothing. These diagnostics do not end the wait when a person is needed. On timeout, each pending cohort gets a line naming the elapsed limit and stage, ending cohort left running.
--json prints one object for a single name, and an object keyed by <team>#<lane> for several once the wait ends:
{"status": "completed", "exit": 0, "stage": "Done", "board": "/repo-worktrees/feat-rate-limits/blackboard.md", "result": "PR: https://github.com/acme/api/pull/42"}status is completed, failed, or timed_out; stage is the board's stage when the wait ended (null without a board); result is the ## Result section, null unless completed with one; a failed entry adds error.
Team reports
When an agent launches a team with a nonempty prompt, that agent gets one TEAM_REPORT message from @rimz each time rimz teams flip Done moves the board into Done. It reports the prompted leader the way a fleet report row reports one agent:
Type: TEAM_REPORT
From: @rimz
Content:
Team forge#feat-rate-limits reached Done; its leader reports:
- @planner: completed in 2h14m, task: "Add rate limiting to the public API", response: /home/me/.rimz/ws/myrepo-f89e/out/boss/planner.<run_id>.output (~1.2k tokens, 31 lines)
Memory: /home/me/proj-worktrees/feat-rate-limits/blackboard.md| Part | Meaning |
|---|---|
| Elapsed | From the launch, or from the flip that last left Done, to this Done |
| Task | The launch --description, falling back to the first line of the launch prompt |
| Response | The leader's last final message, as a file the launcher can read, with its size; no response when the leader never finished a turn |
| Memory | The absolute path of the team's board, as seen by the launcher |
The launching agent's receipt names the leader's response file and rimz teams wait <team>#<lane>, and, unless the launch is detached, rimz teams stop <team>#<lane> for once the report arrives. The report is parked and delivered at the launcher's next turn boundary. The flip receipt adds a report line naming the launcher. A flip out of Done prints report TEAM_REPORT again at the next Done, and the next Done sends a new report.
A team launched with --detach sends no TEAM_REPORT. Its run still follows the board: Done and cohort death settle it and write the leader's response file, a flip out of Done opens the next detached stretch, and each flip receipt prints report none: the team was launched detached in place of the report line. The launcher is not held open or shown as waiting for it; rimz teams wait still blocks on Done.
The seats do not report their own turns, including turns the launcher opens with rimz message, and they add nothing to the launcher's fleet report. When every member ends before Done, the launcher receives one failure TEAM_REPORT with the last board stage and the leader's last response; if the board already reads Done at settlement, it receives the completed report instead. No report is sent when you launched the team yourself, when the launch had no prompt, when the leader's provider lacks native turn hooks (the launch receipt says so), after stop, restart, or room recovery settled the run, when the launcher has ended, or when the board is edited to Done by hand while the cohort stays live. Resume opens no new run, so a cohort resumed after death settlement reports nothing at its next Done.
Record an entry on the board
rimz teams record [TEAM#LANE] <SECTION> [TEXT] [--file PATH] [--stdin] appends one timestamped entry to blackboard.md. SECTION is Goal, Decisions, or Result, case-insensitive. Supply exactly one of TEXT, --file PATH, or --stdin; files and stdin are read to EOF. Text loses carriage returns and surrounding whitespace, but keeps internal blank lines. TEXT may start with -; only a value that is itself one of the command's flags (--file, --stdin, -h, --help) needs -- before it, as in rimz teams record Decisions -- --stdin.
An address such as forge#feat-rate-limits selects the live cohort, or the stopped team holding that lane, just as flip does. Without it, the command uses RIMZ_WORKTREE_PATH when set, otherwise the current Git toplevel; this form can still create a board before any cohort exists. No live cohort is required and there is no --team flag. A member of the selected cohort records under its role; other callers record as user. A member of another cohort is refused.
Entries have the following shape (stamp in the configured machine time zone):
- 2026-09-26T15:20:59+02:00 @planner: first line
second line
a paragraph after a blank lineContinuation lines are indented two spaces. The command appends after the section's last nonblank line. A missing section is inserted in Goal, Decisions, Progress, Result order, before the first later section present or at EOF. A missing or empty board gets this template, with the entry under the selected heading:
# Blackboard
## Goal
## Decisions
## Progress
## ResultThere is no Stage line until a flip. Success exits 0 and prints one line naming the section and author, such as recorded Decisions @planner or recorded Goal @user; the entry itself is not echoed. The section prints in its canonical capitalization whatever the input casing. A TEXT argument inside double quotes is expanded by the shell first, so pass text holding backticks or $ through --stdin with a quoted heredoc (<<'EOF'). Recording does not flip the stage, send messages, compact agents, or require a clean worktree or trusted team definition. To amend or remove an existing line, edit the board directly; direct edits take no board lock.
| Error | Result |
|---|---|
| Stage, Progress, or Progress log | Exit 1: names rimz teams flip as the owning command. |
| Unknown section | Exit 1: lists Goal, Decisions, Result. |
| Blank text | Exit 1: provide nonblank text for the board entry. |
| Missing or multiple text sources | Exit 2: supply exactly one text source. |
| Caller belongs to a cohort elsewhere | Exit 1: calling agent belongs to a team cohort in another worktree. |
| No worktree, unreadable input or board, lock timeout, write failure | Error with the underlying failure. |
Flip the board to the next stage
rimz teams flip Explore "board opened; sweep aimed at rate-limit handling"
rimz teams flip Implement "plan ready in plan-notes.md; three advisories carried in"
rimz teams flip Review "implementation committed; report in implement-notes.md" --team forge
rimz teams flip Done "reflection recorded in reflect-notes.md; run complete"rimz teams flip [TEAM#LANE] <STAGE> <NOTE> [--team NAME] sets the board's stage, records the note in its progress ledger, and wakes the stage's owner. NOTE is required for every stage, Done included, and must not be blank. Write it as where the work stands; it is not an instruction to the owner. NOTE may start with -, as in rimz teams flip Review "--no-tests: docs only"; only a note that is itself one of the command's flags (--team, --team=…, -h, --help) needs -- before it.
Which cohort a flip acts on
flip has no worktree flag. Give TEAM#LANE to select a cohort from elsewhere in the room, or run it inside the team's worktree. The # distinguishes an address from a stage.
- With
TEAM#LANE, the cohort supplies its recorded worktree. Without it, the worktree isRIMZ_WORKTREE_PATHwhen set, else the Git toplevel of the current directory. Outside Git with neither an address norRIMZ_WORKTREE_PATH, the flip is refused. - Select the live cohort in that lane or checkout, otherwise the team holding it under the launch hold rules.
LANEmatches as it does forstop,focus, andrestart: the lane, its worktree name, ormainfor the root checkout.--team NAMEfilters the current checkout and cannot be combined withTEAM#LANE. With several live cohorts, the error lists the choices. - A caller in the selected cohort flips as its role. A caller outside any cohort flips as
@user. An agent in a different cohort is refused.
A project team that is not trusted is refused, as for any command that reads an untrusted project config.
With no live members, a user can still flip the held board. The receipt says no live members; a Done flip that ends the board's hold adds checkout released, and one made while a recorded member still holds the checkout does not. Release ends the board's hold, not the checkout itself: no worktree is removed. Other stages name the absent owner as not live; woken on resume.
Stage rules
Stages come from the team definition (configuration → teams). STAGE must match a declared stage exactly and case-sensitively: a name in stages, or in the roles' owns lists when stages is empty. It must have an owning role. Done is always accepted, is implicit and last, and cannot be declared or owned. Put qualifiers such as "delta round" in the note. The command does not enforce pipeline order, and flipping out of Done reopens the work.
A member handing off needs a clean worktree. A hand-off is a member leaving a stage its role owns for one it does not own, Done included. When git status --untracked-files=all lists any path under the worktree, the flip is refused before the board changes and names the paths. The root blackboard.md never counts, and ignored files (including the patterns the team's scratch-files registers) never appear; other memory files count. User flips, same-stage re-fires, moves between stages the member owns, and flips made while another role owns the current stage skip the check, so a human can always force a hand-off.
What a flip writes
The first flip creates <worktree>/blackboard.md when absent. Each flip, under a per-worktree lock:
- Replaces the first line starting
Stage:withStage: <stage> (@<owner>), orStage: Done. With no such line, it inserts one after a leading#heading, else at the top. - Appends a ledger line to the
## Progresssection (an existing## Progress logis used too), creating the section when absent:- YYYY-MM-DDTHH:MM:SS±HH:MM @by: from -> to — note, oropened <to>instead of the transition when there was no stage. The time is RFC 3339 with its UTC offset, written in the configured time zone, and a multiline note is joined onto one line. The sidebar's run clock reads this ledger and still accepts older stamps without an offset (seconds or minute form), read in the configured zone. - Appends a durable
team.stagesignal and fires its subscriptions. - Delivers a
STAGEnotice to the owner, as described below.
Other board text is left as it is; the leader writes the rest of the board.
- 2026-09-12T14:02:11+02:00 @planner: opened Explore — board opened; sweep aimed at rate-limit handling
- 2026-09-12T14:20:36+02:00 @planner: Plan -> Implement — plan ready in plan-notes.md; three advisories carried inTo undo a mistaken flip, flip back to the intended stage; both entries stay in the ledger. A flip to the current stage repeats the ledger line, signal, and delivery. The board and ledger mechanics are in team memory and stages.
The receipt
Flipped Plan -> Implement by @planner (forge#feat-rate-limits · feat-rate-limits)
Explore → Plan → [Implement] → Review → Submit → Reflect → Done
owner @coder, woken at its next turn boundary
compact queued for you: 204k tokens, over 180kThe header reads Opened <stage> on a board with no prior stage and names the flipper, the cohort, and the worktree directory. The pipeline line appears only when the team declares stages. The note is not echoed; it lands in the board's ledger line.
owner row | Meaning |
|---|---|
@<owner>, sent now | The owner was at rest and received the notice immediately. |
@<owner>, woken at its next turn boundary | The notice is parked until the owner's turn ends. |
@<owner>, not live; woken on resume | No live member holds the role. The board and signal still land. |
you, carry on | You own the destination stage; no notice is sent. |
| (omitted) | The stage is Done; no notice is sent. |
The compact row appears only when flip compaction acted: queued for you: <n>k tokens, over <threshold>k, sent, or skipped: <reason>.
The owner's notice
The owner receives a message with Type: STAGE and From: @rimz, delivered at its next done turn boundary; flip has no interrupt option. The body is prose:
@planner flipped the stage Plan -> Implement. Implement is yours: pick it up from blackboard.md.
Note: plan ready in plan-notes.md; three advisories carried inA board with no prior stage reads @<by> opened the stage <stage>., and a same-stage flip reads @<by> re-opened <stage>. It is still yours: pick it up from blackboard.md. When the team declares a leader and the owner is another role, the body ends with that seat's channel rule:
Your report goes in your stage file and anything for the user to @planner; end the turn with the flip and no pane text.When the current stage's owner is resumed (by a team resume, a restart, a single-member restart, or room rebirth), RimZ re-wakes it without waiting for a prompt and without touching the board or ledger. An owner launched fresh into an open stage is re-woken when it registers instead (resume re-wake). A re-wake is a team.stage signal with from equal to to and by set to rimz, and this notice:
The team resumed at stage Implement, which is yours. Nothing flipped since the board's last Progress line: reread blackboard.md and continue from where it stops.Explicit team.stage subscriptions receive the loop's signal message independently of the notice. rimz transcript shows each flip in the lane's conversation (transcript); re-wakes are not shown.
The team.stage signal
| Payload field | Value |
|---|---|
team | Team name. |
instance | team#lane. |
from | Previous stage; absent when the flip opened the board. |
to | Destination stage. |
owner | Owner role; absent for Done. |
by | Flipping role name, user, or rimz for a re-wake. |
note | The flip's note; absent on a re-wake. |
board | Absolute path of blackboard.md. |
at | RFC 3339 time. |
The signal's source is team, and rimz events emit cannot produce it.
Flip compaction
A flip can compact the flipper's own context once it hands off. Set [harness] flip_compact = "180k" for a machine default, or flip-compact on a role to override it; both accept token counts, percentages such as "70%", or "off". An explicit role value wins, including over a machine "off". With neither set, the built-in default is 120k for a role owning Plan, 180k otherwise. The machine default is documented in configuration → hand-off compaction and the role field in the definition reference.
Only a hand-off (the same predicate as the clean-worktree rule) to a stage another role owns is eligible; a flip to Done never compacts, because no member works after it. RimZ checks the member's occupied context against the threshold first; below it, or with occupancy unknown, nothing happens and nothing is recorded. At or above it, RimZ queues or sends the compact command for the flipper's next turn boundary. A missing pane or a compact-command error prints skipped and never fails the flip. Each attempt writes a flip compaction assist record shown in rimz stats. A launch refuses a team whose effective threshold falls on an adapter with no compact command; set flip-compact = "off" on that role, or [harness] flip_compact = "off" when the role inherits the machine setting.
When a flip fails
| Error | Fix |
|---|---|
team `<team>` has no stage owners | Add owns to the team's roles. |
unknown stage `<stage>`; choose one of [...] or Done | Use an exact declared name. |
stage `<stage>` has no owner | Add the stage to a role's owns. |
worktree <path> has uncommitted changes: <paths> | Commit or discard the listed paths, then flip again. |
no matching live team cohort in worktree <path> | Run from the team's worktree. |
multiple live team cohorts in worktree <path>; select a team with --team <name> | Add --team. |
calling agent belongs to a different team cohort | Flip from a member of the selected cohort, or from outside every cohort. |
completed <steps>; <error>; re-run `rimz teams flip <team>#<lane> <stage> "<progress note>"` to repeat the signal and delivery | The board changed but appending the signal or delivering the notice failed. Re-run the flip rather than editing the board by hand. |
A failure to fire subscriptions after the signal is appended is logged and does not fail the flip. Launch and flip also reject invalid stage configuration (blank or padded names, control characters, duplicate owners, a declared or owned Done, owned names missing from a nonempty stages); the rules are in configuration → teams.
Install a team bundle
rimz teams install
rimz teams install forge
rimz teams install forge --force
rimz teams install forge --ref mainBare install lists the bundles under examples/teams/ in the RimZ GitHub repository as a TEAM REF table. install <name> fetches <name>.md and the agent definitions selected by its roster, writing <agents_home>/teams/<name>.md and <agents_home>/agents/<agent>.md. The bundle's kind bases (agents/claude.md, agents/codex.md) are written only where the machine has none; an existing base is never replaced, --force included. The default agents home is ~/.rimz, which RIMZ_HOME relocates; RIMZ_AGENTS_HOME overrides only the definition trees and skill library.
| Flag | Effect |
|---|---|
--ref TAG|BRANCH | Fetch from this tag or branch. The default is the release tag of the running binary, v<version>, so the bundle matches the command. When that tag is missing (a development build), the error suggests --ref main. |
--force | Overwrite existing target definition files. Unrelated files stay. Requires a name. |
Without --force, any existing target is refused. Each file is written atomically. Network, GitHub API, parsing, and filesystem failures stop the install and name the failing source or destination. Run rimz agents validate after installation to check the resulting definitions and skill library.