14 KiB
14 KiB
Shared Helpers (lib/)
All agents source lib/env.sh as their first action. Additional helpers are
sourced as needed.
| File | What it provides | Sourced by |
|---|---|---|
lib/env.sh |
Loads .env, sets FACTORY_ROOT, exports project config (FORGE_REPO, PROJECT_NAME, etc.), defines log(), forge_api(), forge_api_all() (paginates all pages; accepts optional second TOKEN parameter, defaults to $FORGE_TOKEN; handles invalid/empty JSON responses gracefully — returns empty on parse error instead of crashing), woodpecker_api(), wpdb(), memory_guard() (skips agent if RAM < threshold). Auto-loads project TOML if PROJECT_TOML is set. Exports per-agent tokens (FORGE_PLANNER_TOKEN, FORGE_GARDENER_TOKEN, FORGE_VAULT_TOKEN, FORGE_SUPERVISOR_TOKEN, FORGE_PREDICTOR_TOKEN) — each falls back to $FORGE_TOKEN if not set. Vault-only token guard (AD-006): unset GITHUB_TOKEN CLAWHUB_TOKEN so agents never hold external-action tokens — only the runner container receives them. Container note: when DISINTO_CONTAINER=1, .env is NOT re-sourced — compose already injects env vars (including FORGE_URL=http://forgejo:3000) and re-sourcing would clobber them. Save/restore scope (#364): only FORGE_URL is preserved across .env re-sourcing (compose injects http://forgejo:3000, .env has http://localhost:3000). FORGE_TOKEN is NOT preserved so refreshed tokens in .env take effect immediately. Required env var: FORGE_PASS — bot password for git HTTP push (Forgejo 11.x rejects API tokens for git push, #361). |
Every agent |
lib/ci-helpers.sh |
ci_passed() — returns 0 if CI state is "success" (or no CI configured). ci_required_for_pr() — returns 0 if PR has code files (CI required), 1 if non-code only (CI not required). is_infra_step() — returns 0 if a single CI step failure matches infra heuristics (clone/git exit 128, any exit 137, log timeout patterns). classify_pipeline_failure() — returns "infra <reason>" if any failed Woodpecker step matches infra heuristics via is_infra_step(), else "code". ensure_priority_label() — looks up (or creates) the priority label and returns its ID; caches in _PRIORITY_LABEL_ID. ci_commit_status <sha> — queries Woodpecker directly for CI state, falls back to forge commit status API. ci_pipeline_number <sha> — returns the Woodpecker pipeline number for a commit, falls back to parsing forge status target_url. ci_promote <repo_id> <pipeline_num> <environment> — promotes a pipeline to a named Woodpecker environment (vault-gated deployment: vault approves, vault-fire calls this — vault redesign in progress, see #73-#77). ci_get_logs <pipeline_number> [--step <name>] — reads CI logs from Woodpecker SQLite database via lib/ci-log-reader.py; outputs last 200 lines to stdout. Requires mounted woodpecker-data volume at /woodpecker-data. |
dev-poll, review-poll, review-pr |
lib/ci-debug.sh |
CLI tool for Woodpecker CI: list, status, logs, failures subcommands. Not sourced — run directly. |
Humans / dev-agent (tool access) |
lib/ci-log-reader.py |
Python tool: reads CI logs from Woodpecker SQLite database. <pipeline_number> [--step <name>] — returns last 200 lines from failed steps (or specified step). Used by ci_get_logs() in ci-helpers.sh. Requires WOODPECKER_DATA_DIR (default: /woodpecker-data). |
ci-helpers.sh |
lib/load-project.sh |
Parses a projects/*.toml file into env vars (PROJECT_NAME, FORGE_REPO, WOODPECKER_REPO_ID, monitoring toggles, mirror config, etc.). Also exports FORGE_REPO_OWNER (the owner component of FORGE_REPO, e.g. disinto-admin from disinto-admin/disinto). |
env.sh (when PROJECT_TOML is set) |
lib/parse-deps.sh |
Extracts dependency issue numbers from an issue body (stdin → stdout, one number per line). Matches ## Dependencies / ## Depends on / ## Blocked by sections and inline depends on #N / blocked by #N patterns. Inline scan skips fenced code blocks to prevent false positives from code examples in issue bodies. Not sourced — executed via bash lib/parse-deps.sh. |
dev-poll |
lib/formula-session.sh |
acquire_cron_lock(), load_formula(), load_formula_or_profile(), build_context_block(), ensure_ops_repo(), ops_commit_and_push(), build_prompt_footer(), build_sdk_prompt_footer(), formula_worktree_setup(), formula_prepare_profile_context(), formula_lessons_block(), profile_write_journal(), profile_load_lessons(), ensure_profile_repo(), _profile_has_repo(), _count_undigested_journals(), _profile_digest_journals(), _profile_commit_and_push(), resolve_agent_identity(), build_graph_section(), build_scratch_instruction(), read_scratch_context(), cleanup_stale_crashed_worktrees() — shared helpers for formula-driven cron agents (lock, .profile repo management, prompt assembly, worktree setup). Memory guard is provided by memory_guard() in lib/env.sh (not duplicated here). resolve_agent_identity() — sets FORGE_TOKEN, AGENT_IDENTITY, FORGE_REMOTE from per-agent token env vars and FORGE_URL remote detection. build_graph_section() generates the structural-analysis section (runs lib/build-graph.py, formats JSON output) — previously duplicated in planner-run.sh and predictor-run.sh, now shared here. cleanup_stale_crashed_worktrees() — thin wrapper around worktree_cleanup_stale() from lib/worktree.sh (kept for backwards compatibility). |
planner-run.sh, predictor-run.sh, gardener-run.sh, supervisor-run.sh, dev-agent.sh |
lib/guard.sh |
check_active(agent_name) — reads $FACTORY_ROOT/state/.{agent_name}-active; exits 0 (skip) if the file is absent. Factory is off by default — state files must be created to enable each agent. Logs a message to stderr when skipping ([check_active] SKIP: state file not found), so agent dropout is visible in cron logs. Sourced by dev-poll.sh, review-poll.sh, predictor-run.sh, supervisor-run.sh. |
cron entry points |
lib/mirrors.sh |
mirror_push() — pushes $PRIMARY_BRANCH + tags to all configured mirror remotes (fire-and-forget background pushes). Reads MIRROR_NAMES and MIRROR_* vars exported by load-project.sh from the [mirrors] TOML section. Failures are logged but never block the pipeline. Sourced by dev-poll.sh — called after every successful merge. |
dev-poll.sh |
lib/build-graph.py |
Python tool: parses VISION.md, prerequisites.md (from ops repo), AGENTS.md, formulas/*.toml, evidence/ (from ops repo), and forge issues/labels into a NetworkX DiGraph. Runs structural analyses (orphaned objectives, stale prerequisites, thin evidence, circular deps) and outputs a JSON report. Used by review-pr.sh (per-PR changed-file analysis) and predictor-run.sh (full-project analysis) to provide structural context to Claude. |
review-pr.sh, predictor-run.sh |
lib/secret-scan.sh |
scan_for_secrets() — detects potential secrets (API keys, bearer tokens, private keys, URLs with embedded credentials) in text; returns 1 if secrets found. redact_secrets() — replaces detected secret patterns with [REDACTED]. |
issue-lifecycle.sh |
lib/stack-lock.sh |
File-based lock protocol for singleton project stack access. stack_lock_acquire(holder, project) — polls until free, breaks stale heartbeats (>10 min old), claims lock. stack_lock_release(project) — deletes lock file. stack_lock_check(project) — inspect current lock state. stack_lock_heartbeat(project) — update heartbeat timestamp (callers must call every 2 min while holding). Lock files at ~/data/locks/<project>-stack.lock. |
docker/edge/dispatcher.sh, reproduce formula |
lib/tea-helpers.sh |
tea_file_issue(title, body, labels...) — create issue via tea CLI with secret scanning; sets FILED_ISSUE_NUM. tea_relabel(issue_num, labels...) — replace labels using tea's edit subcommand (not label). tea_comment(issue_num, body) — add comment with secret scanning. tea_close(issue_num) — close issue. All use TEA_LOGIN and FORGE_REPO from env.sh. Labels by name (no ID lookup). Tea binary download verified via sha256 checksum. Sourced by env.sh when tea binary is available. |
env.sh (conditional) |
lib/worktree.sh |
Reusable git worktree management: worktree_create(path, branch, [base_ref]) — create worktree, checkout base, fetch submodules. worktree_recover(path, branch, [remote]) — detect existing worktree, reuse if on correct branch (sets _WORKTREE_REUSED), otherwise clean and recreate. worktree_cleanup(path) — git worktree remove --force, clear Claude Code project cache (~/.claude/projects/ matching path). worktree_cleanup_stale([max_age_hours]) — scan /tmp for orphaned worktrees older than threshold, skip preserved and active tmux worktrees, prune. worktree_preserve(path, reason) — mark worktree as preserved for debugging (writes .worktree-preserved marker, skipped by stale cleanup). |
dev-agent.sh, supervisor-run.sh, planner-run.sh, predictor-run.sh, gardener-run.sh |
lib/pr-lifecycle.sh |
Reusable PR lifecycle library: pr_create(), pr_find_by_branch(), pr_poll_ci(), pr_poll_review(), pr_merge(), pr_is_merged(), pr_walk_to_merge(), build_phase_protocol_prompt(). Requires lib/ci-helpers.sh. |
dev-agent.sh (future) |
lib/issue-lifecycle.sh |
Reusable issue lifecycle library: issue_claim() (add in-progress, remove backlog), issue_release() (remove in-progress, add backlog), issue_block() (post diagnostic comment with secret redaction, add blocked label), issue_close(), issue_check_deps() (parse deps, check transitive closure; sets _ISSUE_BLOCKED_BY, _ISSUE_SUGGESTION), issue_suggest_next() (find next unblocked backlog issue; sets _ISSUE_NEXT), issue_post_refusal() (structured refusal comment with dedup). Label IDs cached in globals on first lookup. Sources lib/secret-scan.sh. |
dev-agent.sh (future) |
lib/vault.sh |
Vault PR helper — create vault action PRs on ops repo via Forgejo API (works from containers without SSH). vault_request <action_id> <toml_content> validates TOML (using validate_vault_action from vault/vault-env.sh), creates branch vault/<action-id>, writes vault/actions/<action-id>.toml, creates PR targeting main with title vault: <action-id> and body from context field, returns PR number. Idempotent: if PR exists, returns existing number. Requires FORGE_TOKEN, FORGE_URL, FORGE_REPO, FORGE_OPS_REPO. Uses the calling agent's own token (saves/restores FORGE_TOKEN around sourcing vault-env.sh), so approval workflow respects individual agent identities. |
dev-agent (vault actions), future vault dispatcher |
lib/branch-protection.sh |
Branch protection helpers for Forgejo repos. setup_vault_branch_protection() — configures admin-only merge protection on main (require 1 approval, restrict merge to admin role, block direct pushes). setup_profile_branch_protection() — same protection for .profile repos. verify_branch_protection() — checks protection is correctly configured. remove_branch_protection() — removes protection (cleanup/testing). Handles race condition after initial push: retries with backoff if Forgejo hasn't processed the branch yet. Requires FORGE_TOKEN, FORGE_URL, FORGE_OPS_REPO. |
bin/disinto (hire-an-agent) |
lib/agent-sdk.sh |
agent_run([--resume SESSION_ID] [--worktree DIR] PROMPT) — one-shot claude -p invocation with session persistence. Saves session ID to SID_FILE, reads it back on resume. agent_recover_session() — restore previous session ID from SID_FILE on startup. Nudge guard: skips nudge injection if the worktree is clean and no push is expected, preventing spurious re-invocations. Callers must define SID_FILE, LOGFILE, and log() before sourcing. |
formula-driven agents (dev-agent, planner-run, predictor-run, gardener-run) |
lib/forge-setup.sh |
setup_forge() — Forgejo instance provisioning: creates admin user, bot accounts, org, repos (code + ops), configures webhooks, sets repo topics. Extracted from bin/disinto. Requires FORGE_URL, FORGE_TOKEN, FACTORY_ROOT. Password storage (#361): after creating each bot account, stores its password in .env as FORGE_<BOT>_PASS (e.g. FORGE_PASS, FORGE_REVIEW_PASS, etc.) for use by forge-push.sh. |
bin/disinto (init) |
lib/forge-push.sh |
push_to_forge() — pushes a local clone to the Forgejo remote and verifies the push. _assert_forge_push_globals() validates required env vars before use. Requires FORGE_URL, FORGE_PASS, FACTORY_ROOT, PRIMARY_BRANCH. Auth: uses FORGE_PASS (bot password) for git HTTP push — Forgejo 11.x rejects API tokens for git push (#361). |
bin/disinto (init) |
lib/ops-setup.sh |
setup_ops_repo() — creates ops repo on Forgejo if it doesn't exist, configures bot collaborators, clones/initializes ops repo locally, seeds directory structure (vault, knowledge, evidence). Exports _ACTUAL_OPS_SLUG. |
bin/disinto (init) |
lib/ci-setup.sh |
_install_cron_impl() — installs crontab entries for project agents. _create_woodpecker_oauth_impl() — creates OAuth2 app on Forgejo for Woodpecker. _generate_woodpecker_token_impl() — auto-generates WOODPECKER_TOKEN via OAuth2 flow. _activate_woodpecker_repo_impl() — activates repo in Woodpecker. All gated by _load_ci_context() which validates required env vars. |
bin/disinto (init) |
lib/generators.sh |
Template generation for disinto init: generate_compose() — docker-compose.yml, generate_caddyfile() — Caddyfile, generate_staging_index() — staging index, generate_deploy_pipelines() — Woodpecker deployment pipeline configs. Requires FACTORY_ROOT, PROJECT_NAME, PRIMARY_BRANCH. |
bin/disinto (init) |
lib/hire-agent.sh |
disinto_hire_an_agent() — user creation, .profile repo setup, formula copying, branch protection, and state marker creation for hiring a new agent. Requires FORGE_URL, FORGE_TOKEN, FACTORY_ROOT, PROJECT_NAME. Extracted from bin/disinto. |
bin/disinto (hire) |
lib/release.sh |
disinto_release() — vault TOML creation, branch setup on ops repo, PR creation, and auto-merge request for a versioned release. _assert_release_globals() validates required env vars. Requires FORGE_URL, FORGE_TOKEN, FORGE_OPS_REPO, FACTORY_ROOT, PRIMARY_BRANCH. Extracted from bin/disinto. |
bin/disinto (release) |