Files
bench/manager/core/.env.example
T
istosandClaude Opus 5 58b658389b sync: ride the resolved remote, and say when there is none
REMOTE/UPSTREAM were module constants, so a team-mode board whose remote
is named anything but origin synced nothing at all — silently, with a
healthy header. The remote is now resolved per use (config's answer, the
one PRs already honour) and threaded through fetch, publish, replay and
integrate; every message names whatever was resolved.

The silence is the other half. Where _converge()/push_now() returned a
bare 'no-origin' that both callers discarded, _remote() now _note()s at
stalled level first: no remote at all names both fixes (add one, or set
BOARD_GIT_REMOTE), and a BOARD_GIT_REMOTE naming a remote this checkout
does not have stalls naming it rather than quietly using another. It
clears with a recovery line like the offline path, and install() asks at
startup so the chip is there from first paint, not the second beat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 07:33:39 +02:00

141 lines
6.9 KiB
Bash

# Task manager settings — copy to manager/local/.env (gitignored) and edit.
# Precedence: process environment > local/.env > these defaults.
#
# A first run of install.py with no local/.env writes this file there for
# you, asking only what it cannot guess (solo or team, which agent
# adapter, the project's test command) and leaving every other key at the
# default below. `install.py --setup` asks again later; nothing else ever
# rewrites your copy, so new keys added here by an update are yours to
# adopt by hand.
# Port the board serves on. Pinned by default so the URL is bookmarkable;
# adapters and drivers read the same value, so changing it here changes it
# everywhere at once.
BOARD_PORT=26071
# What the tab calls this project: the title is "<project> · bench", so two
# benches side by side are told apart at tab-bar width. Empty = the repo
# directory's name, which is the right answer unless every checkout on this
# machine is called "app".
BOARD_TITLE=
# Which agent adapter runs headless jobs (core/adapters/<name>, overridable
# in local/adapters/<name>). Ships with: claude, opencode.
BOARD_AGENT_ADAPTER=claude
# The binary each adapter launches jobs with. Point them at stub scripts
# to test the board's plumbing without spending tokens.
BOARD_CLAUDE_BIN=claude
BOARD_OPENCODE_BIN=opencode
# The model headless agents run on — an opaque vendor-native name the
# adapter passes through untranslated (claude: a model name or alias for
# --model; opencode: the "provider/model-id" config key). Empty = inherit
# the vendor's own default, i.e. whatever the CLI on this machine would
# pick anyway. The per-intent settings beat the general one for their
# intent only; _REVIEW covers both PR reviews and relevance checks. Work
# agents write code; reviews just read and judge — they can ride a
# cheaper, faster model.
BOARD_AGENT_MODEL=
BOARD_AGENT_MODEL_WORK=
BOARD_AGENT_MODEL_ACT_PR=
BOARD_AGENT_MODEL_REVIEW=
# Command prefixes headless agents may run in their worktree — the
# project's test/check commands, comma-separated, in plain neutral form
# (each adapter renders them into its vendor's permission rules; the
# git/gh grants per launch intent are built in). Headless runs have no
# human at a permission prompt, so a test runner missing from this list
# is a test the work agent cannot run.
BOARD_AGENT_COMMANDS=python3 -m unittest
# What counts as a definition-of-done check (the Focus view's CHECKS
# panel) is a file, not an env var: core/checks ships a generic default,
# and a `checks` file in manager/local/ replaces it wholesale. Format
# (`<label>: <command regex>`) is documented in the default file itself.
# Where work-agent worktrees are created, relative to the repo root.
BOARD_WORKTREES=.worktrees
# GitHub plumbing. The gh CLI used for PRs (stub-able like claude); the git
# remote this board's work goes to (empty = the repo's first remote) — PRs
# and BOARD_SYNC both ride it, and a name set here is used as named, never
# swapped for another remote; and how often to poll open PRs of cards
# sitting in review/ for reviews and checks.
BOARD_GH_BIN=gh
BOARD_GIT_REMOTE=
BOARD_PR_POLL_INTERVAL=60
# Seconds a work-agent launch waits for `git fetch origin main` before
# giving up and branching from local HEAD. Fresh launches branch from
# origin/main when the fetch succeeds; no remote or a dead network just
# means today's behaviour, never a blocked launch.
BOARD_FETCH_TIMEOUT=10
# Claim on move, and commit it. On: a board-made move out of backlog/ or
# to-do/ writes **Assignee:** <git user.name> into the task file (first
# claim only — an existing assignee is preserved), walking a card back to
# backlog/ clears it, and each move commits itself — the move and the claim
# in one commit touching only that task file, messaged
# `board: <number> → <stage> (<name>)`. Nothing is pushed. Off (the
# default) means moves neither write nor clear the assignee and never
# commit — today's behaviour exactly, tasks/ committed by hand. An
# assignee added to a file by hand is still read and shown either way;
# the gate only governs whether a move writes it. Anything but
# empty/0/false/no/off turns it on.
#
# It is also what makes the claim mean something: on, ▸ start work refuses
# a card someone else holds (▸ take over is the deliberate way in) and
# claims an unheld one, and board-made edits to a card in place — the
# **PR:** line — commit themselves too. Off, nothing writes an assignee,
# so nothing reads one as a lock.
BOARD_COMMIT_MOVES=
# Sync boards through origin/main: the second half of team mode, and off
# by default. On, it implies BOARD_COMMIT_MOVES above (a move that never
# commits has nothing to publish) and: each board commit is pushed as it
# is made; a beat fetches and fast-forwards every BOARD_SYNC_INTERVAL
# seconds and once at startup; moves that arrive are narrated with their
# commit author's name; and a card someone else moved first wins the race
# — the local move is dropped with a toast naming who took it.
#
# Two things it will never do. It never publishes a commit the board did
# not make: one local-ahead commit on main without the `board: ` prefix
# stops the push and says which. And it never merges past a divergence or
# into a checkout with uncommitted changes — it says so and waits for a
# human. Both assume the discipline bench already has: code work lives in
# worktrees and PRs, so local main advances only through the board and
# origin.
#
# State syncs; reactions don't. A move that arrives over origin renders
# and narrates on every board but triggers nothing — opening a PR belongs
# to the board whose user made the move, and a review card left without
# one carries an explicit ↑ open PR action instead of N boards guessing.
# The same discipline moves merges to origin: merge & clean up runs
# `gh pr merge` and lets the beat deliver the result, so local main only
# ever fast-forwards. Whoever clicks needs merge rights on the repo.
#
# One board fetches twice a minute at the default interval; raise it on a
# rate-limited or metered remote. Sync rides one remote and `main` only —
# the remote BOARD_GIT_REMOTE names, or the checkout's first one, exactly
# as PRs do. Nothing to ride (no remote, or a BOARD_GIT_REMOTE naming one
# this checkout does not have) is a `sync stalled` chip and a ticker line,
# never a board that looks healthy while syncing nothing.
BOARD_SYNC=
BOARD_SYNC_INTERVAL=30
# Seconds between disk polls of the stage directories.
BOARD_WATCH_INTERVAL=2
# In-memory caps: events kept per session, and board-level history
# (moves + agent lifecycle). Full logs always persist to local/state/.
BOARD_EVENTS_CAP=800
BOARD_HISTORY_CAP=300
# Where update.sh fetches the task-manager's releases from (owner/repo, or
# any GitHub URL). Normally unset: the shipped update.sh is stamped at
# build time with the repo it came from, and this overrides the stamp.
# Updates replace manager/core/ and the top-level scripts; they never touch
# tasks/, plans/, reference/ or manager/local/.
BENCH_SOURCE=