7f12c7fc37
The v3 stack, previously an uncommitted working tree, plus this session's two units and the burn-in instrument. This commit is the burn-in build identity: coordinator and worker must both report this revision before a task is created. Workflow (earlier sessions, uncommitted until now): human decision events and reduction, source cursors and reconcile-before-launch, turn-boundary reconciliation, internal/agentctx as the single renderer, ace-fca phases with sealed artifacts, the trajectory gate, bounded grilling, independent review, task pr enforcement, and human review reflection. Capability restrictions at the agent boundary: an authz.Agent surface at GatedWrite may ask and may not act. It also fixes two bugs the unit exposed -- gated surfaces could not reach the two endpoints written for them, and RequestHumanDecision would block an unowned task while rejecting a question from the session that did own it. Turn-boundary reconcile-failure escalation: a streak of consecutive failures asks the session to hand off, fenced on the lease epoch, with reconcile_failure as a real handoff reason. The worker was dropping the coordinator's verdict on the floor; it now acts on it. Burn-in: herdr.WriteLaunchContext dumps the exact agentctx.Build result to <worktree>/.orchestra/launch.md at every launch, local and federated. BURNIN.md is the runbook. deploy/build.sh stamps both binaries from one commit. go build, go vet and go test ./... pass, 20 packages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
169 lines
8.5 KiB
Bash
169 lines
8.5 KiB
Bash
# Copy to the compose directory as `.env` (chmod 600) and fill in the values
|
|
# you need; `compose.yaml` loads it via `env_file:`. The retired
|
|
# orchestra.service EnvironmentFile= path is gone as of 2026-07-31, and the
|
|
# container has no entrypoint script that sources an env file — compose passes
|
|
# these in directly. Every var below is read directly from os.Getenv in
|
|
# cmd/orchestra/main.go and the packages it wires up — grep ORCHESTRA_ in the
|
|
# repo if this list ever needs re-deriving.
|
|
|
|
# --- Core ---
|
|
ORCHESTRA_DATA=/var/lib/orchestra/data
|
|
ORCHESTRA_PORT=9145
|
|
|
|
# --- Federation worker (set only on a harness host such as workpc) ---
|
|
# ORCHESTRA_URL=http://homesrv:9145
|
|
# ORCHESTRA_WORKER_ID=workpc-opencode # must equal ORCHESTRA_WORKER_HERDR_ID
|
|
# ORCHESTRA_WORKER_TOKEN=<per-worker-secret>
|
|
# ORCHESTRA_FEDERATION_ADMIT_TOKEN=<homesrv-admission-secret>
|
|
# ORCHESTRA_WORKER_HERDR_ID=workpc-opencode
|
|
# ORCHESTRA_WORKER_HARNESS=opencode
|
|
# Pane/process backend. Defaults to herdr. tmux is currently supported only
|
|
# for Claude Code workers; Codex and OpenCode should remain on herdr.
|
|
# ORCHESTRA_WORKER_BACKEND=herdr
|
|
# ORCHESTRA_WORKER_HERDR=/home/orchestra/.config/herdr/herdr.sock
|
|
# With ORCHESTRA_WORKER_BACKEND=tmux, ORCHESTRA_WORKER_HERDR is not used.
|
|
# A bare value selects an isolated tmux -L socket; an absolute path selects -S.
|
|
# ORCHESTRA_WORKER_TMUX_SOCKET=orchestra
|
|
# Optional Claude executable override; defaults to resolving `claude` in PATH.
|
|
# ORCHESTRA_WORKER_HARNESS_COMMAND=/home/orchestra/.local/bin/claude
|
|
# ORCHESTRA_WORKER_STATE=/var/lib/orchestra-worker/state.json
|
|
# ORCHESTRA_GIT_REMOTE=origin
|
|
#
|
|
# One worker process can serve several harnesses (several multiplexers and
|
|
# several agents) by declaring them in a JSON file. The variables above then
|
|
# describe nothing: each entry carries its own backend and harness. Every
|
|
# declared harness is a separate federation identity, because the coordinator
|
|
# authorizes lease calls by comparing the worker id against the lease's harness
|
|
# id, so each needs its own token and registers separately.
|
|
# ORCHESTRA_WORKER_HARNESS_CONFIG_FILE=/etc/orchestra/harnesses.json
|
|
# [
|
|
# {"id":"workpc-claude","harness":"claude","backend":"tmux",
|
|
# "tmux_socket":"orchestra","command":"/home/kami/.local/bin/claude"},
|
|
# {"id":"workpc-opencode","harness":"opencode","backend":"herdr",
|
|
# "herdr":"127.0.0.1:9247"}
|
|
# ]
|
|
# Tokens belong in the environment rather than that file. Each id maps to
|
|
# ORCHESTRA_WORKER_TOKEN_<ID>, uppercased with every other character underscored:
|
|
# ORCHESTRA_WORKER_TOKEN_WORKPC_CLAUDE=<per-identity-secret>
|
|
# ORCHESTRA_WORKER_TOKEN_WORKPC_OPENCODE=<per-identity-secret>
|
|
# Each identity keeps its own state file. Set the directory holding them, or a
|
|
# per-entry "state" path; the default derives one per id next to the worktrees.
|
|
# ORCHESTRA_WORKER_STATE_DIR=/var/lib/orchestra-worker
|
|
# ORCHESTRA_WORKER_ID still names the process for the single-harness form, where
|
|
# it must equal ORCHESTRA_WORKER_HERDR_ID.
|
|
ORCHESTRA_MACHINE_ID=homesrv # required when the registry has multiple machines
|
|
|
|
# Static project/machine/herdr topology (registry.Load). Required for
|
|
# routing across more than one machine; validated at startup.
|
|
ORCHESTRA_CONFIG=/etc/orchestra/config.json
|
|
|
|
# --- Git worktrees (global default; per-project repo/worktree_root in
|
|
# ORCHESTRA_CONFIG overrides this per project — see registry.Project) ---
|
|
ORCHESTRA_REPO=/var/lib/orchestra/repo.git
|
|
ORCHESTRA_WORKTREE_ROOT=/var/lib/orchestra/worktrees
|
|
|
|
# Protocol version fallback for herdrs that don't set "protocol" in
|
|
# ORCHESTRA_CONFIG. Prefer setting it per-herdr in the config; only use this
|
|
# if every herdr on the fleet truly matches.
|
|
#ORCHESTRA_HERDR_PROTOCOL=1
|
|
|
|
# Hard rotation occupancy threshold (0 < x < 1). Default 0.75 if unset/invalid.
|
|
ORCHESTRA_OCCUPANCY_HARD=0.75
|
|
# Advisory handoff threshold and the harness context window used to turn
|
|
# per-session token counts into occupancy. Both values are worker-local.
|
|
ORCHESTRA_OCCUPANCY_SOFT=0.55
|
|
ORCHESTRA_CONTEXT_WINDOW=200000
|
|
# OpenCode stores per-session token counters in SQLite. This optional override
|
|
# must point at the worker-local database; the worker persists the resolved
|
|
# session ID for each lease, never "the latest" session.
|
|
#ORCHESTRA_OPENCODE_DB=/home/orchestra/.local/share/opencode/opencode.db
|
|
|
|
# --- Providers ---
|
|
# Local JSONL task ingestion (baseline adapter).
|
|
#ORCHESTRA_JSONL=/var/lib/orchestra/tasks.jsonl
|
|
|
|
# Gitea issue ingestion + terminal-state reflection.
|
|
#
|
|
# Multiple repos (one per project) — preferred if you have more than one
|
|
# Gitea-backed project. Points at a JSON array of
|
|
# {project,base_url,owner,repo,token,webhook_secret}; project is the
|
|
# registry project id ingested tasks are tagged with. Each source gets its
|
|
# own webhook path: /v1/providers/gitea/webhook/{project}.
|
|
#ORCHESTRA_GITEA_CONFIG=/etc/orchestra/gitea.json
|
|
#
|
|
# Single repo (legacy) — all four required together. Ignored if
|
|
# ORCHESTRA_GITEA_CONFIG is set. Webhook path is the unprefixed
|
|
# /v1/providers/gitea/webhook. Ingested tasks are tagged with project =
|
|
# ORCHESTRA_GITEA_REPO.
|
|
#ORCHESTRA_GITEA_URL=https://gitea.example.internal
|
|
#ORCHESTRA_GITEA_TOKEN=
|
|
#ORCHESTRA_GITEA_OWNER=
|
|
#ORCHESTRA_GITEA_REPO=
|
|
#ORCHESTRA_GITEA_WEBHOOK_SECRET=
|
|
|
|
# Human-input reconciliation. When a Gitea source is configured, issue
|
|
# comments are imported as human decisions immediately before every lease,
|
|
# and a source that cannot be read refuses the lease instead of letting a
|
|
# successor resume from an older intent. Set to "off" only to keep leasing
|
|
# while a source is known down; agents then run without newer comments.
|
|
#ORCHESTRA_HUMAN_RECONCILE=off
|
|
# How many consecutive failed turn-boundary reconciles ask the running session
|
|
# to hand off. Default 3. The successor's pre-lease reconcile then fails closed
|
|
# while the source is still down, so the task waits instead of running on
|
|
# intent Orchestra cannot refresh.
|
|
#ORCHESTRA_RECONCILE_FAILURE_HANDOFF=3
|
|
|
|
# Base branch for pull requests created by `task pr`. Defaults to master. The
|
|
# pull request is created or updated for the task branch orchestra/<task-id>,
|
|
# never duplicated: a repeated submission refreshes the same review.
|
|
#ORCHESTRA_PR_BASE=master
|
|
|
|
# Whose words on a submitted pull request may reopen a task. ACTORS is an
|
|
# allow-list of forge logins; empty trusts anyone not ignored, which is only
|
|
# safe on a private forge with no bots. IGNORE_ACTORS always loses. Comments at
|
|
# or before the submission never reopen anything.
|
|
#ORCHESTRA_REVIEW_ACTORS=kami
|
|
#ORCHESTRA_REVIEW_IGNORE_ACTORS=gitea-actions,orchestra-bot
|
|
|
|
# --- Delivery (notify-only surfaces) ---
|
|
# Telegram: both required together.
|
|
#ORCHESTRA_TELEGRAM_BOT_TOKEN=
|
|
#ORCHESTRA_TELEGRAM_CHAT_ID=
|
|
# ntfy: topic required, token/url optional (self-hosted ntfy). This token is
|
|
# handed *out* to the ntfy server; it is not an inbound credential — see
|
|
# ORCHESTRA_NTFY_SURFACE_TOKEN below.
|
|
#ORCHESTRA_NTFY_TOPIC=
|
|
#ORCHESTRA_NTFY_TOKEN=
|
|
#ORCHESTRA_NTFY_URL=https://ntfy.sh
|
|
|
|
# --- Bus authorization tokens (bearer auth per surface; a surface with no
|
|
# token set has no auth requirement — set these once you have real clients) ---
|
|
#ORCHESTRA_TUI_TOKEN=
|
|
# Required: the service refuses to start without both. The browser UI's
|
|
# task, lifecycle and approval controls are session-gated; it no longer
|
|
# accepts a shared Web bearer token. Generate the bcrypt hash with:
|
|
# go run ./cmd/orchestra-password
|
|
ORCHESTRA_WEB_USERNAME=operator
|
|
ORCHESTRA_WEB_PASSWORD_HASH=
|
|
# Set when the UI is served over plain HTTP, so the session cookie can be
|
|
# sent without Secure. Leave unset behind TLS.
|
|
#ORCHESTRA_UI_INSECURE_COOKIE=1
|
|
#ORCHESTRA_MCP_TOKEN=
|
|
#ORCHESTRA_MAVEN_TOKEN=
|
|
# The credential an in-pane coding session may hold. It buys read access plus
|
|
# the three request endpoints (approval, decision-request, deferred) and
|
|
# nothing else: phase, review, submission, completion and lease changes are
|
|
# refused for this surface at the endpoint and again at the bus. This is the
|
|
# ONLY Orchestra credential that may enter an agent pane; the forge, Vikunja,
|
|
# worker and operator tokens must stay in the worker.
|
|
#ORCHESTRA_AGENT_TOKEN=
|
|
# The turn-boundary endpoint's own token (/v1/harness/turn), authenticated in
|
|
# the handler rather than by the surface gate.
|
|
#ORCHESTRA_HARNESS_TOKEN=
|
|
# Inbound bearer tokens for the notify-only surfaces, separate from the
|
|
# credentials used to *send* (ORCHESTRA_TELEGRAM_BOT_TOKEN, ORCHESTRA_NTFY_TOKEN).
|
|
# S12: ORCHESTRA_NTFY_TOKEN used to serve both roles, so configuring ntfy
|
|
# delivery silently minted a valid inbound credential.
|
|
#ORCHESTRA_TELEGRAM_TOKEN=
|
|
#ORCHESTRA_NTFY_SURFACE_TOKEN=
|