Skip to content

Configuration Reference ​

IMPORTANT

TL;DR: Most runtime behavior, including council size, retry budgets, timeouts, quorum rules, and model selection, is configurable through the UI settings panel. Defaults are tuned for overnight runs; adjust them to match your provider limits and cost tolerance.

The singleton profile is the baseline configuration, accessible through the Configuration button in the LoopTroop UI. You do not need to restart the server after editing it, but settings are not all consumed at the same moment: some are frozen when a ticket starts, while others are read later at phase or session boundaries.

NOTE

Current behavior. The OpenCode step-cap restore/conflict rules and protected Git-hook recovery marker described on this page are current. The ordinary, non-conflicting run remains the normal restore path; a conflict can refuse destructive recovery while preserving the edited files and markers. The remote-mode cookie enforcement, strict Origin checks, port validation, and configured development-origin behavior described below are also current, as is the explicit-directory rule for unverifiable executable ownership.

Where LoopTroop Keeps Its State ​

Everything an installation owns lives in one directory, outside the installation itself, so upgrading, reinstalling, or switching channels does not lose it:

PlatformPath
Linux, macOS$XDG_CONFIG_HOME/looptroop, falling back to ~/.config/looptroop
Windows%APPDATA%\looptroop
AnyLOOPTROOP_CONFIG_DIR, which overrides both

The directory is created owner-only (0700), and files that can carry a token or session state are written 0600.

FileWhat it isSafe to delete?
config.jsonYour settings. The only file here meant to be edited by hand.Resets settings to defaults
app.sqliteProjects, tickets and workflow state. The -wal and -shm files beside it belong to SQLite.No: this is your work
daemon.jsonWhere the running daemon is: host, port, process id, and the token the interface authenticates with. Written at start, cleared at stop.Yes, when nothing is running
daemon.lockHeld for the lifetime of the daemon, so a second one cannot start against the same directory.Yes, when nothing is running
logs/What looptroop logs reads.Yes
update-check.jsonThe last published LoopTroop release seen, and when it was last looked for.Yes: costs one lookup
tool-versions.jsonThe newest published Node, npm and OpenCode versions, behind the comparison doctor prints.Yes: costs one lookup
opencode/State for an OpenCode that LoopTroop started, kept apart from one you run yourself.Yes, when nothing is running

Both caches record the time of the last attempt, failures included, so an offline machine does not retry on every command. Neither holds anything that cannot be fetched again.

XDG_CONFIG_HOME is deliberately ignored on Windows: it is a freedesktop convention, so honouring it there would split one user's data across two locations depending on which shell launched the process.

config.json ​

Unrecognised keys are preserved when the file is rewritten, so settings written by a newer version survive being loaded by an older one, and a malformed file is ignored with a warning rather than preventing startup.

Settings, and where each one comes from ​

Only the settings in this table are resolved with the precedence flag → environment → file → default. Everything else below resolves somewhere else entirely, which is why they are listed separately rather than as one flat list.

Settingconfig.json keyEnvironmentFlagDefault
PortportLOOPTROOP_BACKEND_PORT--port3000
Log levellogLevelLOOPTROOP_LOG_LEVEL-info
OpenCode addressopencodeBaseUrlLOOPTROOP_OPENCODE_BASE_URL-http://127.0.0.1:4096
OpenCode modeopencodeModeLOOPTROOP_OPENCODE_MODE-live
Public browser origin (current behavior)publicOriginLOOPTROOP_PUBLIC_ORIGIN-Unset

Two defaults give way when something else already uses them. A taken default port makes the daemon pick a free one, and an OpenCode address left at its default that is held by a server LoopTroop cannot use makes LoopTroop start its own OpenCode on the next free port, never on LoopTroop's own port. A value you set yourself is used exactly as given, and LoopTroop stops with an error instead.

Resolved elsewhere, and not through that chain:

VariableWhat it does
LOOPTROOP_CONFIG_DIRThe directory everything above lives in. Read before any file exists, so it cannot come from one.
LOOPTROOP_APP_DB_PATHMoves the application database.
LOOPTROOP_ALLOW_REMOTE_APIPermits a non-loopback bind. Requires a token as well.
LOOPTROOP_BACKEND_HOSTThe bind address, once the above allows one.
LOOPTROOP_API_TOKENAuthorises the wider bind. It is not the token the API accepts. See API Reference.
LOOPTROOP_TRUSTED_EXECUTABLE_DIRSExtra directories to look in for git, gh, opencode and the rest, ahead of PATH. See below.
OPENCODE_INSTALL_DIR, OPENCODE_DIRAbsolute directory hints LoopTroop uses to find the OpenCode CLI. These settings do not install or move OpenCode. See below.

Where LoopTroop looks for its tools ​

LoopTroop picks the file it runs for git, gh, opencode, npm and the other tools it starts, instead of letting PATH decide, and it never runs one from the current directory. Tools installed by nvm, Homebrew, Nix, scoop, a CI tool cache or a project's node_modules/.bin all work.

For OpenCode, LoopTroop also searches its canonical directories, including ~/.opencode/bin and a custom directory hint, even when they are absent from PATH. The search order is:

  1. Directories in LOOPTROOP_TRUSTED_EXECUTABLE_DIRS, in the order given.
  2. The first valid absolute hint: OPENCODE_INSTALL_DIR, otherwise OPENCODE_DIR.
  3. ~/.opencode/bin (USERPROFILE supplies the home on Windows, with HOME as a fallback).
  4. Windows system directories, on Windows.
  5. Other PATH entries, in their original order.

When both hints are valid, OPENCODE_INSTALL_DIR wins. Empty or relative hints are ignored. A missing executable falls through to home and the remaining entries. Existing PATH aliases to canonical directories keep their spelling; Windows alias matching ignores case and slash style. Custom still precedes home regardless of PATH positions.

Canonical directories take precedence over ordinary PATH. An OpenCode in a project's node_modules/.bin or execution setup's pathPrepend therefore does not override a canonical installation. Use LOOPTROOP_TRUSTED_EXECUTABLE_DIRS when you want a different directory to win.

On Windows, bare opencode and explicit names (opencode.exe, opencode.cmd) follow this order; explicit names select only that extension. Absolute executable paths bypass directory search.

Missing directories or files let the search continue. If the first executable found fails the trust checks, LoopTroop reports a refusal and stops the search; it does not silently run another copy farther down the list.

On macOS and Linux it refuses a tool when the tool's directory, the real file behind a link, or any directory above them belongs to someone other than you, root, or the owner of the Node running LoopTroop. A refused tool is treated like a missing one, and doctor says it was refused and why.

An extensionless Windows path is resolved through the executable siblings listed by PATHEXT, in that order, before the normal path trust checks run. The extensionless file itself is never run.

That search uses only .exe, .com, .cmd and .bat entries. Scripts that need another interpreter, such as .ps1 or .vbs, no longer hide a supported executable later in PATHEXT.

An unmapped Linux owner does not establish trust. The same overflow UID can represent host root or a different host user, so LoopTroop cannot use it to verify ownership. This also applies when Node's own executable has that owner. If you trust the tool's directory, name that absolute directory in LOOPTROOP_TRUSTED_EXECUTABLE_DIRS; otherwise the tool remains refused.

OpenCode in a canonical directory has one ownership exception. Official OpenCode release archives are built on CI runners with UID 1001, so extracting them as root preserves that UID on the binary. LoopTroop excuses this ownership for opencode when its directory chain belongs to a trusted owner, the binary and directory chain are not writable by group or others, and the binary is protected inside a private directory (such as /root or ~ with mode 0700 denying group and other traversal; mode 0555 alone or sticky directories like /tmp are not excused). Sibling binaries in that directory must still pass normal ownership checks. This exception does not accept an unmapped owner; that still needs an explicit trusted-directory setting.

An opencode that belongs to you, to root or to the Node runtime owner needs no exception, so its permission bits are not checked: it gets the same ownership check as git or npm. Ubuntu and Fedora give each user a private group and create new folders group-writable, and the ~/.opencode/bin that the OpenCode installer makes there is accepted. As with those tools, that includes a binary or folder anyone can write to, so keep ~/.opencode writable only by you.

If a tool lives somewhere else on purpose, for example a toolchain owned by a service account, name its directory:

bash
export LOOPTROOP_TRUSTED_EXECUTABLE_DIRS=/opt/tools:/srv/toolchain

Those directories are searched before OpenCode's canonical directories and PATH, and are trusted as they are. They do not have to be on PATH. Separate them with : on macOS and Linux and ; on Windows.

Entries must be absolute directories. Empty or relative entries such as ., tools, or a trailing path separator segment are discarded rather than resolved against the current directory.

This trust policy comes from the daemon's own environment, not from command.env, child processes, or a model-generated command. A child command cannot widen trust by setting its own LOOPTROOP_TRUSTED_EXECUTABLE_DIRS. The OpenCode directory hints also come from LoopTroop's own environment, so putting them in a project command's environment does not change which CLI runs.

For the npm install and upgrade path, the runtime floor is Node 24.18.0 or newer. The launcher, Doctor, install scripts, and package channels enforce the same floor. No npm version is required: LoopTroop has no install scripts, so the npm that came with your Node is the one it needs.

The floor follows Node about three months behind: it moves to the newest Node 24 release that has been out for 90 days, and only once winget, Chocolatey, Scoop and Homebrew all offer it. It never moves to a new Node major on its own. If you keep Node up to date, you will not notice it move.

Runtime markers ​

LOOPTROOP_CONTAINER is set by the container image to record how LoopTroop was installed. It is not a user setting; setting it by hand only makes doctor describe your installation incorrectly.

IMPORTANT

There is deliberately no host setting in config.json. The control interface binds loopback only, and a control plane that executes code on the machine it runs on must not become network-reachable because somebody edited a configuration file. A wider bind takes two environment variables and a token, so it is always a deliberate act. See Running in a container.

What "loopback" means here ​

LoopTroop treats these as loopback:

  • localhost
  • any strict dotted IPv4 address in 127.0.0.0/8, with four octets and no leading zeros
  • ::1
  • IPv4-mapped IPv6 loopback forms whose mapped IPv4 address is inside 127/8

In local mode, it does not treat 127.attacker.example, malformed dotted quads such as 127.0.0.01, URL-shaped strings, or non-loopback mapped addresses as local.

NOTE

Managed and adopted OpenCode health checks refuse HTTP redirects, and managed OpenCode startup validates the configured host before spawning opencode serve. That keeps readiness probes from being redirected somewhere else and keeps malformed host values from becoming process-launch surprises.

Remote access and credentials ​

The default loopback bind is the safest mode for the local control plane. A wider bind requires LOOPTROOP_ALLOW_REMOTE_API, LOOPTROOP_BACKEND_HOST, and LOOPTROOP_API_TOKEN. The API token in that configuration is the permission to expose the wider bind. It is not the live API or browser-session token minted by the daemon and recorded in owner-only daemon state. See API Reference for the credentials used by callers after the daemon starts.

Remote browser sessions require one explicit HTTPS origin in LOOPTROOP_PUBLIC_ORIGIN or the publicOrigin setting. It must be an origin, not a URL with credentials, a route, query, or fragment. Enable remote API access for the browser-facing deployment; the backend can still bind to loopback and use HTTP behind the proxy. Neither setting creates a TLS listener or changes the bind address.

Setting a public origin without LOOPTROOP_ALLOW_REMOTE_API=1 rejects startup with a configuration error. Remove the public origin for a local-only session, or enable remote API access for the proxy deployment.

Cookie-bearing requests with an Origin must match that public origin exactly. Without Origin, they require Sec-Fetch-Site: same-origin and a Host matching the configured public authority, so the proxy must preserve the public Host. Forwarded host and scheme headers are not trusted. Browser cookies use Secure for this configuration, and CLI sign-in links use the public origin while daemon-control API calls continue to use the internal address.

Without a configured public HTTPS origin, remote access is bearer-token only: browser sign-in and session cookies are refused. Adding a bearer header does not bypass checks on a cookie-bearing request. Local mode retains its loopback Host and same-origin checks. Origin parsing rejects alternate IPv4 spellings and explicit port 0; configured development origins remain a separate development-mode exception.

Remote bearer-token support does not enable browser CORS access from arbitrary websites. Requests carrying an Origin must still satisfy the origin policy, even when they carry a bearer token. Scripts that omit Origin are unaffected.

Scope And Inheritance ​

LoopTroop applies configuration in three layers:

LayerWhat it controlsWhen it applies
ProfileApp-wide baseline valuesAdvanced values preselect future-project choices; other supported values resolve through normal inheritance
Project settingSaved Manual QA, Git-hook, and folder-ignore choices, plus nullable AI-question overridesManual QA and the AI-question settings seed new tickets; Git-hook and folder-ignore policy stay project-scoped
Ticket choiceDraft-only Manual QA and AI-question choicesWins over the project choice when the ticket starts
Ticket start lockFrozen planning-critical values captured on StartStays fixed for that ticket run

The Configuration dialog edits the singleton profile. Its collapsed Advanced section contains the defaults for Manual QA, Git-hook policy, and LoopTroop folder ignore policy. The Project form copies those defaults into concrete saved choices for a newly attached project and exposes all three in Project Advanced before attachment. Restoring an existing project keeps its saved choices. Later Configuration edits affect only projects created after the edit.

Other project-level fields may still override the profile where supported. The project fields are:

  • councilMembers
  • maxIterations (Max Bead Retries)
  • perIterationTimeout
  • executionSetupTimeout
  • councilResponseTimeout (AI Response Timeout)
  • minCouncilQuorum
  • interviewQuestions
  • manualQaOverride
  • aiQuestionsOverride
  • aiQuestionWindowOverride
  • gitHookPolicy
  • ignoreMode (attach-time only)

For the nullable general overrides, a project value wins over the profile and an unset field continues to inherit. The three Advanced project choices are concrete on new projects instead: they are copied from Configuration at creation and do not follow later profile edits. Fields without project support always come from the profile.

What locks when you press Start ​

These values are captured before the ticket enters SCANNING_RELEVANT_FILES and stay fixed for that ticket even if you edit the profile afterward:

Locked at startWhy it is frozen
Main implementer model + effort variantThe same model lineup must own the full run for auditability and retry consistency
Council members + their effort variantsCouncil drafting/voting must stay comparable across the ticket lifecycle
Max Interview QuestionsThe compiled interview contract should not change mid-run
Coverage Follow-Up BudgetInterview follow-up budget is part of the approved planning envelope
Interview / PRD / Beads Coverage PassesCoverage-loop budgets must stay stable for that ticket
Structured Output RetriesRepair behavior must stay stable across the ticket's structured phases
Manual QA effective value + sourceThe post-test route must not change after work starts; missing locks on older/in-progress tickets mean disabled
AI Questions + AI Question Wait, with the source of eachEditing the profile at 3 a.m. must not change what an overnight run does mid-flight; missing locks on older/in-progress tickets mean the run may not ask
Project Git-hook policy + project sourceRepository-hook behavior must stay stable throughout setup, internal commits, and integration

What is read later instead of locked ​

These values are not frozen into the ticket-start lock. They are picked up when the relevant phase, prompt, or log pipeline reads them:

Read laterTypical read timing
AI Response Timeout, Min Council QuorumWhen a planning/final-test model phase starts
Per-Iteration Timeout, Execution Setup Timeout, Max Bead RetriesWhen execution setup, coding, or final-test attempts are prepared
OpenCode Retry Limit, OpenCode Retry Grace Window, OpenCode Max StepsWhen new OpenCode prompt/session settings are assembled
Tool Input / Output / Error Max CharsWhen tool-log formatting runs (backend cache is refreshed periodically)

That means an edit can affect a ticket that is already in progress only if the ticket has not yet crossed the boundary where that specific value is read. It does not rewrite already-running prompts, already-started timers, or already-locked planning budgets.

Configuration Dialog Behavior ​

The docs links on each control point back to this page, but the UI itself also has a few behaviors worth knowing:

  • OpenCode health is checked live. The health probe checks connectivity, protocol/version, and authentication without loading the catalog. Separate model queries show whether discovery is still loading, failed, or returned no models.
  • The reload button refreshes provider/model data. The teal icon beside AI Models, labelled Reload OpenCode providers and models, stays enabled during ordinary reads, including the first load, and disables only during manual reload. It cancels pending reads and shows loading while reloading OpenCode's catalog, then updates open pickers on success without a browser reload. If reload fails before a catalog has loaded, ordinary discovery resumes for that scope while the original reload error stays visible; the reload POST is not repeated. Use it after changing provider credentials or when discovery stalls. Opening Configuration keeps cached models visible. Busy reloads keep cached catalogs without automatic retry; finish prompts and unanswered questions, then retry. Rejected reloads show the cause. This does not restart opencode serve or interrupt active ticket worktree instances.
  • Catalog reads wait for v2 providers. LoopTroop waits for plugin activation before initial and post-reload reads. See model discovery for deadlines and failure handling.

NOTE

Current behavior. Configuration and related form snapshot handling described below is current client behavior.

  • Dirty state follows actual values. The dialog compares its current profile values with the saved or initial snapshot, including model variants and other custom controls. Closing warns only while those values differ; typing and then restoring the snapshot clears the warning. During profile loading, or when no profile exists yet, values typed in the gap are not absorbed into a clean baseline when hydration arrives.
  • Saves keep the right draft. A successful save acknowledges the snapshot sent by that request. A failed save leaves the draft dirty, and edits made while the request completes or while a background refetch runs remain visible. An unsaved in-memory modal draft is not promised to survive a reload.

See model discovery for discovery deadlines, cancellation, and retries that follow OpenCode's reported reload progress.

  • Model pickers show currently available models. When models exist, an unselected picker and its open search field show a count, for example 1,111 models found. Search models…. The count covers the current catalog before text or free-model filters; a selected model keeps its name in the closed picker. Inside the picker you can search by model name, provider, or family and filter to free models. Click a provider heading in the results to collapse or expand its models; the heading stays visible. Each entry shows the provider's display name with the exact stored model ID in parentheses beside it whenever the two differ, so the value LoopTroop sends to OpenCode is visible without opening the saved configuration. Searching matches that full ID as well as the display name. OpenCode v1 can also return a broader catalog through Show all providers; v2 reports only available providers and enabled models, so its picker does not offer that toggle.
  • Model selection is announced accessibly. The selected model is the committed value (aria-selected); keyboard movement uses aria-activedescendant until a choice is committed. Closed pickers expose aria-busy during manual reload without changing the selection. Loading, connection failures, discovery timeouts, and other model-catalog errors are announced separately from an empty catalog. Other errors show their actual message.
  • Duplicate model selection is prevented. The main implementer is auto-included in the council, and the picker disables models already chosen in another council slot.
  • Effort controls are conditional. The effort / thinking picker only appears when the selected model advertises variants, and the saved variant is stored per slot.
  • Advanced is collapsed by default. Open it to set the Manual QA, Git-hook, and folder-ignore defaults copied into future projects; saving Configuration does not update projects that are already attached.
  • Numeric validation is strict. All numeric fields must be whole numbers, and edits below or above a field's range show an error and block saving. AI Response Timeout, Execution Setup Timeout, Per-Iteration Timeout, and OpenCode Retry Grace Window keep total seconds as the saved value and show compact synchronized Minutes and Seconds editors inside the same field; changing either representation updates the other immediately. Coverage remains displayed in percent, while the API stores timeout/delay values in milliseconds.
  • The About button opens a separate window for application and update details. The version beside the header title opens the same window. A quiet monochrome icon appears beside that version only when a newer published release is available.

About Window ​

The About window is a read-only summary of updates, the current runtime environment, and storage layout.

It shows:

  • the current and latest published app versions;
  • whether an update is available and which install channel owns this copy;
  • the exact ordered upgrade, restart, or container-recreation guidance for that channel;
  • a Changelog button that opens the latest GitHub release and shows its complete release body on hover or keyboard focus;
  • the operating system / runtime environment;
  • the application location;
  • the app database path;
  • the global configuration directory;
  • the current number of attached projects;
  • a short note explaining that each attached project also keeps local LoopTroop state inside its own .looptroop/ folder.

This is meant to answer three quick questions without opening logs or artifacts:

  • "Is there a newer version, and how do I update this particular installation?"
  • "Where does the app keep its own data?"
  • "Where does each project keep its local LoopTroop state?"

Prompts ​

Prompts are configured separately from the profile, through the Prompts button in the top-right header (route /prompts). Unlike profile settings, prompt edits are stored as YAML files on disk under <config dir>/templates (one file per prompt) rather than in the application database.

Prompt edits are read when a phase builds its prompt, so a save applies to runs started afterwards; a phase already in flight keeps the prompt it was launched with. A corrupt or invalid template file never blocks a run: LoopTroop falls back to the built-in default for that prompt and reports it as a warning banner in the Prompts screen.

See Customizing Prompts for the storage layout, validation rules, and editor controls.

Quick Reference ​

SettingDefaultRangeGroupRead timing
Main Implementer Model(required)any available modelAI Modelsticket start lock
Council Members(required, 1 to 9 additional)any available modelsAI Modelsticket start lock
OpenCode Retry Limit100 to 50OpenCode Provider Recoverynext OpenCode prompt/session
OpenCode Retry Grace Window60 s0 to 3600 sOpenCode Provider Recoverynext OpenCode prompt/session
OpenCode Max Steps0 (no limit)0 to 500OpenCode Provider Recoverynext coding/final-test session
AI Response Timeout1200 s10 to 3600 sAI Thinkingnext planning/final-test model phase
Min Council Quorum21 to 6AI Thinkingnext planning phase
Max Interview Questions500 to 50AI Thinkingticket start lock
Structured Output Retries10 to 5AI Thinkingticket start lock
AI QuestionsOnOn / OffAdvancedticket start lock
AI Question Wait5 minutes1 to 60 whole minutesAdvancedticket start lock
Coverage Follow-Up Budget20 %0 to 100 %Coverageticket start lock
Interview Coverage Passes21 to 10Coverageticket start lock
PRD Coverage Passes52 to 20Coverageticket start lock
Beads Coverage Passes52 to 20Coverageticket start lock
Manual QAenabledenabled / disabledAdvancedticket start lock
Git Hook PolicyCheckObserve / Check / Require / RunAdvancedticket start lock
LoopTroop Folder Ignore PolicyThis cloneRepository / This clone / NowhereAdvancedproject attachment
Per-Iteration Timeout1200 s0 to 3600 sImplementation & Workspace Setupnext coding/final-test attempt
Execution Setup Timeout1200 s0 to 3600 sImplementation & Workspace Setupnext execution-setup attempt
Max Bead Retries50 to 20Implementation & Workspace Setupnext execution/final-test attempt
Tool Input Max Chars4,000500 to 50,000Logginglive log formatting (cached briefly)
Tool Output Max Chars12,0001,000 to 100,000Logginglive log formatting (cached briefly)
Tool Error Max Chars6,000500 to 50,000Logginglive log formatting (cached briefly)

Manual QA ​

Manual QA is an optional human verification loop between final tests and integration. Its profile default is manualQaEnabled: true. Configuration and Project place it in their collapsed Advanced sections. Ticket controls expose it in Advanced and the Draft workspace until Start. All scopes offer only Enabled / Disabled; new project and ticket saves persist the selected boolean explicitly. Legacy unset values remain readable and display their resolved parent/default boolean until the user chooses an explicit value.

Hovering Enabled or Disabled explains the resulting workflow route, including whether LoopTroop creates a checklist and waits for user verification. The help button beside each Manual QA control explains that scope and opens this section in the locally served documentation started with the application.

Resolution is deterministic:

  1. a non-null ticket manualQaOverride wins;
  2. otherwise a non-null project manualQaOverride wins;
  3. otherwise the profile manualQaEnabled boolean is used.

On Start, LoopTroop persists both lockedManualQaEnabled and lockedManualQaSource (ticket, project, or profile). Only Draft tickets may change their override, and later profile/project edits cannot change the route of a started ticket. Existing in-progress tickets that do not have a locked value behave as disabled.

Manual QA Improvement drafts use the same explicit Enabled/Disabled choice for the new child ticket. Their collapsed Advanced control starts from the current effective project/profile value and is stored with the chosen P1 to P5 priority, so child creation does not depend on a later configuration change.

When the lock is disabled, TESTS_PASSED keeps the direct RUNNING_FINAL_TEST → INTEGRATING_CHANGES route. When enabled, it enters GENERATING_QA_CHECKLIST → WAITING_MANUAL_QA; a submitted failure creates QA-fix beads and loops through Coding and fresh final tests before the next checklist version.


LoopTroop Folder Ignore Policy ​

LoopTroop stores project state under /.looptroop/ and ticket-owned runtime artifacts under /.ticket/. The folder-ignore policy decides where LoopTroop appends rules for those two paths when a project is attached. It is a project setting, not a ticket setting, because every ticket and worktree for the project uses the same storage boundary.

The profile field is ignoreMode, and its built-in default is local (This clone). Configuration Advanced chooses the default for future projects. Project Advanced shows the same control after the selected folder has been validated as a Git repository, lets you change the choice before attachment, and saves the effective value with the project. Restoring existing LoopTroop state restores that saved choice. Configuration changes never rewrite an attached project's ignore destination.

ChoiceStored valueDestination and effect
RepositoryrepoAppends /.looptroop/ and /.ticket/ to the repository's tracked .gitignore. The file is visible to Git and, if committed, the rules apply to every clone.
This clone (default)localAppends the rules to this clone's Git exclude file, normally .git/info/exclude. Nothing is added to the project's tracked files.
NowhereskipDoes not add ignore rules. LoopTroop warns that its runtime folders can appear in Git status and must not be committed.

Rules are appended safely without deleting existing ignore content, and LoopTroop does not remove a rule automatically if the project setting later changes. Ticket initialization reapplies the project's saved destination to the main checkout. For either non-skip mode, if a new worktree still lacks effective rules, for example because a repository .gitignore change has not been committed yet, LoopTroop closes that gap through the shared Git exclude.

Both scopes present the policy as a single row, matching the other Advanced options: a short description on the left and a Repository / This clone / Nowhere selector on the right. Hovering a choice explains where it writes and what that costs, and choosing Nowhere adds a warning below the row. The ? beside the label summarizes what /.looptroop/ and /.ticket/ contain and where each choice writes; activating it opens this section.


AI Models ​

Configure providers, credentials and agents in OpenCode. Its v2 config uses the native providers and agents sections. LoopTroop asks the authenticated server for models it reports as available, then passes the selected model and variant through for each prompt. See OpenCode's provider configuration and agent configuration.

Main Implementer Model ​

Type: model selector
Required: yes

The main implementer is the primary model LoopTroop assigns to a ticket. LoopTroop validates and locks it when you press Start, then uses that same model from SCANNING_RELEVANT_FILES through final verification.

What it does:

  • Runs the initial single-model groundwork (SCANNING_RELEVANT_FILES) before any council phase starts.
  • Is automatically included in every council phase and always participates in drafting and voting.
  • Handles all coding iterations during CODING.
  • Runs the final verification pass in RUNNING_FINAL_TEST.

How to choose:

Pick the model you trust most for sustained reasoning and code generation. Other council members exist to challenge the plan quality; the main implementer is the one writing and validating the code, so reliability matters more than pure creativity here.

If the model supports effort or thinking variants (see Effort / Thinking Variant), prefer a higher-effort variant for complex tickets.

For OpenRouter models, LoopTroop supports the routing choices shown in the configuration UI, including :floor, :nitro, :thinking, :extended, and :free. None is selected by default, which sends the base model ID with no routing suffix. LoopTroop saves any selected suffix, highlights it again when Configuration is reopened, and registers that exact model ID with its managed OpenCode server before a ticket runs. Routing changes affect the selected model ID and its OpenCode registration; effort remains a separate per-slot setting.

If OpenCode is offline, you can save other profile edits while leaving the existing routing choice unchanged. Selecting a different routing choice still requires a live OpenCode check.

TIP

You can change the main implementer between tickets. The choice is locked per-ticket once work starts, so adjustments to the profile only affect future tickets.

See also: LLM Council → Main Implementer


Council Members ​

Type: model selector (1 to 9 slots, in addition to the main implementer) Required: at least 1 additional member

Council members are the additional models that participate in independent drafting and structured voting during the interview, PRD, and beads planning phases.

What they do:

  • Each member independently drafts an artifact (interview questions, PRD, or bead plan) without seeing other members' work.
  • Each member votes on anonymized drafts using a structured rubric.
  • The winning direction is refined and used as the planning artifact for the next phase.

What they do not do:

Council members do not participate in execution. Coding, final testing, and PR creation are all handled exclusively by the main implementer.

How to choose:

Diversity matters more than raw quality here. Mixing models from different families, sizes, or providers tends to surface more varied plans and catch more blind spots than stacking three instances of the same model.

The minimum viable council is the main implementer plus one additional member. The Min Council Quorum setting determines how many members must return a valid response before the pipeline trusts the result.

While a council step runs, you can stop or retry one member without affecting the others. A member you stop does not count toward quorum. See LLM Council → Stopping Or Retrying One Model.

The UI prevents duplicate picks across council slots, so if you cannot select a model twice that is intentional rather than a catalog bug.

The auto-included main implementer row shows its selected effort variant in muted text. Change that variant only in the Main Implementer section above.

TIP

Up to 9 council slots are available in addition to the main implementer, for a maximum council size of 10.

See also: LLM Council → Council Members


Effort / Thinking Variant ​

Type: variant selector (per model, optional)

Some models expose multiple effort or thinking modes (for example, minimal, low, medium, high, xhigh, or max). When a selected model advertises variants, an effort picker appears below that slot's model selector. The None choice is always available, selected by default, and selected again whenever you change that model; it leaves the provider's effort behavior unmodified. If a model exposes no variants, the control stays hidden.

What it does:

The selected named variant is passed as part of the model configuration when LoopTroop calls that model. Choosing None clears any saved override instead of sending a literal none variant. Higher-effort variants generally produce better reasoning at the cost of slower responses and higher token usage.

How to choose:

  • For the main implementer on complex or large-scope tickets, prefer a higher-effort variant.
  • For council members, a balance of one high-effort and one lower-effort member often gives diverse results without making every planning phase slow.
  • If a model times out repeatedly under AI Response Timeout, lower its effort variant before increasing the timeout. During a council step you can also stop a slow model, or retry it, without waiting for the timeout.

OpenCode Provider Recovery ​

These settings apply to OpenCode prompt execution across the workflow, including CODING. They cover planning, council/coverage prompts, execution setup generation, coding prompts, final-test generation, PR drafting, and other phases that use OpenCode.

OpenCode Retry Limit ​

Type: integer Default: 10 Range: 0 to 50

How many continuable OpenCode session.status retry events LoopTroop allows before it stops waiting for provider recovery and blocks the active prompt for human decision.

This is separate from Max Bead Retries and Structured Output Retries. It applies to provider/transport interruptions inside one OpenCode prompt, such as rate limits, usage limits, overload, temporary unavailability, timeouts, fetch failures, and socket resets.

When the limit is reached, LoopTroop routes the active phase to BLOCKED_ERROR with provider diagnostics. If the session is provably resumable, the UI can offer Continue; otherwise you fall back to Retry or Cancel. During CODING, provider stalls handled here do not consume the bead retry budget by themselves.

Trade-offs:

Lower (0 to 2)Higher (10 to 50)
Blocks quickly when a provider is unavailableGives OpenCode more room to recover internally
Saves time and tokens during hard rate limitsMay wait longer before manual recovery is offered
0 blocks on the first matching retry eventUseful for bursty providers with short retry windows

See also: OpenCode Integration → Prompt Runner


OpenCode Retry Grace Window ​

Type: integer (seconds) Default: 60 s Range: 0 to 3600 s

How long LoopTroop lets an OpenCode prompt sit in a continuable retry state with no real progress before it blocks, even if the retry count has not yet reached OpenCode Retry Limit.

The timer starts when OpenCode reports a matching retry status and is cleared by real prompt progress. Set it to 0 to disable the grace timer and rely only on the retry count.

Trade-offs:

Lower (0 to 10 s)Higher (60 to 3600 s)
Surfaces stuck retry loops quicklyAllows longer provider backoff windows
Better for interactive supervisionBetter for unattended runs with temporary provider load
0 disables the timerLong windows can delay manual intervention

See also: OpenCode Integration → Prompt Runner


OpenCode Max Steps ​

Type: integer
Default: 0 (no limit; OpenCode default)
Range: 0 to 500

Maximum number of steps OpenCode is allowed to perform per session. When the limit is reached, OpenCode instructs the model to summarize its work and close the session; LoopTroop then starts a fresh session to continue.

Steps vs messages: Each step is one full round-trip: the model reads the full context, decides which tools to call, and receives their results. Each step generates approximately two messages in the execution log (one assistant message with tool calls, one with tool results). So messages=25 in the log corresponds roughly to 12 to 13 steps.

What 0 means: LoopTroop does not touch opencode.json at all. OpenCode runs with no step cap and the model stops whenever it decides naturally. This is the default behavior. When a session ends without producing a text response (the model stopped mid-step), LoopTroop will automatically start a new session and show a visible notification in the ALL tab.

When to set a value: If you observe sessions running for a very large number of messages and then silently restarting, setting a cap (e.g. 20) ensures OpenCode wraps up and summarizes at a predictable point. A session that hits the configured limit produces a summary response, so the restart is cleaner than a natural mid-step stop.

Implementation detail: When opencodeSteps > 0, LoopTroop sets the cap in opencode.json at the root of the ticket worktree before coding starts. On an ordinary non-conflicting completion or recoverable error, it restores the recorded file; if the current bytes conflict with the restore marker, recovery preserves the edited file and sidecar and refuses a destructive overwrite.

If the project has no opencode.json of its own, LoopTroop creates one holding just the step cap. It does not add an opencode.json rule to a common Git exclude. While the valid restore marker exists, exact commit selection keeps the temporary root config out of bead and final candidate commits; the file can remain visible to ordinary Git status until cleanup.

When that cap-created file is edited, the restore marker records that the original file was absent and stays beside the edited file. Recovery refuses to remove or reset it until the ownership conflict is resolved; it does not treat the edited file as disposable just because LoopTroop created it.

If the project ships its own opencode.json, the cap is merged into it. Everything else in the file, including MCP servers, providers, permissions, and other agents, stays in force for the whole run. On an ordinary non-conflicting completion, the file is put back as it was; if LoopTroop is killed outright before that happens, the sidecar lets the next start restore it when the run-owned bytes are still unchanged. A conflicting edit remains visible with its sidecar for deliberate recovery. How the file is tracked in git is left alone.

The cap never reaches your git history. For as long as a valid marker is in place, opencode.json is kept out of the commits LoopTroop makes for each bead and listed among that commit's skipped files. Restoring the file afterwards would put the worktree right, but it could not take back a commit. During an ordinary non-conflicting retry, the worktree reset leaves the capped file alone and the cap is reapplied for the next attempt. If current bytes conflict with the marker, the destructive reset/recovery is refused instead; the edited file and sidecar remain available until the conflict is resolved.

A file LoopTroop cannot merge into is left exactly as it is, and the run continues with no step cap: unreadable JSON, a top level that is not a JSON object, an agent section shaped some other way, or a symlink. The ticket log says which it was. The same holds if the file changes while the run is going: that change is yours, so it is reported rather than overwritten, and your version from before the run is kept in the ticket directory until you deal with it. Ordinary capped retries continue when there is no conflict. A later bead can run without applying a fresh cap when no destructive reset is needed, while valid marker evidence keeps the root config out of bead and final staging. If the sidecar is missing after a restart, LoopTroop has no durable ownership evidence and leaves the file unattributed rather than guessing. Filesystem-equivalent casing follows the actual worktree paths; native Windows/macOS equivalent-case behavior is not claimed here.

Trade-offs:

Lower (5 to 15)Higher (30 to 100)
Sessions wrap up and summarize more frequentlyFewer session restarts overall
More predictable restart pointsModel may run longer before being forced to summarize
Useful for models that tend to drift in very long sessionsUseful when tasks genuinely need many uninterrupted steps
0 = no limit, same as not setting the value0 is the OpenCode default

See also: OpenCode Integration → Prompt Runner


AI Thinking ​

AI Response Timeout ​

Type: integer (seconds)
Default: 1200 s (20 minutes)
Range: 10 to 3600 s

The maximum time LoopTroop will wait for a model response in non-coding model-output phases. It covers relevant-files scanning, council drafting/voting/refinement, coverage and expansion prompts, interview QA prompts, execution setup-plan drafting/regeneration, final-test model prompts, and PR title/body drafting.

This setting does not govern coding attempts or PREPARING_EXECUTION_ENV workspace setup. Use Per-Iteration Timeout for coding and Execution Setup Timeout for pre-implementation workspace setup.

What happens when it expires:

The request is abandoned and the active phase handles the timeout according to its workflow. In council phases, timed-out responses do not count toward Min Council Quorum; if quorum is no longer met, the phase enters BLOCKED_ERROR. In single-model planning phases, the ticket blocks with timeout diagnostics. In RUNNING_FINAL_TEST, only model prompt waits use this setting; shell command execution remains governed by the execution/final-test timeout budget.

In a council step you can stop a slow model instead of waiting for its timeout. A stopped model does not count toward Min Council Quorum either. A model you retry gets the full timeout again, counted from its restart, so a step with a retried model can run longer than this setting. See LLM Council → Stopping Or Retrying One Model.

Trade-offs:

LowerHigher
Fail fast when a provider is stalled or slowTolerate larger context windows, heavy thinking variants, or slow providers
More likely to block on slow modelsLess likely to block due to transient slowness

When to change:

  • Increase if you are using high-effort thinking variants and see frequent timeout blocks.
  • Increase if your OpenCode provider has high network latency or rate-limited batches.
  • Decrease if you want fast failure feedback when a model is unavailable instead of waiting 20 minutes.

See also: LLM Council → AI Response Timeout


Min Council Quorum ​

Type: integer
Default: 2
Range: 1 to 6

The minimum number of valid council responses LoopTroop requires before it trusts a drafting or voting phase.

What "valid" means:

A model response is valid if it returns within AI Response Timeout and its structured output can be parsed without terminal errors. Malformed or timed-out responses do not count toward quorum, and neither does a model you stopped.

What happens when quorum is not met:

The phase enters BLOCKED_ERROR. This is intentional: a plan built from one draft when you configured two is not trustworthy, so LoopTroop refuses to advance silently.

If stopping a model would leave the step unable to reach quorum, the Stop confirmation warns you first. You can still stop it, and the step then fails this way when the round ends.

Trade-offs:

Lower (1)Higher (3 to 6)
Survives when one model is unavailableNeeds more of the council to be healthy and responsive
Lower diversity guaranteeStronger diversity guarantee
Useful if running a lean councilOnly practical with a full council of that size

WARNING

Setting quorum higher than your total council size guarantees permanent blocks. Keep quorum ≤ the number of configured council members (including the main implementer).

See also: LLM Council → Min Council Quorum


Max Interview Questions ​

Type: integer
Default: 50
Range: 0 to 50

Caps how many initial clarifying questions the compiled interview document can contain before the UI starts presenting them to you across one or more batches.

What it controls:

After COMPILING_INTERVIEW finishes, the interview document can have up to this many questions in the initial compiled checklist. The UI may present that checklist across multiple batches, but questions beyond the cap are not generated. This is a hard ceiling on initial intake depth.

Trade-offs:

LowerHigher
Faster intake for simple ticketsRicher context for the PRD and beads planning
May leave ambiguities unresolvedMore questions to answer before planning can start

When to change:

  • Lower for routine or well-scoped tickets where you already know the requirements.
  • Keep at maximum (50) for exploratory or large-scope work where ambiguity is costly later.
  • Treat 0 as an edge-case/testing value, not as the normal way to skip the interview. The workflow still expects a real compiled interview artifact; use Skip All during the interview itself if you want to advance with minimal answers.

See also: Ticket Flow → Interview


Structured Output Retries ​

Type: integer Default: 1 Range: 0 to 5

Controls how many automatic retry prompts LoopTroop may send after the first model response fails structured-output validation. The value is locked onto each ticket when it starts, so profile changes affect future tickets and unstarted tickets only.

This setting applies to structured-output repair paths such as council drafts/votes/refinements, relevant-files scan, interview batch generation, PRD/beads coverage, execution setup reports, final-test generation, PR drafting, and the completion-marker structured retry inside one coding iteration. It does not change coverage pass limits, coding bead iteration count, execution setup/final-test attempt budgets, or manual Retry from BLOCKED_ERROR.

Session behavior:

  • Validation errors normally use a continued session retry prompt so the model can correct only the malformed output.
  • Empty responses, provider/session errors, and transport-style failures use a fresh session where the original prompt is sent again.
  • Council draft/vote/refine retries are documented fresh-session structured retries by design.

Trade-offs:

Lower (0)Higher (2 to 5)
Fails fast and spends fewer tokensMore tolerance for malformed YAML/JSON or transient provider output
0 disables automatic structured repair promptsHigher values can delay surfacing persistent prompt/parser issues

AI Questions ​

Type: On / Off
Default: On
Profile field: aiQuestionsEnabled

OpenCode's question tool lets a running model stop mid-step and ask you something. LoopTroop runs unattended, so a stop with no end is a stalled run. This setting decides whether a model may ask at all; AI Question Wait decides how long it waits before the run carries on without you.

Configuration, Project, and New Ticket place AI questions and AI question wait in Advanced. The wait is an indented subitem directly below AI questions, without a separator. Labels, descriptions, and ? help links are on the left; controls are aligned to the right. Hover or focus a help link for an explanation; activate it to open the option's documentation. Configuration offers On / Off for AI questions; Project and Ticket add Inherit and show the effective choice and its source. The Draft workspace offers the same layout until Start. Tab focuses the selected choice in each group; arrow keys change the choice.

The two settings cascade independently, so a ticket can set its own wait while taking the on/off answer from its project. Each resolves the same way:

  1. a non-null ticket override wins;
  2. otherwise a non-null project override wins;
  3. otherwise the profile value is used.

On Start, LoopTroop freezes both values and where each came from: lockedAiQuestionsEnabled / lockedAiQuestionsSource and lockedAiQuestionWindow / lockedAiQuestionWindowSource (ticket, project, or profile). Only Draft tickets may change either override. A started ticket shows both read-only under Advanced Settings in its header, with the level each came from. A ticket that started before these settings existed has no locked values and may not ask at all: a run already in flight should not silently gain the ability to stop.

Three cases beat the setting, whatever it says:

  • The interview. It generates its own questions and has its own screen for them. A tool question there would put two unrelated kinds of question on screen at once. The exclusion is derived from the interview workflow group, so a status added to the interview later is covered without anyone remembering to.
  • Steps running the disabled tool policy. Those prompts only reformat text they were handed: compiling interview answers into questions, writing a pull request body, summarizing verification output. A step with nothing to investigate has nothing to ask about. See Tool Policy Layer.
  • The preflight capability probe. It is a diagnostic, not a workflow step.

What you see when a model asks:

A collapsible panel opens at the top of the ticket and pushes the workspace down. There is no modal. When more than one model is asking, each gets its own tab. The countdown appears once, in the panel header, because there is only one. Elsewhere in the app a slim bar slides down naming the ticket that is waiting.

On regular viewports, answer and skip controls stay visible in the panel header, to the left of the waiting count, while long questions scroll below. The panel can grow to half the viewport, and its header wraps on smaller screens. On very short viewports, the whole panel scrolls so its fields remain reachable. Send answer or Send answers submits only the selected model tab's request. Skip opens confirmation for that request, which can contain several questions; the button reads Skip this question or Skip this request (N questions).

When more than one question is waiting, Skip all covers every request pending across every model tab when you confirm, including questions that arrive while you enter a reason. The confirmation button reads Skip all N questions. You can give one optional reason, kept when switching model tabs and recorded against each skipped request. Bulk confirmation warns when refusing council members could leave the round below quorum and block the ticket.

While a skip is being sent, confirmation and reason editing are disabled. Back remains available and leaves confirmation without canceling requests already sent. If some requests fail, their questions stay pending and the panel shows each error. A later bulk confirmation covers all requests then pending, including new arrivals; completed requests are not retried. Back, collapsing the panel, or resolution of the requests tracked by confirmation clears its draft. Ctrl/Cmd+Enter in an answer or skip-reason field sends the selected request's answers or confirms the skip when that action is enabled.

On the board, the ticket moves to Needs Input and its status badge pulses blue, distinct from the red used for errors, because a question is not a failure. The ticket's workflow status does not change; only the board column does.

What happens when nobody answers:

The question refuses itself and the model carries on without an answer. The refusal is recorded in the ticket's skip trail under a timeout actor rather than under your name, along with the configured wait, the elapsed time, and every unanswered question the refusal covered. Skipping by hand takes an optional reason, recorded the same way. In a council phase a refused member may return nothing at all, which can drop the round below Min Council Quorum and block the ticket; the receipt says so, instead of leaving a bare quorum failure with no cause attached.

OpenCode's reject call carries only a request id, so a reason stays on the LoopTroop side. The model is never told why it was refused.

When to change:

  • Turn it off for fully unattended overnight runs where nobody will be watching, and every step should decide for itself.
  • Leave it on when you want a model to check an ambiguous requirement with you rather than guess, and you are around to answer.

AI Question Wait ​

Type: duration (whole minutes in the Custom control)
Default: 5 minutes
Range: 1 to 60 minutes; Custom requires whole minutes
Profile field: aiQuestionWindow (stored in milliseconds)

How long a question waits for you before the run carries on.

In Configuration Advanced, choose Default for 5 minutes or Custom to enter 1 to 60 whole minutes. Project and Ticket Advanced use Inherit / Custom and show the effective duration and its source. Ticket Inherit follows the project's effective wait; Project Inherit follows Configuration. Selecting Default or Inherit removes the custom override. Configuration treats a change between Default and Custom as an unsaved edit even when both use 5 minutes. The wait and the choice to allow questions resolve independently.

The wait controls are disabled when effective AI questions are Off, including when Inherit resolves to Off. Turning questions off shows the last valid duration and keeps the selected mode and any unfinished input. Inactive wait errors do not block saving. Turning questions back on restores the input and its validation.

Collapsing Advanced preserves unfinished input and validation. While questions are On, a blank, fractional, or out-of-range Custom wait blocks Configuration and Project saves, ticket creation, and Start. Closing a form with an invalid wait edit asks before discarding it. A short error stays visible below the Advanced heading while the section is closed. Enter a valid whole number or choose Default or Inherit to clear the error. In a saved draft, an invalid wait blocks Start; you can still save the description or change another setting.

In a saved Draft ticket, a valid custom wait saves when you leave the input, press Enter, or close the view, including with Escape. Changing the wait mode saves immediately. If you click another setting, save the description, or choose Start during a save, that action waits for the earlier save to succeed. A failed save stops queued actions and shows an error, even if Advanced is collapsed. Controls stay usable and keep keyboard focus during saves; they lock once Start is requested or while inherited settings load.

Custom accepts whole minutes from 1 to 60. The API uses the same rule, expressed as multiples of 60000 milliseconds. An unfinished custom edit survives background updates while you are typing.

Waiting does not use up the step's working time. While a question is pending, every clock on the ticket stops, and the elapsed wall time is credited back when it resolves. A step can therefore take its full timeout plus the time it spent waiting on you. The wait does not have to fit inside Per-Iteration Timeout, Execution Setup Timeout, or AI Response Timeout, and there is no validation tying it to any of them. This holds in every step that can ask, including the ones that do not manage a clock of their own.

Waiting is not counted as implementation time either. A question does not change the ticket's status, so a wait inside CODING would otherwise be recorded as coding, inflating the ticket's active duration and training the delivery estimate on throughput that never happened. It is recorded separately and shown on its own line in the ticket header when there is any.

One countdown per step, shared by every model asking inside it. It cannot be one per question: OpenCode's reply carries every answer in a single payload, so expiring question 2 would discard the answers already typed into 1 and 3. It is not one per request either, because a council seats several models in one step and that would put three countdowns on screen for one decision. A new model asking resets a running clock to full; it does not restart a stopped one.

Any interaction stops the clock, permanently. Switching model tabs, moving between questions, focusing an answer field, and pressing Stop timer are the same event. There is no resume. The ways out are answering and skipping, and until you do one of them the ticket waits in Needs Input for as long as it takes.

The deadline belongs to the server. Close the browser, come back two minutes later, and two minutes are gone. The page corrects for clock skew against a serverNow field sent with every timer update, but it never owns the clock.

Sessions survive a daemon restart, so questions and their countdown clocks do too. A countdown you had stopped stays stopped. One still inside its window keeps the time it had left. One whose wait ran out while the daemon was down is refused immediately rather than being handed another full window, so a restart cannot postpone an expiry indefinitely. A question whose session did not come back is refused under a system actor.

Trade-offs:

LowerHigher
A run left alone recovers sooner and keeps movingMore chance you see the question and answer it
More questions refused unanswered, and more council members returning nothingA ticket sits in Needs Input longer before it decides for itself

Coverage ​

Coverage settings control the self-checking loops that run after drafting. LoopTroop uses coverage passes to improve artifact completeness before you review and approve. All three domains (interview, PRD, beads) have independent pass budgets.

Coverage Follow-Up Budget ​

Type: integer (percent)
Default: 20 %
Range: 0 to 100 %

Limits how many additional coverage follow-up questions the VERIFYING_INTERVIEW_COVERAGE pass can add relative to the original compiled interview size.

Example: With Max Interview Questions = 50 and Coverage Follow-Up Budget = 20 %, the follow-up pass can add at most 10 extra questions (20 % of 50).

0% means 0 questions. When this setting is zero, interview coverage may still record gaps, but it must not generate follow-up questions.

What it controls:

After the initial compiled interview is complete, the coverage pass checks whether important gaps remain. If it finds gaps, it generates targeted follow-up questions. This setting prevents an unbounded coverage loop of "just a few more questions"; it does not limit how the initial compiled checklist is batched for presentation.

Trade-offs:

Lower (0 to 10 %)Higher (50 to 100 %)
Minimal extra questions after first roundDeep coverage at the cost of more follow-up rounds
Risks shipping a PRD with unresolved ambiguitiesMay feel exhaustive for simple tickets

When to change:

  • Raise for high-stakes tickets where missed requirements are expensive.
  • Lower or zero for tickets where you trust your initial answers are complete.

See also: Ticket Flow → Coverage Follow-Up Budget


Interview Coverage Passes ​

Type: integer
Default: 2
Range: 1 to 10

Caps how many times VERIFYING_INTERVIEW_COVERAGE may run follow-up cycles before LoopTroop stops extending the loop and advances to interview approval regardless of remaining gaps.

What happens at the cap:

When this limit is reached, LoopTroop moves to WAITING_INTERVIEW_APPROVAL with whatever coverage state exists. Any unresolved gaps are visible to you at approval time.

Trade-offs:

Lower (1 to 2)Higher (5 to 10)
Faster path to interview approvalMore thorough gap-filling before approval
May leave small coverage gaps for you to notice at approvalCan feel slow on well-scoped tickets

See also: Ticket Flow → Interview Coverage Passes


PRD Coverage Passes ​

Type: integer
Default: 5
Range: 2 to 20

Caps how many revision cycles VERIFYING_PRD_COVERAGE may run while reconciling the PRD against the winning model's Full Answers artifact.

Each pass reads the current PRD candidate, identifies gaps relative to that winning Full Answers artifact, and rewrites the candidate in-place. When coverage is clean or the cap is reached, LoopTroop advances to WAITING_PRD_APPROVAL.

What you see at approval:

If the cap was reached before coverage was clean, unresolved gap warnings appear on the PRD approval screen. You can still approve with gaps, edit the PRD manually, or click Fix gaps with AI to run one fresh targeted extra fix and one fresh coverage check. These approval-screen extra fixes are manual and unlimited; this pass setting only controls the automatic coverage loop before approval.

Trade-offs:

Lower (2 to 3)Higher (10 to 20)
Faster PRD approval, smaller token costHigher chance of a complete PRD before you review
More manual editing may be needed at approvalSlower for large PRDs with many gaps

See also: Ticket Flow → PRD Coverage Passes


Beads Coverage Passes ​

Type: integer
Default: 5
Range: 2 to 20

Caps how many revision cycles VERIFYING_BEADS_COVERAGE may run while reconciling the semantic bead blueprint against the PRD.

Once coverage is clean or this cap is reached, LoopTroop advances to EXPANDING_BEADS, which is a separate step that converts the blueprint into execution-ready bead records. If unresolved gaps are still visible on the later beads approval screen, you can click Fix gaps with AI to run one fresh targeted extra fix and one fresh coverage check; if the semantic blueprint changes, expansion is rerun so the approval plan stays current. These approval-screen extra fixes are manual and unlimited; this pass setting only controls the automatic coverage loop before approval.

TIP

EXPANDING_BEADS runs independently after VERIFYING_BEADS_COVERAGE finishes. Increasing this setting does not affect the expansion step; it only controls the semantic blueprint revision loop.

Trade-offs:

Lower (2 to 3)Higher (10 to 20)
Faster path to beads approvalHigher chance of a coverage-clean blueprint
More likely to miss PRD requirements in the bead planSlower for large or complex PRDs

See also: Ticket Flow → Beads Coverage Passes


Pre-Implementation ​

Git Hook Policy ​

Type: four-choice project policy Default: Check (recommended)

Choose how LoopTroop handles repository hooks. The linked buttons appear in Configuration Advanced and Project Advanced; the selected choice is visibly highlighted as soon as each screen opens. Configuration supplies the initial choice for a new project, and the project saves that concrete choice. Tickets do not expose a Git-hook control. Hovering each button summarizes whether hooks are bypassed, whether explicit checks run, and whether a failure can block.

ChoiceStored valueWhat LoopTroop does
Observeobserve_onlyBypasses hooks on LoopTroop-owned Git operations and records that explicit validation was skipped
Check (recommended)validate_advisoryBypasses native hooks and runs the visible approved validation commands; failures and timeouts are warnings
Requirevalidate_requiredBypasses native hooks and blocks when an approved validation command fails or times out
Runuse_native_hooksLets Git run repository hooks normally on LoopTroop-owned commits and pushes; hooks may block or modify the Git operation

Check, Require, and Run are not the same. Check and Require turn off hooks for internal Git commands and perform the reviewed commands explicitly, where output and file effects are auditable. Check continues with a warning; Require blocks. Run leaves repository hooks active inside Git itself.

When a project is created without an explicit API/CLI choice, LoopTroop copies the current profile gitHookPolicy; the built-in fallback is validate_advisory. An explicit project choice wins. LoopTroop snapshots that project policy when a ticket starts, so later project edits cannot alter the run.

Execution setup shows the locked project policy and detected hooks as read-only, backend-authoritative fields. You may add, edit, reorder, or remove validation commands. Raw-YAML or structured edits that try to change git_hooks.policy are replaced with the locked project policy when the plan is parsed or saved. An unknown hook never causes LoopTroop to invent an ecosystem-specific command. Removing all validation commands is allowed and the approval receipt records that exact decision.

Check and Require run their approved commands under a snapshot of the worktree and the Git index, and put both back the mutations that run introduced. If the snapshot cannot be taken, validation is refused rather than run unprotected: Require reports it as a blocking error and Check as a warning, and the commands do not run at all. If validation is interrupted, the persisted marker binds the worktree, Git directory, index/worktree trees, and initial untracked set. Invalid or escaped markers fail before recovery writes; unknown untracked additions stay intact and reentry is refused until they can be attributed safely. If the restore itself fails, that is reported alongside whatever validation found, and blocks under either choice, because the next step would otherwise start from hook output nobody asked for. This protection applies to the approved validation path and does not promise that unrelated hook commands are harmless or fully transactional.

This policy affects only LoopTroop's internal Git operations. It does not alter the repository's hook configuration for your own Git commands. The ? beside each control opens this section.

An unresolved restore from a previous validation blocks both Check and Require. The refusal includes the retained recovery marker's location and explains which worktree changes need attention before retrying.


Implementation & Workspace Setup ​

Per-Iteration Timeout ​

Type: integer (seconds)
Default: 1200 s (20 minutes)
Range: 0 to 3600 s

The maximum runtime for a single bead attempt in CODING, including implementation, agent-owned bead-scoped checks, and structured completion. Planned test commands are starting guidance and may be adapted when repository evidence requires it; LoopTroop does not independently rerun them after done/pass. If the deadline expires before valid completion, LoopTroop treats it as a failed iteration and routes it through the standard Ralph retry path. This timeout is separate from OpenCode/provider interruption handling, which can preserve an addressable session for Continue. Ticket-level Final Testing remains a separate mandatory gate.

What retry means here:

LoopTroop generates a context wipe note summarizing the failure when possible, abandons the timed-out session so stale completions cannot finalize the bead, and attempts a safe reset to the bead's start snapshot before opening a fresh OpenCode session and retrying up to Max Bead Retries times. A conflicting OpenCode step-cap marker can refuse that destructive reset and leave CODING blocked until recovery is safe. Repeated iteration timeouts consume this same attempt budget; once it is exhausted, CODING blocks with BEAD_RETRY_BUDGET_EXHAUSTED.

Trade-offs:

LowerHigher
Fails faster on stuck sessionsAllows more time for large beads or slow models
Wastes less time on runaway coding loopsRisk of waiting a long time before a stuck session is aborted

When to change:

  • Increase for beads that involve large test suite runs, slow builds, or high-latency tool calls.
  • Decrease for projects where you want fast failure feedback and the model tends to get stuck.
  • Setting to 0 disables the timeout (not recommended for production use).

See also: Beads & Execution → Per-Iteration Timeout


Execution Setup Timeout ​

Type: integer (seconds)
Default: 1200 s (20 minutes)
Range: 0 to 3600 s

The maximum total active-work budget for one PREPARING_EXECUTION_ENV attempt, which runs after the current-host setup plan is approved and before coding begins. One deadline is shared by session acquisition, prompts, provider recovery, continuations, structured-output corrections, setup-scoped online lookup, backend command/probe/hook validation, worktree inspection, and retry-note generation. None of those steps restarts the current attempt's clock.

What execution setup does:

The setup phase can materialize user-approved non-reproducible ignored or untracked inputs, install user-space toolchains under .ticket/runtime/execution-setup/tool-cache, warm caches, build native dependencies, or prepare repository-local runtime artifacts. Commands are stored as either a direct program with arguments or a script for an explicit POSIX, Command Prompt, or PowerShell shell. Working directories stay repository-relative; environment variables and PATH additions are structured data applied directly to subprocesses. A host-specific launcher is generated only when the coding agent needs the same prepared environment. The plan targets the detected current host, including WSL as Linux, while remaining agnostic to programming language, build system, and project layout. Workspace-input previews use conservative default file-count and size limits; a reviewed per-input override can allow a larger copy.

The long setup timeout remains available for real provisioning work such as toolchain downloads. When a completed setup turn contains only a short progress update, LoopTroop continues the same session up to two times without consuming a setup attempt or structured-output repair, but each continuation receives only the time remaining on the current attempt. Completed but malformed results use the separate Structured Output Retries setting under that same deadline. OpenCode Retry Limit and Retry Grace Window still apply within each prompt, but cannot extend the setup attempt beyond its deadline. A third progress-only response fails that attempt with a plain incomplete-setup explanation. Actionable blocked results can use the normal setup-attempt budget; a blocked result proving that no safe provisioning path exists stops immediately.

Every genuine automatic, tooling-persistence, manual, or user-requested retry receives a new full Execution Setup Timeout budget. When setup exhausts its automatic retry budget, Retry with extra note... can grant one manual setup attempt. This does not raise or replace the configured retry budget. It sends the entered text directly to the preserved setup session for that one attempt.

When the deadline expires, LoopTroop stops scheduling new setup work and returns a setup-timeout error. Process termination, session cleanup, safe worktree reset, and approved-input rematerialization may finish just after the deadline so a later retry starts safely; cleanup does not consume the new attempt's budget. A timeout before session creation is still an ordinary failed setup attempt and is eligible for configured retries.

Trade-offs:

LowerHigher
Fails fast if setup is stuck or misconfiguredAllows more time for heavy installs or slow network downloads
Fine for repos with no heavy setup stepNeeded if setup involves large dependency downloads

When to change:

  • Increase for projects with heavyweight setup steps such as installing toolchains, running docker pull, or bootstrapping large node_modules.
  • Leave at default for most repos where setup runs in seconds or is not needed.
  • Setting to 0 disables the aggregate setup deadline; existing command-level safety limits still apply.

See also: Beads & Execution → Execution Setup Timeout


Max Bead Retries ​

Type: integer
Default: 5
Range: 0 to 20

NOTE

Current behavior. The automatic bead-response continuation scope and finite/zero semantics below describe the current implementation. User-facing Continue across workflow phases is separate and is not counted by this cap.

How many iteration attempts LoopTroop allows for a failing bead before it enters BLOCKED_ERROR. Within each bead iteration, a finite value separately caps automatic bead-response continuation turns; 0 means unlimited for that automatic path. The same limit is also used for final-test retries in RUNNING_FINAL_TEST.

What "fresh session" means:

Each ordinary, safe retry discards the polluted conversational state from the failed attempt, resets the worktree to the bead's start commit, opens a brand-new OpenCode session, and starts over with the context wipe note from the previous attempt as context. A conflicting step-cap marker can refuse the destructive reset and preserve the edited config and sidecar instead. See Beads & Execution: Bounded Ralph-Style Retry for the full design rationale.

Startup and manual-retry recovery can avoid a fresh attempt when the interrupted bead already has a current matching bead_execution checkpoint or an explicitly preserved session continuation. In those cases LoopTroop finalizes the checkpointed result or continues the exact session. An otherwise unresumable in-progress attempt is appended to Failed Iteration Notes, safely reset, and advanced to the next iteration under this retry budget. Its replacement receives a fresh per-iteration timeout window.

Trade-offs:

Lower (0 to 2)Higher (10 to 20)
Fails fast, lower token costMore attempts before giving up
Less tolerance for transient model failuresUseful for flaky tests or non-deterministic environments
0 means unlimited automatic continuation and needs deliberate useHigh values can mask persistent coding problems

When to change:

  • Lower for tickets in well-understood codebases where repeated failures usually indicate a real problem, not a fluke.
  • Raise for greenfield work, unstable test suites, or providers with high per-call variance.
  • Set to 0 only when unlimited automatic continuation is intentional; a finite value keeps that path bounded.

See also: Beads & Execution → Max Bead Retries


Logging ​

These three settings control how much of each tool call is stored in the LoopTroop logs. They do not affect what the model sees during execution; they only control what is persisted for display in the UI and diagnostics.

The backend reads these caps live from the profile, but it caches them briefly to avoid a database read on every stream event. In practice, a change usually shows up quickly without requiring a restart, but it may not affect lines already emitted moments earlier.

Tool Input Max Chars ​

Type: integer (characters)
Default: 4,000
Range: 500 to 50,000

Hard cap on the number of characters stored for tool inputs in the execution log. Input beyond this limit is truncated at log write time.

When to change:

  • Increase if log entries for write-heavy tools (large file writes, bulk inserts) are being cut off and you need the full content for debugging.
  • Decrease to reduce database size in long-running or high-throughput tickets.

Tool Output Max Chars ​

Type: integer (characters)
Default: 12,000
Range: 1,000 to 100,000

Hard cap on the number of characters stored for tool outputs in the execution log.

Tool outputs are typically larger than inputs (think: test run output, command stdout, file read results), which is why the default is higher than the input cap.

Internal SYS > CMD entries are logged after command completion. Quiet deterministic commands use concise summaries, while real stdout/stderr remains capped here.

When to change:

  • Increase if you need to see the full output of long test suites or verbose build commands in the log.
  • Decrease for projects where tool outputs are consistently short and you want to reduce storage pressure.

Tool Error Max Chars ​

Type: integer (characters)
Default: 6,000
Range: 500 to 50,000

Hard cap on the number of characters stored for tool errors in the execution log.

Error output is usually more compact than stdout but often more important to preserve for debugging, which is why the default is between the input and output caps.

When to change:

  • Increase if stack traces or compiler errors are being truncated in a way that makes debugging difficult.
  • Decrease if error output is consistently short for your stack.

See also: Beads & Execution → Tool Log Truncation

LoopTroop documentation for the current runtime.