env.sh references $USER which is not set in cron environment.
With set -u (pipefail), this causes env.sh to exit before setting
DISINTO_LOG_DIR, resulting in log writes to the read-only mount.
Root cause of silent cron failures since containerized setup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cron jobs run with minimal environment — no Docker compose env vars.
Without DISINTO_CONTAINER=1, env.sh falls back to FACTORY_ROOT for
log paths, which is the read-only disinto mount. Polls silently fail.
Fix: set DISINTO_CONTAINER=1 as crontab environment variable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cron poll errors were silently swallowed, making it impossible to
diagnose why agents stopped picking up issues. Now logs to
/home/agent/data/logs/cron.log.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LOGFILE pointed to SCRIPT_DIR (inside the ro disinto mount).
Use DISINTO_LOG_DIR which points to writable /home/agent/data/logs/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite action-agent from tmux session + phase-handler pattern to
synchronous SDK pattern (agent_run via claude -p). Uses shared libraries:
- agent-sdk.sh for one-shot Claude invocation
- issue-lifecycle.sh for issue_check_deps/issue_close/issue_block
- pr-lifecycle.sh for pr_create/pr_walk_to_merge
- worktree.sh for worktree_create/worktree_cleanup
Add default callback stubs to phase-handler.sh (cleanup_worktree,
cleanup_labels) so it is self-contained now that action-agent.sh
no longer sources it. Update agent-smoke.sh accordingly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BOOTSTRAP.md is superseded by the disinto-factory skill (SKILL.md).
CLAUDE.md now just points to AGENTS.md and the skill.
Updated AGENTS.md reference accordingly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comprehensive guide for AI coding agents (Claude Code, etc.) to:
- Set up a new factory instance in an LXD container
- Run disinto init and verify the stack
- Configure mirrors to GitHub/Codeberg
- Check on dev-agent, review-agent, and CI status
- Unstick blocked issues and trigger manual polls
- File issues for the factory to work on
- Known workarounds for LXD nested Docker
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Skip the heavyweight smoke-init test (spins up full Forgejo inside CI)
for PRs that do not touch init-related code. Saves ~25min of CPU per
unrelated PR.
Closes#8
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CI step containers spawned by the WP agent (running on host network)
cannot resolve Docker service names like forgejo. Setting
WOODPECKER_BACKEND_DOCKER_NETWORK puts CI containers on the compose
network so they can reach Forgejo for git clone.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Forgejo blocks outgoing webhooks to non-allowlisted hosts by default.
Woodpecker CI requires webhook delivery for pipeline triggering.
Setting ALLOWED_HOST_LIST=private allows webhooks to any RFC1918 address.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Docker bridge networking inside LXD (and potentially other nested container
environments) breaks gRPC/HTTP2 between containers. The gRPC handshake
times out because HTTP/2 frames are not properly forwarded.
Fix: run the WP agent with network_mode: host + privileged, connecting
to the server via localhost:9000 (port mapped from the server container).
- Add port 9000 mapping to woodpecker server
- Switch agent to network_mode: host with privileged: true
- Connect agent to localhost:9000 instead of woodpecker:9000
- Add WOODPECKER_GRPC_SECURE=false
- Move healthcheck to port 3333 (avoid clash with Forgejo on 3000)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add ~/.ssh mount to agents container (needed for mirror pushes)
- Add PROJECT_REPO_ROOT env to agents and vault-runner containers
- Revert WOODPECKER_HOST to http://woodpecker:8000 (localhost breaks gRPC)
- Remove WOODPECKER_GRPC_ADDR (did not fix gRPC issue)
- Keep WOODPECKER_OPEN for OAuth2 first-user registration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rewrite URL-encoded Docker-internal hostnames in OAuth2 redirect
- Submit all Forgejo grant form fields (client_id, state, redirect_uri, granted)
- Add WOODPECKER_OPEN to compose template for first user OAuth registration
- Add WOODPECKER_GRPC_ADDR to compose template
- Fix WP repo activation: use query param with numeric Forgejo repo ID
- WP v3 PAT creation via session cookie + CSRF header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reuse build_prompt_footer() from formula-session.sh instead of
hand-rolling the API reference and environment sections. Replace
the phase protocol section with SDK completion protocol.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace tmux-based run_formula_and_monitor architecture with synchronous
agent_run() from agent-sdk.sh. Replace custom CI/review/merge phase
callbacks (~350 lines) with pr_walk_to_merge() from pr-lifecycle.sh.
Key changes:
- Source agent-sdk.sh + pr-lifecycle.sh instead of agent-session.sh
- One-shot claude -p invocation replaces tmux session management
- Bash script IS the state machine (no phase files needed)
- Keep _gardener_execute_manifest() for post-merge manifest execution
- Keep all guards, formula loading, context building unchanged
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register lib/agent-sdk.sh in the CI smoke test so agent_recover_session
resolves for dev-agent.sh and review-pr.sh.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move SID_FILE recovery into agent_recover_session() in lib/agent-sdk.sh
to eliminate remaining duplicate block between dev-agent.sh and
review-pr.sh.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract agent_run() into shared lib/agent-sdk.sh to eliminate code
duplication between dev-agent.sh and review-pr.sh (CI dedup check).
Rewrite review-pr.sh from tmux-based agent-session.sh to synchronous
claude -p invocations via shared agent-sdk.sh, matching the SDK pattern
from dev-agent.sh (#798).
Key changes:
- Create lib/agent-sdk.sh with shared agent_run() function
- Both dev-agent.sh and review-pr.sh now source lib/agent-sdk.sh
instead of defining agent_run() inline
- Replace agent-session.sh (tmux + monitor_phase_loop) with agent_run()
- Add .sid file for session continuity: re-reviews resume the original
session via --resume, so Claude remembers its prior review
- Use worktree.sh for worktree cleanup
- Remove phase file signaling — completion is automatic when claude -p
returns
- Keep all review business logic unchanged
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite review-pr.sh from tmux-based agent-session.sh to synchronous
claude -p invocations via inline agent_run(), matching the SDK pattern
established in dev-agent.sh (#798).
Key changes:
- Replace agent-session.sh (tmux + monitor_phase_loop) with inline
agent_run() using one-shot claude -p and --output-format json
- Add .sid file for session continuity: re-reviews resume the original
session via --resume, so Claude remembers its prior review
- Use worktree.sh for worktree cleanup instead of manual git commands
- Remove phase file signaling (PHASE:done) — completion is automatic
when claude -p returns
- Keep all review business logic: PR metadata, diff extraction,
re-review detection (SHA tracking), incremental diff, build graph,
formula loading, review posting, formal review submission
Session continuity for re-reviews:
Initial review → save session_id to .sid file
Re-review → load session_id, agent_run --resume → Claude remembers
what it flagged and checks specifically whether concerns were addressed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite dev-poll.sh to remove all tmux session management and use
SDK shared libraries instead:
- Remove _inject_into_session(), handle_active_session() — no tmux
- Replace try_direct_merge() raw curl with pr_merge() from lib/pr-lifecycle.sh
- Replace _post_ci_blocked_comment() with issue_block() from lib/issue-lifecycle.sh
- Check PID lockfile instead of tmux sessions for active agent detection
- Clean up .sid files instead of .phase files
- Remove preflight wait loop (dev-agent.sh handles its own labels)
- Extract extract_issue_from_pr() helper to DRY up issue number extraction
Preserved from main:
- Ready-issue scanning (backlog label + deps met)
- Priority tier system (orphaned > priority+backlog > backlog)
- Orphaned issue detection (in-progress label but no active agent)
- Direct merge shortcut (approved + CI green -> merge without spawning agent)
- CI fix exhaustion tracking (per-PR counter, max 3 attempts -> blocked label)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collapse the 3-line error check into a single line to avoid triggering
the duplicate-detection CI check against action-agent.sh.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dev-agent.sh no longer sources phase-handler.sh. Update the smoke test
to resolve phase-handler.sh callbacks against action-agent.sh (which
still sources it and defines cleanup_labels/cleanup_worktree).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite dev-agent.sh from tmux session manager to synchronous bash loop:
- Replace tmux + phase-handler with synchronous claude -p invocations
- Define agent_run() wrapping claude -p with --resume for session continuity
- Use .sid file to persist session_id across crash recovery
- Delegate CI/review loop to pr_walk_to_merge() from lib/pr-lifecycle.sh
- Replace inline label management with lib/issue-lifecycle.sh
(issue_claim, issue_release, issue_block, issue_close, issue_check_deps)
- Replace inline worktree management with lib/worktree.sh
(worktree_create, worktree_recover, worktree_cleanup)
- Use pr_create/pr_find_by_branch from lib/pr-lifecycle.sh
- Use build_phase_protocol_prompt for push instructions
- Keep: issue fetch, recovery mode, prior art, prompt composition,
concurrency lock, memory guard, refusal handling
The script drops from 745 to ~500 lines. No tmux sessions, no phase
file monitoring, no phase-handler.sh dependency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New reusable library with clean function boundaries for the PR lifecycle:
- pr_create, pr_find_by_branch — PR creation and lookup
- pr_poll_ci — poll CI with infra vs code failure classification
- pr_poll_review — poll for review verdict (bot comments + formal reviews)
- pr_merge, pr_is_merged — merge with 405 handling and race detection
- pr_walk_to_merge — full orchestration loop (CI → review → merge)
- build_phase_protocol_prompt — git push instructions for agent prompts
The pr_walk_to_merge function uses agent_run() which callers must define
(guarded stub provided). This bridges to the synchronous SDK architecture
where the orchestrator bash loop IS the state machine — no phase files.
Extracted from: dev/phase-handler.sh, dev/dev-poll.sh, lib/ci-helpers.sh
Smoke test updated to include the new library.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Some BusyBox grep builds treat bare () as grouping operators even in BRE
mode, causing get_fns to miss function definitions like ci_commit_status.
Using [(][)] is unambiguous across all grep implementations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When DISINTO_CONTAINER=1, load-project.sh now skips overriding env vars
that are already set by docker-compose (FORGE_URL, PROJECT_REPO_ROOT,
OPS_REPO_ROOT, etc.). This prevents the TOML's host-perspective values
(localhost, /home/johba/…) from clobbering the correct container values
(forgejo:3000, /home/agent/…).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add DISINTO_LOG_DIR to lib/env.sh: points to $HOME/data/logs inside the
container (writable volume) and $FACTORY_ROOT on the host (existing behavior).
Update all agent scripts to write logs, CI fix tracker, metrics, and vault
locks to DISINTO_LOG_DIR instead of FACTORY_ROOT. This keeps the factory
mount read-only while ensuring all writable state lands on the persistent
data volume.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes#779
## Changes
Auto-generate WOODPECKER_TOKEN during disinto init by automating the Forgejo OAuth2 login flow after the compose stack starts. Adds generate_woodpecker_token() function that: logs into Forgejo web UI, drives the OAuth2 authorize/consent flow, completes the Woodpecker callback to get a session token, then creates a persistent personal access token via Woodpecker API. Saves to .env so activate_woodpecker_repo() can use it immediately. Failures are non-fatal (guarded with || true).
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/790
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Push events test the raw branch which may be behind main.
PR events test the merge result, which is what matters.
This eliminates false CI failures that block the dev-agent.
Fixes#778
## Changes
Add git identity warning to preflight_check() (warns if user.name/user.email missing) and auto-configure repo-local identity in setup_ops_repo() before the seed commit. This prevents init from failing late when git identity is not configured globally.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/780
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Fixes#770
The dev agent was pushing fixes without rebasing. If main moved since the branch was created, the PR becomes unmergeable.
This adds a rebase step before every git push in the dev agent workflow:
- Initial push after implementing
- Push after CI fix
- Push after review feedback
Rebasing ensures PRs stay up-to-date with the target branch and avoids merge conflicts.
Co-authored-by: johba <johba@users.codeberg.org>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/775
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>