ReadonlycachedReadonlydirtyMost recent error from a refreshFromGist() attempt, or null when the
last attempt succeeded or was skipped by the throttle. Lets callers
(StateManager) distinguish "throttled, nothing new to see" from "fetch
failed, you're now operating on stale state" without changing the
existing boolean return contract (#1193).
Bootstrap the Gist store: locate or create the backing Gist, populate the in-memory cache, and write the local cache file.
Bootstrap with migration from an existing local state. If a Gist already exists (found via local ID or search), uses it — no migration needed. If no Gist exists, creates one seeded with the provided existingState instead of a fresh state.
OptionalanalyzedIssueConversations?: { analyzedAt: string; repo: string; url: string }[]OptionalclosedPRs?: {Opt-in gate for the auto-format-before-push hook (#1045). Default false: the hook does nothing on every push unless the user explicitly enables it.
Repos (owner/repo) to softly downrank in discovery results (#1464).
Milder than excludeRepos' hard filter: scout pushes matches below
equally-recommended candidates but does not remove them, and a strong
affinity boost can still outweigh the penalty (scout #168).
Threaded to scout via scout-bridge.ts.
Issue label types (e.g. "bug", "good first issue") to softly boost in
discovery ranking, matched case-insensitively against issue labels
(scout #168 / #1464). Does not filter results or change viability
scores. Threaded to scout via scout-bridge.ts.
OptionaldiffToolCustomCommand?: stringOptionalexcludeOrgs?: string[]Threshold (in minutes) for the SessionStart PR health one-liner (#1255).
The cached digest only refreshes when the user runs /oss; SessionStart
fires every session. Without a freshness gate the line drifts arbitrarily
stale between runs. When the cache is older than this many minutes (and
not yet 7 days old, which keeps the existing catch-up nudge), the line is
suppressed entirely. Default 30 minutes.
OptionalissueListPath?: stringOptionallocalRepoScanPaths?: string[]OptionalreviewMaxPasses?: numberConvergence cap for the multi-agent review loop in
workflows/dispatch-review.md (#1275). When unset, the workflow
falls back to per-mode defaults (5 for diff, 3 for plan). Lower
values shorten the loop at the cost of skipping later iterations
if findings persist; higher values give the loop more chances to
converge before bailing. Optional — leave unset to use the
defaults.
Optionalscope?: ("advanced" | "beginner" | "intermediate")[]OptionalsetupCompletedAt?: stringOptionalskippedIssuesPath?: stringOptional Ollama HTTP host override. Defaults to http://127.0.0.1:11434
when empty. Useful when Ollama runs on a different machine on the
local network.
Optional Ollama model for SLM pre-triage during issue vetting (#1122).
Empty disables the feature. Recommended: gemma4:e4b (default for
capable hardware), gemma4:e2b or qwen3:1.7b for low-RAM machines.
Threaded through to scout via the bridge in scout-bridge.ts.
OptionalstarredReposLastFetched?: stringOptionalstatusOverrides?: Record<OptionalgistId?: stringOptionallastDigest?: {OptionallastDigestAt?: stringOptionallastStrategyAt?: stringISO timestamp of the most recent computeStrategy invocation
embedded in a daily run output (#1270). The cadence gate in
daily.ts consults this — strategy snapshots fire every 30 days OR
when 5+ PRs have merged since the last snapshot, whichever comes
first. Below STRATEGY_MIN_PRS merged PRs the gate stays
silent regardless of cadence.
OptionallocalRepoCache?: {OptionalmergedPRs?: {OptionalmonthlyClosedCounts?: Record<string, number>OptionalmonthlyMergedCounts?: Record<string, number>OptionalmonthlyOpenedCounts?: Record<string, number>OptionalprFollowUpHistory?: Record<Per-PR follow-up history (#1277). Keyed by PR URL. Each entry
records a tier-bucketed follow-up that the user drafted (and
presumably posted via draft-review-post). The dormant-pr
workflow reads this before drafting to enforce the
one-follow-up-per-timeframe rule documented in
skills/pr-etiquette/SKILL.md.
OptionalworkflowState?: {Pause-point snapshot for resumable workflows (#1280). Set when
the user picks "Done for now" mid-workflow; cleared when the
workflow completes or the user explicitly discards. The router
reads this on every /oss invocation and offers Resume /
Restart / Discard when present.
BootstrapResult extended with migrated: true if a new Gist was created from local state
Read a freeform document from the in-memory cache. Returns null if the file has not been loaded (or does not exist in the Gist). Synchronous — all Gist contents are loaded into memory at bootstrap.
Return the resolved Gist ID (available after bootstrap).
Return all filenames in the in-memory cache whose names start with prefix.
Useful for listing all guidelines files (e.g. prefix guidelines--).
Mark a file as dirty so it will be included in the next push() call.
Push all dirty files to the backing Gist.
Behavior:
If-Match header (#1510). The
Gist PATCH endpoint rejects conditional headers on unsafe methods
with HTTP 400, so the server cannot enforce optimistic concurrency.state.json is among the dirty files, push() re-reads the Gist
first and compares the remote state.json against the baseline
captured at our last fetch. If it moved under us, another machine
wrote concurrently and push() throws GistConcurrencyError
instead of clobbering — preserving the StateManager compare-and-swap
contract (#1235). The local mutation stays in memory so the caller
can refreshFromGist() and reapply. There is a small unavoidable
TOCTOU window between the re-read and the write (the Gist API offers
no atomic conditional write), but it is far narrower than the
last-fetch-to-push window the dropped If-Match covered.files parameter is a partial update, so a freeform-only push needs
no re-read and cannot clobber another file.false.Returns true on success (or when there is nothing to push).
Returns false if a push fails on both attempts.
Throws GistConcurrencyError when state.json moved remotely
since our last fetch (#1235, #1510).
Throws GistCorruptError when the pre-write re-read finds a
corrupt remote (so the caller does not retry against it).
Throws if the Gist ID has not been resolved yet (bootstrap not called).
Re-fetch the Gist and update the in-memory cache. Throttled to at most once per 30 seconds — ATTEMPTS, not just successes: a failed fetch stamps the throttle too (#1443), so an outage does not turn every SPA poll into an immediate full re-fetch.
Returns a discriminated union so callers can tell apart the four outcomes that previously collapsed into a single boolean (#1209 L9):
{ status: 'refreshed' } — fresh data loaded successfully.{ status: 'no-gist' } — store not in Gist mode (e.g. degraded).{ status: 'throttled', sinceLastMs } — within the 30s throttle.{ status: 'error', error } — fetch attempt failed.Write a freeform document into the in-memory cache and mark it dirty
so it will be included in the next push() call.
Stage new state JSON for the next push(). Updates the in-memory cache
for state.json and marks it dirty.
Gist-backed state store with in-memory file cache and local write-through.