Skip to content

Agent Clans, Sessions, and Tribes

SASE uses three different kinds of agent grouping. Agent sessions were formerly called agent families.

Concept Directive or naming form Purpose
Agent clan %clan:<name> / %id(<id>, clan=<name>) Declare or join a named, rootless container for parallel agents
Agent session %i(<suffix>, session=<parent>) A strictly sequential chain named <session>--<suffix>
Agent tribe %id([<id>], tribe=<name>) / #tribe A user-managed label displayed with an @ prefix, such as @review

Dot-separated names also define an agent hood: foo.bar and foo.baz are neighbors in hood foo, and the agent named foo belongs to hood foo as well. A deeper name belongs to every hood along its dotted path, so sase's TUI can group foo.bar.worker with peers under foo.bar and cousins under foo. A session joins hoods under its bare session name, not its root member's -- name, so a session foo and a single agent foo.bar are related in both directions exactly as two single agents with those names would be. Clans use that namespace rule deliberately, while dotted names alone do not create clan or session membership.

Parallel Agent Clans

An agent clan is a container, never an agent. A %clan prompt spells its full hood-qualified %id; other members can use %id(<id>, clan=<name>) to derive that name and join the same clan:

%id:release.build
%clan:release
Compile the release.
---
%id(test, clan=release)
Test the release.
---
%id(land, clan=release)
%wait:release.build,release.test
Publish the release after both members finish.

The short form is %c:release. %clan is create-only: exactly one prompt may declare a clan, and declaring a clan that already exists is an error. Use %clan(<name>, tribe=<tribe>) (or the %c(...) alias) to assign the declaration's tribe to the entire clan generation; tribe= on %id cannot be combined with clan membership. Every other member uses clan=. That form joins an existing clan or creates it implicitly without a tribe, takes exactly one member id, allows dotted ids, and accepts a leading ! for forced reuse. Static names and templates such as %id(cld, clan=research.{@1}) work; the derived research.{@1}.cld name flows through normal template allocation. In macro swarms, prefer keyed markers like {@1} so every clan member, wait, fork/resume target, and prose reference is substituted in the parent dispatch before any member starts. Bare templates such as research.@ still work, but their references use latest-wins lookup and are unsafe for late-starting swarm members. See Macro template directives for {@<id>} and {@<id>!}.

Launch-time clan summaries

The declaring member can attach a short description to its clan generation. sase's TUI displays this description near the top of the clan's CLAN panel; it is metadata and is not sent to the member as work instructions. When the clan belongs to a tribe, the tribe's TRIBE document (shown when the whole tribe panel is focused) also indexes this description in its CLAN SUMMARIES section (see Tribe Side Panels). Use a literal for stable context, the double-colon shorthand for a larger text block, or an executable when the description depends on state available as the runner starts. A literal keeps the work prompt immediately below the declaration:

%id:research.lead
%clan(research, tribe=study, summary="Audit authentication and authorization")
Review the security boundary.

The text-block shorthand ends when the next top-level directive or macro reference begins:

%id:release.lead
%clan:release:: Coordinate the release checks and summarize blockers.
#release_work

For a computed description, name an executable instead:

%id:triage.lead
%clan(triage, summary_script=./describe-triage)
Triage the current failures.

The value may also contain shell-style quoted arguments. Use the directive text-block form when the command itself contains spaces or quotes:

%id:release.lead
%clan(release, summary_script=[[sase_clan_summary_plan "plans/release plan.md"]])
Coordinate the release.

sase_clan_summary_plan renders any valid tale or epic plan with the same logical PLAN-lane presentation used by sase's TUI. Its first argument is the plan reference; when that argument is omitted, it reads SASE_EPIC_PLAN_REF instead.

summary= accepts the usual directive values: a bare token, a quoted string for text containing spaces or special characters, or a multiline [[...]] text block. The :: shorthand requires a following space or end of line and captures everything until the next top-level line that starts a directive (%) or macro reference (#). That captured text becomes only the summary, so use summary= when ordinary work instructions follow the declaration directly. summary= and summary_script= are mutually exclusive, and both belong only on the create-only %clan declaration; %id(..., clan=...) joiners cannot declare or replace a summary.

A summary executable may run synchronously twice: first while SASE extracts launch directives, before dependency waits, runner-slot admission, and workspace preparation, and again after the primary workspace and every applicable sidecar and linked-repository workspace have been prepared. The first attempt uses the workspace path with which the runner started; for a deferred-workspace launch, that is the placeholder workspace. The second attempt uses the real prepared workspace claimed after the wait. A waiting runner that re-execs to load updated SASE code can repeat this sequence, so summary executables must be read-only and idempotent.

A bare executable name is resolved next to the running Python interpreter and then on PATH; a value containing / is resolved as an executable absolute path or a path relative to that initial workspace. SASE first probes the complete value as a literal executable, preserving executable filenames that contain spaces. If that fails, it applies shell-style quoting, resolves the first token by the same rules, and passes the remaining tokens directly as argv; it never invokes a shell.

Each attempt inherits the runner environment available at that point. The post-preparation attempt therefore sees environment updates made while preparing the workspace and linked repositories. SASE gives both attempts the same identity contract: it overrides SASE_CLAN_NAME, SASE_CLAN_GENERATION, and, when the declaration has one, SASE_CLAN_TRIBE (otherwise an ambient clan-tribe value is removed). Epic work also provides SASE_EPIC_PLAN_REF, SASE_EPIC_PLAN_SNAPSHOT, SASE_EPIC_BEAD_ID, SASE_PHASE_BEAD_ID, and SASE_EPIC_CLAN_TRIBE; SASE reconstructs these values from persisted agent metadata after launch-only variables have been consumed. The snapshot is an absolute, project-scoped, guaranteed-local best-effort copy used by the built-in epic summary script after ordinary checkout candidates. The original plan reference remains the displayed and persisted association.

Standard output becomes the summary and standard error is appended to the agent log. Every attempt has the same 20-second timeout and non-fatal failure handling, and the stored summary is capped at 32 KiB of UTF-8. Missing executables, malformed quoting, timeouts, nonzero exits, and empty output are logged without blocking the agent launch. SASE uses the last successful non-empty output: a successful post-preparation attempt replaces the extraction-time value, while a later failed or empty attempt leaves the newest successful summary untouched.

SASE trims trailing whitespace and records the result in the clan's durable record under <sase_home>/agent_clans/<clan>.json, keyed by clan generation. What is recorded and when: a %clan declarer records its declared tribe= and either its literal summary= (source declared) or its summary_script= (source declared) plus the script's non-empty output (source script); an epic-nominated joiner records its script output (source script) and script (source propagated); any member carrying the epic environment tribe records that tribe (source propagated, fill-only); every post-preparation summary refresh records the fresh non-empty output (source script); and just before any artifact directory is deleted, its clan attributes are captured into the record (source captured, fill-only).

Precedence: for a (clan, generation) key, an attribute present in the record (including an explicit edited-unset tombstone) wins over member-derived values, so member artifacts that predate the record — legacy, imported, or remote artifacts — still resolve, but never override it. declared, script, edited, and inherited overwrites beat member values; propagated and captured only fill missing attributes, so a clan-level tribe edit sticks even when newer epic members carry clan_tribe=epic. An empty or failed summary never erases a recorded one. The scan contract therefore resolves summaries and tribes within one clan generation from the record first, falling back to the newest explicit member declaration only when the record is silent. Rich markup is rendered when valid and shown as literal text when invalid.

Because the record outlives any single member, clan summaries and tribes survive kills, dismissals, relaunches, and full restarts: deleting the declaring agent's artifacts captures its attributes first, and later scans — full, bounded, and delta alike — apply the record over whatever member artifacts remain. The saved description is distinct from the foldable sections that sase's TUI synthesizes below it from member artifacts and activity.

Pressing N on a clan row or on any clan member sets the whole clan generation's recorded tribe through the same durable path, and clearing it writes an explicit edited-unset tombstone. The unset sticks even when members still carry an epic tribe, because fill-only propagated values never overwrite the record. Member edits also keep their agent_meta.json and %clan prompt rewrites so older readers still see the new tribe.

Re-creating a clan: when a launch creates a new generation of a previously recorded clan without an explicit tribe= (and without an epic environment tribe), the new member inherits the remembered tribe; without an explicit summary=/summary_script= (and without an epic nomination), it re-runs the remembered summary script through the usual launch-time summary path, falling back to the remembered text when the script is missing or produces no output. Inherited values are stored in the new member's metadata, recorded under the new generation with source inherited, and named with their source generations in one agent-log line. Explicit values always win, tombstoned tribes are never inherited, joining an existing generation changes nothing, and a runner re-exec does not re-apply values already in preserved metadata.

Clan membership is execution-neutral. It does not add waits, change launch order, choose a workspace or model, or otherwise rewrite launch behavior. Use %wait explicitly wherever ordering is required. The clan=, session=, and tribe= keywords on %id are mutually exclusive, and none can be combined with %clan in the same segment.

While the legacy_agent_family_syntax sunset flag is on (the default), the retired family keyword on %id is accepted as session=. The same flag still accepts the family and kind agent-query values, the --next-fork family value, a gate "fork": "family", and the SASE_AGENT_FAMILY_ATTACH environment variable. New prompts should use the session spellings. Turning the flag off rejects those new uses. A record that was already stored still reads. The retired family keyword and session= together are an error in either flag state. See feature_flags.

The clan name is permanently reserved as a container name and cannot also belong to an agent. Each member must be named <clan>.<suffix>; launch planning rejects an out-of-hood name before spawning it. A clan may contain ordinary agents, workflow steps, and sequential sessions whose names stay inside the same hood.

%wait:<clan> waits for every member of the newest clan generation. An exact member name targets only that member. Killing or dismissing the synthetic clan row cascades to its live members, while acting on one member leaves the rest of the clan alone.

Retrying a clan member from sase's TUI keeps it in the same named clan. sase's TUI rewrites the prompt into %id(<new-member-id>, clan=<clan>), where the member id carries the retry suffix. It does not repeat the create-only %clan declaration. If the original prompt used a clan template such as research.@ or research.{@1}, sase's TUI first substitutes the member's concrete clan, such as research.2.

sase's TUI renders every grouping row with a trailing color-coded name and no kind icon. A clan is synthetic and ends with an orchid <name> after its rolled-up status counts; its @tribe labels follow the name. A real multi-member session root ends with its bare azure container <name>, while its concrete member rows retain their exact --<suffix> names. Plain agent annotations and a lone plan proposer with only its display-only planner child remain gold. Press l once on a collapsed clan to reveal its direct members. The clan's outer fold is binary, so move to a session or workflow row and press l there to reveal that row's descendants. Lowercase h moves from any agent, Bash, Python, parallel, embedded, or compatibility workflow step to its validated immediate workflow, session, clan, or tribe parent without changing fold state. Uppercase H first retreats a selected open workflow or sequential-session agent node by one fold level. After that agent node is collapsed, the next press fully collapses every remaining open agent node in the next grouping scope, then collapses only the open canonical clan enclosing the selection. The next press from that collapsed clan container collapses every remaining open canonical clan in the group, and only then does a later press fall back to selected-row structural handling and grouping collapse. A selection without an open enclosing workflow, session, or clan proceeds directly to the group-wide remaining-agent-node sweep. Selecting the clan row shows an aggregate CLAN header and a navigable summary of every section represented across its members. In the Agents list, direct members sort by status priority — Failed, Stopped, Running/Starting, Queued, Waiting, Done — and then by launch recency within a bucket. The CLAN MEMBERS jump-panel roster uses chronological launch order instead, keeping its number-to-member mapping stable while statuses change. The runtime is the union of member run intervals, with human-wait windows excluded — including a gate turn's pending and settling window — so concurrent members are not double-counted. When a sequential session has a concrete agent or monitor turn currently executing, the collapsed and expanded session container row shows 🏃‍♂️ <current-turn-runtime> / <session-total-runtime> so the active turn duration is visible without opening the session. A clan container's live suffix collapses its parallel lanes with a minimum instead, since more than one lane can be live at once: <lowest-running-lane-runtime> / <clan-total-runtime>, where a sequential-session lane contributes its own total runtime -- the same value its own row shows to the right of its suffix.

Clan summary folding

Clan summaries collect member errors, output and workflow variables, replies, SASE context, slow tool calls, and prompts below the saved clan summary in the metadata body; the numbered CLAN MEMBERS roster lives in the jump panel, followed by CLAN NEIGHBORS when another clan shares its dotted hood. Two clans are neighbors when their presented names share the same root hood (foo, foo.bar, foo.baz, and foo.bar.deep share foo), compared case-insensitively at dot boundaries and excluding the selected clan, ordinary rows, malformed names, and unrelated prefixes such as foobar. Neighbor rows show full clan names and keep each target's stable identity including its generation. Known-empty section kinds are omitted. If required disk-backed content is not known yet, the document ends with one dim ⋯ scanning member data… tail instead of showing a placeholder for each section. Members and neighbors share one continuous number ladder up to 100 targets: 0–9 for documents with at most ten entries, or 00–99 for the first 100 entries in a larger document. Additional entries appear only in an unnumbered remainder count. Press a number while the clan is selected to expand only that member's ancestor chain and jump to its row, or to reveal a neighboring clan through folds and panels; with sase-1ao.3 selected the neighbor digit lands on sase-1ao and back again, and Ctrl+O returns to the previous selection. Esc cancels a pending first digit. Use Ctrl+J and Ctrl+K to move between the visible section headings; numbered roster rows live in the jump panel, so they are neither Ctrl+J/Ctrl+K stops nor za/zA targets.

The summary has three session-only fold levels:

Level Clan summary content
1 Up to 100 numbered member and neighbor rows (in the jump panel) plus a heading and count for each represented section
2 Bounded triage digests, such as one-line error and reply previews, variable values, and context-lane summaries
3 Full section bodies grouped by member for detailed investigation

Press zz to cycle levels 1 → 2 → 3 → 1. Press zZ below level 3 to open every fold to level 3, or press it at level 3 to close every fold to level 1. Use z1-z3 to select an exact level. za cycles only the section at the top of the metadata viewport; zA toggles that section between collapsed and fully expanded. A valid panel-level cycle, extreme toggle, or direct selection clears these per-section overrides. The Fold: N/3 field in the CLAN header always shows the current panel level, while the ▸/▾/▼ heading glyph shows each section's effective level. Unknown disk-backed sections stay hidden during enrichment behind one scanning member data… tail; represented sections appear when known, and known-empty sections remain omitted. The compact roster and its numeric jumps remain available at every level.

The fold prefix is available only while the Agents tab is active. Press uppercase Z to zoom an agent row's detail panel or the selected tribe panel's metadata document, = to isolate or restore a tribe panel from whole-panel focus or a row selection inside a panel, and - to sweep every open agent node and clan (never a grouping banner) in the focused tribe panel closed in one press (or restore the last sweep) from whole-panel focus, a row selection, or merged layout; lowercase z starts fold mode. Fold state is panel-wide and applies when a clan or a sase agent is selected. Using a fold chord on a regular sase agent folds its NEIGHBORS and SLOW TOOL CALLS sections across that agent's own three-level scale, leaves its other sections unchanged, and updates the session state for the next container selection.

Epic bead-work example

sase bead work <epic-id> puts every phase worker and the final land agent in clan <epic-id> and tribe @epic. %wait(for_epic=) follows epics an agent launches and is unrelated to tribe @epic. For an epic named sase-6g, the generated prompt has this shape:

%id(!sase-6g.1, bead=sase-6g.1)
%clan(sase-6g, tribe=epic, summary_script=sase_clan_summary_epic)
#bd/work_phase_bead:sase-6g.1
---
%id(!land, clan=sase-6g, bead=sase-6g)
%wait(sase-6g.1, for_epic=false)
%wait(bead=sase-6g.1)
#bd/land_epic:sase-6g

Generated phase and land waits use for_epic=false on their agent dependency and also require phase-bead closure. A user-authored %wait:worker normally follows any epics that worker launches, but this generated schedule already uses its phase beads as the completion condition. The clan container itself is not a land agent or other executable process. The bead= association lets each runner claim its phase or epic only after those waits and workspace preparation. If the epic clan already exists during a re-work, every phase and land segment uses the clan= join form. The built-in sase_clan_summary_epic script renders the epic's launch-time clan summary.

Sequential Agent Sessions

An agent session is a strictly sequential chain. A session is created only when %i(suffix, session=parent) attaches the first follow-up to an existing agent. At that point SASE renames the original agent with its own --<role> suffix and reserves the bare base name as a pure session container. Generic originals become <session>--0; plan proposers use <session>--plan. Because creation requires an attachment, a session always has at least two members.

For example, attaching a reviewer to agent foo creates session foo, renames the original to foo--0, and names the new member foo--reviewer:

%i(reviewer, session=foo) Review the diff produced by this session.
%i(tester, session=foo) Run the focused tests and report any failures.
%i(@, session=planner) #with_feedback:: Add failure handling before coding.

The positional suffix is a bare token: write %i(reviewer, session=foo), not %i(--reviewer, session=foo). %i(@, session=foo) allocates the next free numeric suffix.

Every session member has an agent_session_role derived from its suffix:

Suffix Role Display behavior
plan, code, epic, commit Corresponding built-in role Built-in plan-chain status rules
Numeric (@ allocates the next free number) Feedback or question round Built-in round status rules
Any other word (reviewer, tester, audit) The suffix itself, an open set Ordinary RUNNING/DONE statuses

Arbitrary suffixes are ordinary session labels, not configured lifecycle hooks. SASE does not discover or execute custom kind: agent_session definitions. Replace a stale definition with an explicit session attachment or an agent-requested launch.

Session members were formerly called shells: an agent turn is the assistant speaking, a monitor turn is a tool result arriving, and a gate turn is the human's move.

A --mon suffix (and --mon-0, --mon-1, … for later members in the same session) is a monitor turn: a session member whose work is one supervised OS command instead of an LLM turn, created by sase monitor start. See Monitors.

A --gate suffix (then --gate-0, --gate-1, …) is a gate turn: a named, non-LLM session member that owns a durable user decision. The asking agent ends its turn, the pending gate occupies no runner slot and contributes no accumulated session or clan runtime, and the turn settles after the decision's commands complete. It can retain or release the workspace claim according to its claim policy. An answered branch may launch the next agent-turn member; timeout, stop, failure, and loss do so only when that branch explicitly declares a follow-up. The built-in question, plan, workflow HITL, and agent-initiated launch flows use this model, as can custom sase gate create --turn requests. See Command-backed interaction gates.

sase pipe '<prompt>' creates a session member the same way a plan approval or a question follow-up does: it ends the calling agent's turn in-process and continues the run as the next member, in the same workspace and claim. The successor gets the next free numeric suffix (role feedback) by default, or an explicit --name TOKEN suffix (role: the token itself), per the suffix table above. See Monitors: Pipe vs. monitor.

SASE resolves parent to the newest visible matching agent or session member in the current project. If the parent is still running, the new member appears immediately as WAITING and starts only after that exact parent artifact completes successfully. If the parent fails, stops, or is killed, the queued member becomes STOPPED and SASE sends a completion notification.

If the parent is missing, ambiguous, or dismissed, or the composed member name already exists, launch preparation fails before spawning the member. Collision errors suggest %i(@, session=parent). %wait:<session> and #fork references to the bare session name resolve through the session container; sase agent wait <session> uses the same session target and waits for successors that appear after the wait begins. An exact --<suffix> name targets one member. A member attached to an agent already inside a clan inherits that clan membership.

A monitor or gate turn that ended unsuccessfully without handing off to a follow-up member normally keeps a bare-session wait blocked. Retries are the exception: when the same session generation (the newest root plus its attached members) also contains a newer turn of the same kind, SASE ignores the older failed turn while resolving the bare session name. For example, if --mon fails to start and --mon-0 takes over, the session wait follows --mon-0 and the other members instead of staying blocked on --mon. The newer turn only replaces the older failure; it still has to finish successfully (or hand off) before the session can settle. Kinds never mix: a newer gate does not excuse a failed monitor, or vice versa. An exact wait on the old turn's full name still reports that turn's own failed outcome. A session member that has crossed its own dependency waits and is only queued for a runner slot is still a live member, so bare-session %wait and #fork targets stay blocked until it finishes. Members still parked on their own dependency waits stay out of the session aggregate so sibling waits cannot deadlock. A failed turn that handed off to a follow-up does not release a #fork wait while that follow-up is still pending.

#fork:<session> contributes every known concrete turn — agent, monitor, and gate turns alike — in chain order, oldest first, including turns that ended unsuccessfully with their recorded failure context. Only a turn that is still running, or whose transcript or log is missing or unreadable, is listed as not shown rather than injected. Shared inherited history is de-duplicated across the included agent-turn transcripts. When a session member forks its own session, that member is omitted from both the shown and not-shown member lists. At least one shown member is required. Use #fork:<session>--<suffix> when only one member should be a parent — this also accepts a monitor's --mon/--mon-N suffix, and a monitor's exact durable proc ID is always the unambiguous choice if its reusable proc name is ever reused. A session container can also be combined with independent agent, proc/monitor, session, clan, or tribe parents in one multi-parent fork.

Session detail folding

Selecting a real multi-member session root in sase's TUI opens the Main deck with underlined SESSION (cyan, matching the name), with a numbered SESSION TURNS roster in the jump panel in stable chain order: agent turns in chain order, with each monitor spliced in directly after its starter turn. The original member and each follow-up are direct jump targets; synthetic planner projections and legacy parallel-family scaffolding are not. The roster follows the global panel fold keys (zz, zZ, and the direct level keys); the root's foldable output variables, workflow variables, SASE context, slow calls, and errors use the same chords plus za/zA.

Session summaries have two effective levels. Level 1 shows bounded activity, wait/retry, context, and compact member metadata; level 2 adds full foldable metadata plus member workspace, timestamp, and attempt annotations (roster annotations show when the jump panel is expanded with .). Press zZ at level 1 to open every fold to level 2, or at level 2 to close every fold to level 1. Press z1 or z2 to select either level directly. z3 and z4 are invalid in a session context and leave both the panel level and section overrides untouched. A member-specific override inherits from the SESSION TURNS section, which in turn inherits the panel level; any leftover roster override still applies until a global fold key clears overrides. The numbered roster and its digit jumps remain present at both effective levels.

The session root's SLOW TOOL CALLS section also follows that two-position scale. Level 1 keeps one aligned row per call with a short target digest and a tail explaining that full commands are hidden. Level 2 retains those rows and adds the wrapped full command or target, timing and outcome facts, errors, output previews, subagent statistics, and relative slow-time rank beneath each call.

AGENT PROMPT and the consolidated AGENT REPLY are always shown in full at both session levels, without fold glyphs or section overrides. They remain navigation anchors for Ctrl+J/Ctrl+K; za and zA skip them without changing the override registry. The session's AGENT MACRO renders in the sticky header panel above the data deck (a collapsed preview, or in full after d) rather than in the body. Absent macro and prompt sections are omitted, while reply rows for members that have not responded yet remain visible with their pending state.

A session root is a sase agent, so its jump panel also carries a NEIGHBORS section listing the sase agent's ancestors, descendants, and hood neighbors; it sits after SESSION TURNS when both exist. The session participates under its bare session name rather than the root member's -- name, so a session fam lists fam.helper as a descendant and fam.helper lists fam back as its ancestor. Both rosters draw their digits from one continuous ladder, so session members are numbered first and neighbors after, with a single shared number width. Session members already shown under SESSION TURNS are never repeated in NEIGHBORS; they are reported as a dim … +N also listed under SESSION TURNS tail. Every neighbor is always listed and numbered after the session members, whatever the fold level. See Sase Agent Neighbors Section for the full behavior, which single agents share through their own three-level scale.

Session member detail folding

Selecting a session turn row — not the container — also renders a numbered SESSION TURNS roster in the jump panel: every turn of the enclosing session in the same stable chain order, except the selected turn itself, numbered starting from 0. The heading carries a dim · <session name> suffix naming the session. Digit jumps behave exactly as they do on the container roster — 0–9 (or two-key 00–99 past ten turns) reveal the target turn, and a roster that changed since the panel was drawn cancels the jump with a warning instead of landing somewhere stale.

Unlike the container's two-level session scale, a member panel folds every other section on the selected member's own three-level agent scale (z1–z3, zz, za, zA), while its jump-panel roster follows the global panel fold keys, so no Fold: N/M header line appears. A member row is an agent turn node rather than a sase agent, so its panel names that with underlined AGENT TURN (gold, matching the name), has no NEIGHBORS section, and shows only SESSION TURNS for the enclosing session. The container panel names itself SESSION.

Per-member model lanes

A session container has no single model: %m overrides, provider defaults, and per-member reasoning effort can differ along the chain, and one shared Model: line would hide that. So when a session projects to two or more concrete members, the Model: field in the session root's detail-panel header expands into one lane per member instead of a single value:

Model:  --plan    · CLAUDE(opus) @ high ← @large
        --code    · CODEX(gpt-5.1-codex) ← @medium
        --review  · default

Each lane's value uses the same PROVIDER(model) @ <effort> ← @<alias> rendering as every other SASE surface — the single-agent panel and sase agent show included — so one reading habit covers all of them. The ← @<alias> chip appears only when the member was launched with an @ model alias, and it is launch-time provenance: completed runs keep showing the alias that launched them even if that alias is later retargeted or deleted. Member labels are the --<suffix> labels from the SESSION TURNS roster, padded to one aligned value column, and a member with no recorded model renders a dim default. Long values wrap beneath that column rather than pushing the layout wide. At most 12 lanes are shown; a larger session adds a dim … +N more turns (see SESSION TURNS) tail. The lanes are not part of the two-level fold scale — they read the same at level 1 and level 2. A session that projects to fewer than two concrete members, and every ordinary single agent, keeps the original one-line Model: field.

Two bundled macros help assemble common follow-up prompt bodies. They build text only; %i performs the attachment:

%i(@, session=planner) #with_feedback:: Add failure handling before coding.
%i(@, session=planner) #with_q_and_a(qa_file=/tmp/qa_rounds.json):: Continue with the base prompt.

The full directive grammar is documented under Macro directives.

Attaching within a multi-agent prompt

A later segment can attach to a statically named parent from an earlier segment:

%i:foo Plan the change.
---
%i(reviewer, session=foo) Review foo's plan.

The attached member waits for the in-batch parent to complete successfully. This lookup supports earlier static names such as %i:foo or %i(foo); template-named and auto-named parents must already have an artifact before they can be used as attachment targets.

Sase Agents, Sessions, and Commit Provenance

A sase agent is either a session or a single agent that does not belong to one. Commit provenance is anchored on the sase agent, not on the concrete turn that happened to be running: a commit by fam--code is tagged SASE_AGENT=<username>.<machine>.fam and links to sessions/<username>.<machine>.fam.md with no member anchor, while a solo agent's footer is exactly what it has always been. The same projection is used for the sidecar publication identity and for the agent rows on plan headers and bead pages, so a session appears once as itself instead of once per member.

The practical consequence is that the session page is the durable home of a session's commits. Members come and go — a member's artifact can be cleaned up long before the session is done — but the sase agent outlives them, so its commit history is carried on the session container and rendered on the session page, with member-attributed rows keeping their role and sase-agent-level rows showing —. Commits made before this change name a concrete member and are still read that way forever; nothing is rewritten. See runtime provenance and browsing page anatomy.

Agent Tribes

An agent tribe is a user-facing label for related agents across clans and sessions. Assign one at launch with the tribe= keyword on %id, or use #tribe when the agent should be auto-named:

%id(api-review, tribe=review) Review the API boundary.
---
#tribe:review Review another boundary with an automatic id.

sase's TUI displays tribes with an @ prefix and splits the Agents tab into panels such as @review and @epic. The clan's single declaration assigns one effective tribe to the whole generation; joiner prompts omit tribe=. Older clan generations without any clan_tribe value fall back to the distinct post-hoc member tribe assignments they carry.

Press N in sase's TUI to set or clear the focused agent's tribe (or every marked agent). On a clan row or any clan member, the modal targets clan <name> and sets the whole clan generation's recorded tribe (see Launch-time clan summaries). When the focused or marked agent is the declaring clan member itself, sase's TUI also rewrites its stored %clan(<clan>, tribe=<tribe>) and its clan_tribe metadata. For a joiner, sase's TUI updates only the metadata and never invents a second %clan declaration. Pressing N on the clan row itself writes only the clan record and leaves member prompts alone. The CLI manages the per-agent assignment store for any named agent:

sase agent tribe set -n <agent> -t <tribe>
sase agent tribe unset -n <agent>
sase agent tribe list [-n <agent>]

Pass a bare tribe name to set, without the display-only @ prefix. Names may contain letters, digits, underscores, dots, and dashes. set exits with status 2 for an invalid name, an unknown agent, or the reserved name default. The CLI updates only the assignment store; it does not rewrite the agent's prompt or metadata. Per-agent assignments are stored canonically in ~/.sase/agent_tribes.json with a tribe field. If that file does not exist, SASE reads the legacy ~/.sase/agent_tags.json scalar tag and list tags shapes. The first mutation writes all imported assignments to the canonical store, which is authoritative from then on. Existing artifacts and saved bundles can still be read when they use the legacy tag field, but rewritten metadata, new bundles, CLI output, and editor projections use tribe. Clan-wide assignments use the separate per-member clan_tribe metadata and are resolved across the generation. For sase's TUI panel grouping, that explicit clan assignment takes precedence over per-agent assignments.

sase's TUI derives the reserved @default panel for agents whose outer presentation root has no effective tribe. This fallback is display-only: SASE does not write default into agent metadata or the assignment store. An agent that nonetheless carries a stored default tribe joins the same panel, and clearing any user-managed tribe returns the agent there. Because the panel never resolves to a real entity, %wait:@default and #fork:@default are rejected at launch.

Moving agents between tabs

Press N in sase's TUI to open the Tribe & Tab modal: the second input moves the focused agent (or every marked agent) to a named tab with tab completion, leaving the tribe untouched when its input is empty. Typing main (or pressing Ctrl+T) moves back to the default tab. The move is optimistic with rollback, shows a Moved 2 agents to blog toast, and remote rows are skipped with the reason "tab moves run on the owning machine". The same move is available from the CLI, which rewrites the whole presentation root (session, clan generation, or workflow) and its stored %tab directive:

sase agent tab set -n <agent> -t <tab>
sase agent tab unset -n <agent>
sase agent tab list [-n <agent>] [-j/--json]

A move writes agent_tab with agent_tab_source: moved to the root's metadata. set exits with status 2 for an unknown agent or an invalid tab name (reserved local/all are rejected with guidance, and main is redirected to unset).

The built-in job tribe

Agents launched by AXE jobs belong to the built-in @job tribe, whose panel starts collapsed so routine background work stays quiet. For compatibility, SASE stores that tribe under its historical name chop. Assigning job through %id(tribe=job), #tribe:job, %clan(<clan>, tribe=job), the N modal, or sase agent tribe set -t job persists chop, and @job in %wait or #fork targets the same agents. A few surfaces show the stored name instead of the public one: sase agent tribe list prints chop, and prompt completion and the panel's W/F keys insert @chop, which targets the same tribe.

Two exceptions apply. If existing agent or clan records already use a literal job tribe, job refers to that literal tribe instead of the built-in one. If your configuration defines both ace.tribes.chop and ace.tribes.job with different settings, assigning job fails with an error that names both keys, and nothing is written.

Tribe panel focus and folding

In the split layout, a tribe panel is also a selectable container. Repeated lowercase h follows the validated workflow → session → clan → tribe ladder and selects the whole expanded panel after the structural parent chain is exhausted; h on the selected panel collapses it when another panel remains visible. Press l to expand a collapsed panel while keeping container focus, then l again to return to the row sase's TUI remembered for that panel. Uppercase L instead hints every visible agent-node, clan, and banner fold in the focused tribe so one key toggles one fold; on a collapsed panel it warns instead of expanding. Lowercase h on a collapsed panel selects the visually bottom-most expanded panel without changing panel folds; Ctrl+O returns to the collapsed origin. If every live panel is collapsed, h retains the existing already-collapsed warning. While an expanded whole panel is selected, j / k cycle across every panel, including collapsed ones, without descending, and l or Esc returns to the remembered row. J / K skip collapsed panels and move to the first / last selectable row of the next / previous expanded panel; they do nothing when no other panel is expanded. Whole-panel focus is unavailable in the merged layout. Apostrophe jump can select any split-panel title, including a lone expanded panel, but a lone panel cannot be collapsed. Press Z with a whole tribe panel selected to zoom that tribe's metadata document. Press = to isolate the focused panel by keeping it expanded and collapsing every sibling without changing its remembered row. = works from whole-panel focus and from a row selection inside a panel alike; from a row, it isolates the panel that holds the cursor without changing the selected row. When isolation changes the layout, sase's TUI remembers the prior collapsed-panel set for the session: ↺ title markers and the = restore panels footer hint show that the next = will restore it. A separate sibling-panel or layout mutation invalidates that one-step restore.

Press - to sweep every open agent node and clan — never a grouping banner such as Done or Running — in the focused panel closed in one press. It resolves scope the same way = does — from whole-panel focus, from a row or banner selection inside a panel, and in merged layout, where it treats the merged roster as one scope — and it never collapses the panel itself. When the focused panel has nothing left to collapse, - reverses itself and re-expands exactly the folds its own last sweep in that panel closed, restoring each structural fold to the level it held before. The restore is filtered at press time to folds still live in that panel and still collapsed, so it tolerates folds re-expanded by hand and never resurrects a fold that no longer exists. Each panel remembers at most one sweep; a fresh sweep replaces that panel's record. Armed panels mark each fold - would re-expand with a gold ▿ on the owner row and ▿N in the panel title, clearing the markers as soon as the next press would sweep instead. The footer shows - collapse folds or - restore folds depending on which direction the next press would take. A panel with only open grouping banners reports nothing to collapse or restore.

Press _ for -'s all-panels sibling: one press sweeps every open agent node and clan fold in every eligible tribe panel at once, sharing -'s per-panel records so the two compose freely. It skips any effectively collapsed panel in both directions and works identically from any selection, including whole-panel focus on a collapsed panel. With nothing left to sweep anywhere, it restores every panel's last sweep. The footer shows _ collapse all folds / _ restore all folds once at least two panels are eligible.

Uppercase H on a selected expanded panel hints every currently expanded agent node, clan, and top-level grouping banner in that panel — including owners hidden behind a collapsed banner — using the same adaptive hint keys as L, restricted to folds that are not already collapsed. Typing a hint fully collapses that one fold and leaves the remembered row and every other fold untouched; H never expands and never collapses the panel itself, which stays lowercase h's job. A panel with nothing expanded warns without arming hint mode; an already collapsed panel keeps the existing already-collapsed warning. Whole-panel H is unavailable in merged layout, where the existing row/group-scoped ladder remains in effect. Use ,H to open the same collapse hints from any row, or from a selected panel to hint every tribe. That row ladder first retreats a selected open workflow or session one fold level, then remaining group-wide agent nodes, then the selected open clan, then every remaining open canonical clan in the next group; the grouping banner closes only after those structural rungs are saturated. Custom keys bound to hooks_or_collapse_all receive the same contextual behavior and footer labels.

Whole-panel focus replaces the ordinary agent detail with a TRIBE document. Its four zz metadata detail levels are:

Level Name Tribe summary content
1 Glance Header, compact numbered top-level roster (in the jump panel), attention previews, clan-summary and prompt headline indexes (up to 8 each), and headings/counts for non-empty sections
2 Triage Bounded previews for every represented section
3 Inspect Nested roster detail and grouped full section bodies, still with protective bounds
4 Forensics Unbounded bodies, tracebacks, the richest member annotations, and all-time runtime statistics and percentiles

From levels 1-3, zZ opens every fold to level 4; at level 4, it closes every fold to level 1. za and zA adjust the section, or the CLAN SUMMARIES/PROMPTS entry, at the top of the metadata viewport. Reply, slow-call, prompt, and clan-summary presence enrichment is requested off-thread at every tribe level so known-empty sections can remain absent; all-time runtime statistics remain level-4-only. Unknown required disk-backed content produces one dim ⋯ scanning member data… document tail rather than per-section placeholders. The compact roster and its fixed numeric jump targets remain present at all four levels; the number keys jump to top-level clans, sessions, workflows, or agents and expand only the required ancestors.

Use z1-z3 to select the collapsed, expanded, or fully expanded view directly; z4 selects the exhaustive view, including unbounded roster annotations and runtime statistics. Direct numeric fold chords remain inside fold mode and do not trigger numbered member jumps. Outside fold mode, these fixed metadata-member numbers are separate from ordinary apostrophe entry hints, whose adaptive keys may use two characters in a large list.

The ,H leader chord opens the same collapse-by-hint picker as whole-panel H, from any selection. From a row or banner it hints every expanded agent node, clan, workflow, session, and top-level grouping banner in the focused tribe. From a selected tribe panel it hints those owners across every expanded tribe panel and adds a title chip on each expanded panel so picking it collapses that panel. Typing a hint fully collapses that one entry and exits; Esc cancels. The ordinary apostrophe jump mode includes both expanded and collapsed split-panel titles as destinations and preserves Ctrl+O jump-back history.

Tribe wait and fork targets

Use an @<tribe> reference where %wait or #fork normally accepts an agent name:

%wait:@review
#fork:@review

This is a next-entity target, not a request to wait for every historical member of the tribe. %wait:@review selects the earliest successfully completed @review entity launched after the waiting agent: either one standalone agent or one complete clan generation. Older entities, the waiting agent itself, failed agents, and incomplete clans do not satisfy the dependency. A tribe-assigned member of a clan enrolls the whole generation, so that candidate becomes eligible only after every member required by the normal clan wait succeeds.

#fork:@review implies the same wait, then resumes from the selected entity. A standalone match contributes its full conversation. A clan match contributes one launch-ordered clan summary containing each member's sanitized prompts, outcome/model metadata, reply size, and transcript path; full member replies are deliberately omitted so the child can open only the transcripts it needs. Tribe targets can be mixed with explicit agent or clan parents in a multi-parent fork, and sase's TUI prompt completion offers visible @tribe values for both %wait and #fork. When no %id is supplied, tribe waits and forks use neutral auto-names rather than derived .w* or .f* names because the eventual parent is unknown at launch planning time.

sase's TUI can insert these group references directly. Select a clan's synthetic container row and press F for #fork:<clan>, or press W for %wait:<clan>. For a tribe, give its named panel whole-panel focus—expanded or collapsed—and use the same keys for #fork:@<tribe> or %wait:@<tribe>. The reserved @default panel and grouping banners are not group targets, and marked rows take precedence over the focused clan or tribe for W. For a selected clan or tribe, sase's TUI prefixes either prompt with a VCS tag only when every real agent currently in that scope resolves to the same workflow and ref. Otherwise it omits the VCS tag so you can add the intended #git, #gh, or other workflow reference yourself. Marked waits instead take VCS context from the selected marked row, or the first named mark when the selection is elsewhere. The current rows determine only that optional VCS prefix; they do not pin the eventual clan or tribe fork source. See Forking Agents and Groups for selection and revalidation behavior.

Agent-Initiated Session Launches

User-initiated launches are direct: prompts submitted through normal launch surfaces, including prompts containing %i(suffix, session=parent), do not require launch approval.

When a running agent requests another launch, SASE creates a typed LaunchApproval request and spawns nothing until a human approves it. Agents use the generated /sase_run skill and submit a structured request:

sase launch request -f launch_request.json -o json

The request may contain %i(suffix, session=parent) in its prompt, so the approved launch joins an existing session with any valid suffix. launch_preview.md shows the resolved launch plan before approval. Inside an agent, the request creates a pending LAUNCH gate turn, hands off the session lane, and ends the requesting turn. Its default requester_continuation.mode is resume_requester: after approval, rejection, timeout, or gate/dispatch failure, one successor resumes the original assignment with the gate decision, feedback, typed launch results, requester identity, workspace/session context, and the recorded checkpoint. A stopped gate remains terminal. Set the mode explicitly to terminal_handoff when the requester truly has no remaining work; no settlement branch then resumes it.

The approved helper prompt and requester continuation cannot both target the requester's session lane. If the stored prompt uses session=parent (or names that same session), target a different session or select terminal_handoff so the lane has one owner. Outside an agent, the request defaults to terminal handoff, prints the creation descriptor, and returns immediately. A script that needs to block can use its request_id with sase gate wait -i <request-id> -k launch -j as a separate step.

Approve or reject from sase's TUI, or use:

sase launch approve <selector>
sase launch reject <selector> [-f <feedback>]

The selector may be a request ID, notification ID, or unique notification prefix. Approval verifies the neutral request bundle, revalidates and replans the stored prompt in its original working directory, and records host dispatch status in the write-once response. A multi-slot launch is all-or-nothing. In-flight requests from the legacy launch-request layout remain answerable during the compatibility window.

For the complete request schema, preview behavior, slot limits, and dispatch rules, see Launch Approval and sase launch request --help.