Skip to content

Configuration ​

Stoat is an ASP.NET Core application, so everything below is ordinary .NET configuration: an appsettings.json in the folder you start it from, environment variables (Stoat__DataPath, with a double underscore for each :), or command-line configuration. Every key has a working default, so nothing needs to be set to get started.

The store ​

KeyDefaultWhat it does
Stoat:ConnectionString—A SQLite connection string. Wins over Stoat:DataPath when set.
Stoat:DataPath~/.stoat/coordinationDirectory for stoat.db when no connection string is given.
Stoat:LiveUpdatestrueLets the await_* tools wake the moment a fact changes, and pushes changes to the web UI. Leave it on: with it off, waiting agents and open pages no longer hear about changes as they happen. Plan status stays correct either way.

The store is one SQLite file, created on first run. There is no database server to install.

Ports ​

KeyDefault
Stoat:RunReceiverUrl (or STOAT_RUN_RECEIVER_URL)http://localhost:5527: where Stoat receives Bobcat runs. Never 5525, which is bobcat ui's
ASPNETCORE_URLSunset: Stoat binds http://localhost:5526 and the run receiver

To move only the receiver, set Stoat:RunReceiverUrl or STOAT_RUN_RECEIVER_URL. To move coordination off 5526, set ASPNETCORE_URLS. It replaces both addresses, so list the receiver in it too (http://localhost:6526;http://localhost:6527). Use the environment variable: a --urls argument on the command line has no effect. Every route is served on every bound port.

Binding an address other machines can reach (http://0.0.0.0:5526, a LAN address) serves them, and a Stoat that other machines reach is Stoat Team, which needs a licence: see Licence. On localhost, the default, it is free.

Observation ​

Stoat watches GitHub, nuget.org, npmjs.org and the runs it receives, and records something only when what it sees differs from what it last saw.

KeyDefaultWhat it does
Stoat:GitHubTokenGITHUB_TOKEN, else GH_TOKEN, else gh auth tokenToken for issue and PR observation, and for the GitHub text a zoomed-in node shows. With none of these, GitHub is not observed at all, issue and PR nodes read unknown, and the startup log says so.
Stoat:GitHubTokenFromGhtruefalse stops Stoat from asking a signed-in GitHub CLI for its token.
Stoat:GitHubPollSeconds60How often GitHub is swept: one GraphQL query per repository a plan references. Open issues and pull requests are read on every sweep; closed and merged ones every 15 minutes, so a reopened issue can take that long to show. When GitHub's rate limit is spent, sweeps pause until it resets, and the plan page says so.
Stoat:NuGetPollSeconds60How often the package feeds — nuget.org, npmjs.org and any configured feed — are polled.
Stoat:Feeds:{name}:Url / :Path / :RegistryA named feed a publish node can reference: a NuGet V3 service index, a local folder of .nupkg files, or an npm registry. Username/Password authenticate it; for npm, Password is the auth token. nuget.org and npmjs.org need no configuration.
Stoat:RunObservationBackstopSeconds300Runs are observed as they arrive, so this is only a safety net. It catches a run whose publisher went silent (an orphaned run), which no arriving event can announce.
Stoat:BobcatUrl—Read runs from a run console on another server instead of this process's own receiver. Leave it unset unless runs are received somewhere else.
Stoat:BobcatPollSeconds15How often that remote console is polled.
Stoat:RepositoryIconRefreshHours24How often each repository Stoat knows is looked at for an icon of its own: one REST tree read per repository through the GitHub token, and the file only when it changed. No GitHub token, no icons.
Stoat:IconsPath~/.stoat/iconsWhere the repository icons are kept, with an index of what each look found, so a restart asks GitHub nothing until an entry is due.
Stoat:Pollerstruefalse runs no pollers at all: nothing is observed, which is only useful for a test host.
Stoat:ObservationHistoryEvents100How many recent observations Stoat keeps for each observed thing (an issue, a feed, a session) beside its latest state. Once a day older ones are compacted away; nothing reads them. A negative value turns compaction off.
Stoat:ObservationRetentionHours24How often that compaction runs. The first run is Stoat:ObservationRetentionDelaySeconds (600) after startup.

Plans and sessions ​

KeyDefaultWhat it does
Stoat:PlansPath (STOAT_PLANS)~/.stoat/plansA directory of plan YAML, imported at startup and on POST /api/plans/rescan. It only seeds: a file creates a plan the store has never had, and is otherwise ignored, because the store is the master copy.
Stoat:PurgedPath~/.stoat/purgedWhere a purged plan's YAML is written before it is deleted.
Stoat:ClaudeConfigPathCLAUDE_CONFIG_DIR, else ~/.claudeClaude Code's directory, read for session observation.
Stoat:SessionPollSeconds5How often sessions are read.
Stoat:SessionActivitySeconds90How recently a transcript must have changed to read as activity.
Stoat:AskPersonParkSeconds240The longest one ask_person call parks before it answers pending with the question's id. Kept under the 300 seconds an MCP client commonly allows a tool call, so the client never cuts the call off; the question stays open either way.

Starting runners from the plan page ​

A repository's band on the plan page can start stoat run-plan on this machine (Starting a runner from the page).

KeyDefaultWhat it does
Stoat:RunnerStartstruefalse turns the page's Start… off on this server: the band shows the command to run in a terminal instead.
Stoat:RunnerLogsPath~/.stoat/runnersWhere a started runner's output goes, one {plan}-{owner}-{name}-{time}.log per start.
Stoat:LaunchersPath~/.stoat/launchers.jsonThe launcher profiles a started runner's --launcher is checked against.
Stoat:RunnerExecutablethe running stoatThe command a start runs, when it should not be the process the server runs as.

Notifications ​

When something waits on you, you should hear about it wherever you are. The top bar's waiting on you badge is on every page; these reach further. Nothing leaves the machine unless a webhook or Discord is set.

KeyDefaultWhat it does
Stoat:Notifications:Desktopon on macOS, off elsewhereAn OS notification on this machine. On macOS it uses terminal-notifier when it is installed (brew install terminal-notifier): the notification says Stoat, a click opens the node's page, and a repeat replaces the earlier one. Without it, osascript posts it, and macOS shows it as Script Editor's. notify-send on Linux. false turns it off.
Stoat:Notifications:Discord:Webhook—A Discord channel's webhook URL. Each notification is an embed with the plan, node, repository and a link to the node, in the plan's colour, and nothing in it can ping anyone. Always opt-in; keep it out of plans and commits.
Stoat:Notifications:Webhook—A URL each notification is POSTed to: ntfy, a Slack incoming webhook, anything that takes a POST. Always opt-in.
Stoat:Notifications:WebhookFormatjsonjson (a text field Slack reads, plus the fields) or text (the sentence alone, as ntfy shows it).
Stoat:Notifications:Kindsquestion, give-up, review, person, stalled, limit, main-red, driftWhat notifies: question (an agent asks you), give-up (the runner gave up on a node), review (a manual-review PR waits for you, or an agent's PR the runner could not fix or merge), person (a node of yours came ready), stalled (a plan with work waiting and nothing running), limit (a usage limit), main-red, drift, and go-ahead and cloud, which are off by default. A callout's own name (fix, usage-limit, unmergeable) still selects it.
Stoat:Notifications:BaseUrlhttp://localhost:5526Where Stoat is, for the link to the node's page.

Each thing notifies when it appears, and again only after it went away and came back. A disconnected runner's callouts never notify. An agent's ask_person question waiting on a person notifies as question with no runner at all. When more than five are due at once (Stoat restarting with forty PRs open, say), the most urgent four are sent and the rest are summed up in one.

Runs and the Event Model ​

The run receiver uses the same Monitor: / BOBCAT_MONITOR_* names as Bobcat's own run console.

KeyEnvironment variableDefaultWhat it does
Monitor:DataPathBOBCAT_MONITOR_DATA~/.bobcat/monitor/runsRun archives and the Event Model store.
Monitor:RetentionDaysBOBCAT_MONITOR_RETENTION_DAYS14Ages out run archives that have not changed for this many days. The only setting that ever deletes an archive file. 0 turns aging off.
Monitor:RetentionRunsBOBCAT_MONITOR_RETENTION_RUNS10How many runs the receiver lists per job (a repository plus a suite), so a busy repository cannot push a quiet one's runs out. Older runs are ejected: their archive moves to ejected/ and is not deleted.
Stoat:EventModelStaleAfterDays7How far a producer's Event Model half may trail the newest half of its model before it is flagged stale. Flagged, never dropped.

The command-line tools ​

stoat gate exec, stoat gate run, stoat warnings push, stoat run-plan and stoat runner are clients of a running Stoat, and find it from the environment:

VariableDefaultRead by
STOAT_URLhttp://localhost:5526stoat gate exec, stoat gate run and stoat warnings push, unless --url is given (run-plan takes --url only)
STOAT_RUN_RECEIVER_URLhttp://localhost:5527everything that adds Stoat's receiver to BOBCAT_MONITOR_URL, and stoat runner
BOBCAT_RUN_TAG—stoat gate exec: the gate to report for, {plan}/{node}; run-plan sets it for each agent

Launcher profiles for run-plan are ~/.stoat/launchers.json (or --launchers); see Launchers.

Licence ​

KeyEnvironment variable
JasperFx:LicenseKeyJASPERFX__LICENSEKEY

Stoat needs no key on its own machine. A server other machines reach is Stoat Team, which needs a CritterStack licence; one key serves Stoat and CritterWatch. The key is read once at startup, so restart after setting it, and a server in the Development environment needs none. The 0.6.0 preview does not check it yet. See Installation.

Memory recall ​

recall is a full-text search over each memory's title, tags and body, matching whole words and the start of longer ones (wolverine finds WolverineFx), best match first. The stoat tool ships without an embedding model, so there is no semantic search and nothing to configure.

Licensed under the Business Source License 1.1.