A project could run bench for months without a manager/local/.env: everything fell back to core/.env.example, so the two settings that change what bench is — claim-on-move and syncing through origin/main — were invisible to anyone who had not read that file. install.py now writes it on a first run. It asks three questions no default can be right about (solo or team, which agent adapter, the project's test command) and writes core/.env.example with the answers substituted into their lines, comments and all keys intact — so the written file is where the project reads what else it can change. - Runs after first_boot_clean: .env is one of the two things the first-boot guard reads, so writing it earlier would skip the clean. - Never asks without a terminal on stdin. install.py sits on the path of start.sh, update.sh and every hook, so no TTY prints one line and carries on rather than blocking a board start on an invisible prompt. --dry-run reports the questions and writes nothing. - An existing .env is never touched; --setup is the only way back to the questions, pre-filling from the current file and rewriting it in place, so start.sh's fallback BOARD_PORT line survives. - Bare Enter takes every default (the result is the example verbatim, i.e. today's behaviour exactly); Ctrl-D skips the rest. start.sh needed no change — it already calls install.py before the port dance, which is the right order. Tests drive the interactive runs over a real pty and the non-interactive ones with /dev/null on stdin. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
135 lines
6.5 KiB
Bash
135 lines
6.5 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 PRs are pushed to (empty = the repo's first 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 `origin` and `main` only.
|
|
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=
|