Configuration
junco reads one JSON file: ~/.junco/config.json, resolved from the
environment only — the working directory never matters, and the deprecated
--config flag is ignored. A legacy ~/.config/junco/config.json
(respects XDG_CONFIG_HOME) keeps working until
junco data migrate moves it. Every field is optional — omit a key and its
default applies. The guided way to produce the file is the setup walkthrough
(junco dashboard on a first run); the headless way is
junco config init.
Levers marked live apply on the daemon's next poll after the file changes — no
restart. Levers marked restart need junco restart;
junco status lists any pending ones. Inspect and edit from the command line:
junco config list junco config get worker.pollIntervalSeconds junco config set worker.dailyBudgetUsd 5
A minimal config is the empty object {} — local endpoint, sandbox on, GitHub
bridge off. A typical hosted-catalog setup touches three things:
{
"model": { "id": "<provider>/<model-name>" },
"worker": { "dailyBudgetUsd": 5 },
"github": {
"enabled": true,
"repos": [{ "nwo": "acme/reef-api", "path": "~/code/reef-api" }]
}
}
junco config list print the real ones. An unset model.baseUrl means
the local default, http://127.0.0.1:1234/v1 — any OpenAI-compatible endpoint
works.
Deprecated path keys (vaultRoot, juncoSubdir,
observability.stateDir, git.worktreeRoot,
github.externalReposRoot) still work, warn once at startup, and are flagged by
junco doctor; junco data migrate unifies them under
dataDir. TOML configs are no longer read — a nearby config.toml
is a startup error, not a silent ignore.
Environment variables
JUNCO_LOG_JSON=1- Force JSON log lines even on a TTY.
GH_CONFIG_DIR- Injected by the daemon for bot-account GitHub traffic; not yours to set.
$VISUAL/$EDITOR- Editor opened by
junco analyze edit. XDG_CONFIG_HOME- Relocates the default config directory.
- provider key vars
- Hosted catalog models read their provider's conventional env var when
model.apiKeyis unset;model.apiKeyalso accepts a literal or a"$ENV_VAR"reference.
Every lever
Generated from junco config list at the version stamped below — names, types,
defaults, and descriptions are junco's own. read-only marks
structured levers you edit in the file directly rather than via
junco config set.
top-level
dataDirstring- Unified data root — queue, reviews, outbox, mirror, clones, worktrees, transcripts. default undefined · restart
Everything junco keeps on disk resolves under this one root (default
~/.local/state/junco):
<dataDir>/ queue/ inbox · processing · done · failed review/ parked assess findings · parked analyze drafts outbox/ queued GitHub writes (+ dead/ after 3 attempts) clones/ watched/ and external/ managed checkouts worktrees/ ephemeral per-ticket build worktrees transcripts/ <ticket-id>.jsonl per-run event streams watchlist.json · spend.json · worker.log · migrated.json
The root writes itself a .gitignore (*), so pointing
dataDir inside a git checkout can never dirty a commit. junco data
prints the live tree with counts and provenance; junco data migrate folds any
legacy-key layout into it.
vaultRootstring- Root directory Junco keeps its ticket queue under. default undefined · restart
juncoSubdirstring- Subdirectory under vaultRoot holding inbox/processing/done/failed. default "Junco" · restart
toolsstructured, read-only- Tool allowlist granted to the coding agent. default ["read","bash","edit","write","grep","find","ls"] · live
updateCheckboolean- Enable periodic update checks for new Junco releases. default true · live
model.*
model.idstring- Provider-prefixed model id, e.g. <provider>/<model-name>. default "local/my-model" · live
model.sourcestring- Model resolution mode: auto (catalog for non-local providers without an explicit baseUrl), catalog, or inline. default "auto" · live
model.modelsJsonstring- Path to a Pi-style models.json; when set, provider+model load from that file and the inline capability fields are ignored. default undefined · live
model.apistring- Pi API style, e.g. openai-completions. default "openai-completions" · live
model.baseUrlstring- OpenAI-compatible /v1 endpoint base URL. Unset = local default (http://127.0.0.1:1234/v1); setting it forces inline resolution. default undefined · live
model.apiKeysecret- API key for the inference endpoint. Literal, "$ENV_VAR" reference, or unset to use the provider's env var (e.g. <PROVIDER>_API_KEY) for hosted catalog models. default undefined · live
model.retry.maxRetriesnumber- SDK auto-retry attempts on transient provider errors; unset = SDK default (3). default undefined · live
model.retry.baseDelayMsnumber- Base delay for SDK auto-retry backoff in ms; unset = SDK default (2000). default undefined · live
model.reasoningboolean- Whether the model supports reasoning/thinking tokens. default true · live
model.inputstructured, read-only- Accepted input modalities for the model. default ["text","image"] · live
model.contextWindownumber- Model context window size in tokens. default 131072 · live
model.maxTokensnumber- Max output tokens per model call. default 49152 · live
model.cost.inputnumber- Cost per input token, for cost tracking/reporting. default 0 · live
model.cost.outputnumber- Cost per output token, for cost tracking/reporting. default 0 · live
model.cost.cacheReadnumber- Cost per cache-read token, for cost tracking/reporting. default 0 · live
model.cost.cacheWritenumber- Cost per cache-write token, for cost tracking/reporting. default 0 · live
model.thinkingLevelstring- Worker default reasoning/thinking level. default "medium" · live
model.compatstructured, read-only- Provider compatibility overrides (developer role, reasoning effort, thinking format, etc.), merged over junco's defaults. default {} · live
worker.*
worker.defaultTimeoutMinutesnumber- Default per-ticket execution timeout in minutes. default 30 · live
worker.pollIntervalSecondsnumber- Seconds between inbox polls when idle. default 15 · live
worker.startupPollSecondsnumber- Seconds the daemon waits/polls at startup before normal polling begins. default 30 · live
worker.startupWaitboolean- Whether the daemon waits at startup for crash-recovery grace before claiming. default true · live
worker.endpointProbeauto | always | never- Endpoint probe policy: auto (probe local/inline, skip hosted catalog), always, or never. default "auto" · live
worker.maxTransientRetriesnumber- Max retries for transient failures before a ticket is marked failed. default 2 · live
worker.retryBackoffSecondsnumber- Backoff seconds before a requeued ticket becomes eligible again. default 60 · live
worker.maxConcurrentnumber- Parallel ticket slots; same-repo tickets always serialize (restart to apply — the serial-vs-scheduler mode fork is chosen once at startup). default 1 · restart
worker.commitLeftoversboolean- Sweep uncommitted leftovers into a final commit at run end. default false · live
worker.dailyBudgetUsdnumber- Daily USD spend cap; claiming pauses once reached until local midnight (0 disables). default 0 · live
spend.json, surfaced on /health and the dashboard). At the cap,
claiming pauses — loudly, without burning any ticket's retry budget — and resumes at local
midnight or when you raise the cap. 0 disables the cap but keeps the ledger.supervisor.*
supervisor.enabledboolean- Enable the supervisor (nudge/escalate/kill loop-guard). default true · live
supervisor.budgetPerKindnumber- Budget of guard interventions allowed per kind before escalation. default 1 · live
supervisor.escalationWindowTurnsnumber- Turn window over which supervisor escalation is evaluated. default 3 · live
supervisor.outputBudgetPerTurnnumber- Max output budget per turn before the supervisor nudges. default 12000 · live
supervisor.outputBudgetPostCommitnumber- Max output budget per turn once a commit has landed. default 24000 · live
git.*
git.gitBinstring- Path/name of the git binary to invoke. default "git" · live
git.ghBinstring- Path/name of the GitHub CLI (gh) binary to invoke. default "gh" · live
git.defaultBaseBranchstring- Default base branch PRs are opened against. default "main" · live
git.branchPrefixstring- Prefix applied to branches Junco creates. default "junco/" · live
git.worktreeRootstring- Deprecated: overrides dataDir for per-ticket git worktrees only. default undefined · live
git.removeWorktreeOnSuccessboolean- Remove the git worktree after a successful run. default true · live
git.allowedRepoRootsstructured, read-only- Containment rail: when non-empty, PR-flow tickets may only target repos under these roots ([] = anywhere). default [] · live
repo: lies outside them fails plan-lint before any agent
runs. An empty list means any path — fine for a single-user machine, worth narrowing wherever
anything else can write tickets.pr.*
pr.draftByDefaultboolean- Open PRs as drafts by default. default true · live
pr.defaultLabelsstructured, read-only- Labels applied to every PR Junco opens. default [] · live
verify.*
verify.enabledboolean- Run the verify (build/test) phase before opening a PR. default true · live
verify.commandTimeoutnumber- Timeout in seconds for the verify command. default 60 · live
verify.blockOnFailboolean- Block PR creation when verify fails (vs. warn and continue). default false · live
sandbox.*
Agent tool subprocesses run OS-confined: writes jailed to the worktree plus scratch,
reads of secret paths denied, environment scrubbed, network egress denied unless a ticket
sets network: true. Backends: Seatbelt on macOS (built in), bubblewrap on Linux
(apt/dnf install bubblewrap).
bwrap the worker refuses to run tickets rather than run them unconfined; install
bubblewrap or set sandbox.backend: "none" deliberately.sandbox.enabledboolean- Wrap agent tool subprocesses in an OS sandbox (env scrub + path jail). default true · live
sandbox.backendauto | seatbelt | bwrap | none- Sandbox backend: auto (seatbelt on macOS, bwrap on Linux), a forced one, or none. default "auto" · live
sandbox.networkdeny | allow- Default network egress for agent tool subprocesses (per-ticket network:true widens it). default "deny" · live
sandbox.extraDenyReadstructured, read-only- Extra absolute paths whose reads are denied (added to the built-in secret deny-list). default [] · live
sandbox.extraAllowWritestructured, read-only- Extra absolute paths where writes are permitted (added to worktree + scratch). default [] · live
critic.*
critic.enabledboolean- Run the post-session critic review pass before finalizing a PR. default true · live
critic.maxRetriesnumber- Max critic-requested revision retries. default 1 · live
critic.thinkingstring- Thinking level used for critic review calls. default "minimal" · live
planLint.*
planLint.enabledboolean- Run plan-lint checks on ticket plans before execution. default true · live
planLint.blockOnErrorboolean- Block execution when plan-lint finds errors (vs. warn). default true · live
planLint.checkLabelsboolean- Include label checks in plan-lint. default true · live
observability.*
observability.healthEnabledboolean- Enable the /health metrics HTTP server. default true · restart
observability.healthHoststring- Bind address for /health; non-loopback exposes metrics (restart to rebind). default "127.0.0.1" · restart
observability.healthPortnumber- Port the /health metrics server binds (restart to rebind). default 8787 · restart
observability.logLeveldebug | info | warn | error- Daemon-wide log threshold (applied live). default "info" · live
observability.stateDirstring- Deprecated: overrides dataDir for the entire data root. default undefined · restart
observability.logToFileboolean- Write daemon logs to a file under dataDir. default true · restart
observability.transcriptsboolean- Write per-ticket event transcripts under dataDir. default true · restart
github.*
github.enabledboolean- Enable the GitHub issues→inbox bridge (disabled by default: zero gh calls). default false · restart
github.triggerLabelstring- Approval label that triggers the PR flow; lifecycle labels derive from it. Restart to apply — the reporter bakes in the label prefix at startup. default "junco" · restart
github.askLabelstring- Issue label that routes to the read-only Q&A path (defaults to `<triggerLabel>:ask`). Restart to apply (see triggerLabel). default undefined · restart
github.pollIntervalSecondsnumber- GitHub bridge sweep cadence, independent of the worker poll interval. default 60 · live
github.requireApprovalboolean- When false, a plan-ready GitHub ticket auto-executes on the next sweep. default true · live
false removes the human gate:
any plan-ready issue executes on the next sweep. On a repo with other collaborators, someone
with triage-only access could steer work they could never approve. Keep it true
anywhere that isn't a private personal repo.github.plannerModelIdstring- Planning-session model id override for GitHub tickets (same endpoint). default undefined · live
github.externalReposRootstring- Root directory for managed clones of unowned repos (fork-PR flow). default undefined · live
github.reposstructured, read-only- Explicit list of watched GitHub repos (owner/repo name-with-owner + local path). default [] · live
botAccount.*
botAccount.enabledboolean- Act as a dedicated bot account for all daemon GitHub traffic (log it in with: junco auth login). default false · restart
botAccount.configDirstring- Isolated gh config dir holding the bot login (GH_CONFIG_DIR for daemon gh/git). default "~/.junco/gh" · restart
assess.*
assess.maxIssuesPerRunnumber- Cap on issues filed per `junco assess` run. default 20 · live
assess.minSeveritycritical | high | medium | low- Drop assessment findings below this severity. default "low" · live
assess.npmBinstring- Binary for the dependency scan (npm audit --json). default "npm" · live
assess.fileAsme | bot- Identity `junco assess file` posts under: me (your gh login) or bot (the dedicated bot account; fails loud when its login is missing). default "me" · live
skills.*
skills.harnessDirsstructured, read-only- Harness skills dirs that receive a junco-dispatch symlink (standing consent; managed by 'junco skill install' and the wizard). default [] · restart