Gentle Shell is the gentle-shell coding-agent workspace built for Pi, not a theme. The gentle-pi package integrates the shell bar, workspace changes, provider usage where Pi exposes it, and native agent orchestration views into a Pi session. Start with the README for the product overview.
For development, use ODD and feature recovery. TDD follows configured mode, and native review remains a separate user-owned choice.
Source map: shell extension, shell bar, changes model, changes view, usage model, usage view, agents extension, and agent runner.
The v2.6.0 release makes the workspace state more durable and inspectable:
- Registered worktrees survive reloads.
/gentle:changesgroups each dirty root and presents status, line counts, and lazy diffs without conflating identical paths from different worktrees. - Fullscreen pointer navigation and the responsive sidebar keep changes, agents, and TODO usable at changing terminal widths; cached frames avoid redrawing inactive sidebar content while live status still updates.
- The Agents List and Details views preserve the orchestrator/session hierarchy and completion, abort, and lost-exit history. Parent-child queries and notifications have an explicit handoff path, while model, effort, and usage stay observable per task.
- Named
/gentle:profilesatomically route the orchestrator separately from packaged and review roles; see the technical reference for the profile model.
The source checkout prepares gentle-pi 3.7.0 with a package-local Gentle AI v3.7.0 pin; this does not imply that the package release has been published.
Gentle Shell is the Pi workspace experience provided by the gentle-pi package. It follows the Gentle themes: one border language, rose for whatever is alive.
At 140 columns or wider, fullscreen splits into a live header row over a transcript-and-rail split, both driven by lib/shell-sidebar-layout.ts:
✿ Gentle Shell ⟡ ~/work/gentle-pi main ⟡ gpt-5.5 · medium · team ctx ▰▰▰▰▱▱▱▱ 45% ⟡ $9.49 sub
- The header is one row, always visible, and carries only what changes every frame: session identity on the left (brand, cwd, branch, dirty count, model · effort · profile) and the two live counters right-aligned (the context gauge and session cost). It never shows the working/thinking state or extension statuses — those stay in the prompt title and the compact bar. When the terminal is too narrow for everything, segments give way in a fixed order — profile, then effort, then the whole cwd/branch/dirty group — before the counters are touched; below that, only the brand survives, and below that the header renders nothing.
- The right rail scrolls Status → Changes → TODO, each an event-driven card that only repaints when its own state changes: a model switch or a cost tick refreshes the header, not the rail. Every card (sidebar or not) paints the same rose frame — the rounded border in the theme's plain border role, the title in the accent role — the look every
CARD_TONE.INFOcard in Gentle Shell uses (warning/error/success cards keep their own tone colors). - The Status card carries only what an explicit event refreshes: Project (cwd, branch, session name, active profile), Changes, and Integrations (other extensions' statuses). Model, effort, context, cost, and the per-model usage table live in the header instead — the header ticks every frame, so duplicating them in a card would just make that card repaint every frame too.
- Gentle Agents is not part of the rail in any mode: its one card stays above the editor, where it already lived, with fixed right-aligned columns for
model · effort, tokens, cost, and elapsed, each sized to the widest value among the shown tasks — so the numbers line up vertically even when one row's values are much shorter than another's. A queued task fills only the elapsed column with the wordqueued, leaving the other columns blank rather than overwriting the row. - The sidebar reuses its last frame until something it paints changes, so silent frames stay cheap; a per-section cache means one card's changing digest (or the header's) never forces an unrelated card to redraw.
- Narrow terminals and regular mode keep the compact bottom bar and the above-editor Agents widget, with no header row and no sidebar.
Below 140 columns, or in regular mode, the compact bottom bar replaces pi's three-line footer with a single line of segments instead:
✿ gentle shell ⟡ ~/work/gentle-pi main ⟡ gpt-5.5 · medium ⟡ ctx ▰▰▰▰▱▱▱▱ 45% ⟡ $9.49 sub ⟡ MCP: 3 servers enabled Release notes
- Context is a gauge, not a number. It turns amber at 80% and red at 95%; after compaction it shows
?%until the next response. - Cost carries
subwhen the active model runs on a subscription login. - Statuses other extensions publish through
setStatusare appended as trailing segments; the session name sits at the right edge. - On narrow terminals the session name is dropped first, then trailing segments, before the line is truncated.
The prompt wraps pi's editor in a rounded frame with a petal that shows what the agent is doing:
╭─ ✿ working ──────────────────────────────────────────╮
│ type, or / for commands │
╰──────────────────────────────────────────────────────╯
- The petal is still while pi waits, spins with a
workinglabel while the agent works, and turns amber with aqueuedlabel when messages are waiting behind the current turn. pi's own "Working" row above the editor is hidden, since the frame already says it. - The frame uses the theme's border color over the panel background, so the prompt reads as one panel with the cards around it; the editor's scroll indicators stay inside the frame.
- The hint appears only while the editor is empty.
- If another extension already installed a custom editor, Gentle Shell leaves it alone.
Changes shows captured write/edit operations from this agent session and its owned subagents. It does not scan the repository on startup, read all untracked files, or poll live files in the background. Fullscreen, the sidebar, and mouse interaction are unchanged.
✎ 3 files · +42 −7 · extensions/gentle-shell.ts, lib/shell-bar.ts, tests/x.test.ts · /gentle:changes
- A worktree appears only after a captured successful mutation. Reading a file, opening a directory, registering a worktree, or launching a child is not mutation evidence.
- Diffs compare the content observed before the agent's first captured operation with its latest captured result, not with HEAD. Consecutive agent edits combine; an agent revert removes its net change.
- Edits from your editor or other sessions do not update these captured diffs. If an external or unobserved edit breaks continuity before the next agent operation on the same file, the file is marked diff unavailable, rather than mixing ownership.
- Ordinary attribution accepts only worktrees in the coordinating session's Git clone. A separately authorized foreign child can contribute target-bound Changes without registering its repository as a same-clone worktree. Child evidence requires an owned, successfully spawned task, paired successful write/edit events, and matching canonical target and live grant; model claims alone are not evidence.
- A changed file's worktree is resolved from its own directory upward (
git rev-parse --show-toplevelstarting there, never from an ancestor's cwd), so a repository nested inside another — a project scaffolded inside a personal workspace clone, say — is always attributed to its own, inner repository, never the outer one. - When changes span more than one worktree, each tree header shows that root's own branch name,
no commits yetfor an unborn branch, ordetachedonly for a real detached HEAD. The label is read from Git's HEAD once per root while the overlay is open (symbolic-refandrev-parse --verify); the overlay still never runsstatus,diffor a worktree scan on your behalf. - Coverage is deliberately limited to write/edit tools. Shell commands, custom mutation tools, failed/interrupted outcomes and children without the capture extension provide no attributed diff. A missing row does not mean the repository is clean or that no other changes occurred.
Capture reads only the named target, up to 64 KiB and 2,000 text lines. Binary, oversized, nonregular and unverifiable snapshots show unavailable counts, never fabricated zero-count proof. At most 256 operation identities and 4 MiB of serialized evidence are retained per session; reaching the limit produces a warning.
Snapshots are stored locally in Pi custom entries (gentle-pi.session-change/v1), including bounded before/after source text. Exit/resume and reload restore captures only for the exact same session UUID. New sessions and forks do not inherit attribution from another UUID. Ephemeral --no-session runs do not persist after exit. Capturing remains active in headless children and when the visual shell is disabled.
The separate session_worktree_register tool still registers canonical same-clone roots for coordination, but registration alone never adds files to Changes. Existing gentle-pi.session-worktree/v1 entries do not establish file-level attribution.
/gentle:changes or alt+g opens the two-pane viewer. Worktrees are accordion groups on the left; selecting a file displays its captured diff on the right.
j/kor arrows navigate. On a group, Enter, Space or Right expands it; Left returns to its parent or collapses it.ctrl+j/kor Page Up/Down scroll the diff; Escape orqcloses.- Fullscreen left-click selects files; mouse wheels scroll the file list and diff independently. Hovering an unselected row (worktree or file, in either pane's list) paints it in the same shared hover role every clickable surface in the shell uses; it never opens or selects the file, and never overrides the already-selected row's own role.
- Opening, pressing
r, and the overlay's refresh cadence consult only the captured session model. They never rescan Git or load the current file contents. Same-line-count edits invalidate the diff preview by content revision. - On a file,
oor Enter opens the actual current file in$VISUALor$EDITOR, with its worktree as cwd. Edits made there are external and are not attributed to the agent. GENTLE_PI_SHELL_CHANGES_KEYrebinds the shortcut;offdisables it.GENTLE_PI_SHELL_CHANGES_POLL_MScontrols only the open overlay's in-memory refresh.GENTLE_PI_SHELL_CHANGES_WATCH_MSno longer enables filesystem polling.- No captured changes means no widget and an informational notice; it does not assert that the working tree is clean.
/gentle:commands or alt+k opens a curated, grouped command menu, OpenCode-style — not a raw listing of every registered extension command. Entries are grouped under Configuration, Session, Diagnostics, and Skills, each shown by a human label with its shortcut hint where it has one; a command only appears when it is both in the curated set and actually registered. The Search row filters by label, by the underlying command name, and by description; arrows or ctrl+j/ctrl+k move, enter runs the highlighted entry exactly as if its command had been typed, escape closes. GENTLE_PI_COMMANDS_KEY rebinds the shortcut; off disables it. Built-in Pi commands are not listed. The default is alt+k, not ctrl+k, because Pi reserves ctrl+k for the editor's delete-to-line-end action.
To use ctrl+p like OpenCode, rebind Pi's app.model.cycleForward in ~/.pi/agent/keybindings.json (Pi reserves that action, so an extension cannot take ctrl+p while it holds it) and set GENTLE_PI_COMMANDS_KEY=ctrl+p.
Subscription usage shows in the bar after the cost, and /gentle:usage opens a panel with one row per window of every provider: the limit name, its meter, its percentage and, when that window reports one, its reset, all on one line. Codex, Claude and NaN all read the same way. In fullscreen mode, clicking the header's usage segment opens this same panel. The panel's own footer hints (r refresh, esc close) are clickable too, not just keyboard shortcuts, and hovering either one paints it in the shell's shared hover role while a refresh already in flight ignores a repeated click. The panel opens immediately: it draws whatever snapshots the store already holds and says refreshing… while the open refresh runs underneath it, repainting as answers land.
✿ gentle shell ⟡ … ⟡ $9.49 sub ⟡ codex 5h ▰▰▰▰▰▱▱▱ 62% · week 31%
The panel rows a provider reports its windows with:
✿ nan · updated just now
deepseek-v4-flash ▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱ 26% · resets in 12d 17h
glm5.3-flash ▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱▱ 11% · resets in 12d 17h
-
For Codex, usage comes from the same account usage endpoint the Codex CLI reads, using the OAuth token pi already holds. It is fetched at session start, at most every 5 minutes after a turn, and on
rin the panel. Rate-limit headers on SSE responses are picked up too. The same refresh covers every provider the session targets: the active model's own provider plus every provider the active profile's subagent routing names — a repository pin decides which profile that is, falling back to the global active profile when no pin applies. Each provider keeps its own 5-minute window, its own stale-source guard, and its own last good snapshot. Providers refresh concurrently, each inside its own bounded window (default 10s,GENTLE_PI_SHELL_USAGE_TIMEOUT_MS): the abort signal reaches the underlying fetch — composed with the caller's own signal when it carries one, never replacing it — a provider that outlives its window wears the generic failure note, and whatever it answers afterwards is discarded — a late answer never replaces what the timeout settled, exactly like the stale-source guard above. -
A routing entry names its provider with a qualified ref (
provider/model); a bare model id is resolved through the model registry only when exactly one provider carries that id, and is left untargeted rather than guessed when none or several do. The targeted scope is resolved when a refresh runs — at session start, on each turn's throttled refresh, onror reopening the panel, and when a usage source registers — so a profile switch is picked up by the next refresh rather than live per render. -
For Claude Pro/Max, usage arrives in the rate-limit headers of every response, so the 5h and weekly windows appear after the first turn.
-
For NaN Cloud, usage comes from the quota endpoint the official dashboard reads, with the same API key pi already holds. Each metered model reports one allowance for the billing period, and that window carries no label: the model id names it in the bar and the reset text says what it is in the panel. A model that also reports a rolling window shows that one labeled next to it (
4h), which today's payload does not send; percentages are tokens used over the allowance, exactly as the dashboard draws them, and the allowance is the full-period cap (fullCap) whenever the model reports a positive one, becausecapalone is the prorated allowance of the period in progress. It is fetched under the same 5-minute rule as Codex, counted per provider so a switch fetches the provider it switched to, refuses redirects so the bearer cannot be replayed to another origin, and keeps no cached copy. The endpoint sits outside NaN's published OpenAPI, so the parser reads it defensively: a model that reports no allowance is skipped, as the dashboard skips it, while a metered model whose usage cannot be read fails the whole read, so a partial payload never replaces a complete snapshot with a cheaper-looking one. A session that already has a snapshot keeps the last valid one through a malformed payload or a failed fetch, and the pending note appears only while there is nothing to draw. -
Extensions can register a usage source for their own provider: gentle-shell has no built-in knowledge of it, but treats it exactly like Codex or NaN once registered. Emit
gentle-pi:usage-source/v1onpi.eventswith{ schema: "gentle-pi.usage-source/v1", provider, pendingNote?, fetch(apiKey, fetchFn, now) }, wherefetchresolves aProviderUsagethe same shape the built-in providers produce, orundefinedwhen there is nothing to show yet. A malformed payload, afetchthat isn't a function, a provider id outside the safe id pattern, or afetchcall that throws or rejects is ignored rather than crashing the shell. ThefetchFna source receives is bounded the same way: once the provider's window expires it aborts, and a later resolution is discarded. Re-registering the same provider replaces its source, so emitting again at everysession_startis safe and keeps load order irrelevant. Once registered, the provider showspendingNote(or the same "no usage yet · r to fetch" default the built-ins use) until its first fetch, and a registration that arrives after the session already started, for any targeted provider (the session's own or a subagent route of the active profile), triggers one immediate refresh of that provider instead of waiting for the next turn or the 5-minute window. Example, using a neutral provider id:pi.events.emit("gentle-pi:usage-source/v1", { schema: "gentle-pi.usage-source/v1", provider: "acme-cloud", fetch: async (apiKey, fetchFn, now) => { if (!apiKey) return undefined; const response = await fetchFn("https://acme.example/usage", { headers: { Authorization: `Bearer ${apiKey}` } }); if (!response.ok) return undefined; return { provider: "acme-cloud", plan: "Acme · 42 credits", limits: [], fetchedAt: now }; }, });
-
The bar names the subscription it shows (
codex,claude, a NaN model) and always follows the active model. A provider with per-model allowances draws the session model's own meter, falling back to its family and then to the account total, never to whichever model the payload happens to list first — and that holds for a payload that reports a single metered model too, because one allowance is still per-model data rather than a reason to echo the first entry. The panel puts the active provider first, marked with the petal, and says why it has no data when it does not: API-key providers have no subscription windows, Claude reports after the first response, Codex and NaN wait for a fetch. It draws exactly the targeted providers, in scope order — a targeted provider with no snapshot explains itself, and one whose latest refresh settled without a snapshot wears a generic nonsecret "fetch failed · r to retry" note: beside its retained snapshot when it has one, or in place of the pending note when it has none. The note tracks actual failures only — a refresh still in flight never reads as failed, Claude (headers-only) is never dressed up as one, and the next successful refresh clears it. A provider recorded under a previous profile's routing is not current scope after a profile switch. A provider without per-model allowances keeps its single aggregate line in the sidebar, unchanged. -
A provider with per-model allowances is ordered by family on both surfaces: a family stays together, the family that consumes most comes first, and the models inside it follow the same rule, most used first. There are no
totalrows anywhere — an aggregate nobody can act on only costs space — so the account and family totals survive only as the bar's fallback name when the session model holds no allowance of its own (nan total). An allowance row leaves the window label empty and printsname meter percent, while a labeled sub-window (4h) keeps its column, and the reset a window reports rides that same line after a·; a window without one ends at its percentage, never on a dangling separator. The sidebar's Usage group prints those same rows in that same order, so the breakdown does not require opening the panel, and stops at the percentage: the reset dates stay in the panel. A row whose windows all round to0%is dropped from that group — an allowance nobody has touched yet tells the reader nothing the missing row does not — and the same rule retires the aggregate line of a provider without raw allowances once every window it shows sits at0%; the bar and the panel keep printing it, so a zeroed subscription is still verifiable there. -
Only the plan name and the windows are kept; account details in the payload are discarded.
-
Gauges turn amber at 80% and red at 95%, like the context gauge.
Gentle notices are drawn as cards: the same rounded frame as the prompt. An informational card paints the rounded frame in the theme's plain border role and its title in the accent role — the rose look every sidebar card, the review preflight reminder, and a quiet Agents card share. A warning, error, or success card paints its frame and title in its own tone color instead.
╭─ ✿ Gentle AI · review preflight ─────────────────────────────────────╮
│ Receipt-driven development is enabled, and this worktree holds an │
│ unreviewed candidate (target sha256:…). First determine whether the │
│ user explicitly left this exact target unreviewed. If yes, do not │
╰──────────────────────────────────────────────────────────────────────╯
- Quiet tools use thin rounded cards with their actual name in the top rule (
read,bash,grep,find,ls,edit,write); bash keeps its command visible. Collapsed results show up to three physical preview rows, including search/list entries or changed diff lines alongside useful totals. Expand with the configured key shown in the top rule for complete available output and image handling. - Every call into the gentle-ai binary and every
gentle_reviewtool draws a rose card titled like the quietreadcard: the colored 🌹 emoji, a short name, then the operation (🌹 rdd inspect,🌹 gentle-ai version), withrunning/preparing/failedshown until the call completes (🌹 rdd running · start). The rail uses the existing theme roles: warning while running/partial, success on completion, error on failure. Collapsed results show up to three useful physical rows, not just a line count. A JSON envelope instead collapses to one summary line of its key fields (status, outcome, risk, action, reason code, diagnostic message, e.g.blocked · start · fresh_target_ready) and expands as pretty-printed JSON. The expand key sits in the top rule once finished, and elapsed timing stays on the closing rule. Reviewer captures name their lens (rdd capture · risk; the group lists all four). - The review preflight reminder renders as a card in the transcript with the expand key in its top rule. Collapsed, it previews up to three non-blank physical rows of the reminder; expanded, it shows the full text.
- An active dev-binary override shows above the editor at startup as a 🌹 gentle-ai card, in amber, naming the binary and its digest, and leaves with the first prompt; an invalid override shows in red with the reason.
- Subagents draw their own card; see Gentle Agents below.
Pick how conversation cards look in /gentle:customize → Cards. The choice applies immediately and is saved in card-style.json in the Gentle Pi config home; it is not part of visual profiles or visual reset.
| Style | Look |
|---|---|
neon |
The outlined rounded card shown above. |
float (default) |
A borderless panel on the tone's tool background (success/info, pending, error), with a tone-colored ▎ accent bar, a one-column margin on each side, a blank row above the heading and at the bottom, and a blank row between the heading and the body. |
▎
▎ ⌖ find *.md in . ctrl+o to expand
▎
▎ README.md
▎
floatapplies to tool, Code and 🌹 cards, Agent result and stale cards, the review preflight reminder, and the dev-binary notice. The Agents, Todos and Status panels keep the outlined frame in both styles.- A theme without a tool background, or a card narrower than 10 columns, falls back to
neon. A malformedcard-style.jsonreads asfloatand the panel refuses to overwrite it.
With quiet tools enabled, codemode uses the same rounded Code card. The collapsed view shows up to eight observed child calls in their original order, including repeats, with Pi's actual status and available nonnegative duration. Additional calls and failures are counted. Error payloads have a separate two-row preview even when their child falls outside the first eight; final output has a three-row physical budget, and a full-output locator remains visible when available.
- JavaScript and child arguments stay out of the collapsed preview. Expand with the configured key shown in the top rule for the actual script, all observed children, complete available error/output text, image fallback and full-output locator.
- Host failure/partial flags and observed child failures retain their existing semantic colors; no generic
finishedheading, inferred children, progress percentage, or aggregate duration is added. Pi's final status/wall-time header stays in expanded output rather than displacing useful collapsed content. Child success does not promise rollback or overall success. - Missing metadata is reported honestly. Terminal controls are stripped from displayed text; this is terminal-spoofing protection, not secret redaction. Both collapsed previews and expanded content can contain sensitive data.
- Only presentation changes: upstream execution, schema, loadout, exposure and inactive-by-default behavior stay intact.
GENTLE_PI_QUIET_TOOLS=0leaves the upstream presentation alone and does not change tool activation.
Gentle Shell ships its own interactive tools instead of depending on third-party extensions; the built-ins replace npm:pi-subagents-j0k3r and npm:@juicesharp/rpiv-todo (see Gentle Agents and Gentle Todo below for the removal steps).
ask_user_question— one to four structured questions in a single questionnaire, each with two to four options, multi-select, per-option descriptions and previews — rendered as real TUI dialogs, usable in the live session.ask_user_choice— one exactly representable single-select question, with an opt-in free-text response.todo— plan tracking with the Gentle Todo card (see Gentle Todo below).gentle_review/ capture tools — the native review surface for receipt-driven development.- Optional companions (separately installed, never bundled):
gentle-engramfor persistent memory,pi-web-accessfor web access when a task needs it and your policy allows it,pi-lensfor additional inspection surfaces,pi-intercomfor cross-session communication where your Pi setup supports it, and@juicesharp/rpiv-ask-user-questionfor interactive choice support where a separately installed extension fits your setup. These are companions, not hidden prerequisites or a claim that every Pi installation has every capability; persistent memory is not bundled withgentle-pi.
The current package requires Pi 0.99.1 or newer and Node >=22.19.0 (development tests pin Pi 0.99.1). Use the latest Pi release; gentle-pi does not update your installed Pi automatically. Children, including any GENTLE_PI_AGENTS_PI override, must emit agent_settled: agent_end records a run's output but is not completion because retries or queued continuations may follow.
The subagent_* tools and the agents card replace the third-party subagents package (remove npm:pi-subagents-j0k3r from your pi packages; while it is still installed the tools stay unregistered and a warning says so at startup). Agent definitions and settings are the ones you already have: markdown agents in ~/.pi/agent/agents/, ~/.pi/agent/subagents/, <cwd>/.pi/agents/, <cwd>/.pi/subagents/ (project beats global, subagents/ beats agents/), and subagents.json at the global and project level (default_model, default_effort, default_mode, model_profiles, stall_timeout_ms, tool_stall_timeout_ms, max_concurrency, history_max_tasks).
Agent paths follow GENTLE_PI_AGENT_HOME, then PI_CODING_AGENT_DIR, then ~/.pi/agent for definitions, config, history, child sessions, and transcripts. These overrides select the agent profile; they do not sandbox project or shared global resources.
╭─ ❀ Agents · 1 active · 1 done ─────────────────────────────── 1m24s ╮
│ ✓ gentle-ai-explore map footer sources gpt-5.6-terra · 34k · $0.27 · 25s │
│ ◐ gentle-ai-worker write shell footer gpt-5.6-terra · 120k · $12.50 · 41s │
╰──────────────────────────────────────────────────────────────────────────────────╯
The card is above the editor in every mode, including fullscreen — it is not one of the sidebar's cards. Each metadata field (model · effort, tokens, cost, elapsed) gets its own fixed, right-aligned column sized to the widest value among the shown tasks, so the numbers line up vertically even when one row's values are much shorter than another's; a queued task fills only the elapsed column with the word queued, leaving the rest of the row blank rather than overwriting it. When the card is too narrow for every column, it degrades one column at a time and the same way for every row: the task text goes first, then the model · effort label, then tokens, then cost; elapsed is the last column standing, since it is the one value the reader cannot rebuild from anything else on screen.
Every subagent is its own pi --mode rpc child process, so the terminal never runs subagent work: the host reads JSON lines, applies each one as a small delta to a bounded per-task thread, and notifies only the listeners of that task. A task-mode child's question (ctx.ui.select, confirm, input, editor) reaches you as an ordinary pi dialog; a background child's question is dismissed. Subagents have no automatic total execution timeout: a long-running child remains live while it continues emitting RPC events. A silent child still times out through the configurable stall_timeout_ms watchdog (default four minutes). An announced tool call that is still running is live work, not silence, so it is bounded by tool_stall_timeout_ms instead (default 30 minutes, never below stall_timeout_ms). Closing pi stops the children that are still running.
Delegated children (GENTLE_PI_AGENTS_CHILD=1) load the same context files as their parent, minus the gentle-ai managed blocks that bind themselves to the orchestrator, such as orchestrator and agent-routing (the full list lives in lib/child-context-files.ts). Every other managed block (for example codegraph-guidance, engram-protocol, or remote-authorization nested inside agent-routing) and all unmanaged project text reach the child unchanged. A marker counts only when it is alone on its line outside fenced code; if a file's markers are unbalanced, mismatched, or ambiguous, that file is passed through unfiltered. Gentle Agents launches every child with --extension pointing at the packaged extensions/child-context.ts, because a child does not load the gentle-pi package on its own in the isolated Gentle Shell home; if that file is missing, the child starts without it and keeps today's unfiltered context. The extension registers only a before_agent_start hook and does nothing outside a child session, so primary sessions always receive their context files as-is.
subagent_list_agents,subagent_run(agent,task,label?,context?,workspace_root?orrepository_root?,mode?task or background),subagent_status,subagent_result,subagent_list_tasks,subagent_reply(one current-session reply to a live child query),subagent_cancel,subagent_send_message(steer a running child),subagent_continue(resume a finished task in its own session).orchestrator_session_id,orchestrator_list, andorchestrator_send_messageprovide local-profile session notifications. List results advertise IDs only and reachability remains unknown. Sending selects the sole advertised peer or asks the user to choose; outbound messages require explicit interactive human consent before dispatch (Allow once, Allow for this session, or Deny), and fail closed if interactive UI or its selector is unavailable, even after a session grant. Each send requires a caller-supplied reason with at least 8 characters after trimming and at most 512 UTF-8 bytes. The consent preview visibly escapes controls and Unicode line separators; the delivered message remains unchanged. A successful ACK means the peer accepted the notification for delivery, not that it read or completed work. This is notification-and-ACK transport only: it has no cross-session queries, offline queue, retries, broadcasts, or read/completion guarantees. On Unix, presence records remain in the profile's private transport directory while socket endpoints use a private, profile-hashed directory below the canonical system temporary directory, keeping endpoint length independent of the profile path and at most 100 encoded bytes. The shared system temporary parent is only validated (current-user-owned without group/other write, or root/current-user-owned, world-writable, and sticky); it is never claimed, permissioned, or cleaned up by gentle-pi. On POSIX, the transport uses private Unix-domain sockets; on Windows, it uses private named pipes scoped by the current account SID, served by a package-local PowerShell helper (runtime/windows-session-transport.ps1): the transport selects that fixed helper, and availability and delivery depend on the helper's bounded startup and pipe checks. Notification and ACK limits remain bounded across platforms.subagent_run.workspace_rootselects the parent's main worktree or an existing linked worktree in the parent's Git clone only. Validation happens before queueing; the child runs at that canonical root. Successful OS spawn registers it in the originating parent's same-clone registry, including delayed queued launches; failed spawns do not register.- Alternatively,
subagent_run.repository_rootselects an explicit canonical root of an independent Git repository; the two root selectors cannot be combined. A direct interactive parent must grant that clone before queue or child session-directory writes. The grant belongs to the live parent session and canonical Git common directory: subsequent launches there can reuse it, but denial, cancellation, lost UI, reload, or changed session/repository identity fails closed. Print, RPC, and child callers cannot request a foreign target; foreign remediation launches are unsupported. Task and background launches still obey their ordinary mode restrictions. Queued tasks revalidate immediately before spawn;subagent_continueretains the target cwd and revalidates the grant rather than prompting to restore a lost one. Status and task details expose the cwd. Foreign children never enter the same-clone registry or its footer/widget counts. A delegation grant is not permission to review, commit, push, or deliver in the target repository. - Background work requires a live interactive/RPC parent. Both
subagent_runandsubagent_continuereject background mode inpi -pbefore creating or spawning a task: the parent exits before it can receive a later result. Use task mode for bounded print-mode work. - A background task's result comes back to the model as a
gentle-agents.resultmessage and starts a new turn when the agent is idle; the model never polls. Its Agent result card uses the success color when the task completed and the error color otherwise. Collapsed, it previews up to three non-blank rows of the answer or error, leaving out theSubagent … (task …) <outcome>.bookkeeping line the model reads; older results without that line preview their full text. Expanded, it shows the complete message, header included. A result held past the stale window becomes a transcript-only Stale agent result card in the warning color: it previews up to three rows of its warning and never shows an answer it does not have (usesubagent_resultfor that). - A configured child can call
subagent_parent_messagewith bounded, well-formed Unicode text. Notifications retain their existing admission semantics. Akind: "query"waits for one strictly correlatedsubagent_replyfor at most 30 seconds; each child has at most four pending queries, and disconnect, timeout, stop, and send failure settle each request once. The current parent session alone can reply. The first admitted task-mode query ends the original tool response while its child keeps running; its eventual non-cancelled completion returns once as a follow-up only if that same session is still active. Channel closure prevents later sends and automatic retry is not provided. Peer transport, offline delivery, retries, and broadcasts are unsupported. - The card shows the active session's tasks only: after
/newor/resumethe earlier session's tasks leave it and come back with their session. Finished rows stay for one minute (three at most), and the card spends at most a quarter of the terminal (three to eight rows) on tasks; beyond that the rest fold into one… N more · alt+a to viewline so the editor never leaves the screen. Questions and running work keep their rows first. /gentle:agentsoralt+aopens a full-terminal overlay. At 60+ columns, the split view shows groups/tasks beside the retained semantic thread; uppercaseFor Fullscreen expands that thread. At 12–59 columns, click a current subagent directly to inspect its thread; in All sessions, first select its orchestrator.Enter/Tabalso enter a narrow selection. Back orEscapereturns one level, closing only at the root; Close orqcloses globally without cancelling children. Selection and manual thread scrolling survive Back and resize.- Mouse controls take priority over keyboard hints: Follow (
f), Open session (o), Stop (s, legacyc, owned active tasks only), and Scope (a). A compact footer's>cycles through actions. Scope switches between this session's direct active children and all open orchestrators, including idle ones. Open writes a markdown transcript for$EDITOR, not a resumed child session.j/kmove through lists or scroll an expanded thread;ctrl+j/ctrl+kand Page Down/Up page the thread. In Pi fullscreen mode, the wheel scrolls the viewport under the pointer; regular terminal mode does not capture mouse input. Below 12 columns or three rows, only a bounded Close cell remains; zero-sized terminals render nothing. - The thread displays all retained Text, Thinking, Note, and Tool content without an additional presentation cap; existing store limits and truncation markers still apply. Only the selected task is subscribed while the overlay is open.
- Thread entries are presented as labeled Text, Thinking, Note, or Tool blocks; tool blocks show their status and nonempty output.
- Current scope has no orchestrator wrapper. Its own session's finished subagents stay listed as history after the active ones — newest ended first — with their terminal glyph, elapsed frozen at completion, and their thread inspectable; a finished row is never cancellable. The header reads
N active · M finished. History is capped at 200 finished tasks per session (oldest dropped); resuming a session (session_startwith reasonresume) restores that session's own finished tasks from disk automatically, a brand-new session starts empty, and All sessions discovers open Pi instances sharing the same agent profile, even across repositories — it does not infer open sessions from retained tasks and stays presence-only (no cross-session history browsing). Directory headings support left/right and mouse expansion, and cannot stop or open a task. Peer children and their retained threads are read-only: no local stop, editor-open, or continuation routing, and no import into the local task store. - Presence refresh is paged while the overlay is open. Graceful shutdown withdraws an instance; after abrupt closure its last heartbeat may remain visible for up to 15 seconds plus the time to complete the next directory refresh. A recent heartbeat is a heuristic, not proof that a process is alive. Same-profile, same-user processes share retained activity text; this is not an authorization channel.
alt+sconfirms stopping the current active or queued subagents owned by the current process.GENTLE_PI_AGENTS_STOP_KEYrebinds it;offdisables it.- Finished tasks are written to
~/.pi/agent/gentle-agents/tasks/(one JSON per task, newesthistory_max_taskskept, default 200) and come back on demand forsubagent_resultandsubagent_continue; an id looked up this way from an unrelated session never enters the overlay or becomes cancellable. Child sessions live under~/.pi/agent/gentle-agents/sessions/. ctrl+shift+acollapses the card to its first row (GENTLE_PI_AGENTS_KEY),GENTLE_PI_AGENTS_VIEW_KEYrebinds the overlay,GENTLE_PI_AGENTS_PIoverrides the pi command used for children, andGENTLE_PI_AGENTS=0disables the tools and the card.
The todo tool and its card replace the third-party todo extension (remove npm:@juicesharp/rpiv-todo from your pi packages; sessions written by it replay into the new card).
╭─ ❀ Todos · 1 of 3 ──────────────────────────────────────╮
│ ✓ Add quiet tool rendering │
│ ◐ Fix quiet tools conflict · fixing conflict │
│ ○ Show git bash tails │
╰─────────────────────────────────────────────────────────╯
Three things keep the list current, which a static tool description cannot:
writereplaces the whole list in one call, so the model rewrites the plan instead of patching it;add,update,clear, andlistremain for single moves.- Every turn's system prompt carries the open tasks and the rules: in_progress before starting, done right after finishing, update before ending the turn.
- A list that goes two turns untouched while tasks stay open turns amber with
stale · N turns, and the prompt says so, so the model brings it up to date.
A finished list stays on screen for the turn it finished in and clears at the next. ctrl+shift+t collapses the card to the task in progress (GENTLE_PI_TODO_KEY rebinds it, off disables it); GENTLE_PI_TODO=0 disables the tool and the card.
The Gentle AI harness (ODD workflow, identity, review contract) and the open-tasks block are appended to before_agent_start's systemPromptOptions.appendSystemPrompt instead of being returned as a replacement systemPrompt (gentle-shell#1485). Provider bridges such as pi-claude-bridge forward only those structured sections after their own preset and drop a returned systemPrompt, so this route reaches every provider, bridged or not.
Set GENTLE_PI_SHELL=0 to keep pi's built-in footer and editor.