241 lines
8.4 KiB
TOML
241 lines
8.4 KiB
TOML
# formulas/run-architect.toml — Architect formula
|
|
#
|
|
# Executed by architect-run.sh via cron — strategic decomposition of vision
|
|
# issues into development sprints.
|
|
#
|
|
# This formula orchestrates the architect agent's pitching workflow:
|
|
# Step 1: Preflight — validate prerequisites, select up to 3 target issues
|
|
# Step 2: Research + pitch — analyze codebase and write sprint pitch (loop over selected issues)
|
|
# Step 3: Sprint PR creation (one PR per pitch)
|
|
#
|
|
# Design phase (ACCEPT/REJECT handling, questions, answer processing) is
|
|
# orchestrated by bash in architect-run.sh — not by this formula.
|
|
# See architect-run.sh for the bash-driven state machine:
|
|
# - Bash reads reviews API for ACCEPT/REJECT detection (deterministic)
|
|
# - REJECT handled entirely in bash (close PR, delete branch, journal)
|
|
# - ACCEPT: bash invokes model with human guidance injected
|
|
# - Answers: bash resumes saved session with answers injected
|
|
#
|
|
# AGENTS.md maintenance is handled by the gardener (#246).
|
|
|
|
name = "run-architect"
|
|
description = "Architect: strategic decomposition of vision into sprints"
|
|
version = 2
|
|
model = "opus"
|
|
|
|
[context]
|
|
files = ["VISION.md", "AGENTS.md"]
|
|
# Prerequisite tree loaded from ops repo (ops: prefix)
|
|
# Sprints directory tracked in ops repo
|
|
|
|
[[steps]]
|
|
id = "preflight"
|
|
title = "Preflight: validate prerequisites, select up to 3 target issues"
|
|
description = """
|
|
This step is performed by bash in architect-run.sh before the model is invoked.
|
|
|
|
Bash handles:
|
|
1. Pull latest code from both disinto repo and ops repo
|
|
2. Read prerequisite tree from $OPS_REPO_ROOT/prerequisites.md
|
|
3. Fetch open issues labeled 'vision' from Forgejo API
|
|
4. Check for open architect PRs on ops repo
|
|
5. Process existing PRs via bash-driven design phase (ACCEPT/REJECT/answers)
|
|
6. After handling existing PRs, count remaining open architect PRs
|
|
7. Select up to (3 - open_architect_pr_count) vision issues for new pitches
|
|
8. If no vision issues, signal PHASE:done
|
|
|
|
## Multi-pitch selection (up to 3 per run)
|
|
|
|
After handling existing PRs, determine how many new pitches can be created:
|
|
|
|
pitch_budget = 3 - <number of open architect PRs remaining after handling>
|
|
|
|
For each available pitch slot:
|
|
1. From the vision issues list, skip any issue that already has an open architect PR
|
|
2. Skip any issue that already has the `in-progress` label
|
|
3. Check for existing sub-issues filed from this vision issue
|
|
4. Check for merged sprint PRs referencing this vision issue
|
|
5. From remaining candidates, pick the most unblocking issue first
|
|
6. Add to ARCHITECT_TARGET_ISSUES array
|
|
|
|
Skip conditions:
|
|
- If no vision issues are found, signal PHASE:done
|
|
- If pitch_budget <= 0 (already 3 open architect PRs), skip pitching
|
|
- If all vision issues already have open architect PRs, signal PHASE:done
|
|
- If all vision issues have open sub-issues, skip pitching
|
|
- If all vision issues have merged sprint PRs, skip pitching
|
|
|
|
Output:
|
|
- Sets ARCHITECT_TARGET_ISSUES as a JSON array of issue numbers to pitch (up to 3)
|
|
"""
|
|
|
|
[[steps]]
|
|
id = "research_pitch"
|
|
title = "Research + pitch: analyze codebase and write sprint pitches (loop over selected issues)"
|
|
description = """
|
|
This step performs deep codebase research and writes a sprint pitch for EACH
|
|
vision issue in ARCHITECT_TARGET_ISSUES.
|
|
|
|
For each issue in ARCHITECT_TARGET_ISSUES, perform the following:
|
|
|
|
Actions:
|
|
|
|
1. Read the codebase deeply:
|
|
- Read all files mentioned in the issue body
|
|
- Search for existing interfaces that could be reused
|
|
- Check what infrastructure already exists
|
|
|
|
2. Assess complexity and cost:
|
|
- How many files/subsystems are touched?
|
|
- What new infrastructure would need to be maintained after this sprint?
|
|
- What are the risks (breaking changes, security implications, integration complexity)?
|
|
- Is this mostly gluecode or greenfield?
|
|
|
|
3. Write sprint pitch to a per-issue scratch file for PR creation step:
|
|
- File path: /tmp/architect-{project}-scratch-{issue_number}.md
|
|
|
|
# Sprint pitch: <name>
|
|
|
|
## Vision issues
|
|
- #N — <title>
|
|
|
|
## What this enables
|
|
<what the project can do after this sprint that it can't do now>
|
|
|
|
## What exists today
|
|
<current state — infrastructure, interfaces, code that can be reused>
|
|
|
|
## Complexity
|
|
<number of files, subsystems, estimated sub-issues>
|
|
<gluecode vs greenfield ratio>
|
|
|
|
## Risks
|
|
<what could go wrong, what breaks if this is done badly>
|
|
|
|
## Cost — new infra to maintain
|
|
<what ongoing maintenance burden does this sprint add>
|
|
<new services, cron jobs, formulas, agent roles>
|
|
|
|
## Recommendation
|
|
<architect's assessment: worth it / defer / alternative approach>
|
|
|
|
IMPORTANT: Do NOT include design forks or questions yet. The pitch is a go/no-go
|
|
decision for the human. Questions come only after acceptance.
|
|
|
|
Output:
|
|
- Writes one scratch file per vision issue: /tmp/architect-{project}-scratch-{issue_number}.md
|
|
- Each pitch serves as input for sprint PR creation step
|
|
- If ARCHITECT_TARGET_ISSUES is empty (budget exhausted or no candidates), skip this step
|
|
"""
|
|
|
|
[[steps]]
|
|
id = "sprint_pr_creation"
|
|
title = "Sprint PR creation (one PR per pitch)"
|
|
description = """
|
|
This step creates a PR on the ops repo for EACH sprint pitch produced in step 2.
|
|
One PR per vision issue — loop over all scratch files.
|
|
|
|
## Create pitch PRs (from research output)
|
|
|
|
For each vision issue in ARCHITECT_TARGET_ISSUES that produced a scratch file
|
|
(/tmp/architect-{project}-scratch-{issue_number}.md):
|
|
|
|
1. Create branch `architect/<sprint-slug>` on ops repo via Forgejo API
|
|
- Sprint slug: lowercase, hyphenated version of sprint name
|
|
- Use Forgejo API: POST /repos/{owner}/{repo}/git/branches
|
|
|
|
2. Write sprint spec file to sprints/<sprint-slug>.md on the new branch:
|
|
|
|
# Sprint: <name>
|
|
|
|
## Vision issues
|
|
- #N — <title>
|
|
|
|
## What this enables
|
|
<what the project can do after this sprint that it can't do now>
|
|
|
|
## What exists today
|
|
<current state — infrastructure, interfaces, code that can be reused>
|
|
|
|
## Complexity
|
|
<number of files/subsystems, estimated sub-issues>
|
|
<gluecode vs greenfield ratio>
|
|
|
|
## Risks
|
|
<what could go wrong, what breaks if this is done badly>
|
|
|
|
## Cost — new infra to maintain
|
|
<what ongoing maintenance burden does this sprint add>
|
|
<new services, cron jobs, formulas, agent roles>
|
|
|
|
## Recommendation
|
|
<architect's assessment: worth it / defer / alternative approach>
|
|
|
|
3. Create PR on ops repo via Forgejo API:
|
|
- Title: `architect: <sprint summary>`
|
|
- Body: **plain markdown text** from the scratch file (pitch content with sections: What this enables, Complexity, Risks, Cost, Recommendation). Preserve newlines as-is — do NOT JSON-encode the body.
|
|
- Base branch: primary branch (main/master)
|
|
- Head branch: architect/<sprint-slug>
|
|
- Footer: "Reply `ACCEPT` to proceed with design questions, or `REJECT: <reason>` to decline."
|
|
|
|
4. Add `in-progress` label to the vision issue on the disinto repo:
|
|
- Look up the `in-progress` label ID via `GET /repos/{owner}/{repo}/labels`
|
|
- Add the label via `POST /repos/{owner}/{repo}/issues/{vision_issue_number}/labels`
|
|
Body: `{"labels": [<in-progress-label-id>]}`
|
|
|
|
5. After creating all PRs, signal PHASE:done
|
|
|
|
## Forgejo API Reference
|
|
|
|
All operations use the Forgejo API with `Authorization: token ${FORGE_TOKEN}` header.
|
|
|
|
### Create branch
|
|
```
|
|
POST /repos/{owner}/{repo}/branches
|
|
Body: {"new_branch_name": "architect/<sprint-slug>", "old_branch_name": "main"}
|
|
```
|
|
|
|
### Create/update file
|
|
```
|
|
PUT /repos/{owner}/{repo}/contents/<path>
|
|
Body: {"message": "sprint: add <sprint-slug>.md", "content": "<base64-encoded-content>", "branch": "architect/<sprint-slug>"}
|
|
```
|
|
|
|
### Create PR
|
|
```
|
|
POST /repos/{owner}/{repo}/pulls
|
|
Body: {"title": "architect: <sprint summary>", "body": "<markdown-text>", "head": "architect/<sprint-slug>", "base": "main"}
|
|
```
|
|
|
|
**Important: PR body format**
|
|
- The `body` field must contain **plain markdown text** (the raw content from the scratch file)
|
|
- Do NOT JSON-encode or escape the body — pass it as a JSON string value
|
|
- Newlines and markdown formatting (headings, lists, etc.) must be preserved as-is
|
|
|
|
### Close PR
|
|
```
|
|
PATCH /repos/{owner}/{repo}/pulls/{index}
|
|
Body: {"state": "closed"}
|
|
```
|
|
|
|
### Delete branch
|
|
```
|
|
DELETE /repos/{owner}/{repo}/git/branches/<branch-name>
|
|
```
|
|
|
|
### Get labels (look up label IDs by name)
|
|
```
|
|
GET /repos/{owner}/{repo}/labels
|
|
```
|
|
|
|
### Add label to issue (for in-progress on vision issue)
|
|
```
|
|
POST /repos/{owner}/{repo}/issues/{index}/labels
|
|
Body: {"labels": [<label-id>]}
|
|
```
|
|
|
|
### Remove label from issue (for in-progress removal on REJECT)
|
|
```
|
|
DELETE /repos/{owner}/{repo}/issues/{index}/labels/{label-id}
|
|
```
|
|
"""
|