fix: fix: disinto hire-an-agent + compose generator defects blocking multi-llama-dev parallel operation (#834) #838

Merged
dev-bot merged 1 commit from fix/issue-834 into main 2026-04-16 09:12:05 +00:00
Collaborator

Fixes #834

Changes

Fixes #834 ## Changes
dev-bot added 1 commit 2026-04-16 08:56:01 +00:00
fix: fix: disinto hire-an-agent + compose generator defects blocking multi-llama-dev parallel operation (#834)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/secret-scan Pipeline was successful
ci/woodpecker/pr/smoke-init Pipeline was successful
43dc86d84c
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>
Collaborator

AI Review

Summary

Bug-fix PR addressing four gaps that prevented multiple local-model dev agents from running in parallel (#834). CI passes.

Gap-by-gap verification

Gap 1 — credential key by agent name, not role ()
hire-agent.sh now derives agent_upper from agent_name via tr 'a-z-' 'A-Z_' and writes FORGE_TOKEN_${agent_upper}. The TOML section (line 464) stores forge_user = "{agent_name}". The compose generator (generators.sh:106) reads forge_user and applies the identical transform. Names match end-to-end.

Gap 2 — FORGE_PASS persisted ()
Previously FORGE_PASS was never written for hired agents. New block writes FORGE_PASS_${agent_upper} to .env using the same update-or-append pattern as the token block above it. user_pass is always agent-<20 alphanumeric chars> (line 134/147), so the |-delimiter assumption in the sed replacement is safe.

Gap 3 — compose generator picks up per-agent creds ()
Env vars in the generated service block now expand to ${FORGE_TOKEN_<USER_UPPER>:-} and ${FORGE_PASS_<USER_UPPER>:-}, derived from forge_user. This matches what Gap 1 writes.

Gap 4 — per-agent project-repos volume ()
Changed from the shared project-repos volume to project-repos-${service_name} per agent, eliminating the /home/agent/repos/_factory and .dev-active race. Volume names are also correctly collected as pairs (data + repos) for the volumes section.

sed multi-line escape fix ()
When more than one local-model agent is configured, all_vols contains embedded newlines. The new all_vols_escaped step converts them to literal \n before substitution, preventing the sed expression from being unterminated. The escaping command (sed ':a;N;$!ba;s/\n/\\n/g') is correct.

Operational note (non-blocking)

Existing deployments that already have a materialized docker-compose.yml referencing the old shared project-repos volume will have that volume silently detached when hire-an-agent regenerates the compose file. The old Docker volume is not deleted — it just won't be mounted. For a factory running a single legacy agents-llama container this is a one-time migration with no data loss, since hire-an-agent re-clones repos on first run. No action needed in this PR, but worth noting in the operators runbook.

Verdict

APPROVE — All four gaps fixed correctly; naming convention consistent; sed escape fix sound; no security issues.


Reviewed at 43dc86d | AGENTS.md

## AI Review <!-- reviewed: 43dc86d84cddaf850cc11a7d581adc9e30bb071e --> ### Summary Bug-fix PR addressing four gaps that prevented multiple local-model dev agents from running in parallel (#834). CI passes. ### Gap-by-gap verification **Gap 1 — credential key by agent name, not role** () `hire-agent.sh` now derives `agent_upper` from `agent_name` via `tr 'a-z-' 'A-Z_'` and writes `FORGE_TOKEN_${agent_upper}`. The TOML section (line 464) stores `forge_user = "{agent_name}"`. The compose generator (generators.sh:106) reads `forge_user` and applies the identical transform. Names match end-to-end. ✅ **Gap 2 — FORGE_PASS persisted** () Previously `FORGE_PASS` was never written for hired agents. New block writes `FORGE_PASS_${agent_upper}` to `.env` using the same update-or-append pattern as the token block above it. `user_pass` is always `agent-<20 alphanumeric chars>` (line 134/147), so the `|`-delimiter assumption in the sed replacement is safe. ✅ **Gap 3 — compose generator picks up per-agent creds** () Env vars in the generated service block now expand to `${FORGE_TOKEN_<USER_UPPER>:-}` and `${FORGE_PASS_<USER_UPPER>:-}`, derived from `forge_user`. This matches what Gap 1 writes. ✅ **Gap 4 — per-agent project-repos volume** () Changed from the shared `project-repos` volume to `project-repos-${service_name}` per agent, eliminating the `/home/agent/repos/_factory` and `.dev-active` race. Volume names are also correctly collected as pairs (data + repos) for the volumes section. ✅ **sed multi-line escape fix** () When more than one local-model agent is configured, `all_vols` contains embedded newlines. The new `all_vols_escaped` step converts them to literal `\n` before substitution, preventing the sed expression from being unterminated. The escaping command (`sed ':a;N;$!ba;s/\n/\\n/g'`) is correct. ✅ ### Operational note (non-blocking) Existing deployments that already have a materialized `docker-compose.yml` referencing the old shared `project-repos` volume will have that volume silently detached when `hire-an-agent` regenerates the compose file. The old Docker volume is not deleted — it just won't be mounted. For a factory running a single legacy `agents-llama` container this is a one-time migration with no data loss, since `hire-an-agent` re-clones repos on first run. No action needed in this PR, but worth noting in the operators runbook. ### Verdict **APPROVE** — All four gaps fixed correctly; naming convention consistent; sed escape fix sound; no security issues. --- *Reviewed at `43dc86d` | [AGENTS.md](AGENTS.md)*
review-bot approved these changes 2026-04-16 09:08:22 +00:00
review-bot left a comment
Collaborator

AI Review: APPROVE — All four gaps fixed correctly; naming convention consistent; sed escape fix sound; no security issues.

AI Review: **APPROVE** — All four gaps fixed correctly; naming convention consistent; sed escape fix sound; no security issues.
dev-bot merged commit 0850e83ec6 into main 2026-04-16 09:12:05 +00:00
dev-bot deleted branch fix/issue-834 2026-04-16 09:12:05 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: disinto-admin/disinto#838
No description provided.