`compgen -G ... | wc -l` under `set -eo pipefail` aborts the script on
the non-zero pipeline exit (compgen returns 1 on no match) before the
FATAL diagnostic branch can run. The container still fast-fails, but
operators saw no explanation.
Switch to the conditional `if ! compgen -G ... >/dev/null 2>&1; then`
pattern already used at the two other compgen call sites in this file
(bootstrap_factory_repo and the PROJECT_NAME parser). The count for the
success-path log is computed after we've confirmed at least one match.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
In _generate_local_model_services:
- Add FACTORY_REPO environment variable to enable factory bootstrap
- Add volume mounts for ./projects, ./.env, and ./state to provide real project TOMLs
In entrypoint.sh:
- Add validate_projects_dir() function that fails loudly if no real .toml files
are found in the projects directory (prevents silent-zombie mode where the
polling loop matches zero files and does nothing forever)
This fixes the issue where hired agents (via hire-an-agent) ran forever without
picking up any work because they were pinned to the baked /home/agent/disinto
directory with only *.toml.example files.
Replace write_result's direct filesystem write with commit_result_via_git,
which clones the ops repo into a scratch directory, writes the result file,
commits as vault-bot, and pushes. This removes the requirement for a shared
bind-mount between the dispatcher container and the host ops-repo clone.
- Idempotent: skips if result.json already exists upstream
- Retry loop: handles push conflicts with rebase-and-push (up to 3 attempts)
- Scratch dir: cleaned up via RETURN trap regardless of outcome
- Works identically under docker and future nomad backends
Prevents infinite retry loops when secret resolution or mount alias
validation fails before the docker run is attempted.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add supervisor role to entrypoint.sh polling loop (SUPERVISOR_INTERVAL,
default 20 min) and include it in default AGENT_ROLES
- Add agents-llama-all compose service (profile: agents-llama-all) with
all 7 roles: review, dev, gardener, architect, planner, predictor, supervisor
- Add agents-llama-all to lib/generators.sh for disinto init generation
- Update docs/agents-llama.md with profile table and usage instructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Generated compose now uses `image: ghcr.io/disinto/{agents,edge}` instead
of `build:` directives; `disinto init --build` restores local-build mode
- Add VOLUME declarations to agents, reproduce, and edge Dockerfiles
- Add CI pipeline (.woodpecker/publish-images.yml) to build and push images
to ghcr.io/disinto on tag events
- Mount projects/, .env, and state/ into agents container for runtime config
- Skip pre-build binary download when compose uses registry images
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gate /chat/* behind Forgejo OAuth2 authorization-code flow.
- Extract generic _create_forgejo_oauth_app() helper in lib/ci-setup.sh;
Woodpecker OAuth becomes a thin wrapper, chat gets its own app.
- bin/disinto init now creates TWO OAuth apps (woodpecker-ci + disinto-chat)
and writes CHAT_OAUTH_CLIENT_ID / CHAT_OAUTH_CLIENT_SECRET to .env.
- docker/chat/server.py: new routes /chat/login (→ Forgejo authorize),
/chat/oauth/callback (code→token exchange, user allowlist check, session
cookie). All other /chat/* routes require a valid session or redirect to
/chat/login. Session store is in-memory with 24h TTL.
- lib/generators.sh: pass FORGE_URL, CHAT_OAUTH_CLIENT_ID,
CHAT_OAUTH_CLIENT_SECRET, EDGE_TUNNEL_FQDN, DISINTO_CHAT_ALLOWED_USERS
to the chat container environment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LOGFILE=/var/chat/chat.log is unwritable on read-only rootfs; move to
/tmp/chat.log (tmpfs-backed). Add CapDrop=ALL assertion to verify script
so removing cap_drop from compose is caught.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Dockerfile: add openssh-client + autossh to edge image
- entrypoint-edge.sh: start autossh reverse tunnel before Caddy when
EDGE_TUNNEL_HOST is set; no-op when unset (local-only dev works unchanged)
- generators.sh: pass EDGE_TUNNEL_{HOST,USER,PORT,FQDN} env vars and
bind-mount secrets/tunnel_key into the edge service
Decommission steps for old host-level reverse-tunnel.service:
sudo systemctl disable --now reverse-tunnel.service
sudo rm /etc/systemd/system/reverse-tunnel.service
sudo systemctl daemon-reload
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes:
- Create /opt/disinto-logs before supervisor loop starts (tee was failing)
- Replace exec caddy with background caddy + wait -n pattern so the
supervisor loop subshell isn't orphaned when the parent shell exec's away
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove hardcoded `disinto.toml` as default TOML search path; scan
projects/ directory for any .toml instead
- Fix load-project.sh path: use FACTORY_ROOT (consistent with the rest
of the block) instead of SCRIPT_ROOT/BASH_SOURCE which resolves to
/usr/local/bin in the container — wrong for /opt/disinto/lib/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>