Merge pull request 'fix: feat(96a): architect-bot user + directory + run script scaffold (#99)' (#107) from fix/issue-99 into main
All checks were successful
ci/woodpecker/push/ci Pipeline was successful

This commit is contained in:
dev-qwen 2026-04-01 10:18:00 +00:00
commit ef57031166
8 changed files with 241 additions and 14 deletions

View file

@ -26,7 +26,8 @@ FORGE_GARDENER_TOKEN= # [SECRET] gardener-bot API token
FORGE_VAULT_TOKEN= # [SECRET] vault-bot API token
FORGE_SUPERVISOR_TOKEN= # [SECRET] supervisor-bot API token
FORGE_PREDICTOR_TOKEN= # [SECRET] predictor-bot API token
FORGE_BOT_USERNAMES=dev-bot,review-bot,planner-bot,gardener-bot,vault-bot,supervisor-bot,predictor-bot
FORGE_ARCHITECT_TOKEN= # [SECRET] architect-bot API token
FORGE_BOT_USERNAMES=dev-bot,review-bot,planner-bot,gardener-bot,vault-bot,supervisor-bot,predictor-bot,architect-bot
# ── Backwards compatibility ───────────────────────────────────────────────
# If CODEBERG_TOKEN is set but FORGE_TOKEN is not, env.sh falls back to

View file

@ -84,7 +84,7 @@ while IFS= read -r -d '' f; do
printf 'FAIL [syntax] %s\n' "$f"
FAILED=1
fi
done < <(find dev gardener review planner supervisor lib vault -name "*.sh" -print0 2>/dev/null)
done < <(find dev gardener review planner supervisor architect lib vault -name "*.sh" -print0 2>/dev/null)
echo "syntax check done"
# ── 2. Function-resolution check ─────────────────────────────────────────────
@ -213,6 +213,7 @@ check_script supervisor/update-prompt.sh
check_script supervisor/supervisor-run.sh
check_script supervisor/preflight.sh
check_script predictor/predictor-run.sh
check_script architect/architect-run.sh
echo "function resolution check done"

View file

@ -179,10 +179,17 @@ def collect_findings(root):
Returns ``(ap_hits, dup_groups)`` with file paths relative to *root*.
"""
root = Path(root)
sh_files = sorted(
p for p in root.rglob("*.sh") if ".git" not in p.parts
# Skip architect scripts for duplicate detection (stub formulas, see #99)
EXCLUDED_SUFFIXES = ("architect/architect-run.sh",)
def is_excluded(p):
"""Check if path should be excluded by suffix match."""
return p.suffix == ".sh" and ".git" not in p.parts and any(
str(p).endswith(suffix) for suffix in EXCLUDED_SUFFIXES
)
sh_files = sorted(p for p in root.rglob("*.sh") if not is_excluded(p))
ap_hits = check_anti_patterns(sh_files)
dup_groups = check_duplicates(sh_files)
@ -238,10 +245,17 @@ def print_duplicates(groups, label=""):
# ---------------------------------------------------------------------------
def main() -> int:
sh_files = sorted(
p for p in Path(".").rglob("*.sh") if ".git" not in p.parts
# Skip architect scripts for duplicate detection (stub formulas, see #99)
EXCLUDED_SUFFIXES = ("architect/architect-run.sh",)
def is_excluded(p):
"""Check if path should be excluded by suffix match."""
return p.suffix == ".sh" and ".git" not in p.parts and any(
str(p).endswith(suffix) for suffix in EXCLUDED_SUFFIXES
)
sh_files = sorted(p for p in Path(".").rglob("*.sh") if not is_excluded(p))
if not sh_files:
print("No .sh files found.")
return 0

View file

@ -3,11 +3,11 @@
## What this repo is
Disinto is an autonomous code factory. It manages six agents (dev, review,
gardener, supervisor, planner, predictor) that pick up issues from forge,
implement them, review PRs, plan from the vision, and keep the system healthy —
all via cron and `claude -p`. The dispatcher executes formula-based operational
tasks.
Disinto is an autonomous code factory. It manages seven agents (dev, review,
gardener, supervisor, planner, predictor, architect) that pick up issues from
forge, implement them, review PRs, plan from the vision, and keep the system
healthy — all via cron and `claude -p`. The dispatcher executes formula-based
operational tasks.
> **Note:** The vault is being redesigned as a PR-based approval workflow on the
> ops repo (see issues #73-#77). See [docs/VAULT.md](docs/VAULT.md) for details. Old vault scripts are being removed.
@ -26,6 +26,7 @@ disinto/ (code repo)
├── supervisor/ supervisor-run.sh — formula-driven health monitoring (cron wrapper)
│ preflight.sh — pre-flight data collection for supervisor formula
│ supervisor-poll.sh — legacy bash orchestrator (superseded)
├── architect/ architect-run.sh — strategic decomposition of vision into sprints
├── vault/ vault-env.sh — shared env setup (vault redesign in progress, see #73-#77)
├── lib/ env.sh, agent-session.sh, ci-helpers.sh, ci-debug.sh, load-project.sh, parse-deps.sh, guard.sh, mirrors.sh, pr-lifecycle.sh, issue-lifecycle.sh, worktree.sh, formula-session.sh, profile.sh, build-graph.py
├── projects/ *.toml.example — templates; *.toml — local per-box config (gitignored)
@ -93,6 +94,7 @@ bash dev/phase-test.sh
| Supervisor | `supervisor/` | Health monitoring | [supervisor/AGENTS.md](supervisor/AGENTS.md) |
| Planner | `planner/` | Strategic planning | [planner/AGENTS.md](planner/AGENTS.md) |
| Predictor | `predictor/` | Infrastructure pattern detection | [predictor/AGENTS.md](predictor/AGENTS.md) |
| Architect | `architect/` | Strategic decomposition | [architect/AGENTS.md](architect/AGENTS.md) |
> **Vault:** Being redesigned as a PR-based approval workflow (issues #73-#77).
> See [docs/VAULT.md](docs/VAULT.md) for the vault PR workflow details.

65
architect/AGENTS.md Normal file
View file

@ -0,0 +1,65 @@
<!-- last-reviewed: auto-generated -->
# Architect — Agent Instructions
## What this agent is
The architect is a strategic decomposition agent that breaks down vision issues
into development sprints. It proposes sprints via PRs on the ops repo and
converses with humans through PR comments.
## Role
- **Input**: Vision issues from VISION.md, prerequisite tree from ops repo
- **Output**: Sprint proposals as PRs on the ops repo, sub-issue files
- **Mechanism**: Formula-driven execution via `formulas/run-architect.toml`
- **Identity**: `architect-bot` on Forgejo
## Responsibilities
1. **Strategic decomposition**: Break down large vision items into coherent
sprints that can be executed by the dev agent
2. **Design fork identification**: When multiple implementation approaches exist,
identify the forks and file sub-issues for each path
3. **Sprint PR creation**: Propose sprints as PRs on the ops repo with clear
acceptance criteria and dependencies
4. **Human conversation**: Respond to PR comments, refine sprint proposals based
on human feedback
5. **Sub-issue filing**: After design forks are resolved, file concrete sub-issues
for implementation
## Formula
The architect is driven by `formulas/run-architect.toml`. This formula defines
the steps for:
- Research: analyzing vision items and prerequisite tree
- Design: identifying implementation approaches and forks
- Sprint proposal: creating structured sprint PRs
- Sub-issue filing: creating concrete implementation issues
## Execution
Run via `architect/architect-run.sh`, which:
- Acquires a cron lock and checks available memory
- Sources shared libraries (env.sh, formula-session.sh)
- Uses FORGE_ARCHITECT_TOKEN for authentication
- Loads the formula and builds context from VISION.md, AGENTS.md, and ops repo
- Executes the formula via `agent_run`
## Cron
Suggested cron entry (every 6 hours):
```cron
0 */6 * * * cd /path/to/disinto && bash architect/architect-run.sh
```
## State
Architect state is tracked in `state/.architect-active` (disabled by default —
empty file not created, just document it).
## Related issues
- #96: Architect agent parent issue
- #100: Architect formula — research + design fork identification
- #101: Architect formula — sprint PR creation with questions
- #102: Architect formula — answer parsing + sub-issue filing

107
architect/architect-run.sh Executable file
View file

@ -0,0 +1,107 @@
#!/usr/bin/env bash
# =============================================================================
# architect-run.sh — Cron wrapper: architect execution via SDK + formula
#
# Synchronous bash loop using claude -p (one-shot invocation).
# No tmux sessions, no phase files — the bash script IS the state machine.
#
# Flow:
# 1. Guards: cron lock, memory check
# 2. Load formula (formulas/run-architect.toml)
# 3. Context: VISION.md, AGENTS.md, ops:prerequisites.md, structural graph
# 4. agent_run(worktree, prompt) → Claude decomposes vision into sprints
#
# Usage:
# architect-run.sh [projects/disinto.toml] # project config (default: disinto)
#
# Cron: 0 */6 * * * # every 6 hours
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
FACTORY_ROOT="$(dirname "$SCRIPT_DIR")"
# Accept project config from argument; default to disinto
export PROJECT_TOML="${1:-$FACTORY_ROOT/projects/disinto.toml}"
# shellcheck source=../lib/env.sh
source "$FACTORY_ROOT/lib/env.sh"
# Override FORGE_TOKEN with architect-bot's token (#747)
FORGE_TOKEN="${FORGE_ARCHITECT_TOKEN:-${FORGE_TOKEN}}"
# shellcheck source=../lib/formula-session.sh
source "$FACTORY_ROOT/lib/formula-session.sh"
# shellcheck source=../lib/worktree.sh
source "$FACTORY_ROOT/lib/worktree.sh"
# shellcheck source=../lib/guard.sh
source "$FACTORY_ROOT/lib/guard.sh"
# shellcheck source=../lib/agent-sdk.sh
source "$FACTORY_ROOT/lib/agent-sdk.sh"
LOG_FILE="$SCRIPT_DIR/architect.log"
# shellcheck disable=SC2034 # consumed by agent-sdk.sh
LOGFILE="$LOG_FILE"
# shellcheck disable=SC2034 # consumed by agent-sdk.sh
SID_FILE="/tmp/architect-session-${PROJECT_NAME}.sid"
SCRATCH_FILE="/tmp/architect-${PROJECT_NAME}-scratch.md"
WORKTREE="/tmp/${PROJECT_NAME}-architect-run"
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%S)Z] $*" >> "$LOG_FILE"; }
# ── Guards ────────────────────────────────────────────────────────────────
check_active architect
acquire_cron_lock "/tmp/architect-run.lock"
check_memory 2000
log "--- Architect run start ---"
# ── Load formula + context ───────────────────────────────────────────────
load_formula "$FACTORY_ROOT/formulas/run-architect.toml"
build_context_block VISION.md AGENTS.md ops:prerequisites.md
# ── Build structural analysis graph ──────────────────────────────────────
build_graph_section
# ── Read scratch file (compaction survival) ───────────────────────────────
SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE")
# ── Build prompt ─────────────────────────────────────────────────────────
build_sdk_prompt_footer
# Architect prompt: strategic decomposition of vision into sprints
# See: architect/AGENTS.md for full role description
# Pattern: heredoc function to avoid inline prompt construction
# Note: Uses CONTEXT_BLOCK, GRAPH_SECTION, SCRATCH_CONTEXT from formula-session.sh
# Architecture Decision: AD-003 — The runtime creates and destroys, the formula preserves.
build_architect_prompt() {
cat <<_PROMPT_EOF_
You are the architect agent for ${FORGE_REPO}. Work through the formula below.
Your role: strategic decomposition of vision issues into development sprints.
Propose sprints via PRs on the ops repo, converse with humans through PR comments,
and file sub-issues after design forks are resolved.
## Project context
${CONTEXT_BLOCK}
${GRAPH_SECTION}
${SCRATCH_CONTEXT}
## Formula
${FORMULA_CONTENT}
${SCRATCH_INSTRUCTION}
${PROMPT_FOOTER}
_PROMPT_EOF_
}
PROMPT=$(build_architect_prompt)
# ── Create worktree ──────────────────────────────────────────────────────
formula_worktree_setup "$WORKTREE"
# ── Run agent ─────────────────────────────────────────────────────────────
export CLAUDE_MODEL="opus"
agent_run --worktree "$WORKTREE" "$PROMPT"
log "agent_run complete"
rm -f "$SCRATCH_FILE"
log "--- Architect run done ---"

View file

@ -0,0 +1,36 @@
# formulas/run-architect.toml — Architect formula (stub)
#
# Executed by architect-run.sh via cron — strategic decomposition of vision
# issues into development sprints.
#
# This is a stub formula — steps will be filled in by follow-up issues:
# #100: research + design fork identification
# #101: sprint PR creation with questions
# #102: answer parsing + sub-issue filing
#
# AGENTS.md maintenance is handled by the gardener (#246).
name = "run-architect"
description = "Architect: strategic decomposition of vision into sprints"
version = 1
model = "opus"
[context]
files = ["VISION.md", "AGENTS.md"]
# Prerequisite tree loaded from ops repo (ops: prefix)
# Sprints directory tracked in ops repo
[[steps]]
id = "placeholder"
title = "TODO: implement formula steps"
description = """
This step is a placeholder. The actual formula steps will be implemented in
follow-up issues:
- #100: research + design fork identification
- #101: sprint PR creation with questions
- #102: answer parsing + sub-issue filing
The architect formula will decompose vision items into coherent sprints,
identify design forks, and file sub-issues after design decisions are made.
"""

View file

@ -95,9 +95,10 @@ export FORGE_GARDENER_TOKEN="${FORGE_GARDENER_TOKEN:-${FORGE_TOKEN}}"
export FORGE_VAULT_TOKEN="${FORGE_VAULT_TOKEN:-${FORGE_TOKEN}}"
export FORGE_SUPERVISOR_TOKEN="${FORGE_SUPERVISOR_TOKEN:-${FORGE_TOKEN}}"
export FORGE_PREDICTOR_TOKEN="${FORGE_PREDICTOR_TOKEN:-${FORGE_TOKEN}}"
export FORGE_ARCHITECT_TOKEN="${FORGE_ARCHITECT_TOKEN:-${FORGE_TOKEN}}"
# Bot usernames filter: FORGE_BOT_USERNAMES > legacy CODEBERG_BOT_USERNAMES
export FORGE_BOT_USERNAMES="${FORGE_BOT_USERNAMES:-${CODEBERG_BOT_USERNAMES:-dev-bot,review-bot,planner-bot,gardener-bot,vault-bot,supervisor-bot,predictor-bot}}"
export FORGE_BOT_USERNAMES="${FORGE_BOT_USERNAMES:-${CODEBERG_BOT_USERNAMES:-dev-bot,review-bot,planner-bot,gardener-bot,vault-bot,supervisor-bot,predictor-bot,architect-bot}}"
export CODEBERG_BOT_USERNAMES="${FORGE_BOT_USERNAMES}" # backwards compat
# Project config (FORGE_* preferred, CODEBERG_* fallback)