disinto/.env.example

131 lines
9.4 KiB
Text
Raw Normal View History

# Disinto — Environment Configuration
# Copy to .env and fill in your values.
# NEVER commit .env to the repo.
#
# With SOPS + age installed, `disinto init` encrypts secrets into .env.enc
# and removes plaintext .env. To migrate an existing .env: `disinto secrets migrate`
#
# Variables marked [SECRET] are credentials that grant access if leaked.
# Variables marked [CONFIG] are non-sensitive and safe in plaintext.
# ── Per-project config ────────────────────────────────────────────────────
# Project-specific settings (FORGE_REPO, PROJECT_REPO_ROOT, PRIMARY_BRANCH,
# WOODPECKER_REPO_ID) now live in projects/*.toml — see projects/harb.toml
# for an example. Do NOT set them here; they leak into every session.
# ── Forge (Forgejo) ─────────────────────────────────────────────────────
FORGE_URL=http://localhost:3000 # [CONFIG] local Forgejo instance
# ── Auth tokens ───────────────────────────────────────────────────────────
# Each agent has its own Forgejo account and API token (#747).
# Per-agent tokens fall back to FORGE_TOKEN if not set.
#
# Tokens and passwords are auto-generated by `disinto init` and stored in .env.
# Each bot user gets:
# - FORGE_TOKEN_<BOT> = API token for REST calls (user identity via /api/v1/user)
# - FORGE_PASS_<BOT> = password for git HTTP push (#361, Forgejo 11.x limitation)
#
fix: fix: disinto hire-an-agent + compose generator defects blocking multi-llama-dev parallel operation (#834) Hiring a second llama-backed dev agent (e.g. `dev-qwen2`) alongside `dev-qwen` tripped four defects that prevented safe parallel operation. Gap 1 — hire-agent keyed per-agent token as FORGE_<ROLE>_TOKEN, so two dev-role agents overwrote each other's token in .env. Re-key by agent name via `tr 'a-z-' 'A-Z_'`: FORGE_TOKEN_<AGENT_UPPER>. Gap 2 — hire-agent generated a random FORGE_PASS but never wrote it to .env. The container's git credential helper needs both token and pass to push over HTTPS (#361). Persist FORGE_PASS_<AGENT_UPPER> with the same update-in-place idempotency as the token. Gap 3 — _generate_local_model_services hardcoded FORGE_TOKEN_LLAMA for every local-model service, forcing all hired llama agents to share one Forgejo identity. Derive USER_UPPER from the TOML's `forge_user` field and emit \${FORGE_TOKEN_<USER_UPPER>:-} per service. Gap 4 — every local-model service mounted the shared `project-repos` volume, so concurrent llama devs collided on /_factory worktree and state/.dev-active. Switch to per-agent `project-repos-<service_name>` and emit the matching top-level volume. Also escape embedded newlines in `$all_vols` before the sed insertion so multi-agent volume lists don't unterminate the substitute command. .env.example documents the new FORGE_TOKEN_<AGENT> / FORGE_PASS_<AGENT> naming convention (and preserves the legacy FORGE_TOKEN_LLAMA path used by the ENABLE_LLAMA_AGENT=1 singleton build). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:55:45 +00:00
# Local-model agents hired with `disinto hire-an-agent` are keyed by *agent
# name* (not role), so multiple local-model dev agents can coexist without
# colliding on credentials (#834). For an agent named `dev-qwen2` the vars are:
# - FORGE_TOKEN_DEV_QWEN2
# - FORGE_PASS_DEV_QWEN2
# Name conversion: tr 'a-z-' 'A-Z_' (lowercase→UPPER, hyphens→underscores).
# The compose generator looks these up via the agent's `forge_user` field in
# the project TOML. Configure local-model agents via [agents.X] sections in
# projects/*.toml — this is the canonical activation path.
FORGE_TOKEN= # [SECRET] dev-bot API token (default for all agents)
FORGE_PASS= # [SECRET] dev-bot password for git HTTP push (#361)
FORGE_REVIEW_TOKEN= # [SECRET] review-bot API token
FORGE_REVIEW_PASS= # [SECRET] review-bot password for git HTTP push
FORGE_PLANNER_TOKEN= # [SECRET] planner-bot API token
FORGE_PLANNER_PASS= # [SECRET] planner-bot password for git HTTP push
FORGE_GARDENER_TOKEN= # [SECRET] gardener-bot API token
FORGE_GARDENER_PASS= # [SECRET] gardener-bot password for git HTTP push
FORGE_VAULT_TOKEN= # [SECRET] vault-bot API token
FORGE_VAULT_PASS= # [SECRET] vault-bot password for git HTTP push
FORGE_SUPERVISOR_TOKEN= # [SECRET] supervisor-bot API token
FORGE_SUPERVISOR_PASS= # [SECRET] supervisor-bot password for git HTTP push
FORGE_PREDICTOR_TOKEN= # [SECRET] predictor-bot API token
FORGE_PREDICTOR_PASS= # [SECRET] predictor-bot password for git HTTP push
FORGE_ARCHITECT_TOKEN= # [SECRET] architect-bot API token
FORGE_ARCHITECT_PASS= # [SECRET] architect-bot password for git HTTP push
fix: bug: architect pitch prompt guardrail is prose-only — model bypasses "NEVER call Forgejo API" via Bash tool; fix via permission scoping + PR-driven sub-issue filing (#764) Shift the guardrail from prose prompt constraints into Forgejo's permission layer. architect-bot loses all write access on the project repo (now read-only for context gathering). Sub-issues are produced by a new filer-bot identity that runs only after a human merges a sprint PR on the ops repo. Changes: - architect-run.sh: remove all project-repo writes (add_inprogress_label, close_vision_issue, check_and_close_completed_visions); add ## Sub-issues block to pitch format with filer:begin/end markers - formulas/run-architect.toml: add Sub-issues schema to pitch format; strip issue-creation API refs; document read-only constraint on project repo - lib/formula-session.sh: remove Create issue curl template from build_prompt_footer (architect cannot create issues) - lib/sprint-filer.sh (new): parser + idempotent filer using FORGE_FILER_TOKEN; parses filer:begin/end blocks, creates issues with decomposed-from markers, adds in-progress label, handles vision lifecycle closure - .woodpecker/ops-filer.yml (new): CI pipeline on ops repo main-branch push that invokes sprint-filer.sh after sprint PR merge - lib/env.sh, .env.example, docker-compose.yml: add FORGE_FILER_TOKEN for filer-bot identity; add filer-bot to FORGE_BOT_USERNAMES - AGENTS.md: add Filer agent entry; update in-progress label docs - .woodpecker/agent-smoke.sh: register sprint-filer.sh for smoke test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:41:16 +00:00
FORGE_FILER_TOKEN= # [SECRET] filer-bot API token (issues:write on project repo only)
FORGE_FILER_PASS= # [SECRET] filer-bot password for git HTTP push
FORGE_BOT_USERNAMES=dev-bot,review-bot,planner-bot,gardener-bot,vault-bot,supervisor-bot,predictor-bot,architect-bot,filer-bot
# ── Backwards compatibility ───────────────────────────────────────────────
# If CODEBERG_TOKEN is set but FORGE_TOKEN is not, env.sh falls back to
# CODEBERG_TOKEN automatically (same for REVIEW_BOT_TOKEN, CODEBERG_REPO,
# CODEBERG_BOT_USERNAMES). No action needed for existing deployments.
# Per-agent tokens default to FORGE_TOKEN when unset (single-token setups).
# ── Woodpecker CI ─────────────────────────────────────────────────────────
WOODPECKER_TOKEN= # [SECRET] Woodpecker API token
WOODPECKER_SERVER=http://localhost:8000 # [CONFIG] Woodpecker server URL
WOODPECKER_AGENT_SECRET= # [SECRET] shared secret for server↔agent auth (auto-generated)
# Woodpecker privileged-plugin allowlist — comma-separated image names
# Add plugins/docker (and others) here to allow privileged execution
WOODPECKER_PLUGINS_PRIVILEGED=plugins/docker
# WOODPECKER_REPO_ID — now per-project, set in projects/*.toml [ci] section
# Woodpecker Postgres (for direct DB queries)
WOODPECKER_DB_PASSWORD= # [SECRET] Postgres password
WOODPECKER_DB_USER=woodpecker # [CONFIG] Postgres user
WOODPECKER_DB_HOST=127.0.0.1 # [CONFIG] Postgres host
WOODPECKER_DB_NAME=woodpecker # [CONFIG] Postgres database name
# ── Chat OAuth (#708) ────────────────────────────────────────────────────
CHAT_OAUTH_CLIENT_ID= # [SECRET] Chat OAuth2 client ID (auto-generated by init)
CHAT_OAUTH_CLIENT_SECRET= # [SECRET] Chat OAuth2 client secret (auto-generated by init)
DISINTO_CHAT_ALLOWED_USERS= # [CONFIG] CSV of allowed usernames (disinto-admin always allowed)
FORWARD_AUTH_SECRET= # [SECRET] Shared secret for Caddy ↔ chat forward_auth (#709)
# ── Vault-only secrets (DO NOT put these in .env) ────────────────────────
# These tokens grant access to external systems (GitHub, ClawHub, deploy targets).
# They live ONLY in secrets/<NAME>.enc (age-encrypted, one file per key) and are
# decrypted into the ephemeral runner container at fire time (#745, #777).
# lib/env.sh explicitly unsets them so agents can never hold them directly —
# all external actions go through vault dispatch.
#
# GITHUB_TOKEN — GitHub API access (publish, deploy, post)
# CLAWHUB_TOKEN — ClawHub registry credentials (publish)
# CADDY_SSH_KEY — SSH key for Caddy log collection
# (deploy keys) — SSH keys for deployment targets
#
# To manage secrets: disinto secrets add/show/remove/list
# ── Project-specific secrets ──────────────────────────────────────────────
# Store all project secrets here so formulas reference env vars, never hardcode.
BASE_RPC_URL= # [SECRET] on-chain RPC endpoint
# ── Tuning ────────────────────────────────────────────────────────────────
CLAUDE_TIMEOUT=7200 # [CONFIG] max seconds per Claude invocation
# ── Host paths (Nomad-portable) ────────────────────────────────────────────
# These env vars externalize host-side bind-mount paths from docker-compose.yml.
# At cutover, Nomad jobspecs reference the same vars — no path translation.
# Defaults point at current paths so an empty .env override still works.
CLAUDE_BIN_DIR=/usr/local/bin/claude # [CONFIG] host path to claude CLI binary (resolved by `disinto init`)
CLAUDE_CONFIG_FILE=${HOME}/.claude.json # [CONFIG] host path to claude config JSON file
CLAUDE_DIR=${HOME}/.claude # [CONFIG] host path to .claude directory (reproduce/edge)
AGENT_SSH_DIR=${HOME}/.ssh # [CONFIG] host path to SSH keys directory
SOPS_AGE_DIR=${HOME}/.config/sops/age # [CONFIG] host path to SOPS age key directory
# ── Claude Code shared OAuth state ─────────────────────────────────────────
# Shared directory used by every factory container so Claude Code's internal
# proper-lockfile-based OAuth refresh lock works across containers. Both
# values must live outside $HOME (so docker bind mounts don't depend on UID
# mapping) and must be the same absolute path on host and inside each
# container. See docs/CLAUDE-AUTH-CONCURRENCY.md.
CLAUDE_SHARED_DIR=/var/lib/disinto/claude-shared
CLAUDE_CONFIG_DIR=${CLAUDE_SHARED_DIR}/config
# ── Factory safety ────────────────────────────────────────────────────────
# Disables Claude Code auto-updater, telemetry, error reporting, and bug
# command. Factory sessions are production processes — they must never phone
# home or auto-update mid-session. Added after #725 (crash during red-team run).
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 # [CONFIG] suppress all non-essential traffic