Gira
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. Open the Gira Activity Bar view. In User Settings (JSON) — or Remote User settings when connected remotely — configure at least one endpoint and a model reference:
{
"gira.endpoints": [{
"id": "my-endpoint",
"baseUrl": "https://example.org/v1",
"models": [{ "id": "my-model", "contextWindow": 32768, "maxOutputTokens": 2048 }]
}],
"gira.defaultModel": "my-endpoint/my-model"
}
Replace the illustrative address/model with your own provider's values. The base URL must point to the provider's OpenAI-compatible API root (the client uses chat completions). Use Gira: Set API Key (or Set key on the sidebar Settings page) to select an endpoint and enter its key into VS Code SecretStorage; do not put keys in settings, prompt files, or the repository. Gira: Clear API Keys removes stored keys. Endpoints without authentication can omit the key. If required by your gateway, configure the endpoint's authHeader, authPrefix, headers, maxConcurrentRequests, and the model's maxTokensField/extraBody; never put secrets in plain-text headers/extraBody. gira.endpoints, gira.defaultModel, gira.request.maxRetries and gira.request.timeoutSeconds 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. 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. Select a configured model in the sidebar or use Gira: Select Model. 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 set stream_options.include_usage; token counts and the stats line appear only when the endpoint reports usage.
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.
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), 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 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 (Session options ⋯ → Instructions, or the link in the Settings page's Harness header) 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. 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.
Permissions and command execution
Use the idle sidebar Permissions sheet (the shield button on the composer) to change the current session's mode. The default for new sessions (and /clear) is gira.permissions.defaultMode in User settings, also editable in the Settings page's Default permissions card; 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) |
Ask before: Edits (setting gira.edits.requireApproval) is a restrictive override in every mode, including full auto; it never weakens ask. Permission changes are unavailable during an active turn. 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.
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.
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; Session options → Background jobs lists the session's jobs with their status, elapsed time and Stop. 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.
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 Session options 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: 1–9 toggle options, 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 Settings → Harness → Context. 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. 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. Session options → Session details has a Context management block with 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 and Reset to default. 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: 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); 0 turns any of them off, and 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.
Copy and transcript export
Your messages and the final answer of each turn always show a labelled Copy button; the other controls appear on hover or keyboard focus, and stay visible on narrow sidebars:
- Copy on a message (Copy message) copies its plain text; Copy on a turn's final answer (Copy answer) copies the answer's Markdown source. Intermediate answer segments keep a hover-only Copy answer.
- Copy code on a fenced code block copies just the code, without its fence.
- Tool-card footers offer Copy input and Copy output when available: the command or tool arguments, and the result (such as file content, command output or a unified diff).
- Copy turn beside an answer copies that turn as Markdown: your message, tool summaries and the answer, without reasoning.
- Copy result copies a delegated agent's result: on the agent's page a labelled Copy (tooltip "Copy result") under its final answer, and beside each result in a "Delegating to" row.
- Session options ⋯ → Copy last answer, or Gira: Copy Last Answer in the Command Palette, copies the current session's latest final answer.
- Session options ⋯ → 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.
Copy buttons briefly show Copied or Copy failed.
To save the session, type /export, run Gira: Export Transcript in the Command Palette, or choose Session options ⋯ → 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 Settings → Harness → Transcripts, 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.
Configured secrets are replaced by ***. Transcripts may still contain source code or secrets from tool output: only configured secrets are redacted. Review a transcript before sharing or committing it. Transcripts are Git-ignored by default and kept forever unless you change Housekeeping → Keep transcripts.
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 and a todo list itself: 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, 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 todos are 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: 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 most 30 items; one item is in progress at a time and the next pending item starts automatically.
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 edit sheet or /goal. In an untrusted workspace or with no folder open, goals and todos still work but no document is written (the strip says no document (untrusted)).
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 open todos or 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 strip) cancels a pending continuation.
Commands: /goal shows the goal; /goal <objective> sets your own goal (replacing an existing one) and immediately asks the agent to draft its done when and todos and start on T1; /goal pause, /goal resume and /goal clear control it. /todo shows the list and /todo clear clears it. /build <plan> seeds the todo list from the plan's - [ ] (or numbered) items when no list exists. /clear, /new and /delete mark the goal cleared in its document. Delegated agents receive the parent goal and document path with their task.
Strip and sheet: while a goal or todos exist, a strip above the composer shows ◎ <objective> · done/total · <current todo>, toned by status. Click it to expand the todo list and done when, with Open document, Edit and Pause/Resume. Edit opens a sheet with the objective, done when and constraints and a todo editor (text, status, add, remove, move up/down); Save updates the goal and document and tells the agent what you changed before its next request. 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 strip, /goal and /todo, reminders and continuation.
Finished goal documents are removed by autoclean after gira.cleanup.goalsDays (default 90; see Autoclean); active and paused goals are kept.
Goal and harness settings (per window unless noted):
| Setting |
Default |
Meaning |
gira.goals.enabled |
true |
Goal and todo tools, strip, /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 open todos or an active goal |
gira.goals.autoContinue |
0 |
Automatic turns toward an active goal per message (0, 5, 10, 20; 0 = off) |
gira.cleanup.goalsDays |
90 |
Delete finished goal documents older than this many days (0 = keep) |
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, capped at 2 000 characters each; requires the Gira log level to be Trace (machine-scoped) |
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 = 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 |
gira.commands.commitGuard |
"ask" |
"ask" = one-time approval per git commit, "deny" = refuse, "off" = ordinary permissions (User settings only, machine-scoped) |
The Gira view has a top bar (sessions drawer, session title with a status dot, Agents badge and session options), an agents strip while agents run, the conversation, and a dock at the bottom. The sessions button carries a badge with the number of other sessions still running; it turns amber when one of them needs approval or has a question, and its tooltip says so (for example 2 sessions running · 1 needs approval). Tool calls render as quiet one-line rows that slide and fade in and expand into their output; consecutive calls share a group whose "Ran N tools" head appears from the second call, and delegated agents show as "Delegating to" rows: one agent's chip opens that agent, and two or more show a single "N agents · M running" chip that opens the agents list. The status line shows Compacting context while compaction runs. Banners above the conversation report missing endpoints, untrusted workspaces and errors, with their action buttons.
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 and a row of controls below: a / button that starts a slash command, a branch chip (a git-branch icon and the branch name, e.g. main, with a small amber dot when there are uncommitted changes, detached @<sha> for a detached HEAD, and alias:branch in multi-root windows, following the active editor's folder; hover for the branch, change state, ahead/behind and repository path; click opens Source Control; hidden without a Git repository, with gira.git.showBranch: false, or on sidebars 300 px wide or narrower, where the branch is still shown in Source Control), the model button (opens the model sheet with endpoint sections and their models), the shield permissions button (opens the Permissions sheet: Ask before Edits / Commands checkboxes and a Full auto checkbox; its label hides on sidebars 340 px or narrower, it turns red in full auto and shows a lock when edits need approval), a context pill showing used / window tokens (a percentage on narrow sidebars; a tick marks the autocompaction or autohandoff threshold, the pill turns amber from that threshold and red from 90 % or the output-headroom cap; hover for exact estimated tokens and the threshold), and one round button that is Send when idle and Stop while a turn runs. Session options opens a sheet for turn mode (Build, Plan or Discuss), workspace roots, settings, Rename session, Copy last answer and Session details (a sheet including the session's token totals and context management). 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. The drawer lists saved sessions and New session, running sessions first; the pencil renames a session (as does /rename <title>), deleting a session used within the last hour asks inline (✓/✕) while older ones are deleted directly, and Clear all asks in a VS Code dialog.
The Settings page has two groups, Models (the Endpoints card) and Harness. A row of chips at the top of Harness (Context · Goals · Commands · Tools · Transcripts · Housekeeping · Appearance · Permissions; it wraps on narrow sidebars) jumps to each card, and the Harness header links to the Instructions page. 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. The commit guard is the exception: its enforcement applies immediately, even to a running turn.
- Context: the default strategy (
gira.context.strategy: Compact, Handoff or Off) and the Default threshold (gira.compaction.threshold, 30–90 % in 5 % steps; unused while the strategy is Off).
- Goals & todos: the Goals and todos switch (
gira.goals.enabled), Reminder cadence (gira.goals.reminderEvery), Stop nudge (gira.goals.stopReminder) and Auto-continuation (gira.goals.autoContinue).
- Commands: one switch per slash 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 cannot be disabled, disabling /discuss also blocks discussion mode, and /goal /todo are greyed while goals are off.
- Tools: Commit guard (Ask for approval / Deny / Off,
gira.commands.commitGuard; see Permissions and command execution), Ask tool (gira.tools.ask; off, the agent asks in chat instead), Subagents (gira.subagents.enabled, off by default; on, it offers the agent tool and the delegation guidance; existing agent rows always render), Background jobs (gira.tools.backgroundJobs; off, commands always run in the foreground and there is no jobs tool), @ mentions (gira.context.mentions; the paperclip is unaffected), Loop guard (gira.agent.loopGuard), Log request bodies (trace level) (gira.log.bodies) and Open log.
- Transcripts: Auto-save (Off / After each turn), Tool output (None / Summary / Full), Include reasoning and Export now; see Copy and transcript export.
- Housekeeping: Keep handoffs, Keep decisions, Keep goal documents and Keep transcripts (Off = keep forever, 7–180 days;
gira.cleanup.handoffsDays, gira.cleanup.decisionsDays, gira.cleanup.goalsDays, gira.cleanup.transcriptsDays), Git-ignore generated files (gira.git.ignoreArtifacts, including transcripts by default) and Run /cleanup now.
- Appearance: Show interaction stats (
gira.ui.showStats), Animations (gira.ui.animations; the OS reduced-motion setting always wins) and Group tool calls (gira.ui.groupTools, default on; off gives every tool call its own row).
- Default permissions:
gira.permissions.defaultMode in User settings (new sessions and /clear only).
Endpoints holds the default model select and the endpoint list, with an empty state when none are configured. You can add, edit and remove endpoints there; each change asks in a native VS Code dialog, and adding an endpoint or changing its base URL, auth or headers clears its stored key (re-enter it, and re-enter header values when editing). Detect models fetches the models an endpoint offers. Per model you can set label, context window, max output, reasoning and reasoning style, plus advanced maxTokensField/extraBody. 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. Keys are still set or cleared through VS Code's password input box. 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 running agents by name; agents open as full-sidebar pages: the top-bar Agents badge opens the agents list (Running and Finished sections), a row opens that agent's page, and Back (or Escape) returns to the list; an agent chip or strip entry 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 limits the child to read_file, list_files and search_files. 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 beside Detect models 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. 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 paperclip (Add file to context) opens the Add to context sheet: Active file attaches the file in the active editor (or only its selected lines when there is a selection), and Choose a workspace file… opens a Quick Pick of root-relative paths. 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 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: the drawer 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. 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 drawer's pencil, Session options → Rename session or /rename <title>; a new session is titled automatically from its first prompt. Failures show as Error cards in the conversation. Every icon button has hover text.
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 turns run at once across sessions; a send at the cap shows 3 sessions are already running — wait or stop one, and a background wake-up or continuation at the cap waits until a turn ends. Approvals and questions from a background session do not appear in the conversation you are in: the drawer row shows Needs approval or Question for you, the sessions badge turns amber, and the card appears when you open that session. Deleting a running session from the drawer stops it first, then deletes it. A workspace root change or loss of Trust stops every session. Set gira.sessions.maxRunning to 1 to run one turn at a time while still switching freely.
Agents: an agent's page has a live header line (step · current tool · elapsed · last update), keeps its thinking open while it streams, and groups its tool calls like the main conversation. An agent working in another directory shows it as a chip in its header, the agents list, the agents strip 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.
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 sheet, drawer, panel 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 Session options ⋯, Settings → Harness → Tools, 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. A - means that value was unavailable. Debug adds request starts and retry decisions.
Request bodies and raw stream chunks are logged only when both gira.log.bodies is true and the Gira log level is Trace. Enable Log request bodies (trace level) in the Tools card 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; set it with Gira: Set API Key, or clear it if none is needed |
not_found |
Endpoint not found |
Check the base URL path and model id; try Detect models |
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 |
server |
Endpoint error |
Check the endpoint's logs for the reported HTTP failure |
network |
Connection failed |
The endpoint cannot be reached; check whether the server is running |
dns |
DNS lookup failed |
Check the host in gira.endpoints[].baseUrl |
tls |
TLS failed |
Check the certificate and HTTP/HTTPS configuration |
timeout |
Timed out |
Check the server or raise gira.request.timeoutSeconds |
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 |
Open log is always available on classified error cards. Set API key appears for authentication failures; Open settings appears for authentication, missing-endpoint/model and invalid-request errors. Retry re-sends the last user message's text when Gira is idle and the error is the last row and is retryable (or a connection failure); it does not reattach files. It is never offered for Invalid request or Context too large, where repeating the same request would not help.
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 …)).
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 via Gira: Set API Key (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 (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 |
gira.gitBridge.maxParallel |
0 |
Concurrent upstream calls (0–64); 0 uses the endpoint's maxConcurrentRequests, else 4 |
gira.gitBridge.pollSeconds |
3 |
Requests-lane poll interval |
gira.gitBridge.publishSeconds |
1 |
Minimum gap between response pushes |
gira.gitBridge.upstreamTimeoutSeconds |
600 |
Timeout per upstream call |
gira.gitBridge.autoClean |
off |
off, threshold or idle (see below) |
gira.gitBridge.autoCleanMegabytes |
200 |
Lane size (MB) that triggers threshold auto-clean |
gira.gitBridge.autoCleanIdleMinutes |
30 |
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) |
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.
Session options ⋯ → 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.
- 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.
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.
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; 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.
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.