Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,24 @@ The Brain asks `pyauto-heart readiness --json`, reasons over the result, and onl
on a **green** verdict triggers Build's release. Heart never triggers Build;
Build never re-derives a decision the Brain already made.

## Brain agents consult one another (a society of agents)

Brain agents are not limited to driving organs — they can **consult each other**.
The canonical example is the **Build Agent**, which does not query Heart directly:
it consults the **Health Agent**, and only the Health Agent talks to the Heart
organ. So the Build Agent's full chain is:

```
Mind → Build Agent → Health Agent → Heart → GREEN/YELLOW/RED
→ Build Agent → Build (execute)
```

This generalises: a future Feature Agent can ask the Health Agent whether the
tree is fit for a refactor; a future Release Agent can ask the Build Agent to
package a release. Reasoning lives in Brain agents that consult one another; the
organs (Heart, Hands/Build, Memory) provide capabilities and state. The Build
Agent is the reusable template for this pattern.

## Specialist reasoning agents

Each agent is a directory under `agents/<name>/` with:
Expand All @@ -81,19 +99,36 @@ Each agent is a directory under `agents/<name>/` with:

Current agents:

- **`agents/build/`** — the executive function for execution work. Consults the
Health Agent, reasons over the verdict, and on a healthy result delegates to
the appropriate PyAutoBuild capability. The canonical example of the Brain
coordinating *multiple* organs. Has `build` / `deploy` / `release` modes —
release is isolated as a mode now, with a clean seam to a future Release Agent.
- **`agents/release/`** — reasons over `pyauto-heart readiness`, and on green
triggers the PyAutoBuild release executor (`autobuild pre_build` → `release.yml`).
- **`agents/health/`** — reasons over the PyAutoHeart monitoring/readiness surface.

> **Build Agent vs. release mode vs. the release agent.** The Build Agent owns
> all execution orchestration and keeps release as one of its modes (broad build
> scope: generate, run, aggregate, package, tag). `agents/release/` is the older,
> narrower readiness→`pre_build` driver. The mature architecture splits a
> dedicated **Release Agent** out of the Build Agent's release mode — making
> release-specific decisions (versioning, changelogs, PyPI/tags, human approval),
> consulting the Health Agent *more strictly*, then requesting execution from the
> Build Agent / PyAutoBuild. Until then: one agent now, clean seam for two later.

More specialist agents are expected over time (e.g. a Feature agent that reasons
over PyAutoMind tasks, a Build agent that coordinates execution, several health
agents each reasoning over a different part of Heart); add them as new
`agents/<name>/` directories.
over PyAutoMind tasks, Bug / Refactor / Documentation / Research agents, and a
split-out Release agent). The Build Agent is the reusable template — add new
ones as `agents/<name>/` directories following its shape (a concise `AGENTS.md`,
a deterministic entrypoint, and a capability audit of any organ it drives).

## Running

```bash
bin/pyauto-brain help # list agents
bin/pyauto-brain build # consult health, then delegate execution to Build
bin/pyauto-brain build --dry-run # reason + plan only (emit the BuildDecision)
bin/pyauto-brain release # reason about readiness, then release on green
bin/pyauto-brain health # one health tick + readiness verdict
```
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,32 @@ Brain → Heart (gate) → Build (execute)

## Specialist reasoning agents

- **`agents/build/`** — the executive function for execution work. Consults the
Health Agent, reasons over the verdict, and on a healthy result delegates to
PyAutoBuild. The canonical example of the Brain coordinating multiple organs;
has `build` / `deploy` / `release` modes.
- **`agents/release/`** — reasons over `pyauto-heart readiness` → on green, runs
the PyAutoBuild release executor.
- **`agents/health/`** — reasons over the PyAutoHeart monitoring / readiness surface.

Brain agents can also **consult one another**: the Build Agent doesn't query
Heart directly — it asks the Health Agent, which is the only agent that talks to
the Heart organ.

```
Mind → Build Agent → Health Agent → Heart → GREEN/YELLOW/RED
→ Build Agent → Build (execute)
```

Release is a **mode** of the Build Agent today (because PyAutoBuild owns
release/build/deploy execution), isolated so it can split into a dedicated
**Release Agent** later — one agent now, clean seam for two later.

## Usage

```bash
bin/pyauto-brain help # list agents
bin/pyauto-brain build # consult health, then delegate execution to Build
bin/pyauto-brain release # reason about readiness, then release on green
bin/pyauto-brain health # one health tick + readiness verdict
```
Expand Down
46 changes: 46 additions & 0 deletions agents/_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,49 @@ readiness_verdict() {
heart="$(resolve_heart)" || return $?
"$heart" readiness --json | python3 -c 'import json,sys; print(json.load(sys.stdin).get("verdict","unknown"))'
}

# _agents_dir — directory holding the sibling agents (this file lives in it).
_agents_dir() {
cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd
}

# consult_health_agent_verdict [--refresh] — ask the *sibling Health Agent* for
# the readiness verdict, rather than querying PyAutoHeart directly. This is the
# Brain-agent-consults-Brain-agent pattern: a specialist agent reasons *with*
# another specialist agent, and only the Health Agent talks to the Heart organ.
# It keeps the Build Agent decoupled from Heart's surface and lets future agents
# (Feature, Release, ...) consult one another the same way.
#
# --refresh ask the Health Agent to refresh Heart's state first (a fresh
# gate); release-grade work uses this, ordinary build work does not.
#
# Echoes one of: green | yellow | red | unknown. Never fails the caller — an
# unresolvable/again-unknown verdict is reported as "unknown" (treated as YELLOW
# by callers), never silently as green.
consult_health_agent_verdict() {
local refresh=0
[[ "${1:-}" == "--refresh" ]] && refresh=1
local health
health="$(_agents_dir)/health/health.sh"
if [[ ! -f "$health" ]]; then
echo "unknown"
return 0
fi
if [[ "$refresh" -eq 1 ]]; then
bash "$health" tick >/dev/null 2>&1 || true
fi
# Capture into a variable rather than piping straight out: the caller may have
# `set -o pipefail`, under which a non-zero exit from the (possibly
# Heart-less) Health Agent would otherwise double-fire a fallback. The python
# below always prints exactly one token, even on empty/garbage input.
local out
out="$(bash "$health" readiness --json 2>/dev/null | python3 -c '
import json, sys
try:
v = json.load(sys.stdin).get("verdict", "unknown")
print(v or "unknown")
except Exception:
print("unknown")
' 2>/dev/null)"
printf '%s\n' "${out:-unknown}"
}
107 changes: 107 additions & 0 deletions agents/build/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Build agent

The second canonical **PyAutoBrain** reasoning agent, and the reference example
of how the Brain coordinates *multiple* organs. It is the executive function for
execution work: it owns the build *workflow* but delegates the *building* to
PyAutoBuild and the *health decision* to the Health Agent.

```
Mind → Build Agent → Health Agent → Heart → GREEN/YELLOW/RED
→ Build Agent → PyAutoBuild (execute)
```

## Fundamental principle

**The Build Agent does not build software itself — PyAutoBuild does.** The Build
Agent decides *whether* building should happen, *what* to build, *which*
PyAutoBuild capability to invoke, and *whether to proceed or stop*. It reasons;
PyAutoBuild executes. It must never duplicate PyAutoBuild functionality.

## Brain agents consult one another

The Build Agent does not call PyAutoHeart directly. It **consults the sibling
Health Agent**, which is the only agent that talks to the Heart organ. This is
the society-of-agents pattern: specialist Brain agents reason *with* each other,
while the organs (Heart, Hands, Memory) provide capabilities and state. Future
agents generalise the same way — a Feature Agent asking the Health Agent if the
tree is fit for a refactor; a Release Agent asking the Build Agent to package.

## Modes (one agent now, clean seam for a Release Agent later)

Release is in scope today because PyAutoBuild currently owns release/build/deploy
execution. It is isolated as its own **mode** so release-specific reasoning never
bleeds into generic build execution, and can split into a dedicated Release Agent
later with no churn to build mode.

| Mode | Default action | Gate policy | Routes to (PyAutoBuild) |
|------|----------------|-------------|--------------------------|
| `build` | `run_all` | lenient — GREEN/YELLOW proceed, RED aborts | `generate`, `run`, `run_python`, `run_all`, `script_matrix`, `aggregate_results`, `slow_skip_check`, `repro_command`, `bump_colab_urls` |
| `deploy` | `generate` | cautious — GREEN proceeds, YELLOW needs `--force`, RED aborts | `generate`, `bump_colab_urls` |
| `release` | `pre_build` | strict — refreshes health first; GREEN proceeds, YELLOW needs `--force`, RED aborts | `pre_build`, `tag_and_merge`, `generate_release_notes`, `create_analysis_issue`, `aggregate_results` |

Release consults health *more strictly*: it asks the Health Agent to refresh
Heart's state first (`--refresh`) so a release is never gated on a stale verdict.
An **unknown** verdict collapses to YELLOW — never silently GREEN.

## Build lifecycle

1. Receive a build request (mode + action).
2. Validate the action against the mode (reject health-shim commands — those are
Heart's surface, reached via `pyauto-brain health`).
3. Consult the Health Agent for the readiness verdict.
4. Interpret it: **GREEN** proceed · **YELLOW** caution (proceed in build mode,
else `--force`) · **RED** abort with blockers.
5. Invoke the appropriate PyAutoBuild capability.
6. Emit a structured `BuildDecision`.

## Run

```bash
bin/pyauto-brain build # build mode, run_all, after health consult
bin/pyauto-brain build generate autolens # build mode, generate notebooks for autolens
bin/pyauto-brain build --dry-run # reason + plan only, do not execute
bin/pyauto-brain build --json generate ag # emit only the BuildDecision JSON
bin/pyauto-brain build --mode deploy --force generate
bin/pyauto-brain build --mode release -- 2 # release mode; forward minor_version 2 to pre_build
```

Anything after `--` is forwarded verbatim to the PyAutoBuild subcommand.

Exit codes: `0` proceeded/delegated (or dry-run) · `2` yellow blocked (use
`--force`) · `3` red blocked · `4` unknown/could-not-consult · `5` invalid
mode/action.

## BuildDecision (the structured return)

`--json` (or the `-- BuildDecision --` block) emits:

```json
{
"agent": "build",
"mode": "build|deploy|release",
"requested_action": "<PyAutoBuild capability>",
"health_status": "green|yellow|red|unknown",
"decision": "proceed|proceed-with-caution|abort",
"execution_plan": ["autobuild <action> <args>"],
"execution_summary": "<one line>",
"warnings": ["..."],
"blockers": ["..."],
"follow_up_recommendations": ["..."],
"dry_run": false
}
```

A future Python `BuildAgent().execute(...)` wrapper can return this same shape.

## What this agent must never do

- Build, package, tag, or publish anything itself — that is PyAutoBuild's job.
- Query PyAutoHeart directly or re-derive a readiness verdict — consult the
Health Agent.
- Re-own a health-shim command (`verify_install`, `url_check`, `watch`, `status`,
`tick`, `fix`) — those belong to Heart, reached via `pyauto-brain health`.
- Mix release-specific reasoning into generic build execution — keep it in
release mode.

See [`BUILD_CAPABILITIES.md`](./BUILD_CAPABILITIES.md) for the audit of every
PyAutoBuild capability the agent calls, and the execution/health boundary.
82 changes: 82 additions & 0 deletions agents/build/BUILD_CAPABILITIES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# PyAutoBuild capabilities known to the Build Agent

This audit records the execution surface the PyAutoBrain Build Agent reasons over
and **calls**. The agent must treat every item here as a PyAutoBuild capability,
not as logic to reimplement inside Brain. Source of truth: the `autobuild`
dispatcher (`PyAutoBuild/bin/autobuild`) and `PyAutoBuild/CLAUDE.md`.

## Execution capabilities (the Build Agent calls these)

From `autobuild help`:

| Capability | What it does | Build Agent mode |
|------------|--------------|------------------|
| `pre_build` | Format, regenerate notebooks, push workspaces, then dispatch `release.yml`. | release |
| `tag_and_merge` | Commit and tag every library repo for a release. | release |
| `generate_release_notes` | Generate release notes from merged PRs and create GitHub Releases. | release |
| `create_analysis_issue` | Open a GitHub issue with the release report and assign Copilot. | release |
| `generate` | Convert a workspace's `scripts/` to `notebooks/`. | build, deploy |
| `run` | Execute notebooks in a workspace folder. | build |
| `run_python` | Execute Python scripts in a workspace folder. | build |
| `run_all` | Run scripts across one or more workspaces, produce summary reports. | build |
| `script_matrix` | Output a JSON `{name, directory}` matrix for GitHub Actions. | build |
| `aggregate_results` | Aggregate per-job JSON into a release-readiness report. | build, release |
| `slow_skip_check` | Surface SLOW / NEEDS_FIX entries in workspace `no_run.yaml`. | build |
| `repro_command` | Emit the shell command autobuild uses to run one script. | build |
| `bump_colab_urls` | Rewrite Colab URLs in cwd from an old to a new date-tag. | build, deploy |

Underlying implementation assets the agent never re-owns: `autobuild/run_python.py`,
`run.py`, `generate.py`, `script_matrix.py`, `aggregate_results.py`,
`tag_and_merge.sh`, `build_util.py`, the `release.yml` GitHub workflow, and the
per-workspace `config/build/{no_run,env_vars,copy_files,visualise_notebooks}.yaml`.

## Boundary audit — execution vs. health

PyAutoBuild is meant to be a **pure executor**: it runs no readiness checks of
its own. Confirmed against `PyAutoBuild/CLAUDE.md` ("PyAutoBuild is the executor
… it runs **no** release-readiness checks of its own").

It does, however, still expose **health-shim commands** that delegate to the
health authority (named PyAutoPulse in current PyAutoBuild docs; that is
PyAutoHeart, which keeps a `pyauto-pulse` back-compat shim):

- `verify_install` — shim → health authority (deep install-path checks).
- `url_check` — shim → health authority (forbidden Binder/Colab URL guard).
- `watch` / `status` / `tick` / `fix` — monitoring-daemon shims.

**Decision:** these are health concerns, not build actions. The Build Agent
**refuses to route them** and points the caller at `pyauto-brain health <cmd>`
instead. They belong to PyAutoHeart and are reached through the Health Agent —
never re-owned by the Build Agent, and never duplicated in Brain. No non-trivial
readiness logic was found living *inside* PyAutoBuild itself (the shims only
delegate); if any ever appears, migrate it to PyAutoHeart and leave only
delegation in PyAutoBuild.

This keeps the architecture clean:

```
reasoning → PyAutoBrain (Build Agent, Health Agent)
health → PyAutoHeart (via the Health Agent)
execution → PyAutoBuild (via the Build Agent)
```

## Drift note

Current PyAutoBuild guidance still uses the older name **PyAutoPulse** for the
health authority and **PyAutoAgent** for the reasoning layer in places. The Build
Agent reasons about *categories of capability* (execution vs. health), not fixed
names, so a rename in PyAutoBuild does not break it. When PyAutoBuild gains or
renames an execution subcommand, update the table above; do not encode the list
anywhere the agent must re-derive at runtime beyond the per-mode allowlists in
`build.sh`.

## Build Agent decision policy (recap)

- **GREEN** — proceed; invoke the requested PyAutoBuild capability.
- **YELLOW** — build mode proceeds with a warning; deploy/release require
`--force`. An unknown verdict is treated as YELLOW.
- **RED** — abort; surface Heart's blockers (via the Health Agent) and do not
execute.

The Build Agent may sequence, plan, and explain execution, but it must never run
a build step itself, query Heart directly, or re-derive the readiness verdict.
Loading