Gira is an MIT-licensed coding assistant in the VS Code sidebar (publisher zahmed, VS Code 1.129.0 or newer). It streams responses from your configured OpenAI-compatible endpoint, reads/searches workspace files, proposes line-anchored edits with post-write diffs, delegates to parallel agents, and saves local conversations. No separate CLI or runtime is needed to use the installed extension.
Set up
Install Gira (zahmed.gira) from the VS Code Extensions view and open the Gira Activity Bar view. With no model set up, the banner reads No model set up yet; its Set up button (or Gira: Set API Key, or Gira: Open Settings) opens Gira settings → Models & endpoints, the one place where you connect a model. Gira settings is a single searchable page of thirteen collapsible groups (Search settings and Jump to group sit at its top), and every Gira setting can be edited there, so you never have to open settings.json. The short version:
Paste the endpoint URL: the provider's OpenAI-compatible API root, usually ending in /v1.
Paste the API key. It goes to VS Code SecretStorage, is sent only to that URL's host (the page names the host) and is never shown again: afterwards the row reads Key set with Replace and Clear. Keys never belong in settings, prompt files or the repository. A key typed only to list models is used once and not stored. Endpoints that need no key can leave the field empty (Detect without a key).
Gira checks the endpoint for its models (automatically once the URL and key are filled in; Detect repeats it) and lists them. Tick the ones to use and mark one Default. A new model starts at the context window and output limit the endpoint reports, or at labelled working estimates (8,192 context / 1,024 output) for a limit it does not report; both are editable per model (Edit), and Use automatic values puts them back.
Press Save, then press Auto-configure on the saved model to let Gira work out its settings (see Setting up a model).
If the endpoint has no /models list, add model ids by hand.
Changing an endpoint's URL or auth settings removes its saved key; the page says so before you save and asks no confirmation dialog. Removing an endpoint (Remove…, confirmed inline) also removes its key; if it provided the default model, the default moves to another model.
Advanced holds the less common fields. Endpoint: name, id, auth header and prefix (or Send no auth header), extra headers, max concurrent requests. Model: images, reasoning, tool support, max tokens field, stream usage, response mode and the other recorded response variants, stream idle allowance and extra body. Every optional field has its own Reset to default: it removes a saved optional value when you press Save, while Discard edits returns the form to what is saved. Never put secrets in plain-text headers or extra body.
Gira: Select Model and Gira: Clear API Keys open the same page. The model chip in the composer opens a popover that switches the model of the current session: the models grouped by endpoint (↑/↓ and Enter choose; from eight models on, a filter field narrows the list by name or id), one compact Reasoning row for the session's reasoning choice, and Manage models last, which opens this page. A model's id is in its tooltip, and shows in the row when two models share a name. The popover does not dim the chat; it closes on Escape, a click elsewhere, switching away from the window or a session switch. Switching is refused while a turn, a subagent or a queued message exists, and the rows say so.
Streamed reasoning is displayed only if the endpoint emits it. Cancel stops the current turn and its children; the turn then ends with a single Cancelled card (or Step limit when it reached the step limit). Requests ask for stream_options.include_usage unless the endpoint rejected it and the model records that; token counts and the stats line appear only when the endpoint reports usage.
Gira needs a model that honours tools and system messages. With the STARK gateway, use a -withtools model (for example gemini-3.8-flash-withtools); its other models ignore both. Auto-configure checks tool support for you (see below).
Setting up a model
Set the provider. In Gira settings → Models & endpoints press Add and paste the endpoint URL, the provider's OpenAI-compatible API root, usually ending in /v1.
Add the key. Paste the API key. It is stored in VS Code SecretStorage and sent only to that URL's host; afterwards the row reads Key set. Endpoints that need no key can use Detect without a key.
Check models. Gira asks the endpoint for its model list and shows the models it offers. The list, and any limits it reports, are reused by Auto-configure for five minutes while the URL and key are unchanged.
Add a model. Tick a listed model (or type an id when there is no list), mark one Default and press Save.
Auto-configure. Press Auto-configure on the saved model. Above the button the card lists each check that will run, the worst-case cost and what the click consents to; two options (Recheck configured capabilities and Check unknown limits with larger synthetic prompts) are off by default. One press runs the pass and saves the result.
Ready. The card shows what changed and why, with the evidence, and the model is usable; Undo restores the earlier values.
What Auto-configure sends and costs. Only synthetic setup data is sent: never your workspace, conversation, instructions or files, and never your custom extra body. A standard run is at most 5 requests and 208 output tokens: one request for the model list (none when the Check models list is still fresh), one tiny streamed chat request (at most 64 output tokens) that carries a fixed synthetic tool which is never run, up to two corrected sends of that request when the provider names a rejected option (stream_options, the token field or tools) or while asking whether a reasoning control exists, and one tiny 32×32 synthetic image unless the model list already declares image input (at most 16 output tokens). With Check unknown limits with larger synthetic prompts and no reported context maximum, two more requests of 2,048 and 8,192 bytes of filler (16 output tokens each) raise the worst case to 7 requests and 240 output tokens. Each request is bounded to 15 seconds, and the card shows this cost before you press the button.
What is saved. The result saves automatically, with its evidence and a change record; Undo restores the previous values (the last five changes are kept). Auto-configure writes only what it observed or the provider reported, and never changes a value you pinned by typing it: a number you type is your own declared value, and Use automatic values returns it to automatic.
Reported limits are used in full. A context window or output limit the provider reports is saved and used as reported. There is no default cap: a request sends the model's full output capacity, lowered only by the context left after your prompt and a 1,024-token safety reserve. The Optional user cap row is unset by default and only ever lowers a capacity.
Unreported limits are labelled estimates. A limit the provider does not report is saved as a Working estimate (8,192 context / 1,024 output), never as a measured maximum. A successful larger sample is saved as an Observed lower bound, and a number you typed shows as a Declared override.
Tools, usage, token field, reasoning and images are saved only on evidence. A valid synthetic tool call saves tool support; an explicit rejection of tools saves it as unsupported, and a tool-using request to such a model is refused with a message instead of silently dropping its tools. A reasoning control is saved only if the model list declares it or the server echoes it back; an endpoint that merely accepts a field proves nothing. Image input is saved as supported only after a correct answer about the synthetic picture, or when the model list declares it.
Runtime learning. Pressing Auto-configure also lets that model learn from later requests (the Learning from later requests switch on its card turns this off at any time; a model you never auto-configured keeps exactly its configured limits and saves nothing). Each change is saved with an Undo and shown as Model configuration adjusted: …, even when Settings is closed.
Output limit and token field. If the endpoint rejects a request's output limit and states a smaller maximum, Gira resends the same input once with that limit and saves it. If it explicitly rejects the token field, Gira resends once with the other of max_tokens and max_completion_tokens and saves the switch only after the corrected request succeeded.
Context repair. If the endpoint says a request is too large and states a smaller context window, Gira resends once with that window. When the conversation does not fit, it first runs one bounded compaction (at most two summary requests); if it still cannot fit, you get the original error with what to do next.
Usage growth. When a reply's reported usage shows the model handled more context or output than is saved, Gira raises the saved value to what it observed, labelled as an observed lower bound. Your caps still apply.
Wire variants. Four known deviations from the usual Chat Completions stream are recognised, and only these: a complete JSON body answering a stream request, usage in a frame with no choices, a final choice with no delta, and finish reasons named end_turn, eos, eos_token, max_tokens, max_output_tokens or function_call (the last only with a complete tool call). They are saved only after a whole turn validated; an endpoint that rejects streaming is asked once without it. Malformed replies are still rejected and tool calls are still validated in full.
Per-model idle allowance. If the sample's tool arguments arrive in one piece, Gira may save a 600-second stream idle allowance for the model. A stream that stays silent past its allowance gets one more attempt with the allowance doubled, and a long gap seen on a request that succeeded can raise it; the allowance never exceeds 600 seconds. A Stream idle timeout you set yourself in Requests & recovery always wins.
Safety limits of the learning. Each logical request makes at most one adaptive repair, and every corrective send counts against your existing retry, retry-wait and overall-deadline limits and the run's automatic-continue budget; with zero retries or zero automatic continues nothing is resent. A pinned value, an optional cap, a field your extra body sets and a strict setting you chose are never changed. Only closed values (numbers and field names) are recorded, never provider text, and a change made after you edited the endpoint's URL, key or model is dropped.
settings.json (optional)
This is an optional alternative, never a requirement: Gira settings can edit every endpoint, model and setting, and its values are the same User-settings values. If you prefer a file, or are migrating endpoint definitions you already have, you can write them by hand in User Settings (JSON), or Remote User settings when connected remotely. Saving from the page rewrites gira.endpoints, which loses any comments inside it. Replace the illustrative address and model with your provider's values:
gira.endpoints, gira.defaultModel, every gira.request.* setting and the gira.log.* settings are machine-scoped and read only from User/Remote User settings: Workspace, .code-workspace and Folder values are ignored in trusted and untrusted workspaces (and restricted in Restricted Mode), so a repository cannot choose where your prompts, files or API key are sent, relax your retry and timeout limits, or turn on content logging. Because they are machine-scoped, Settings Sync does not carry them to other machines. If you previously configured endpoints in workspace settings, copy the endpoint/model definitions you approve into User settings yourself (Gira never imports them); keeping the same endpoint id keeps its stored key. Then start a new session, reselect the model, or reload the window.
Workspace and instructions
Every open workspace folder is available to list/search/read/edit, not just the first. Paths are root-qualified (server/src/a.ts) or absolute paths inside an open folder. A sole folder also accepts relative paths. Folder display names are visible aliases; collisions are disambiguated (app~1, app~2) in VS Code folder order. Use the shown alias to distinguish identical relative filenames. Outside paths and symlink/junction escapes are rejected. In multi-root workspaces commands require a root-qualified cwd; omitted cwd is only valid with one root. With no folder you can still chat and load global skills, but workspace file tools and commands report “No workspace is open”; no home-directory cwd is implied. Changing the root set selects a different session namespace.
With a sole folder shown as Gira, Gira/src/a.ts and src/a.ts name the same file, and bare Gira or Gira/ names the folder itself: a leading alias always means the root, even if a child folder has the same name. Address such a child as ./Gira/src/a.ts (or Gira/Gira/src/a.ts, or its absolute path). Tool output reports that child as ./Gira/..., so any path Gira emits can be passed back unchanged.
list_files fails for a missing target (ENOENT) or a target that is not a directory (ENOTDIR), whether or not the listing is recursive; an existing empty directory lists successfully with no entries.
Language navigation (opt-in):gira.tools.languageIntelligence enables find_definition, find_type_definition, find_implementations and find_references (path, 1-based line/UTF-16 column, optional maxResults), get_hover (path, line, column), document_symbols (path, optional maxResults) and workspace_symbols (query, optional workspace-contained path and maxResults). Installed VS Code language providers supply best-effort navigation, not edit authority. Document queries use the current editor buffer and reject stale results. Location queries default to 100 results and cap requests at 500; hover is sanitized, inert plain text capped at 8 KiB, not executable Markdown or HTML. Serialized output is bounded, and provider waits share a five-second deadline and four unsettled-call slots; cancellation does not free a slot until its provider call settles. Workspace scope filtering is applied after the provider query; an empty result is not proof that the workspace has no matching symbol.
Diagnostics: the same opt-in gira.tools.languageIntelligence enables get_diagnostics, which reads current VS Code diagnostics only for up to 32 explicit workspace-file paths. It can wait for a diagnostic event after a returned baseline; a timeout returns cached evidence, not proof that a file is clean. It is read-only and requires workspace trust.
Structural search:gira.tools.structuralSearch (on by default; Gira settings → Tools & search) offers the read-only structural_search tool, which matches the syntax tree instead of text, so it ignores comments and strings and finds declarations split over several lines. Give either a pattern written as ordinary code of the target language (Console.WriteLine($A), print($$$ARGS); $NAME matches one node, $$$NAME zero or more, $_ any node without capturing) or an ast-grep rule object (kind, regex, has, inside, not, all, any, …), for example C# classes deriving DbContext. It searches C#, Java, Python, TypeScript/TSX and JavaScript files (.cs, .java, .py, .pyi, .ts, .mts, .cts, .tsx, .js, .mjs, .cjs, .jsx), optionally limited by language, path and glob; node_modules and .git are never searched. Each match is path:line:column (1-based, UTF-16 columns) with its first line and the captured metavariables. Limits: 50 matches by default (maxResults, at most 200), 5,000 candidate files, 1 MiB per file (larger and binary files are counted, not searched), 5 s per file, 30 s per call and 32,000 characters of output; every cut-off is reported in the result. Patterns that are not valid code of the language are rejected with the parser's message. It runs inside VS Code as WebAssembly (ast-grep and tree-sitter grammars) in a worker thread: no external program, no network, and nothing loads until the first search or edit of a supported file; the worker stops after 5 idle minutes. The tool declaration adds about 1,640 characters (roughly 410 tokens) to every request while the setting is on; turn it off for small local models.
Search exclusions and limits:search_files takes exclude, up to 16 globs (each up to 256 characters; a leading ! is accepted) matched like glob against the paths it prints (server/vendor/** in a multi-root workspace; a sole folder also accepts bare paths or its alias). A match on a file or on any parent folder drops it, and exclude always wins over glob. A search that stops early says why: [Search stopped at the hit limit (N); more matches exist] or [Search stopped at the 5,000-file listing limit], with or without output budgeting.
Syntax check after edits:gira.tools.syntaxCheck (on by default; Gira settings → Tools & search) parses a C#, Java, Python, TypeScript/TSX or JavaScript file after edit_file or create_file writes it and appends the syntax errors the change introduced (at most five, with line, column and the source line) to the tool result, so a dropped brace is fixed in the next step instead of surfacing in a build. Only new errors are listed: the text before the edit is parsed too and errors it already had are counted but not listed, so legacy or generated files do not trigger noise. The note is advisory and never changes the edit's outcome; it is silent when the file is clean, unsupported (Markdown, JSON, …), over 1 MiB or binary, and says Syntax check skipped: … when the parse timed out (3 s) or the engine is unavailable. The tree-sitter grammars can lag the newest language syntax. The bundled C# grammar (0.23.5) rejects these valid constructs, which are reported as errors when new code uses them: C# 14 extension blocks (extension(string s) { … }), null-conditional assignment (b?.X = 1;), lambdas with modifiers on untyped parameters ((text, out result) => …) and C# 13 where T : allows ref struct; primary constructors, collection expressions, raw strings, required/file, list patterns, file-scoped namespaces and the field keyword parse cleanly. Like structural search it runs as WebAssembly in a worker thread inside VS Code, with no external program, and loads nothing until a supported file is edited. It checks syntax only, not types or whether the project builds.
Line endings and BOM: edits preserve a file's line endings (CRLF) and byte-order mark. Overwriting an existing file with create_file keeps its BOM and CRLF style; a new file is written exactly as given.
Edit failure reasons: every refused or failed edit_file, create_file, write_plan and write_decisions call carries one closed reason, kept on its transcript row and in the saved session: unread (the file was not read first), stale_tag, stale_disk (the file changed since it was read, including while the approval waited), invalid_ops, invalid_arguments, exists (the file exists and overwrite was not set), not_found, outside_workspace, too_large, denied, cancelled, policy_changed (permissions changed during approval), write_failed (the call failed before writing) and outcome_unknown (the write may have partly landed; inspect the file). The row says it in words, for example Rejected: file changed since read, in its tooltip, a caption chip and the expanded card. Session info (the status dot beside the title, or ⋯ → Session info) shows Edit failures: 2 stale tag, 1 denied, counting the main agent and its subagents (the line is absent when nothing failed). Counts are per session and are not exported.
Edit lifecycle and Open diff: an edit's diff is kept on its transcript row from the moment it is prepared, before you approve it (state prepared); it becomes applied right after the write, before the advisory syntax check runs, and a refusal ends it as denied, cancelled, stale, failed or outcome_unknown with the failure reason above. The row keeps the +/− counts and a bounded copy (up to 64 KiB) of the unified diff, which survives a reload. Open diff opens VS Code's native diff of that call's exact before and after text, so a later edit to the same file never changes it. These full images are held in memory only, up to 200 revisions or 16 MiB per session: after eviction, edit-last, closing the session or reloading the window, Open diff says "Historical full revision unavailable" and never falls back to the file on disk. Open diff only works for the session on screen.
Edit rows: an edit, create, plan or decisions row shows its lifecycle as a caption: Proposed from the moment its diff is prepared (while approval waits, with the diff and the +/− counts already on the row), Applied right after the write, or the way it ended without landing: Denied, Cancelled, Stale: … (the file was not read, or changed since it was read; the caption names which), a Rejected: … or Write failed reason, or Outcome unknown: check the file. The caption is also part of the row's accessible name. Expanding the row shows the diff and Open diff from Proposed on, even for a denied proposal. A session restored after a reload keeps each row's caption, counts and recorded diff; rows saved before 1.2 have no caption.
Open in editor:gira.tools.openInEditor (on by default; Gira settings → Tools & search) lets the main agent open a workspace file at given lines when you ask to see it; it keeps your focus unless no editor tab is open, and each file stays open in its own tab. When you ask to see a diff or the changes, it opens the file's git HEAD version beside the working copy instead (VS Code's built-in Git extension is required; untracked files have no diff).
Historical tool evidence (opt-in):gira.tools.outputBudget bounds previews while retaining sanitized produced output for read_tool_output when capture succeeds. Handles are immutable, belong to their originating agent (also readable by the same session's main agent), expire with retention/cleanup, and never renew file-edit snapshot authority. File reads, edit replies, search, commands and text attachments disclose available or unavailable evidence. Attachment retention includes produced views omitted from the preview, not unseen source: file views remain capped at 2,000 lines/256 KiB and directory views at 200 entries/the workspace-index limit. Framing and disclosure count toward the attachment preview budget. Storage/capture failure does not fail an otherwise valid read, send or command.
read_tool_output can also open retained output as a read-only historical document. That view is prior tool output, not current workspace content; opening it or reading its handle never grants or renews file-edit authority.
Instructions are Markdown files added to every session's prompt; settings change how Gira behaves, instructions tell the model what you want. There are two levels:
User instructions:~/.gira/system.md (or <gira.userConfigDir>/system.md) applies to every session in every workspace, regardless of Trust.
Repository instructions:<root>/.gira/system.md in each open folder, in VS Code folder order, applied only in trusted workspaces. For compatibility with other agents' conventions, the folder's root AGENTS.md is added after it while gira.prompts.includeAgentsMd is on (default); Gira never migrates or modifies it.
The assembled prompt is, in order: base and environment, main agent guidance (or the delegated agent's definition), the active session's Preset instructions (<name> r<revision>) section when a preset is pinned, User instructions, then per folder <alias>: repository instructions and <alias>: AGENTS.md, then skills, then the built-in Commit guard section (omitted when the guard is Off), and the mode and restrictions section last. The preset section is reserved in the budget, so optional layers are cut first; any truncation appears in the Effective prompt preview. With no active preset no section is added and the prompt remains byte-identical to before. The commit guard section is reserved in the budget like the base and mode sections, so optional layers are cut before it. Each file is read up to 64 KiB, and the whole prompt is capped at 48 000 characters; when the optional layers exceed what remains after the built-in prompt, the earlier layers are dropped first (user before repository), so the most specific layers win. Files are read again at the start of every turn: the prompt stays constant within a turn and an edit applies from the next turn. Because the prompt prefix changes after an edit, a server with a prompt cache (for example llama.cpp) re-processes it once. Instruction text, including AGENTS and skill files, cannot grant permissions or override workspace containment/Trust. Delegated agents receive the same user and repository layers and skills after their own definition.
The Instructions page (⋯ → Instructions…, or Instructions → in the Context & instructions group of Gira settings) lists the user file and, per folder, .gira/system.md and AGENTS.md, each with its path and a status (Missing, Empty, its size in characters, or Too large). Open opens a file; Create creates a missing one from a short template (without overwriting) and opens it. The Include AGENTS.md switch sets gira.prompts.includeAgentsMd (the same User value as the switch in Gira settings → Context & instructions). In an untrusted workspace the repository files show a lock notice and cannot be created. The Effective prompt card shows how much of the 48 000-character budget each part uses and whether earlier layers will be cut; Preview opens the exact prompt the next turn would send in a read-only editor. With no folder open only the user card is shown.
Agent definitions live in .gira/agents/*.md, globally and, only in trusted workspaces, per folder. Skills live in .gira/skills/<name>/SKILL.md, with additional read-only discovery from .agents/skills/ and .claude/skills/ both globally and per folder. For duplicate named skills/agents, later workspace folders win; within a scope .gira wins over .agents, which wins over .claude. Built-in definitions have lower precedence than global and workspace definitions. Within an active session, pinned preset agents and skills take precedence over discovered entries of the same name; preset skill bodies remain load-on-demand through read_file.
Permissions and command execution
Use the sidebar Permissions popover (the shield icon immediately after the composer's plus) to change the current session's approval choices. It opens above the composer without dimming or freezing the chat: the conversation behind it stays readable and scrollable, and it closes on Escape, Tab past its last control, a click elsewhere, switching away from the window or a new approval (a click on another composer button switches to that one). A keyboard open (Enter on the shield) focuses the first choice, a mouse open the panel, and closing returns focus to the shield. The popover shows text and checkboxes for Ask before edits, Ask before commands and Full auto, plus Full auto's warning. Full auto clears both asks; selecting either ask deselects Full auto, and both asks can be on together. The composer remains icon-only: a shield with a pencil for edits only, a shield with a terminal for commands only, a plain shield for both asks, and a red shield crossed with an X for Full auto. Hover text describes the effective choices. Keyboard/screen-reader controls retain labels and checked/locked state; while a turn runs or subagents work the choices stay visible but locked, with the reason. The default for new sessions (and /clear) is gira.permissions.defaultMode in User settings, also editable in Gira settings → Permissions & execution (Permissions for new sessions); changing it never alters the open session's mode or interrupts a running turn:
Mode
Edits and plan writes
Commands
ask
Ask every time
Ask every time
auto_edits (default)
Apply and show a diff
Ask
allowlist
Apply and show a diff
Auto-run matching user allowlist commands; ask for others (except git commit, see Commit guard)
full_auto
Apply and show a diff
Auto-run without prompting (except git commit, see Commit guard)
The popover and current-session Settings summary reflect effective approvals, including the edit-approval override. A stored full_auto command mode with edit approval enabled appears as Ask before edits, not selected Full auto. Turning Full auto off restores command approval.
Approval and question cards: a command or edit approval, and a question from the ask tool, appear as a flat panel docked above the composer (a top border, no grab handle or shadow). When the main agent's approval arrives, or a question card appears, Gira moves keyboard focus to the card itself, never to Allow or an answer (an approval also closes any open page or popover first, but not the Agents view, which leaves the dock reachable), so an Enter you were already typing, or one that arrives late, cannot approve or choose anything. Tab moves from the card to its controls. A subagent's approval never takes focus; Review approval (or Answer for a question) on its tool row and in the exact-call view focus the card the same way (an open page or popover is closed first; the Agents view stays open). Pages and popovers fade in with a short shift instead of sliding, and not at all with reduced motion or gira.ui.animations: false.
Ask before: Edits (setting gira.edits.requireApproval) is a restrictive override in every mode, including full auto; it never weakens ask. Permission, model and mode changes are refused while a turn, a control command, any subagent or a message waiting to be answered exists (Stop the agents first. / Cancel the turn before changing …); they never block sending a message. A command approval can allow this exact command for this session: the original command text, canonical cwd, and shell executable/kind must match; changing whitespace/cwd/shell asks again. Such grants reset when a session is reopened, are not carried across workspace root changes, and are ignored in ask mode. gira.commands.allowlist is user/machine-scoped and only applies in allowlist mode: patterns match the entire command, case-sensitively, without trimming; * includes newlines and ? matches one character. Broad patterns can match compound commands, so prefer narrow patterns and inspect them carefully. Turning on Full auto takes effect immediately with no confirmation dialog; while it is active the composer's shield button turns red. Gira is not a sandbox: approved/auto-run commands have your account's access. Children inherit the parent turn's mode, Trust and permission policy.
Commit guard (gira.commands.commitGuard, User settings only; workspace values are ignored, and missing or invalid values mean ask) is an exception to every permission mode. Ask for approval (ask, default): every recognized git commit from the main agent or a subagent, foreground or background, needs a one-time approval. The card offers Allow and Deny but no Allow for session, and Full auto, allowlist patterns and earlier session grants do not skip it. Deny (deny): recognized commits are refused without a card. Off (off): commits follow the ordinary permissions. The agent and subagents get a matching prompt section: with Ask, they must not commit unless you explicitly ask, and then submit the commit for your approval; with Deny, commits are forbidden outright; with Off, the section is omitted. Enforcement reads the setting live: a change applies to commands still pending (switching to Deny blocks an already-approved commit before it starts; switching to Ask while an approval is pending asks you to submit again), while the prompt text updates from the next turn. Detection covers git/git.exe invocations (including paths and global options such as -C/-c), compound command lists, sh/bash -c, powershell/pwsh -Command, cmd /c, and $(…) substitutions. It does not resolve Git or shell aliases, inspect npm/make or other script bodies, evaluate dynamically built or encoded commands, or stop commits made by merge, rebase or plumbing. It is an accident guard, not a sandbox.
Workspace Trust takes precedence over all modes and prompt instructions: untrusted workspaces permit reading/chat, but not source edits, plan writes, commands, or workspace prompt/agent/skill layers. Trust is workspace-wide in multi-root windows.
When an edit, plan or decisions write needs approval, its card shows the proposed diff and offers Open diff beside Deny (and Allow): VS Code's native diff of that call's exact before and after text, so you can review the change in the editor before answering. Opening it does not answer the request. It works for the session on screen and, as in the transcript row, says "Historical full revision unavailable" once the images are gone.
run_command executes after broker policy evaluation, not always after a prompt. The default on Windows is Windows PowerShell 5.1 (powershell.exe); on macOS/Linux it is $SHELL when that is sh, bash, zsh, dash or ksh, otherwise /bin/sh. Commands run with -c, so zsh still sources ~/.zshenv. The run_command tool description names the shell in use. User/machine settings gira.commands.shell and gira.commands.shellKind can choose another executable/kind; pwsh is never selected automatically. The Windows invocation passes a readable plain-text script to -NoProfile -NonInteractive -OutputFormat Text -Command, using native argument escaping. It does not use encoded transport, Invoke-Expression, policy-altering flags, a decoding trampoline, or an execution-policy bypass. Ordinary Constrained Language Mode, AllSigned, and application-control failures remain failures. Output pipes are decoded as UTF-8 (including split sequences), but Windows PowerShell 5.1 and native programs may emit a legacy code page; the resulting non-ASCII text can still render incorrectly. Timeouts/cancellation stop the spawned shell; on Windows its grandchildren may survive. Avoid using commands that leave background processes behind; use a background job instead.
Each foreground run_command call starts a fresh shell process: variables, directory changes and other shell state do not persist between calls. A background command is a separately tracked job, not a reusable persistent shell.
Background commands and jobs
For servers, watchers and other long-running commands the model can call run_command with background: true. The command goes through the same approval policy (its approval card says Runs in the background until stopped), then Gira returns a job id together with about two seconds of initial output. The model follows the job with the jobs tool: output (new output since its last read, plus status), wait (until a regex pattern matches new output, the job exits, or timeoutSeconds elapses; default 60, max 300), kill (stops the job and its process tree) and list. When a job finishes during a turn, a [Background jobs] note reaches the agent that started it before its next step; no note is sent if that agent already saw the exit (for example through jobs wait). If a job the main agent started finishes while no turn is running, a Background job finished — resuming… row appears and, after about 1.5 seconds, the agent gets a turn to report it; several finishes close together share one wake-up, and it happens even while you are typing or have switched to another session (the wake-up then runs in the background and counts toward gira.sessions.maxRunning). The row's ✕ (Don't resume) cancels that wake-up and the note goes with your next message instead. gira.commands.wakeOnJobExit (default on) turns wake-ups off. Jobs started by a subagent belong to it: their notes go to that subagent, not the main agent. A subagent that tries to finish with jobs still running is reminded once to wait for or kill them; any left over are killed and listed in its summary. In the conversation the job's run_command row shows a live output tail, a status chip and a Stop button; ⋯ → Background jobs · N running expands in place to list the session's jobs with their status, elapsed time and Stop (N is the number of jobs running now). Jobs keep running when you press Stop on the turn and when you switch to another session. They are stopped with their process tree when you delete the session, /clear, change the workspace roots, reload or close VS Code, or after gira.commands.backgroundTimeoutSeconds (default 1800; 0 = no limit). gira.commands.maxBackgroundJobs (default 6) limits concurrent jobs per session and gira.commands.jobOutputChars (default 200000) bounds each job's retained output. A process a job deliberately detaches from its tree (for example with Start-Process) can escape the stop.
With gira.tools.outputBudget enabled, background output revisions are retained independently of that bounded live tail, so omitted middle output can still be retrieved. Output/wait calls preserve independent reader cursors; later output creates a new immutable revision rather than changing an earlier handle. Live safe previews are capped at 8 KiB, use complete lines, and withhold unsafe unfinished credential content. In-memory evidence is limited to 1 MiB per job and 8 MiB across active evidence helpers; overflow, privacy withholding or storage failure is reported as unavailable evidence, not a complete capture. Ordinary job execution/wait outcomes remain usable.
Loop guard: if an agent (main or subagent) repeats the identical tool call—same tool, arguments and result; jobs calls count even when their output changes—the model is warned at the 5th repeat (a grey Loop guard · warned · <tool> ×<count> card appears in the conversation) and the turn is stopped at the 10th (a red Loop guard · stopped · <tool> ×<count> card). A subagent stopped this way finishes with status loop.
Plans, reviews and sessions
/plan <request> runs one planning turn; bare /plan toggles sticky planning for ordinary messages. In plan mode the agent can read/delegate and write Markdown plans only under an open folder's .gira/plans/; it cannot edit source files or run commands, even in full auto. Plan save cards show the diff and let you Open the plan or Use plan to start a build turn. Bare /build clears sticky plan or discussion mode without running anything. /build "server/.gira/plans/task.md" reads the current saved plan and starts an explicit build under ordinary permissions; it is not an escalation. /review is read-only and covers changes in all Git repositories inside the open folders, including untracked text; explicit paths can narrow the review. /compact summarizes a long conversation on demand. /new starts a new session, /clear empties the current conversation in place, and /delete deletes the current session and starts a fresh one. /handoff [focus] writes a handoff document to .gira/handoffs/<yyyymmdd-hhmm>-<slug>.md in the first open folder and replaces the context with it; long conversations are summarized in chunks, and the result appears as one handoff card. It needs a trusted workspace with an open folder and writes without an approval prompt because you invoked it. Gira keeps .gira/handoffs/ out of Git through .gira/.gitignore (see Git-ignore below). Typing / in the composer autocompletes commands; Enter on a command that takes no argument sends it. Sessions and transcripts persist locally per ordered root set; snapshots and temporary approvals do not persist.
Discussion mode:/discuss [topic] enters sticky discussion mode (with a topic, it also sends the topic); bare /discuss toggles it ("tell me the topic, or /build to leave"), and /build leaves it. The turn-mode segment in the ⋯ menu also offers Discuss. In discussion mode the agent can read, ask you questions and write documents with write_decisions (Markdown only under an open folder's .gira/decisions/) or write_plan; it cannot edit source files or run commands. The built-in method works in four phases: Clarify (only when the topic is unclear — no identifiable subject, no stated outcome, or no boundable scope — at most three questions), Research (always, before the first decision question: the code the topic touches, existing plans and decisions, and anything you pointed at), Decide (one question at a time with a recommendation and a Grounding: line citing file:line, or "not in the code"), and Write up to .gira/decisions/<yyyymmdd>-<hhmm>-<slug>.md with a ## Research section and an Evidence: line under each decision. To replace the method, add a skill named discuss — .gira/skills/discuss/SKILL.md in a workspace folder, or discuss/SKILL.md in the global skills folder (~/.gira/skills/); a workspace skill wins over a global one.
Questions (ask): the main agent (not subagents) can ask 1–4 questions at once, each with options (one may be marked Recommended), single or multi-select, and free text. A card replaces the composer and steps through the questions. When typed answers are allowed, the options end with Other: choosing it opens a text box for your own answer (in a single-choice question it replaces the listed option; in a multi-select one it is added to the ticked options), and a question without options shows the text box directly. 1–9 toggle options including Other, Enter in the text box answers and moves on (Shift+Enter adds a newline), Skip skips a question, Back returns to the previous one, and Answer in chat dismisses the card so you can reply as a normal message. Stop cancels the question. The transcript row shows each question and its answer.
Context strategy: when a session's context reaches a share of the model's context window (default 60 %, range 30–90 %, or earlier if the model's output headroom caps it), Gira either compacts (summarizes earlier messages), hands off, or does nothing (Off). The default strategy is gira.context.strategy (compact, handoff or off; default compact) and the default threshold gira.compaction.threshold (0.6); both are set in Gira settings → Context & instructions, where the threshold takes any value from 30 to 90 % (fractions such as 61.5 are fine). Each session can override them: /autocompact 70 or /autohandoff 70 choose that strategy at 70 %, on chooses it at the current threshold, off turns context automation off, and default returns to the defaults. A session override or an active preset wins over the defaults and is shown on its row in Gira settings. Bare /autocompact and /autohandoff answer about their own automation with a Context card: Autocompaction 60% · 114k / 190k · default (or · session when overridden), Autohandoff off · autocompacts at 60% when you ask about autohandoff on a compacting session (and Autocompaction off · this session autohandoffs at 60% the other way round), or Automation off · /compact and /handoff only. A change shows the card with a changed chip, /autocompact default with a reset chip, and repeating an identical readout updates the existing card instead of adding another. Click the context percentage in the composer (hover or keyboard focus still shows the read-only readout) to pin the Context controls dialog above it: Compact · Handoff · Off, a slider over the current context fill, a readout such as Autocompaction at 60% · 114k of 190k tokens (plus "capped at N by output headroom" when the cap applies), a Default/Session chip, Reset to default and Compact now (unavailable while a turn runs). Escape closes it and returns focus to the percentage. Changes there (strategy, slider, Reset to default) add no transcript card. A change applies from the next step, also mid-turn.
Autohandoff writes a handoff document to .gira/handoffs/<yyyymmdd-hhmm>-<slug>.md in the first open folder mid-turn, keeps the most recent messages and continues from the [Handoff] document. It needs a trusted workspace with a folder open; otherwise the session compacts instead and shows an Autohandoff · unavailable · compacting instead card once, with the reason in its body. Subagents always compact. With Off, nothing is compacted automatically; if the conversation then no longer fits, the turn fails with "The conversation no longer fits the model context and autocompaction is off. Run /compact or /handoff, or turn it back on with /autocompact on." Compactions and handoffs appear as tool-style cards showing tokens before → after and whether they were automatic or requested (/compact, /handoff); expanding one shows the carried-over summary or the handoff document, and handoff cards have an Open chip. Background-job wake-ups use the same card style.
Git-ignore: after writing a generated file in a trusted workspace, Gira maintains <root>/.gira/.gitignore in that folder with a managed block, between # >>> gira managed (edit outside this block) >>> and # <<< gira managed <<<, that ignores its generated files: handoffs/, goals/ and transcripts/ by default; plans/ and decisions/ are opt-in via gira.git.ignoreArtifacts (items handoffs, goals, plans, decisions, transcripts; [] turns it off and removes the block). Lines outside the markers are yours and are never touched, and Gira never edits your root .gitignore. Repository configuration under .gira/ (system.md, agents/, skills/) is meant to be committed.
Autoclean: Gira deletes its own dated documents once they pass a retention period (any whole number of days from 0 to 3650; 0 keeps them forever; set under Gira settings → Transcripts & cleanup): handoffs after gira.cleanup.handoffsDays (default 30), decisions after gira.cleanup.decisionsDays (default 0 = keep forever), finished goal documents after gira.cleanup.goalsDays (default 90), and transcripts after gira.cleanup.transcriptsDays (default 0 = keep forever); plans are never cleaned. Age comes from the <yyyymmdd>-<hhmm> in the file name; only such files directly inside .gira/handoffs/, .gira/decisions/, .gira/goals/ or .gira/transcripts/ are considered, links are skipped, handoffs referenced by the current session and its transcript file are kept, and goal documents are kept while their Status: is active or paused or they belong to the current session. Cleanup needs a trusted workspace, runs a few seconds after Gira starts (when its view first opens in a window) or the open folders change, and before each new handoff is written; /cleanup runs it now and reports what it removed in a Cleanup card. Removals are logged in the Gira log.
Each tool card finishes as soon as its own call does, so a fast read can show ok while a slower sibling or delegated agent is still running. Cancel marks every started but unfinished tool card—including cards inside delegated agents—as cancelled immediately and keeps any output received so far; already finished cards keep their result. Cancelled calls are recorded as Cancelled tool results in the saved conversation, so the next turn continues from a complete history. Cancel stops Gira waiting for the tool; an in-flight filesystem operation may still settle before the turn fully ends.
Reopened sessions never resume tool calls. A card saved while still running (for example, when VS Code closed mid-turn) opens as cancelled with “Interrupted before this session was restored”, keeping any output it had; finished cards and the conversation are unchanged.
Command tool headers read Command · Run test suite: one title, a centered dot and concise same-call intent, without another title or “Intent:” prefix. New command purposes are limited to 45 Unicode code points and prompted as short, informative actions. Older longer intents are clipped to 45 characters including an ellipsis in the header, with their full intent available on hover; recorded arguments remain unchanged. Without usable intent, the header shows only Command, never raw shell syntax.
Copy and transcript export
Math in replies — $…$, $$…$$, \(…\) and \[…\] — renders as formulas (KaTeX, as native MathML); code spans and code blocks are left alone, a formula that cannot be rendered shows its source, and copy and export keep the original text.
Copy controls are icon-only, with descriptive hover and accessible labels. User-message, final-answer, tool-section and agent-summary copy icons stay visible; code-block controls also appear on hover or keyboard focus:
Copy message copies your message's plain text. Copy final output copies the completed answer's Markdown source, not the whole exchange. Intermediate assistant segments have no message-copy action; Copy turn is no longer shown.
Copy code on a fenced code block copies just the code, without its fence.
Expanded tools have independently collapsible Arguments and Output sections. Arguments starts closed and Output starts open. Agent Instructions starts closed where present. Command text appears in a shaded code pill inside Output, with no separate Command section. Each section has a copy icon that also works while collapsed; copying does not toggle its disclosure.
Copy arguments copies the complete arguments as JSON. Copy output copies the available result, file contents, command output or unified diff, including lines hidden by the visual preview. For command tools it includes the exact command followed by its output. Retained output beyond the available preview still uses Open retained output.
Copy result copies a delegated agent's result on its page or beside a result in a "Delegating to" row. Copy instructions copies its full assignment.
⋯ → Copy last answer, or Gira: Copy Last Answer in the Command Palette, copies the current session's latest final answer.
⋯ → Copy transcript copies the session using the same Markdown layout, tool-output and reasoning settings as export. Delegated agents appear as summary lines, not their full conversations.
Successful copies briefly show a checkmark. Hover text and screen-reader feedback report Copied or Copy failed, without adding visible words to the button.
To save the session, type /export, run Gira: Export Transcript in the Command Palette, or choose ⋯ → Export transcript. Gira writes .gira/transcripts/<yyyymmdd>-<hhmm>-<slug>.md in the first workspace folder and shows a Transcript saved · <path> · <size> card with Open to open the file. Later exports update that session's same file, rather than creating a new snapshot. Export needs a trusted workspace with a folder open; otherwise it reports Export needs a trusted workspace with a folder open.
In Gira settings → Transcripts & cleanup, set Auto-save to After each turn (gira.transcripts.autoSave: "turn") to rewrite the same file after every turn without adding a saved card. The default is Off ("off"); automatic saves are skipped in untrusted or folderless windows. Export now saves manually.
The Markdown file starts with YAML front matter (title, session id, model, started/updated/exported times and turn/tool counts), then a title and chronological ## User / ## Gira sections. Attachment paths, tool calls, agent summaries, errors, system notes and context-compaction markers are included. Tool output (gira.transcripts.toolOutput) controls detail:
None ("none"): one line per tool call.
Summary ("summary", default): the tool line and the first 20 lines of output in a fenced block.
Full ("full"): arguments as JSON and output in fenced blocks, each capped at 20 000 characters. Summary output blocks are capped too; truncation is marked.
Include reasoning (gira.transcripts.includeReasoning, default false) adds collapsible <details> sections. Export and Copy transcript are capped at 2 MiB of UTF-8 text: older turns are dropped first with an omission marker; an oversized remaining turn is truncated.
Copy transcript and Markdown export share the host's credential/image privacy filter, including configured raw and Unicode-escaped key forms, before summary or size limits. Original routine markers, attempts and result-receipt order remain intact. This does not change intentional exact section/message copying or approval/inspection commands. Transcripts can still contain source code or unrecognized secrets from tool output. Review a transcript before sharing or committing it. Transcripts are Git-ignored by default and kept forever unless you change Transcripts & cleanup → Keep transcripts.
Diagrams
A closed ```mermaid or ```svg fence in any reply, thought or agent report renders inline as a preview at most 240 px high, with Copy source; your copy and the transcript export keep the original fence. Each preview is a focusable figure (Tab reaches it) named "Diagram N: …" after the diagram's title (a Mermaid frontmatter title, else the drawing's <title>) or its kind. The text around it is the explanation — a diagram is never the only statement of a fact.
Grammars: Mermaid flowchart (flowchart/graph), sequence, class, state and entity-relationship diagrams, and static SVG. Other Mermaid grammars (pie, gantt, mindmap, architecture, …), %%{…}%% directives and click callbacks are refused and shown as source with the reason.
Titles: a Mermaid diagram can start with one frontmatter block (---, title: Release flow, ---; up to 2 KiB, optional quotes). Gira shows the title (up to 200 characters, as plain text) as the figure header and in the Open diagram tab, and removes the whole block before drawing. Any other frontmatter key (config, displayMode, nested settings, …) is ignored and cannot change how the diagram is drawn; a block with no closing --- or over 2 KiB is refused and shown as source.
Limits: a Mermaid source up to 32 KiB, an SVG up to 128 KiB and 2,000 elements, a rendered result up to 1 MiB, and a two-second drawing deadline. Beyond a limit the fence stays source with the reason. A drawing keeps readable text: it shrinks to fit the sidebar only down to 60 % of its size, then scrolls inside its own box instead of widening the page.
Drawing…: while a reply is still streaming, an unfinished fence shows Drawing… with the source so far (never a half-parsed error); it is drawn once its closing fence arrives. Drawings already finished stay in place while the reply grows.
Open diagram: each drawn diagram in a reply or thought has an expand icon, Open diagram, next to the copy icon (Copy source), which opens an editor tab beside the current one without taking focus, titled "Gira · Diagram — ". The tab shows that exact source revision, drawn by the same renderer, with Fit (the default: the whole drawing, enlarged up to 200 %), 100 %, + and − (25 % to 400 %) and scrollbars; the mouse wheel only scrolls, and the buttons are the only way to zoom. Gira re-reads the diagram from the session's own transcript when you open it and refuses one that has changed since it was drawn. If the conversation later changes the diagram (an edited or regenerated reply, a removed message) the tab keeps showing the revision you opened and says so; text added around an unchanged diagram does not count. The tab keeps updating while you switch the sidebar to another session, holds that session open while it is open, and says so when the session is deleted. Opening or viewing a diagram never sends anything to the model. A diagram in an agent report cannot be opened in a tab yet.
Safety: diagram text is treated as untrusted. Mermaid runs in a disposable sandboxed frame with no VS Code API and no network, and its SVG — like every svg fence — passes an element/attribute allowlist (no scripts, handlers, links, foreignObject, images, animation or external references). The Mermaid renderer is a separate file that is requested only when a Mermaid diagram is near the viewport; a chat without diagrams never loads it. Raw <svg> HTML in a reply is not a diagram.
A diagram that takes too long: at the two-second deadline Gira stops waiting, discards the renderer frame and shows that diagram as source ("Drawing this diagram took too long and was stopped"); the same source is not tried again. Removing a frame does not stop a computation already running inside it, and the frames of one view share a process, so the next diagram can start only when that computation ends. Until then (up to about three seconds per attempt) other Mermaid diagrams show "The diagram renderer is unavailable right now" with their source, and they are tried again after about ten seconds. A computation that never ends keeps Mermaid diagrams unavailable until the Gira view is reloaded; the view itself never stalls, and svg fences are drawn without the renderer and are unaffected. The size limits above keep this rare.
SVG colours: an svg fence can use currentColor and the variables --gira-diagram-bg, --gira-diagram-surface, --gira-diagram-text, --gira-diagram-line and --gira-diagram-accent, which follow the VS Code theme (including high contrast); Mermaid diagrams use the same five colours and are redrawn when the theme changes.
Prompt cost: the system prompt of every request tells the model, once, that replies can show these diagrams and how to title one (about 550 characters, constant, so it does not disturb prompt caching).
Goals and todos
For non-trivial work (three or more steps, work that spans turns, or a check to run later) the agent keeps a goal together with its todo list: a goal always has at least one todo (a single step for small work), and todos exist only under a goal. It calls goal set with the objective, a drafted done when (one measurable end state and how to prove it), optional constraints and context, and the todos in order, then works through them and keeps them current with the todo tool. It does not set a goal for a question or a one-file change. Both tools belong to the main agent only.
goal: set (needs the todos, except when formalising a goal you set with /goal or /build, where omitting them keeps your list), revise (done when, constraints, context; for a goal you set, the agent asks first unless a field is empty), log (a short progress note), complete (needs evidence from a check it ran in this session; refused while a todo is still open or nothing has been checked since the last goal change), block (with a reason, when you are needed) and view. set is refused while a goal exists, and only view works in /review.
todo: needs a goal (every op, including view, is refused without one). update an item by id (T1, T2, …) to done, dropped or blocked (with a note), add steps it discovers, set replaces the list, view. At least 1 and at most 30 items; one item is in progress at a time and the next pending item starts automatically.
Verification freshness is separate from goal status and todo progress. A successful observed command result can carry a host-issued verification:<id>; cite it in goal evidence only when that command checked the goal's done-when. The host reports fresh when no later file mutation was observed, stale when one was observed, or unverified when no current host-recorded successful check is linked. The achieved-goal readout keeps this status separate from goal state and todo done/total: a goal can be achieved while verification is stale or unverified. Checked Markdown boxes and model claims do not create host evidence.
Completion review (gira.goals.completionReview, off by default, read from User settings only; Workspace and Folder values are ignored): before the agent's goal complete is accepted, Gira runs the usual completion checks and then a fresh, read-only copy of the default agent (same model, endpoint and reasoning, a new context, read/list/search and language queries only) that checks the done-when. It receives a host-built packet: the objective, done-when, constraints, todos, the agent's evidence (and, on the re-review, its resolution and the earlier findings), the cited and recent host-recorded checks with their freshness, the files changed since the goal was set with their session diffs, and the newest command output. Findings must cite a file the reviewer read or a diff, a verification:<id>, a todo or a goal field; unsupported findings are dropped. Evidence-backed blockers refuse the completion once and send the agent back to fix or rebut them; its next goal complete gets one final re-review, after which the goal completes either way, marked disputed with the unresolved findings if blockers remain. A reviewer failure, timeout or malformed verdict completes the goal with a Review unavailable warning (fail-open). Stop cancels the review and leaves the goal active; a new message or a goal edit interrupts it. Completion is refused while the agent's subagents are still running. Budgets: 180 s per review, up to 12 requests per review (plus a compaction summary if the reviewer's context fills), at most two reviews per message. A pass is a second opinion from the same model, not proof.
The goal document: in a trusted workspace with a folder open, Gira writes the goal to .gira/goals/<yyyymmdd-hhmm>-<slug>.md in the first folder and re-renders the whole file after every change. It has a header (# Goal: …, a Status: line with the status, who set it, the time and the session, and the document path) and the sections ## Done when, ## Constraints, ## Context, ## Todos (done/total) (with [x], [>], [ ], [-] dropped and [!] blocked markers), ## Progress log, plus ## Evidence when achieved or ## Blocked when blocked. The file is Gira's rendering of the session's state, not an input: edits you make to it are overwritten, so change the goal through the goal editor page or /goal. In an untrusted workspace or with no folder open, goals and todos still work but no document is written (the goal pill says no document (untrusted)).
The Todos section always has at least one item and renders each contiguous group as a bold label above its items.
Reminders: notes starting with [Goal] come from Gira, not from you. After every 8 file-changing calls (edits, file creation, plan and decision writes, commands; gira.goals.reminderEvery: 0, 4, 8 or 12; at most twice per turn; a goal or todo call resets the count) the agent gets a one-line pointer: the objective, the document path, the todo count and the current item, with a request to update the list. After compaction or a handoff it is told once to read the goal document before continuing; compaction and handoff documents keep the document path and todo ids. Stop nudge (gira.goals.stopReminder): once per turn, when the agent ends a turn with an active goal, it is asked to continue, update the list, complete the goal with evidence or block it; this is skipped when its last line is a question, it used ask this turn, the goal is paused or blocked, or in /review.
Auto-continuation (gira.goals.autoContinue: 0 = off, the default, or 5, 10, 20): after a turn ends with an active goal, Gira starts up to that many automatic turns toward it without a new message, each shown as a Goal · continuing (N of M) row. It stops when the goal is achieved, blocked, paused or cleared, after a turn without tool calls, or when the budget is used up; each message you send resets the budget, background-job wake-ups take precedence, and the row's ✕ (or Don't continue on the goal pill) cancels a pending continuation.
Orchestrate continuation. With the Orchestrate preset, active goals continue automatically with no fixed automatic-turn count until achieved or blocked. Each automatic turn gets the full step budget. Five consecutive failing tool calls warn; ten pause automatic work.
Blocked when. Orchestrate requires a goal's Blocked when criteria. Check them before each step and when a delegated result arrives; if one holds, call goal block with the matching criterion and evidence instead of working around it. Once the user resolves the blocker, call goal unblock with what changed, or use Resume on the goal pill. The criteria cover user-only decisions, missing access or credentials, unavailable external dependencies, and checks still failing after two different fixes.
Commands:/goal shows the goal; /goal <objective> sets your own goal (replacing an existing one) with the objective as its single todo T1, and immediately asks the agent to formalise it with a done when and its own todo list and start on T1; /goal pause, /goal resume and /goal clear control it, and /goal clear removes the goal together with its todos. /todo shows the goal's todo list and takes no arguments. /build <plan> with no goal creates a draft goal Implement <plan> whose todos are the plan's checklist and numbered items in source order (nothing is created when the plan has none); each item takes the nearest nonempty H2–H6 heading outside fenced code as its optional group (H1 titles are ignored), and the agent is asked to formalise the goal and keep the seeded list. A checked Markdown checkbox is still an open todo, not verification evidence. /clear, /new and /delete mark the goal cleared in its document. Delegated agents receive the parent goal and document path with their task.
Transcript rows: setting, achieving or blocking the goal shows one row each, Goal set · "objective" · 3 todos, Goal achieved · "objective" or Goal blocked · reason, and expands to the call's arguments and result (for an achieved goal, the evidence and verification) with Open document at the bottom right. Document buttons on transcript rows (goal rows, handoff and transcript-export notes) sit inside the expanded card, so every collapsed row ends with its chevron; only stop/cancel controls stay on the line. These rows never fold into a Steps group: work before and after them forms separate groups. Todo rows read Todo 2/3 · T2 "Fix add() to return a + b" with a status chip: green Complete, In progress, Blocked, Dropped, Added or Set.
With completion review on, the goal complete row carries a chip: Reviewing (round 1 of 2) while it runs, Blockers on a refusal (Goal complete · 2 blockers · round 1 of 2), then Reviewed, Disputed or Review unavailable on Goal achieved; expanding it lists the findings (B1…, C1…) with their references and a hint. A stopped goal call reads Goal complete · stopped. The reviewer has no rows of its own and is not listed among the agents.
Goal pill and page: while a goal exists, a pill sits at the top of the view, directly under the title bar (it fades down into place when a goal is set and fades back out when it is cleared) (the dock keeps only the working line and the active-subagents pill); expanding it pushes the conversation down, and it stays visible while an approval or question card replaces the composer. Collapsed it shows the goal status, done/total and the current step (◎ 2/3 · T3 Run the math tests; · paused or · blocked when so, ✓ 3/3 · Achieved with the verification chip once achieved); the current step is the todo in progress, else the first pending or blocked one, shown without changing its status, and the objective is in the tooltip. Click to expand (it slides open like a tool card, with the same chevron): the objective (Markdown, clamped to three lines), the todo list grouped under its group headings with coloured status icons, the done when, and right-aligned Open document, Edit, Pause/Resume (plus Don't continue while a continuation is pending) and Clear (removes the goal and its todos, like /goal clear). Edit opens a full-height page (Back, Escape or Cancel leaves it without saving) with the objective, done when and constraints and a todo editor (text, optional group up to 60 characters, status, add, remove, move up/down); a goal keeps at least one todo, so the last one cannot be removed and an empty list cannot be saved. Save updates the goal and document and tells the agent what you changed before its next request. Group labels follow items through status changes and reordering. The editor is scoped to its session and closes when you switch sessions. Editing your last message restores the goal and todos to the start of that turn. gira.goals.enabled: false removes the tools, their prompt rules, the pill, /goal and /todo, reminders and continuation.
With completion review on, the pill carries the review chip after the verification chip (◎ 3/3 · Reviewing completion [Round 1 of 2], [2 blockers], ✓ 3/3 · Achieved [Check current] [Reviewed], [Disputed], [Review unavailable]), and expanding it shows the findings section.
Finished goal documents are removed by autoclean after gira.cleanup.goalsDays (default 90; see Autoclean); active and paused goals are kept.
Goal, agent, request and related settings (per window unless noted; every one is editable in Gira settings):
Setting
Default
Meaning
gira.goals.enabled
true
Goal and todo tools, pill, /goal/todo, reminders and continuation
gira.goals.reminderEvery
8
Pointer reminder after this many file-changing calls (0, 4, 8, 12; 0 = none)
gira.goals.stopReminder
true
Nudge once per turn when a turn ends with an active goal
gira.goals.autoContinue
0
Automatic turns toward an active goal per message (0, 5, 10, 20; 0 = off)
gira.goals.completionReview
false
Read-only reviewer checks the done-when before a goal completes (User settings only)
gira.cleanup.goalsDays
90
Delete finished goal documents older than this many days (0–3650; 0 = keep forever)
gira.tools.ask
true
The ask tool; off, questions are asked in plain text
gira.tools.backgroundJobs
true
run_command's background option and the jobs tool
gira.context.mentions
true
The @ file mention popup in the composer
gira.agent.loopGuard
true
Warn and then stop an agent that repeats the same tool call
gira.commands.disabledSlash
[]
Slash commands hidden from / and rejected (not help or new)
gira.git.ignoreArtifacts
["handoffs", "goals", "transcripts"]
Generated folders listed in the managed block of .gira/.gitignore (handoffs, goals, plans, decisions, transcripts; [] = off)
gira.log.bodies
false
Log redacted request bodies and raw stream chunks to the Gira Output channel, capped at 2 000 characters each; requires the Gira log level to be Trace (machine-scoped, User settings only)
gira.transcripts.autoSave
"off"
"off" = manual export only; "turn" = rewrite the session's transcript after each turn
gira.transcripts.toolOutput
"summary"
Tool detail for export and Copy transcript: "none", "summary" (first 20 output lines), "full" (arguments and output)
gira.transcripts.includeReasoning
false
Include reasoning in export and Copy transcript as collapsible sections
gira.cleanup.transcriptsDays
0
Delete dated transcripts older than this many days (0–3650); 0 = keep forever, and the current session's file is always kept
gira.sessions.maxRunning
3
Turns that may run at once across all sessions (1–8); a send at the cap shows an error card
gira.git.showBranch
true
The branch chip in the composer
gira.subagents.enabled
false
Offer the agent tool and delegation guidance; existing agent rows always render
Running subagents per session (1–16, per window); up to twice this many tasks may be outstanding, the rest queue. Editable in Gira settings → Agent & subagents
gira.request.maxRetries
4
Automatic retries of a failed request (0–8), so up to five attempts by default (User settings only, machine-scoped)
gira.request.maxAutoContinues
5
Recovered failures one agent run may use before the next failure ends it (0–20)
gira.request.timeoutSeconds
1800
Overall deadline of one request, retries included (30–3600)
gira.request.connectTimeoutSeconds
30
Time allowed to receive response headers (5–300)
gira.request.idleTimeoutSeconds
300
Silence allowed between data frames of a stream; heartbeat comments do not count (5–600)
gira.request.maxRetryWaitSeconds
120
Total time one request may spend waiting between attempts (0–600)
gira.log.capture
"errors"
What each model API attempt keeps in the session log: "metadata", "errors" (error evidence only) or "bodies" (sanitized request and response text) (User settings only)
gira.log.retentionDays
7
Days session API logs are kept (1–30; User settings only)
Sending while Gira works
You can send a message while a reply streams, while tools run and while subagents work: Send and Stop are both available. A message sent during a turn is acknowledged at once and shown as Queued; it is applied after the current step finishes, never by interrupting the stream, and several queued messages are answered together, in order, by the next run. At most 16 messages can wait; a 17th is refused with a visible reason. A refused message keeps its text and attachment chips and shows the reason beside the composer. Attachments are read once, when the message is accepted.
Stop cancels messages that were accepted but not yet answered (they show Not sent); the message already being answered completes as cancelled. Stop stays visible while subagents run, even when the parent is idle; its tooltip covers the turn and the subagents, not background jobs. Edit and re-send works on the delivered message it belongs to, even with queued messages around it.
Model, permission and mode changes are refused while the parent, a control command, any subagent or a pending message exists (Stop the agents first. / Cancel the turn before changing …); sending is never blocked. Compact and handoff stay available when the parent is idle. A subagent's approval appears above the composer without taking focus, while the main agent's own approvals and questions still replace it. Approvals and questions outlive the end of a turn, are replayed when you reopen their session, and are withdrawn by Stop, /clear or loss of Trust.
Background subagents
With Subagents turned on (Gira settings → Agent & subagents; off by default) the agent tool dispatches its tasks and returns a receipt for each at once. The main agent keeps working, and each child's result is delivered to it as soon as it arrives, at its next step boundary; there is no blocking mode and no polling tool. In a trusted workspace a result that arrives while the parent is idle wakes it; in Restricted Mode nothing starts on its own, so such results stay pending and are delivered with your next message. Automatic continuations after your last message share one extra step allowance (gira.agent.maxSteps); after that the session shows Results ready — send a message to continue and the results wait for your next message.
The Agents view (the top-bar Agents button, or an agent's name or the active-subagents pill) replaces the conversation between the top bar and the dock instead of covering the sidebar, so the composer, any approval or question card (including a subagent's, with its Review approval button on the agent's row) and Stop stay visible and usable while you inspect children. Rows are 36 px. Back returns to the conversation (your place in it is not kept: it reopens at the latest message); Escape goes back inside an agent's detail and otherwise closes the view. Opening a popover from the dock (permissions, model, attach, context) or the sessions switcher closes the view.
Batch tasks that share background into one agent call: one batch is one transcript row, and children still report independently. Put shared background once in the optional root-level context string (unchanged 8,192 UTF-8 bytes, or 8 KiB); keep task-specific targets, constraints and acceptance criteria in each prompt. Context and file selections are captured before asynchronous preparation, including for queued children. They are background task data, not system instructions. Oversized context is rejected before dispatch; omission or an empty string preserves the ordinary task prompt.
Optional batch-level files: [{ path, start?, end? }] automatically supplies every selection to every child in its first request:
{
"intent": "Review shared contract",
"context": "Review only; do not edit or run commands.",
"files": [{ "path": "README.md", "start": 1, "end": 40 }],
"tasks": [
{ "readOnly": true, "prompt": "Task title: SetupReader1\n# Target\nReview the attached setup instructions.\n# Change\nFind missing prerequisites; do not edit or run checks.\n# Acceptance\nReport concrete gaps with line references." },
{ "readOnly": true, "prompt": "Task title: SafetyReader2\n# Target\nReview the attached setup instructions.\n# Change\nFind unsafe endpoint guidance; do not edit or run checks.\n# Acceptance\nReport concrete risks with line references." }
]
}
Select at most six entries. Each full source must be at most 256 KiB, even for a narrow range; the complete rendered bundle, including headers and separators, must fit 64 KiB UTF-8. Invalid, unavailable, binary or oversized selections reject the whole dispatch before any child starts. The aggregate fails rather than truncating or omitting views. Duplicate selections preserve their order and each counts toward the aggregate.
start and end are independently optional positive, inclusive line numbers. Start defaults to 1; end defaults to start + 1999 (2,000 lines). With gira.tools.outputBudget on and an explicit end, that end is used without the legacy 2,000-line cap; otherwise end is capped at start + 1999. EOF clamping, empty files and reversed ranges follow read_file source-view semantics. Attachments are delivered fully within their own byte cap, without preview truncation.
Relative paths resolve against the dispatching session's open workspace (including multi-root aliases), not the task's cwd. Open-workspace absolute paths also work. In a trusted workspace, absolute paths inside registered, non-main, non-bare Git worktrees of open repositories are allowed; arbitrary external paths and symlink/junction escapes are rejected. Restricted Mode permits explicit open-workspace file data, but does not discover external worktrees or grant edits, commands or automatic wakes. Attaching a file never broadens a child's tool permissions or working-directory scope.
Each distinct source is read once per dispatch; running and queued siblings receive the same frozen views even if a file later changes or disappears. A later dispatch reads again. Supplied numbered lines need no extra read_file; their snapshot tag can support an otherwise-authorized edit while current. A stale tag requires a fresh read, and reloading neither re-reads these files nor restores edit authority.
Endpoint disclosure: secret-looking names, including .env and key files, are allowed. Their selected contents go to every selected child's endpoint; attach only data you are authorized to share. Recorded assignments, dispatch/child details, saved records and transcript copy/export keep paths/ranges, not the automatically injected bodies. Attached children use metadata-only API logging, but their ordinary model-authored final reports may quote file contents and are retained intact. This is not secret detection or arbitrary-output data-loss prevention.
Children receive available instruction layers and the skills index, plus the selected agent's configured definition, subject to settings, Trust and prompt budget. A pinned preset's instructions and skills apply to those children, and it supplies a matching selected agent definition; this content stays scoped to that session and its children. They also receive the active parent-goal line, but do not inherit parent history. There are no automatic reusable briefs, contextFrom or cross-preset includes. File views and context remain background, not binding higher-priority instructions.
Parent delivery carries a Gira-generated single-line summary of at most 240 Unicode code points alongside the complete final report or structured result, without repeating the assignment, goal or shared context. The summary is presentation, not independent proof of success. Automatic result delivery and wake timing are unchanged; there is no new coalescing delay. Illustrative prompt-byte savings are estimates, not measured endpoint cost savings. Caching is optional: inspect reported cachedTokens when available; missing counts mean unknown, not zero, and no provider-wide caching guarantee is implied.
Named child rows stay above the composer while agents are active: three are visible normally, or two when the dock is at most 280 px wide or the app is at most 520 px high. Show more reveals the remaining active/attention rows; Finished starts collapsed. Attention determines which rows fit, but visible rows retain admission order. Keyboard focus freezes row membership and order through completion, and a finished row's Stop control becomes inert until focus leaves. The work region is bounded to the smaller of 240 px and 35% of viewport height, with its own scrolling. Titles are taken from an explicit Task title:, a substantive # Change paragraph or a safe task line, with a role/index fallback; they are not generated by another model request.
Click a child's name for its live detail, or its compact action for that exact call's arguments, status and output in one step. Read/List/Search labels describe the actual tool; commands use a generic Run label and optional same-call Intent: instead of exposing shell syntax in compact text, tooltips or accessibility labels. Intent describes the requested purpose, not proof that a process started or succeeded. Commands become Running only after actual process spawn; queued, approval-pending and serial-waiting calls remain Preparing.
Each completion arrives as its own tool-style row, Subagent · AgentTitle · Complete, with the outcome on a chip: green once a successful result is delivered, red for Failed, Step limit, Loop stopped or Interrupted, neutral for Cancelled and amber Held (hover for the reason) while delivery waits for your next message. Expanding it shows the child's final statement and its stats: current context, compactions, tool uses, model iterations, requests and input/output tokens, plus Open transcript. Results are not condensed into a separate summary; with tool grouping on, a result joins the main run it lands in and counts as one step of that Steps block (failed and interrupted results count as failures, cancelled as cancelled), and failed or held results stay visible when the block is collapsed. A completed result held through reload is still Complete, not Interrupted. Same-title children keep separate identities. Visiting a failed child's valid detail clears only its session-local unread-attention marker, not its failure or held delivery. The parent turn's stats include a child's usage only while the dispatching turn is still running. A child that fails does not fail its siblings or the parent.
Live activity is projected independently for the main agent and each child. The parent can show Waiting on children while child activity continues; waiting is live work paused for a result, while a held result is already finished but not yet delivered. A completed child can therefore remain held without being mistaken for running work.
Running subagents (gira.subagents.maxConcurrent, 1–16, default 4, per window) is editable in Gira settings → Agent & subagents. The editor shows your User value, and Configured for this window shows the effective value and where it comes from (a Workspace value still wins). A task or call beyond the limit queues, up to twice the limit outstanding (running plus queued); a call that would exceed that is rejected as a whole. Lowering the limit never cancels accepted children; it applies to the next dispatch, and raising it starts queued children. A session with running children occupies one gira.sessions.maxRunning slot together with its parent.
Stop and an agent page's Stop cancel the children and publish one cancelled report per child; Stop holds those reports and does not wake the parent. /clear cancels the session's subagents and drops their pending results with the conversation. Reloading the window resumes nothing: queued or running children become cancelled with one held Interrupted before this session was restored report, and held results and queued messages (with their already-read attachment text) are delivered once, before your next message, in the saved order. Session files may carry optional inbox and children entries; files saved by 1.0.x load unchanged and are never rewritten by merely opening them.
Child vitals. The Agents roster and the Agents editor tab show a child's stage, elapsed time, request count, tokens and context when available; values the host cannot determine are Unknown, not zero. A completed result waiting for delivery is marked Held, not Running.
Agents editor tab and Message. Open the current session's editor-tab panel with Gira: Open Agents in the Command Palette. It is pinned to that session and shows Stop, Review approval or Review question, Open file, exact tool calls, and Message. You can send Message from either the sidebar Agents view or the editor tab. A message waits for the child's next step boundary and never interrupts its current provider request; if restore interrupts the child first, its queued message is reported as not delivered.
Revive. A stopped, timed-out or restore-interrupted child shows Revive in both Agents views (the sidebar roster and detail, and the Gira: Open Agents editor tab). Revive starts a new run of the same child, with the same agent, task and assignment, under the parent's current preset snapshot, policy and admission limits (it counts toward the outstanding-task limit and needs a trusted folder). The child sees its earlier transcript as history only: completed tool calls are never replayed and prepared file attachments are not supplied again, and no edit authority carries over, so it must re-read a file before editing it. Revive is refused for a child created under a different preset revision, and when the session, Trust or preset can no longer admit it; a refusal shows its reason. Once a new run exists, Stop, Message and Revive actions addressed to the old run are refused. Cancelling the session, Stop or losing Trust cancels a revive that has not started.
Compaction and handoff keep the newly selected input verbatim, compact only the older prefix and add one [Outstanding subagents] snapshot that is data, not an instruction. It carries stable IDs, safe titles, status and optional model/cwd, not full assignments, context or file bodies; handoff documents gain an Unfinished work (background subagents) section. Input that cannot fit the model's context fails with an explicit error and is never truncated.
Automatic recovery
A request that fails for a transient reason (a dropped connection, stream ended early, a malformed response, a missing finish reason, a timeout, HTTP 5xx, or a rate limit) is retried automatically with the same input; nothing is lost and no tool is replayed. gira.request.maxRetries (default 4) allows up to five attempts, and gira.request.maxAutoContinues (default 5, 0–20) limits recovered failures across one agent run, except the pre-output HTTP 429 retries described below. A server's Retry-After is honoured when it fits the retry-wait budget (gira.request.maxRetryWaitSeconds, default 120 s); a longer delay ends the request without sending early. After a rate limit, new requests to that endpoint wait out the cooldown, one probe goes first, and the backlog is paced. Time limits are separate: headers within 30 s (connectTimeoutSeconds), no more than 300 s of silence between data frames (idleTimeoutSeconds; heartbeats do not reset it) and 1,800 s (30 minutes) overall (timeoutSeconds). The longer defaults keep a long tool call or buffered reasoning from being cut off on gateways that send nothing until they finish, and a value you set yourself is kept. A model that was auto-configured can carry its own stream idle allowance (at most 600 s); a Stream idle timeout you set in User settings always wins. All of these settings are edited in Gira settings → Requests & recovery and read only from your User settings. When a 429's own headers report a window with nothing left (x-ratelimit-remaining-<window>: 0) whose reset is later than both Retry-After and the remaining retry-wait budget (for example a daily credit allowance), Gira sends no further attempts: the card names the window and the local time it resets. Shorter windows, such as tokens or requests per minute, are still waited out using Retry-After.
Pre-output HTTP 429 responses are request-local retries, not automatic continuations. They can retry even when the run's automatic-continuation allowance is exhausted, but never bypass maxRetries, cumulative retry wait, the original deadline, cancellation or the endpoint cooldown. An explicit daily-credit-exhaustion message stops retrying even without quota headers; the card reports the reset time when supplied. An ambiguous rate-limit message is not treated as a daily quota.
What you see: the failed attempt's partial text stays as a draft and then becomes a collapsed Interrupted note with the exact request id; it is never copied or exported. Waits show a retry or endpoint countdown, announced politely to screen readers. A tool's own error goes back to the model as a result and is not a provider retry. An HTTP 200 reply that carries an error envelope keeps its real status: transient rate-limit and server errors recover, while authentication, quota, invalid-request and unknown errors stop at once. A real provider 413 keeps its HTTP status on the error card.
When recovery gives up, the error card offers Resume from checkpoint. It re-sends the exact failed request (not the last message), with a fresh recovery budget, and does not replay completed tools or dispatches. It is offered only while that checkpoint is live: reloading, sending a new message, editing, /clear, changing the model, permissions, mode or provider settings, Stop, or a change to instructions, tools or settings withdraws it.
Session logs
⋯ → Session logs… opens a full-sidebar page listing every API call the session made: main-agent, subagent, compaction and handoff requests, each with its status, safe response headers, finish reason, timing and error evidence. Probes (such as Test connection) and the Git bridge are not recorded. Error and discard notes show View API call when the exact request is known. Filters cover All / Main / Subagents, outcome and request-id search; rows carry no request or response text, a detail is at most 256 KiB, the page holds at most 300 entries (50 per page) and one expanded detail, and live updates arrive at most four times a second. Escape closes the page and focus returns to ⋯. Everything is shown as plain text.
Besides Retry-After and the OpenAI-style rate-limit headers, any x-ratelimit-<limit|remaining|reset>-<window> header (for example x-ratelimit-remaining-credits-day) and similar numeric x-ratelimit-* headers are shown with their value; other unrecognized headers are listed by name only. An unlock_url in an error body (a gateway's key-unlock link) is replaced by *** in Session logs, exports and trace output.
Completion-review requests (gira.goals.completionReview) appear under Subagents as agent goal-review.
gira.log.capture chooses what is kept per attempt: metadata (timing, status, ids, counts), errors (the default: also the sanitized error body or stream tail of failed attempts) or bodies (sanitized request and response text as well). A change applies from the next attempt. Logs are stored on this machine only, under <VS Code global storage>/sessions/<workspace key>/api-logs/<session id>/ as a manifest and JSONL segments of 2 MiB, never sent anywhere and never given to the model or any tool; Gira sends no telemetry. Limits: 1 000 attempts and 16 MiB per session, 128 MiB across all workspaces, and a 4 MiB write queue. Logs older than gira.log.retentionDays (default 7) are removed on activation, every 24 hours, when a session opens and as logs grow; shortening the retention applies at the next prune. Deleting a session, Delete all and the newest-50 limit remove its logs; /clear keeps them with a reset marker; a conversation saved by 1.0.x gets no log until it makes a request. Logging never affects a request: a full or slow disk drops records, and the page shows loss counters.
Children dispatched with shared file views always use effective metadata capture, regardless of body/Trace or Diagnostics settings, through retries, compaction and step-limit summaries. Their details show the sanitized paths/ranges and Bodies omitted for attached-file child task. Request, response, error and stream-tail bodies and diagnostic frames are not retained; safe structural counts, headers, usage (including reported cachedTokens), timing and status remain. The parent and children without files retain their ordinary capture policy. This logging policy does not censor model-authored final reports.
The host-provided storage root is canonicalized, including macOS path aliases, before Gira appends its private namespaces; symlinks or junctions within those private namespaces remain rejected.
Clear logs asks in a native dialog that names the session, then removes its logs while the conversation carries on; afterwards the page notes Calls already in progress at Clear are omitted.Copy all copies every retained call (filters are ignored) and Copy this call one call, as compact JSON up to 2 MiB; larger logs say Too large to copy. Use Export.Export first asks Metadata only or Include content, then opens the native Save dialog (which starts outside your workspace folders), and writes one gira-api-log-v1 JSON file atomically. It needs no folder and works in Restricted Mode; metadata-only exports contain no request, response, error or stream text. Gira redacts the bundle again with the credentials it knows, but errors and responses can echo parts of your prompts or code, so read an export before sharing it.
Diagnostics is an explicit opt-in for one session at a time, behind a native content warning: it keeps sanitized raw stream frames in memory only, for requests that start after it is switched on (1 MiB per request, 8 MiB in total, 10 minutes). It ends on Stop capture, the time or size limit, Clear, deleting the session, loss of Trust or a workspace root change. Frames are never written to the log, the clipboard or the page; they enter an export only after a second native confirmation.
Session presets
A preset is a named way of working that applies to one session: it sets some of Gira's settings for that session only, and the session keeps it across reloads. None is the default: with no preset chosen Gira's behaviour is unchanged, and no preset chip or effective-configuration card appears. Presets do not change your permission mode, approval policy, model, endpoint, Trust, logging or commit guard, and never relax approval requirements; any tools or agents they add are declared by the preset and shown in the chooser, whose approval summary always says inherits your approvals.
Choose one from ⋯ → Preset: None…, from the muted Workflow preset: None · Choose… line of an empty session (it never blocks typing and goes with your first message), or with Gira: Choose Session Preset in the Command Palette. The chooser is a non-modal dialog: None and each preset form a radio group (↑/↓ move, Tab reaches the button, Escape closes); the selected one shows its description and revision, the settings it changes beside your own value (Subagents: on — your setting: off), what it adds, an Automatic requests line (extra requests it makes on its own), journal and trust notes, and the approval summary. Use for this session switches it; a session can only switch while it is idle, and a refusal lists each blocker verbatim. A pinned preset keeps the revision you chose: when a newer one exists the chooser says Pinned revision; newer available — re-select to apply. A preset that cannot be read after an update shows as Suspended and blocks new turns until you choose None or another preset.
While a preset is active a chip with its name sits under the title (its accessible label also gives the mode and the approval summary), Session info gains a Preset row, and the sidebar renders the session's values: the context popover shows the strategy and threshold the preset owns read-only, with Controlled by for this session and no Reset. Gira settings keeps editing your settings; it adds This session's effective configuration, listing what the preset owns with the source of each value, and the rows it owns say Controlled by for this session. The built-in catalog includes Discuss, Watch and Orchestrate.
Discuss
Discuss imposes a per-session ceiling on source edits and commands and starts in Discussion mode. Source edits and commands are refused by the host in every permission mode, including Full auto; /build, /plan and bare /discuss cannot change the mode while the preset is active. The refusal note points to Change preset on the active chip under the session title; choose None or another workflow there to leave Discuss. /review may narrow the session further. The existing /discuss mode in None sessions is unchanged.
Discuss still allows scoped plan and decision writes when you ask for them, subject to the same approval behavior as other sessions. It enables structural and semantic code navigation, ask, main-agent-only report_progress, and delegation only to the bundled read-only scout and verifier. For every substantive explanation or architecture diagram, the verifier independently challenges the supplied claims; small factual lookups need not launch one. The host restricts the verifier to read-only tools regardless of its frontmatter and requires bounded structured findings. A verifier failure or missing result is disclosed as unavailable, never as a pass. These checks roughly double provider requests for substantive explanations and diagrams; the chooser states this automatic cost.
Each verifier arrival card shows Checked, Disputed or Unavailable, the verifier run, and expandable findings with openable path:line evidence. When exactly one verifier result is delivered in a turn, the same receipt is also attached to its final answer: “Covers the draft reviewed at This is a review-time receipt, not a hash-bound guarantee: later edits are outside its scope. If a turn receives multiple verifier results, each stays on its arrival card and none is combined into a final-answer receipt.
Watch
Watch is a Build preset for work you want to follow closely. It inherits the session's edit and command approvals: it never forces Ask or loosens an approval requirement. It disables subagents, including the completion reviewer; if your User gira.goals.completionReview setting enables completion review, that setting is unchanged, and the chooser says Unavailable in Watch: no subagents. Watch also turns off automatic continuation and job-exit wake-ups.
Before each edit_file, create_file, write_plan, write_decisions or run_command call, Watch requires a rationale of 8–600 characters. A missing or out-of-range rationale is refused before approval. The rationale is shown with the call.
Work log. Watch records a local Markdown work log in the first workspace folder at .gira/transcripts/<yyyymmdd-hhmm>-watch-<slug>[-n].md; parts roll over at 2 MiB and link together. .gira/transcripts is git-ignored by default, and gira.cleanup.transcriptsDays controls retention. Configured credentials and endpoint header values are redacted, as are credentials and query values from configured endpoint URLs. The log requires a trusted folder. On restore, operations without a recorded outcome are marked interrupted — outcome not established. If a log write fails, the next effectful operation is blocked; an operation already approved completes and the gap is recorded. The work log is a local reference, not a tamper-proof audit, and Gira does not automatically include its contents in model requests.
Live Work. Selecting Watch opens the session's editor tab once without taking focus. It shows prepared edit diffs before approval. Command output has a live tail capped at the last 64 KiB, with truncation and exit status shown; the panel also carries progress notes and pending reviews. Stop, Open diff and Review approval act on that session. Review approval focuses the matching sidebar card; it does not approve or answer the request. Closing the tab never stops work.
The current-action strip above the composer shows the active path or command, its reason, state and a short preview, with Open Live Work. Session info includes a link to the work log. In the Command Palette, Gira: Open Live Work opens or reveals the current session's panel.
Orchestrate
Orchestrate is a Build preset for substantial work managed through delegated roles. Scout and Reviewer are read-only; Implementer can read, create and edit files but cannot run commands. The host enforces each role's tool allowlist regardless of its frontmatter. The main agent owns the goal and todos, records progress updates and structured decisions with report_progress, and delegates work to the named agents.
Orchestrate enables until-blocked goal continuation and child messaging. When it sets a goal, Blocked when is required; the agent checks those criteria before each step and when a child result arrives. If a criterion holds, it must stop and call goal block with that criterion and evidence rather than work around it. After you resolve the blocker, it can call goal unblock with the resolution; the goal pill also offers Resume. message_agent queues a message for a child without interrupting its current request; wait_agent waits for a child event with a 120-second default and a 5–600-second timeout. revive_agent({ agentId, runId, text? }) revives an eligible stopped, timed-out or interrupted child as a new run under the current preset, policy and admission limits, with the same rules as Revive in the Agents views (see Background subagents); optional text (up to 4,000 characters) reaches the child labelled as main-agent data. Only the main agent has these tools, and revive_agent is refused when the child's run id is no longer current.
The chooser says goal turns continue automatically until the goal is achieved or blocked and pause after 10 consecutive failing tool calls. Delegated agents make additional model requests and use tokens. It also says Turns subagents on for this session and that the approval summary describes the inherited policy; Orchestrate does not loosen your approvals.
Presets that enable progress notes provide the main agent with report_progress. It adds a short progress update (up to 300 characters) or a structured decision (choice and reason, with optional alternatives and path:line evidence) as an expandable transcript card while the turn continues. Both note types are included in transcript exports. The tool is available only in a session whose pinned preset enables it; None sessions and subagents do not receive it.
Sidebar
The Gira view has a top bar (the session title, which opens the sessions switcher, with a status dot that reveals Session info on hover or keyboard focus, the Agents badge and the ⋯ session menu), a compact active/attention agent roster, the conversation, and a dock at the bottom. The badge on the title counts other sessions with outstanding work or held results. Its tooltip distinguishes running sessions from sessions with held results; approval, questions and held results turn the badge amber. Held results alone are not running work and offer no Stop action. Tool calls form collapsed Steps history, with each exact call available for inspection; an agent's name opens its own detail. The status line shows Compacting context while compaction runs. Banners above the conversation report missing endpoints, untrusted workspaces and errors, with their action buttons.
While the Agents view is open it takes the place of the conversation between the top bar and the dock; nothing is dimmed or made inert, so a subagent's approval or question card is in the dock below it. Review approval (or Answer) on an agent's row focuses that card and leaves the view open; Tab moves between the view and the dock. A subagent's request never opens, closes or takes focus by itself.
System cards: every system message and every error in the conversation is a tool-style card with a name, a summary and, where there is more to say, an expandable body: Context · … readouts, Cancelled, Step limit · stopped at the step limit, Loop guard · warned · <tool> ×<count> (grey) and Loop guard · stopped · <tool> ×<count> (red), Mode · Plan|Build|Discussion, Cleanup · removed … · kept N (per-kind counts and retention in the body), Commands · N available for /help (the enabled commands in the body), Goal and Todos readouts, Edited · re-sent; files not reverted, Autohandoff · unavailable · compacting instead (the reason in the body), Transcript saved · <path> · <size>, and classified Error · <label> cards (see Errors and the Gira log below). When Show interaction stats is on and no turn is running, the Cancelled, Step limit and loop-guard stop cards and errors carry a stats chip (8 requests · 46 s; hover for the full stats). Consecutive identical readouts update one card instead of stacking. Text notes saved by earlier versions show as Note cards; older errors without classification keep Error · <first line>.
The composer is one bordered pill with the text box on top. Its controls start with plus (Add file to context), then an icon-only Permissions button and the optional branch chip. The branch chip shows the branch name (or detached @<sha>, and alias:branch in multi-root windows), an amber dot for uncommitted changes, and repository details on hover; it follows the active editor and opens Source Control. It is hidden without a Git repository, with gira.git.showBranch: false, or at 300 px and narrower. On the right are the context percentage, optional Stop, the model alias, and Send. Hover or focus the percentage for the usage bar, exact estimated tokens and automation threshold; Escape dismisses the details. The model opens the model popover (see Set up), and Stop remains available while a turn, command or subagent runs (see Sending while Gira works). Type / for slash-command completion; there is no slash button.
While the main agent itself works, a working status line sits above the active-subagents pill: an animated glyph, a playful present-participle verb with an ellipsis and the muted elapsed time (✻ Pondering… · 42 s; hover for the plain activity). The verb's category follows the kind of work the host reports (thinking → cognition, reading/listing/searching → exploration, writing/editing → creation, commands → science, preparing/compacting → culinary, other tools and resumption → mystical), the word within a category is random and rotates every 12 s (a category change waits until the current word has shown for 5 s), each change crossfading rather than snapping, and whimsical words are mixed in increasingly after the first 30 seconds. No model call is involved. The line is hidden while the session is idle, only waiting on subagents or jobs, waiting for a request slot or retry, or needs your approval or answer. gira.ui.workingStatus chooses the playful verb (default), the plain label (Thinking…) or no line. Gira settings → Appearance → Working-status words has one editor per category: choose Use built-in words (the default; nothing is stored), Custom words (one word per row, 1–24 characters, at most 64, no repeats) or Disable category (an empty list). Reset category removes only that category's list; Reset to default removes all of them. If every category is disabled, Gira uses the built-in words. The words apply only while Working status is Playful verb. Reduced motion or gira.ui.animations: false holds the glyph still and swaps words without the fade.
The ⋯ button opens a dropdown menu with four groups: the turn-mode segment (Build, Plan or Discuss; it is locked while a turn runs and says why); Rename and Background jobs · N running (the jobs expand in place, each with its status, elapsed time and Stop); the pages Instructions…, Git bridge…, Gira settings… and Session logs…; and the actions Export transcript, Copy last answer, Copy transcript, Open log and Clear logs. The menu is non-modal, so the conversation stays interactive while it is open; Escape, a click elsewhere or a session switch closes it, and ↑/↓, Home/End and typing a letter move through it. Session info appears in a card when you hover or focus the status dot beside the title; move into the card or Tab to its controls to keep it open. Leaving both the dot and card closes it, as do Escape, opening another surface and switching sessions. Clicking the dot does not pin it open, and the card does not change the header height. It shows the session ID (with a copy button), the workspace roots (alias → folder), trust, one line for the mode and approvals (for example Build · edits automatic · commands ask), the session's request and token totals, the agents' totals and the edit failures by reason; the model and permissions are shown in the composer. The context percentage in the composer opens the context controls (strategy, threshold, Compact now; see Context strategy), and the goal pill carries Clear. The bottom-right of each turn's closing message shows a stats line — ↑ input · ↓ output · tok/s · duration for the main agent, with delegated-agent requests in its tooltip. Saved sessions, New session and renaming or deleting a session are in the sessions switcher (see Sessions below).
Gira settings (⋯ → Gira settings…, or Gira: Open Settings) is one page with a Search settings field, a Jump to group list and thirteen collapsible groups; a search opens the groups that match, and the page edits every Gira setting. Each row shows its range and where its value comes from. The primary editor shows the User value; Configured for this window shows the effective value and its source (User, Workspace or a session preset), and This session shows a preset or session control that wins for the open session. A setting that allows it also offers an explicit Workspace override, edited and reset apart from the User value; settings read only from User settings say so, and a Workspace value is ignored for them. Reset removes the explicit value at that target and never writes the default; a list is one setting: Save writes it, Reset removes it. Buttons show a spinner while their action runs, controls are disabled while another change is pending, and results appear as notes inside the card. Changes apply from the next turn; a running turn keeps its tools. Two exceptions: the commit guard's enforcement applies immediately, even to a running turn, and saving the command allowlist, the shell, the shell syntax or the edit-approval default cancels running turns and rebuilds the approval broker.
Settings opens in one reusable native VS Code editor tab, not a sidebar overlay. Git bridge, model setup, error actions and the command/menu entry points reveal that same tab at the requested group or endpoint. Close it with the native tab X; the sidebar and session switcher remain available. A section outline appears at wider widths, and scrolling stays inside the Settings content area. Effective configuration follows the active sidebar session. Instructions is an internal destination in the same tab; instruction files still open in native text editors.
Models & endpoints: the Endpoints card, where you connect a model (see Setting up a model).
Requests & recovery: retries, automatic continues and the connect, stream-idle, overall and retry-wait limits (gira.request.*; see Automatic recovery), with range checks and a Workspace value shown as ignored. Stream idle defaults to 300 s and overall to 1,800 s; edits apply to the next request.
Agent & subagents: the Subagents switch, Steps per run and Steps per subagent, Running subagents (see Background subagents), Occupied sessions (gira.sessions.maxRunning) and Loop guard.
Permissions & execution: the permission mode for new sessions, the edit-approval default, Commit guard, the command allowlist, shell and shell syntax, command time and output limits, background-job limits and Wake on job exit (see Permissions and command execution). The permission, allowlist, shell and edit-approval settings are read only from User settings.
Context & instructions: the context strategy, the compaction threshold (any value from 30 to 90 %, fractions allowed, for example 61.5), recent tokens kept (0 allowed), the attachment budget (at least 1,000 characters), the file index size (at least 100 files), @ mentions, the global configuration folder (User only, used as typed: Workspace and Folder values are ignored and ~ is not expanded; saving creates and moves nothing) and Include AGENTS.md (also on the Instructions page, the same User value). Instructions → opens the Instructions page. A session override or an active preset wins over these defaults and is shown on its row.
Tools & search: the Ask tool, Structural search, Syntax check after edits, Language intelligence, Open in editor, Background jobs tool, Tool output budget, Bundled ripgrep and the Search result cap (1–200).
Goals & todos: the Goals and todos switch (gira.goals.enabled), Reminder cadence, Stop nudge, Auto-continuation and Completion review (gira.goals.*).
Slash commands: one tick box per command, grouped (Context, Modes, Session, Goals), writing gira.commands.disabledSlash. A disabled command is hidden from the / list and /help and rejected when typed; /help and /new are always available, disabling /discuss also blocks discussion mode, and /goal/todo are greyed while goals are off.
Transcripts & cleanup:Auto-save (Off / After each turn), Tool output (None / Summary / Full) and Include reasoning, the four retention settings (Keep handoffs, Keep decisions, Keep goal documents and Keep transcripts: any whole number of days from 0 to 3650, where 0 keeps files forever), Git-ignore generated files (gira.git.ignoreArtifacts, including transcripts by default), Export now and Run /cleanup now. See Copy and transcript export and Autoclean.
Appearance:Show interaction stats, Animations (the OS reduced-motion setting always wins), Group tool calls (default on; off gives every tool call its own row), the Branch chip (gira.git.showBranch), Automatic session titles (User settings only), Working status and the Working-status words.
Logs & diagnostics:API log capture (Metadata / Errors / Bodies), Keep API logs (days), Log request bodies (trace level) and Open log. These are read only from User settings; Errors capture can echo parts of your prompt, Bodies stores prompts and code on this machine, and shortening retention deletes older logs.
Git bridge: every gira.gitBridge.* setting; see Git bridge.
Experimental: the opt-ins below.
Experimental opt-ins (Gira settings → Experimental: the last group, collapsed by default; searching for a setting such as "argument rules" opens it). All six are User settings only and off by default; a Workspace or Folder value cannot turn one on.
Setting
Default
Meaning
gira.experiments.measurements
false
Record local, source-free counters only; no telemetry or new edit syntax.
gira.experiments.structuredChildren
false
Allow explicitly schema-constrained child tasks and validated result yields; tasks without a schema retain legacy behavior.
gira.experiments.historyPrune
false
Archive only proven duplicate older file reads while retaining a newer identical read; also requires output-budget capture.
gira.experiments.argumentRulesMode
off (off or observe)
Observe User-owned rules against complete validated arguments. Observation cannot block, modify, retry or approve a tool.
gira.experiments.argumentRules
{ "version": 1, "rules": [] }
Bounded version-1 observation rules; invalid rules are unavailable, never a clean pass.
gira.experiments.advisorMode
off (off or advisory)
Use a low-priority advisory request; its findings never verify or gate goal completion.
Invalid boolean or mode values fall back to the disabled mode. Invalid argument-rule configuration fails closed as unavailable, not as a pass; rules do not run scripts or regular expressions.
Argument observation rules are edited on the page. Add a rule (an id and a tool name), then add conditions: a JSON-pointer path such as /command, an operator (exists, is absent, equals, contains text, starts with, is at least, is at most) and a value. For equals, choose the value type: text "1" and number 1 are different. A rule matches a call to its tool when all of its conditions hold. Limits are 32 rules and 16 conditions per rule, with no scripts or regular expressions. The whole rule set is validated before it is saved, and an invalid or missing set is reported as unavailable, never as a clean pass. Saving or resetting rules never turns observation on; Argument observation mode does, and Observe only records which rules matched: it cannot block, change, retry or approve a tool. Reset on the rules removes only the rules, and with observation on but no saved rules the result reads as unavailable.
Endpoints holds one collapsible panel per endpoint, plus Add for a new one, and an empty state when none are configured; there are no confirmation dialogs. A panel has the endpoint URL and an inline masked API key field. A saved key is never shown again: the row reads Key set with Replace and Clear, and the page names the host the key is sent to. Once the URL (and key, if the endpoint needs one) is filled in, Gira detects the models automatically (Detect repeats it, Detect without a key skips the key) and lists them as a checklist; with no /models you add model ids by hand. Tick the models to use and mark one Default (or None, an explicit empty default). A new model starts at the context window and output limit the endpoint reports, or at labelled working estimates (8,192 / 1,024 tokens) for a limit it does not report; Edit changes the label, context window and max output per model, Use automatic values puts the starting limits back without asking for numbers, and Discard edits returns to what is saved. Existing models keep their limits. Auto-configure on a saved model is described under Setting up a model. Advanced holds the endpoint name, id, auth header and prefix (or Send no auth header, a choice separate from leaving the header blank, which means Authorization), extra headers and max concurrent requests, and per model images, reasoning (an explicit profile, with Declared working (my declaration), which is your declaration and not a Gira test), reasoning style, tool support, maxTokensField, stream usage, response mode and the other recorded response variants, the stream idle allowance and extraBody. Every optional field has Reset to default, which removes a saved optional value when you press Save; Discard edits returns to what is saved. Reset endpoints (confirmed inline) removes the whole list, every stored key and a dangling default model. Save applies the panel; changing the URL or auth removes the endpoint's saved key and the page says so first. Remove… deletes the endpoint and its key after an inline confirmation; if it provided the default model, the default moves to another model. Reasoning Model default sends nothing (many endpoints reject reasoning_effort: "none"); Off/Low/Medium/High send reasoning_effort (Off = none), or with style chat_template_kwargs (Qwen/llama.cpp) send chat_template_kwargs.enable_thinking plus the effort level when not Off. When a command or edit needs approval, the composer is replaced by a card showing the command or diff with Allow and Deny, plus Allow for session on ordinary command cards (not on edit or guarded commit cards); the draft is kept and focus returns to the composer when the last card closes. The agents strip shows active/attention agents by name; agents open as full-sidebar pages: the top-bar Agents badge opens the agents list (Active / attention and Finished sections), a row opens that agent's page, and Back (or Escape) returns to the list; an agent chip or strip name in the chat opens that agent's page directly, where Back returns to the chat and All agents opens the list. An agent's page shows its transcript with its instructions rendered as Markdown, and Stop ends one running agent—its parent receives "Cancelled by the user before completion." There is one built-in subagent, agent (general purpose, under the parent's permissions); custom .gira/agents definitions add more. A task with readOnly: true restricts the child to registered read-only file, image and retained-output tools plus enabled semantic queries; a custom agent's explicit tool allowlist can narrow this further. It does not grant commands, edits, jobs or delegation. The agent tool runs each task on the session model unless a per-task model is given, which the model is told to set only when you explicitly ask for one. The tool's description lists the configured agents; agent and model are omitted to use the defaults, never sent empty (an empty or blank value is treated as omitted).
Test connection on a saved endpoint checks the endpoint with a 15-second timeout: it requests /models and checks the first configured model. If the server returns 404 for /models, Gira tries a non-streaming completion with max_tokens: 1 on that model instead. The inline result reports reachability, whether the key was accepted, whether the model was listed (when listing is supported), and latency, for example Reachable · key accepted · model listed · 120 ms. Failures show a classified label and hint; rejected keys offer Set API key (which focuses the key row), or only Unlock key when the endpoint supplies an unlock link. A successful fallback confirms a completion works, not that model listing is supported.
Editing your last message: hover the last message you sent and click the pencil (Edit and re-send). The composer switches to edit mode with a strip explaining that the reply and any tool runs after that message are removed; Enter or the send button (Re-send) replaces the message, and Escape or the strip's ✕ cancels and restores your draft. A running turn is stopped first. Files already changed stay changed; if the undone turn wrote files or ran commands, an Edited · re-sent; files not reverted card says so. A message that was compacted away or replaced by a handoff can't be edited; send a new message instead.
Attachments: the plus (Add file to context) opens the Add to context menu above the composer: Active file attaches the file in the active editor (or only its selected lines when there is a selection), Workspace file… opens a Quick Pick of root-relative paths and Image… opens the image picker (static PNG, JPEG, WebP or GIF, up to 10 MiB; you can also paste an image into your message). ↑/↓, Home/End or a letter move through the items, Enter chooses, Escape closes; choosing an item closes the menu. Typing @ in the composer opens a list of matching files (exact file name first, then name prefix, name substring and fuzzy path matches); ↑/↓ move, Enter or Tab picks, Escape closes. Picking keeps the @path token in your text and adds an attachment chip; @path:10-20 (or @path:10) attaches only those lines. @ followed by a folder name (@src/) mentions that folder: the agent receives its location and immediate contents instead of file text. Both lists come from a cached index that respects .gitignore and files.exclude, skips node_modules, and holds at most gira.context.fileIndexLimit files (default 5000; larger workspaces show "Showing the first N files — refine your search"). Only files inside an open folder can be attached, at most 6 per message. Pending attachments appear as removable chips in the composer (the menu does not repeat them) and as read-only chips under your sent message. They are sent with the message as <attachment> blocks in read_file format, so their line tags can be used with edit_file directly; the blocks together are capped at gira.context.maxAttachmentChars (default 60000).
Scrolling: while tool calls run, the conversation follows the bottom. When the final answer starts streaming, its first line is anchored at the top of the view so you read from the start; a ↓ Latest pill jumps back to the newest output. Scrolling up stops following until you return to the bottom.
Sessions: click the session title (the name with a chevron in the top bar) to open the sessions switcher, a non-modal panel under the title; Escape, a click elsewhere or a session switch closes it. It updates immediately after every session change, and you can open another session or start a New session at any time, even while a turn runs. Running sessions come first. Above eight sessions a filter field narrows the list by title or model (every word must match, in any order; Enter opens the first match and Escape clears the filter), and ↑/↓, Home and End move between rows, Enter opens the focused one. Each row shows a dot and a status line: Working · <tool> · 42 s, Waiting on 2 agents, Waiting on 1 job or Compacting (live dot), Needs approval or Question for you (amber dot), Done · 1m ago, Failed · 3m ago (red dot) or Cancelled; idle sessions show model · 2m ago. A session whose turn finished while you were elsewhere stays bold (unread) until you open it. When a session has todos, a chip on the right shows their progress (3/7). Running rows have a Stop button (Stop this session). A session can be renamed while a turn runs, from the row's pencil, ⋯ → Rename or /rename <title>; deleting a session used within the last hour asks inline (✓/✕) while older ones are deleted directly, and Clear all sessions asks in a VS Code dialog. A new session is titled automatically from its first prompt. Gira: Switch Session in the Command Palette lists the same sessions in a Quick Pick (the title, its status line and a check on the current session) and opens the one you choose in the Gira view. Failures show as Error cards in the conversation. Every icon button has hover text.
Automatic session titles:gira.ui.autoTitles is false by default and reads User settings only; Workspace and Folder values are ignored. This opt-in adds later topic updates to the ordinary first-message fallback title. At an idle checkpoint, after three completed human turns (or an explicit goal change) and no more than once a minute, Gira may send a low-priority text-only request using bounded, redacted excerpts from recent user topics and the explicit goal; attachments and generated content are excluded. A valid title is 3–10 words and at most 80 characters. The request has no tools or retries, and a busy checkpoint is skipped. Foreground work preempts it; new input, manual rename, Stop, a session switch, clear/delete, or configuration/trust changes invalidate its result. Saving the displayed name unchanged in the rename surface still pins it, and existing nonempty legacy titles are protected from automatic replacement.
Concurrent sessions: switching away from a session that is working keeps it running in the background: its turn, delegated agents, background jobs and pending wake-ups or goal continuations carry on, and its conversation is up to date when you return. Each session has its own history, goal, permissions, jobs and approvals; the agent in one session cannot see the others. gira.sessions.maxRunning (1–8, default 3) caps how many sessions are occupied at once: a session is occupied while its turn runs or while its subagents run (a parent and its outstanding subagents share one slot). A send to another session at the cap shows 3 sessions are already running — wait or stop one, work in a session that already holds a slot carries on, and a background wake-up or continuation waits until a slot is free. Approvals and questions from a background session do not appear in the conversation you are in: its row in the sessions switcher shows Needs approval or Question for you, the badge on the title turns amber, and the card appears when you open that session. Deleting a running session from the switcher stops it first, then deletes it. A workspace root change or a Workspace Trust change stops every session (running children are cancelled and their reports held for your next message). Set gira.sessions.maxRunning to 1 to run one session at a time while still switching freely.
Steps and narration: with tool grouping enabled, runs with fewer than five steps stay visible. Longer runs keep the latest three steps visible with expandable Steps history; failures, approvals and an already-open detail remain visible. History expands and collapses with the same 200 ms disclosure animation as tool details, respecting reduced-motion settings. Steps count unique recorded tool attempts, including agent dispatches, invalid, denied and cancelled attempts, plus each subagent result that lands in the run. Thinking stays in the activity history but adds no step, does not advance the grouping threshold and does not consume a recent-step slot; approval is not another step either. Failed counts show a small red X before the number, with accessible failure descriptions instead of visible status text. Only an explicitly marked, bounded <gira-progress>…</gira-progress> response committed successfully with actual tool calls is routine narration. The latest such main-agent line is shown once while its run is active; earlier lines remain in Steps. Unmarked findings, mixed or malformed text, provisional responses and final/no-tool answers stay visible. Existing discarded-attempt recovery is unchanged. Child narration stays in the child's view. These presentation hints add no model request and do not rewrite history or Markdown exports.
Agents: an agent's detail shows its role, model, working directory, full assignment, live activity and Model iterations (the model-loop counter, separate from Steps). It has one current action and at most three recent completed-action links; each opens the exact call, while all calls remain in its Steps transcript. Thinking is not automatically expanded. An agent working in another directory shows it as a chip in its header, the agents list and its "Delegating to" row. For a worktree the chip has a git-branch icon and reads folder · branch (ws-wt · wt-a), just the folder when the branch has the same name, or folder (detached) without a branch; otherwise it shows the folder label. Hover for the absolute path and, for a worktree, its branch.
Subagent dispatch headers: each recorded call shows Subagent · AgentTitle · intent (the tool API name stays agent). Dispatch lines have no cancel control; stop a child from its detail or the agents list. The agent tool requires a concise, action-first intent of at most 28 Unicode code points; historical longer intents are clipped with full hover text, and narrow sidebars hide the intent and its separator together. Titles such as CopperReader1 use only letters and numbers, capped at 32 Unicode code points. New titles come from an explicit Task title: line, otherwise a sanitized role-plus-index fallback, never assignment prose. Duplicate titles keep separate agent-ID cues, and each title opens its exact child. Prefer one batch for tasks sharing background: it remains one call, one row and one step, with independently delivered child reports. Separate calls still produce separate rows. Expanded dispatch details list Shared files (all tasks) once; each child's Instructions lists its inherited refs, not injected file bodies.
Active subagents pill: while children are running or queued, a faded pill sits directly above the input pill (it fades up into place when the first child starts and fades out when the last one finishes) at the same width (full strength on hover or focus). With up to three active children it has one row each, separated by a line, with the fields aligned in columns and divided by dots: title · current context in tokens (3.5k: the child's latest request estimate, replaced by reported prompt usage when the provider returns it; never cumulative input; hover for which) · current tool (Read src/math.ts, or Queued/its activity when none is running) · dispatch intent, and a spinner at the right edge while the child runs. Narrow sidebars drop the intent and its dot first, then clip the title and tool. Each row opens that child's transcript. With four or more it is one N agents active row that opens the agents list. It disappears when no child is active; finished and attention-needing children remain in the agents list. If a child finishes while its detail is open, Back returns focus to the top-bar Agents button. The dock no longer shows a separate Main · status line; the transcript and the Stop/Send button carry the main agent's state.
Send and Stop: while the main agent is working, Stop replaces Send in the same rightmost composer slot; Enter still queues a message for after the current step. When the main agent is only waiting for subagents, Send is shown and a message can be sent without stopping the children.
Worktrees: to work on one repository in parallel, create Git worktrees (git worktree add ../app-wt -b wt-a) and ask the agent to delegate each task with its cwd set to a worktree. An agent task's cwd may be a path inside an open folder or a worktree directory of an open folder's repository; the task's relative paths resolve there and its edits land in that worktree. The main agent's run_command accepts the same kind of cwd, while its file tools stay inside the open folders. Only directories that git worktree list reports for an open repository are allowed; any other outside directory fails with the usual containment error.
Keyboard: Enter sends, Shift+Enter inserts a newline, Escape closes the open popover, page, Agents view or expanded row. The supported minimum sidebar width is 260 px (usable down to 220 px); code blocks and long output scroll inside their row. Colours come from the active VS Code theme; high-contrast themes add borders to cards, pills and rows, and the OS reduced-motion setting (or gira.ui.animations: false) turns off slide, fade, shimmer and pulse animations.
Errors and the Gira log
Open VS Code's Output panel and select Gira, or run Gira: Open Log. Open log is also in the ⋯ menu, Gira settings → Logs & diagnostics, and classified error cards.
Use Developer: Set Log Level… → Gira to choose Trace, Debug, Info, Warning or Error. At Info, each completed model request records its endpoint/model, success or error class, HTTP status, total time, time to first token, token counts, SDK retry count and request id, and providerReqId=<id> when the endpoint sent its own request id (x-request-id, request-id, openai-request-id or x-correlation-id). A - means that value was unavailable. Debug adds request starts and retry decisions.
Request bodies and raw stream chunks are logged only when bothgira.log.bodies is true and the Gira log level is Trace. Enable Log request bodies (trace level) in Gira settings → Logs & diagnostics, or set it in User settings; it is off by default. Bodies are redacted and capped at 2 000 characters each. They can contain prompts, source code and tool arguments/results, so review logs before sharing: only configured secrets are redacted. At Info and higher severity levels, bodies are never logged.
Classified error cards show Error · <label>, the endpoint/model and HTTP status when available, and a provider-message excerpt. Expand the card for the full message and troubleshooting hint:
Error class
Card label
What the hint tells you
auth
Authentication failed
The endpoint rejected the key; enter it in Gira settings → Models & endpoints (the card's Set API key opens it), or clear it if none is needed. HTTP 403 reads Access denied: the key may not use this model or endpoint — choose another model or ask the endpoint's admin; a locked key offers Unlock key
not_found
Endpoint not found
Check the base URL path and model id; try Detect. HTTP 410 reads Model retired: pick the successor the provider message names
bad_request
Invalid request
Read the provider's rejection; check maxTokens, reasoning and extraBody
context_overflow
Context too large
The request exceeds the model's context; use /compact or a smaller context
rate_limited
Rate limited
Retry later, or after the displayed number of seconds when the server supplies a retry delay; when a long quota window (such as a daily credit allowance) is used up, the time it resets — Gira does not retry those
server
Endpoint error
Check the endpoint's logs for the reported HTTP failure; HTTP 502/504 means the endpoint's gateway could not reach its model backend (usually temporary, retried automatically)
network
Connection failed
The endpoint cannot be reached; check whether the server is running
dns
DNS lookup failed
Check the endpoint URL in Gira settings → Models & endpoints
tls
TLS failed
Check the certificate and HTTP/HTTPS configuration
timeout
Timed out
Names the limit that stopped the request: connect (response headers), stream idle (data frames; heartbeat comments do not count), overall, or retry wait, each with the duration it had when the request began. Adjust it in Gira settings → Requests & recovery. Model-picker probes and Test connection use a fixed 15 s cap, and title/advisor background caps are not configurable; neither shows setting advice
malformed_stream
Malformed response
The stream ended early; check the endpoint's logs or lower concurrency
disconnected
Stream ended early
Check the endpoint's logs or lower concurrency
aborted
Cancelled
The request was cancelled
tool
Tool error
See the tool card for details
internal
Internal error
Open the log for details
Other 4xx responses are not retried.
Open log is always available on classified error cards. Set API key appears for authentication failures other than HTTP 403 or locked keys with an unlock link; Open settings appears for authentication failures without an unlock link, missing-endpoint/model and invalid-request errors. View API call opens the exact request in Session logs when its id is known. Resume from checkpoint appears on the last error row when the failed request can still be re-sent exactly (see Automatic recovery); it is never offered for Invalid request or Context too large, where repeating the same request would not help, and errors saved by earlier versions offer Open log only.
Unlock key appears when the endpoint reports that the key is locked and sends an unlock link: Gira names the link's host and asks before opening it in your browser (with a stronger warning when the host is not the endpoint's own site). The link itself is kept in memory only; after a reload, send a message to get a fresh one.
Expanded error cards show Endpoint request ID with a copy button when the endpoint sent one; include it in support tickets to the endpoint's operators.
Git bridge
The Git bridge lets an agent on another machine (for example omp on a resource machine that cannot reach your model) use a model that only your laptop can reach, with a shared Git repository as the only channel. A small OpenAI-compatible shim on the resource machine commits each request as req/<id>.json to a requests lane branch and waits for res/<id>.json on a responses lane. Gira polls the requests lane, sends each request to one of your Gira endpoints over HTTPS, commits the raw reply to the responses lane and deletes answered files once the shim has consumed them. Only one writer per lane: the shim writes requests, Gira writes responses; run the bridge for a prefix in one VS Code window at a time (a second window's Start is refused with Another VS Code window is running this bridge (pid …)). This part describes protocol v1, the default; the opt-in protocol v2 (two encrypted refs and a separate resource-server download) is described under Git bridge v2 below.
Prerequisites:
git on PATH, with push access to the shared bridge repository.
A local clone of that repository with your home branch <you>/main checked out (for example alice/main). Gira takes the prefix from the first path segment of the branch and uses the lanes <you>/requests and <you>/responses, with worktrees under <clone>/.wt/<you>/ (.wt/ is added to .git/info/exclude). A detached HEAD or a one-segment branch is refused with Check out your home branch, e.g. alice/main. Gira never commits to the home branch.
An endpoint in gira.endpoints with its key set on Gira settings → Models & endpoints (if the endpoint needs one). Gira runs in the workspace extension host (extensionKind: workspace), so in a remote window the clone, git and the endpoint must be reachable from the remote side.
Settings (every one is edited in Gira settings → Git bridge; stored in User settings only, machine scope; changes apply at the next Start):
Setting
Default
Meaning
gira.gitBridge.repoPath
""
Absolute path of the clone. Empty keeps the bridge idle and hides the status bar item
gira.gitBridge.model
""
endpointId/modelId to forward to; empty uses gira.defaultModel
Minutes without requests that trigger idle auto-clean
gira.gitBridge.warnMegabytes
100
Lane size (MB) at which the status bar item turns to the warning colour
gira.gitBridge.meterSeconds
60
Size meter interval (10–3600)
Every gira.gitBridge.* setting is editable under Gira settings → Git bridge. Settings that belong to the other protocol sit under v1-only options or v2 model catalog; a search for one opens that disclosure, and nothing ever switches the protocol for you. Each setting shows its source (set in User settings, or not set) and its default, and Reset to default removes only that value: it never clears the bridge key or the HTTPS token, which have their own Clear. Changing the protocol or the clone path applies the next time the bridge starts; a running bridge is not stopped or restarted. A number outside its range is refused when you save; a stored value outside its range is read clamped, shown as such, and left as it is until you edit or reset it.
Commands: Gira: Start Git Bridge, Gira: Stop Git Bridge (aborts active calls), Gira: Clean Git Bridge Lanes (asks for confirmation) and Gira: Open Git Bridge. The bridge does not start on its own when a window opens.
⋯ → Git bridge… (or Gira: Open Git Bridge, or the status bar item) opens the Git bridge page:
Bridge: state, prefix and home branch, repository, upstream endpoint / model, parallel calls, Start / Stop / Clean lanes / Refresh, and the last error.
Startup: the latest startup sequence, separate from general logs, with phase, attempt and live retry countdown while starting. Its last 200 sanitized lines remain after success or failure until the next Start. Starting/stopping show loading indicators; healthy Running has a green light, while current transport failures remain visibly degraded.
Totals: Today, In flight, Avg latency (git / API), Tokens in / out, Errors. Totals live in memory and reset when the window reloads.
Requests: the latest 50 requests, newest first, with arrival time, size, model, state (Queued, Calling, Answered, Published, Cleaned, Cancelled), git wait, API time, tokens and error.
Lanes: commits, objects, bytes, largest item and growth since the last clean for each lane, plus the last clean, the warning threshold and the auto-clean mode.
Log: the last 200 bridge log lines, with Open log for the full Gira log.
Troubleshoot: collects a detailed, sanitized support report under cancellable native progress, then asks where to save the .log file. Collection is limited to 60 seconds and the report to 1 MiB. It records versions, transport/configuration metadata, startup/general logs and read-only Git connection diagnostics; it does not upload anything, change refs/configuration or include prompts, replies, credentials or private keys. Review the retained local paths, hostnames and network metadata before sharing.
Startup retries transient connection failures independently for initial outbox/inbox fetches and publication, with at most five attempts per operation and waits of 1, 2, 4 and 8 seconds. Stop cancels preparation, the active Git process and retry waits. Authentication/configuration and lease failures are not transient connection retries. An uncertain push is reconciled against the remote before another lease-protected publication; failed publication never advances the local success record.
For HTTP(S), a configured bridge token is tried first, without opening an askpass password prompt. If Git rejects authentication, Gira retries that operation once with the system Git credential helper and keeps that source for the rest of the run if it succeeds. An initially missing bridge ref still permits normal lane initialization. The stored token is not changed; the next Start tries it again. TCP timeouts, TLS errors and lease conflicts do not trigger credential switching. Both paths retain inherited Git configuration, including injected proxy/TLS settings. Troubleshoot records the resolved Git executable and compares separately labelled token/helper read-only probes when a token is configured, so an authentication difference can be distinguished from a connection failure.
The status bar item appears when gira.gitBridge.repoPath is set: $(broadcast) Bridge: alice · 12 MB · 340 commits while running, $(debug-stop) when stopped, Bridge: alice · cleaning during a clean. It turns to the warning colour at warnMegabytes and to the error colour when the last start, publish or clean failed; hover shows details. Under v2 the running text is Bridge: alice · v2 · 3 live (the number of entries in the inbox) and the tooltip names the protocol and transport.
Requests are forwarded verbatim except model, which is replaced with the chosen model id. Gira's per-model options (reasoning, extraBody, maxTokensField) are not applied; the agent's own configuration owns those fields. The call is a plain non-streaming POST <baseUrl>/chat/completions with the endpoint's headers and key. Successful replies and the endpoint's JSON errors are passed through byte for byte (except that an unlock_url field, a link for unlocking the laptop's own key, is removed before the reply is committed); network failures, timeouts and non-JSON errors come back as a bridge_error.
Clean lanes rewrites both of your lanes to one empty commit, force-pushes only your two lanes with a lease, and prunes the local clone. It is refused, with the reason shown on the page and in a warning, while requests are in flight (2 requests are in flight), while another clean is running, or while a lane still holds files on origin (alice/requests still has 1 files on origin; wait for the shim to drain them). A running bridge with nothing in flight is stopped for the clean and restarted afterwards.
Auto-clean (gira.gitBridge.autoClean, off by default) runs on size-meter ticks while the bridge is running: threshold cleans when the lanes reach autoCleanMegabytes, idle after autoCleanIdleMinutes without requests with both lanes empty. Both need nothing in flight and at least 10 minutes since the last attempt; a refusal is logged and retried at the next eligible tick. A request that arrives during a clean waits a few seconds.
GitLab notes:
Protected branches: <you>/requests and <you>/responses must not match a protected-branch rule, or the rule must allow force push, or cleaning fails.
Push rules (author email, commit message, maximum file size, signed commits) apply to bridge commits: set the clone's user.email to an accepted address and keep the shim's request size limit under the file-size rule.
Rate limits on authenticated Git over HTTP bound polls and pushes; raise pollSeconds / publishSeconds if you see 429 responses.
Force-pushed history stays on the server until GitLab housekeeping runs, so the project's Repository size drops later than Gira's lane meter.
Privacy: prompts, tool results and replies are committed to the shared repository's Git history and stay there, readable by anyone with access to it, until the lanes are cleaned and the server has pruned the old commits. Only bridge work you are authorized to store in that repository.
Git bridge v2 (opt-in)
Protocol v2 is an alternative to the lane protocol above. It is off by default: gira.gitBridge.protocol is "v1", and with gira.gitBridge.repoPath empty the bridge stays idle either way. Nothing changes for v1 users, and v1 keeps working as described above.
What differs from v1:
Two refs instead of two branches. The resource server writes refs/gira-bridge/<pair>/inbox and Gira writes refs/gira-bridge/<pair>/outbox, where <pair> is the same prefix v1 uses (the first segment of the clone's home branch). They are not branches: they do not show up in branch lists, merge requests or git branch -r, and they hold no history, only one parentless snapshot each, replaced with a force-with-lease push.
Everything is encrypted. Each request, response chunk, response manifest and the model catalog is one AES-256-GCM frame under keys derived from one pasted bridge key. The repository only holds encrypted blobs.
Streaming. Streamed replies reach the resource machine while they are produced, in whole server-sent events; non-streaming replies arrive as one body. Requests are forwarded verbatim except model, which is rewritten from the catalog id to the endpoint's model id. The resource server lists the models of Gira's catalog (endpointId/modelId), so models are chosen in Gira, not on the resource machine.
HTTPS as the primary transport. Gira and the server use plain git fetch and git push against the clone's origin; no worktrees or lane branches are created. The clone still needs its home branch <you>/main checked out, because the prefix comes from it.
Setup (Gira settings → Git bridge; the same fields are User settings, machine scope, and apply at the next Start):
Setting
Default
Meaning
gira.gitBridge.protocol
"v1"
"v1" or "v2"; applies at the next Start
gira.gitBridge.models
[]
endpointId/modelId refs Gira publishes in its catalog; the first is the default. Empty publishes gira.gitBridge.model, else gira.defaultModel. Ignored by v1
v1 only; v2 ignores them (its poll cadence is adaptive)
Bridge key. One key for both sides: 32 random bytes as base64 (44 characters). On Gira settings → Git bridge use Generate (Gira shows the new key once, to paste on the resource machine) or Paste to enter an existing one. It is stored in VS Code SecretStorage (gira.gitBridge.key), never written to settings.json, and is not shown again; the card shows only a fingerprint such as 1A2B-3C4D. The resource server's check prints the fingerprint of the key it read; the two must match. Without a key, Start is refused with Set the bridge key on Settings → Git bridge.
Transport detection. Gira reads the clone's origin URL and shows the transport on the card and the bridge page: HTTPS (bridge token) (an https:// remote with a token set), HTTPS (credential helper) (an https:// remote without a token: Git's own credential helper must already be signed in), SSH (ssh://, git@host:path; keys come from your ssh-agent) or local (a file path or file://).
HTTPS token. For an https:// origin you can store username:token on the card (Set token, Replace, Clear). It is kept in SecretStorage (gira.gitBridge.httpToken), handed to Git through the process environment as an Authorization header (never on a command line, in a log, in the repository or in a message to the page), and also applied to v1's Git operations when set. Use a token with read/write access to this one repository only (GitLab: project access token, role Developer, scopes read_repository and write_repository).
Resource server: a separate zip. The OpenAI-compatible server for the resource machine is not part of the VSIX and Gira never downloads, saves or copies it. It is published as its own artifact next to the VSIX, gira-bridge-server-<version>.zip, with bridge.ini.example, requirements.txt, .cmd launchers and a step-by-step README.md (Python 3.9+ and the cryptography package; check.cmd verifies the set-up, run.cmd serves http://127.0.0.1:8788/v1). Verify the download against the SHA-256 in the release notes.
What is visible in the repository: the ref names refs/gira-bridge/<pair>/inbox and …/outbox, the file names (req-<id>.bin, res-<id>-manifest.bin, res-<id>-c000000.bin, models.bin, where <id> starts with a UTC timestamp), the sizes of the encrypted blobs, and the commit times, author gira-bridge <bridge@invalid> and message gira bridge. Prompts, replies, model names and token usage are not visible without the key. Because every snapshot replaces the previous one, older objects stay on the Git host only until its housekeeping runs. On your machine, Gira keeps a bare repository under <clone>/.wt/<prefix>/v2.git (with local tracking refs under refs/gira-bridge-local/); the clone's branches and working tree are not touched.
On GitLab, a protected-ref or push rule that blocks refs/gira-bridge/* must allow it for the bridge's token.
Clean (Gira: Clean Git Bridge Lanes, shown as Clean bridge under v2) deletes both refs on origin in one atomic push. It is refused while the bridge is running (The bridge is running; stop it before cleaning) or while requests are in flight; it never stops the bridge for you, and a ref that is already gone is not an error. The resource server recreates its inbox when it next needs it, and Gira recreates its outbox at the next Start. There is no size meter or auto-clean under v2: the refs hold one snapshot each.
The page's Live state card replaces the lanes card under v2: transport, inbox entries, responses, chunks and bytes in the outbox, the last fetch and push durations, the catalog revision and the age of the oldest live response.
Privacy: as with v1, the content you send through the bridge is stored on the Git host, here encrypted; whoever holds the key (the resource machine, and anyone you give it to) can read it, and the key is not rotated automatically. To rotate it, Generate a new key (Replace), paste it into the server's bridge.ini, and Clean both refs.
Privacy and safety
The configured endpoint receives conversation/system prompts and relevant instructions, tool declarations/results, and any workspace file content, search results, command output or diffs included in a request. Only send work you are authorized to send to that endpoint. Only endpoints and model defaults from your User settings are used; repository settings cannot redirect requests or the stored key for an endpoint id to another destination. Gira sends no product telemetry; conversations live in VS Code's local extension storage and endpoint keys in VS Code SecretStorage. A locally executed approved command can itself contact external services; Gira cannot constrain its effects. The VSIX bundles JavaScript and UI assets, not a separate command runtime. Third-party notices and release notes are included in THIRD_PARTY_NOTICES.md and CHANGELOG.md.
With completion review on (gira.goals.completionReview), the review packet (goal, todos, evidence, recorded check summaries, session diffs and recent command output) and the files the reviewer reads go to the same endpoint.
Session API logs are described under Session logs: they stay on this machine, gira.log.capture and gira.log.retentionDays are read only from your User settings, and a repository cannot turn content capture on or lengthen retention.
Key-unlock links sent by an endpoint are never written to transcripts, logs or exports; only their host name is shown. A verbatim copy of the link in the endpoint's error message is also removed; differently worded or encoded copies in free text may not be recognized.