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
109 changes: 73 additions & 36 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,73 +75,110 @@ Build never re-derives a decision the Brain already made.

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
it consults the **vitals faculty**, and only the vitals faculty talks to the Heart
organ. So the Build Agent's full chain is:

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

This generalises: a future Feature Agent can ask the Health Agent whether the
This generalises: a future Feature Agent can ask the vitals faculty 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:

- `AGENTS.md` — what the agent reasons about and how to run it.
- a deterministic entrypoint script (`*.sh` / `*.py`) — the part CI and humans
invoke identically, so behaviour isn't re-derived from prose each time.

Current agents:

- **`agents/feature/`** — the **growth function**: reasons over PyAutoMind
`feature/*` intent and decides *how the organism should grow*. Selects the next
feature task (or plans a named one), estimates difficulty, decides whether to
phase, consults PyAutoMemory for scientific/architectural context and (for
risky work) the Health Agent, and emits a `FeatureDecision` that the existing
`start_dev → ship_library/ship_workspace` workflow consumes. It reasons; it
never edits source. (Organism-facing name: *Growth Agent*.)
- **`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.
Agents live in **two tiers** under `agents/`, distinguished by one question —
*does it act, or only opine?*

- **Conductors** (`agents/conductors/<name>/`) — front-door agents a human
**drives**. They *decide **and** act*, delegating execution to the organs.
They have side effects in the world (a plan driven into dev, a build, a
release). This is the small, curated set of things you invoke and converse
with.
- **Faculties** (`agents/faculties/<name>/`) — read-only reasoning capabilities
the conductors **consult**. They *only opine* — return a judgment and stop;
they never dispatch or mutate. They are *sinks* in the consult graph
(everything reaches into them; they reach out only to their sensor organ). Not
chat-first surfaces, though they stay runnable for a quick read.

The rule of thumb: **keep the conductor set small and human-meaningful; let
faculties multiply behind them.** A side-effecting decider is a conductor; a
side-effect-free opinion is a faculty.

Each agent is a directory with an `AGENTS.md` (what it reasons about + how to run
it) and a deterministic entrypoint script (`*.sh` / `*.py`) — the part CI and
humans invoke identically, so behaviour isn't re-derived from prose each time.

### Conductors

- **`agents/conductors/feature/`** — the **growth function**: reasons over
PyAutoMind `feature/*` intent and decides *how the organism should grow*.
Selects the next feature task (or plans a named one), estimates difficulty,
decides whether to phase, consults PyAutoMemory for scientific/architectural
context and (for risky work) the vitals faculty, and emits a `FeatureDecision`
that the existing `start_dev → ship_library/ship_workspace` workflow consumes.
It reasons; it never edits source. (Organism-facing name: *Growth Agent*.)
- **`agents/conductors/build/`** — the executive function for execution work.
Consults the vitals faculty, 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 the release
conductor.
- **`agents/conductors/release/`** — reasons over `pyauto-heart readiness`, and on
green triggers the PyAutoBuild release executor (`autobuild pre_build` →
`release.yml`); also orchestrates release validation (`release rehearse` /
`release validate`) across the MCP boundary.
- **`agents/conductors/health/`** — the organism's **clinician**: runs the health
*loop* with a human — assess → triage → (on your go-ahead) dispatch a
validation leg → re-judge — until Heart goes GREEN. Consults the vitals faculty
for every verdict and delegates all dispatch to the release conductor; it drives
the loop, not the wire. Named for what it manages (the organism's *health*), not
an external visitor. Current scope is *validation + recommend*, checkpointing
every dispatch; *edit-in fixes* are an explicit follow-up. (Skeleton.)

### Faculties

- **`agents/faculties/vitals/`** — the read-only **vitals faculty** (it *reads the
Heart's pulse*): adopts the PyAutoHeart readiness verdict and explains it,
mapping each reason to its capability. It is the single component that talks to
Heart; the conductors (build, release, feature, health) all consult it rather
than querying Heart directly. It never dispatches or mutates — that inertness is
why it is safe for everyone to call.

> **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,
> scope: generate, run, aggregate, package, tag). `agents/conductors/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
> consulting the vitals faculty *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 (Bug / Refactor / Documentation /
Research agents, and a split-out Release agent); the Feature Agent above is the
first of these, the Brain agent that reasons over PyAutoMind `feature/*` intent.
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 — the Feature Agent's
`MIND_TAXONOMY.md` is that audit for the PyAutoMind/PyAutoMemory surface).
Research agents, cost/risk faculties, …). When adding one, **place it by tier**:
a side-effecting decider you drive → `agents/conductors/<name>/`; a read-only
opinion the conductors consult → `agents/faculties/<name>/`. Follow the Build
Agent's shape (a concise `AGENTS.md` opening with its `Tier:` line, a
deterministic entrypoint, and a capability audit of any organ it drives — the
Feature Agent's `MIND_TAXONOMY.md` is that audit for the PyAutoMind/PyAutoMemory
surface). Keep the conductor set small; prefer adding a faculty when the new
thing only reasons.

## Running

```bash
bin/pyauto-brain help # list agents
bin/pyauto-brain feature # select the best next PyAutoMind feature task
bin/pyauto-brain feature feature/autofit/sbi.md # plan a specific feature task
bin/pyauto-brain build # consult health, then delegate execution to Build
bin/pyauto-brain build # consult vitals, 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 + the unified dashboard card
bin/pyauto-brain health # (conductor) run the health loop with a human, toward green
bin/pyauto-brain vitals # (faculty) one tick + the unified dashboard card (raw read)
```

Like the other PyAuto repos, PyAutoBrain runs from its checkout (no pip install);
Expand Down
49 changes: 35 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,40 @@ 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.
Agents live in **two tiers** under `agents/`, split by one question — *does it
act, or only opine?* **Conductors** (`agents/conductors/`) are front doors you
drive: they decide *and* act, delegating execution to the organs. **Faculties**
(`agents/faculties/`) are read-only reasoning capabilities the conductors
consult: they only return a judgment and stop. Keep the conductor set small; let
faculties multiply behind them.

**Conductors:**

- **`agents/conductors/feature/`** — the growth function: reasons over PyAutoMind
`feature/*` intent and plans how the organism grows.
- **`agents/conductors/build/`** — the executive function for execution work.
Consults the vitals faculty, reasons over the verdict, and on a healthy result
delegates to PyAutoBuild. Has `build` / `deploy` / `release` modes.
- **`agents/conductors/release/`** — reasons over `pyauto-heart readiness` → on
green, runs the PyAutoBuild release executor; also orchestrates release
validation (`release rehearse` / `release validate`).
- **`agents/conductors/health/`** — the organism's clinician: runs the health
loop with a human — assess → triage → (on your go-ahead) dispatch a validation
leg → re-judge — until Heart goes green. Consults the vitals faculty and
delegates dispatch to the release conductor. (Skeleton; validation + recommend.)

**Faculties:**

- **`agents/faculties/vitals/`** — read-only: reads the Heart's pulse — adopts the
PyAutoHeart readiness verdict and explains it. The single component that talks
to Heart.

Brain agents **consult one another**: a conductor doesn't query Heart directly —
it asks the vitals faculty, which is the only agent that talks to the Heart
organ.

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

Expand All @@ -67,9 +87,10 @@ release/build/deploy execution), isolated so it can split into a dedicated

```bash
bin/pyauto-brain help # list agents
bin/pyauto-brain build # consult health, then delegate execution to Build
bin/pyauto-brain build # consult vitals, then delegate execution to Build
bin/pyauto-brain release # reason about readiness, then release on green
bin/pyauto-brain health # one health tick + the unified dashboard card
bin/pyauto-brain health # (conductor) run the health loop with a human, toward green
bin/pyauto-brain vitals # (faculty) one tick + the unified dashboard card (raw read)
```

PyAutoBrain runs from its checkout (no pip install), resolving the sibling
Expand Down
38 changes: 24 additions & 14 deletions agents/_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,41 +73,48 @@ readiness_verdict() {
}

# _agents_dir — directory holding the sibling agents (this file lives in it).
# Agents are organised into two tiers beneath it: conductors/ (front-door agents
# a human drives) and faculties/ (read-only reasoning capabilities the conductors
# consult). This helper returns the tier-parent (agents/); callers add the tier.
_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.
# consult_vitals_verdict [--refresh] — ask the *sibling vitals faculty* for the
# readiness verdict, rather than querying PyAutoHeart directly. This is the
# Brain-agent-consults-Brain-agent pattern: a conductor reasons *with* a
# read-only faculty, and only the vitals faculty talks to the Heart organ. It
# keeps the conductors (build, release, feature, health) decoupled from Heart's
# surface and lets them all read the verdict the same way.
#
# --refresh ask the Health Agent to refresh Heart's state first (a fresh
# (Back-compat: `consult_health_agent_verdict` remains as an alias below — the
# faculty was renamed health -> vitals, and the loop conductor took the name
# `health`.)
#
# --refresh ask the vitals faculty 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() {
consult_vitals_verdict() {
local refresh=0
[[ "${1:-}" == "--refresh" ]] && refresh=1
local health
health="$(_agents_dir)/health/health.sh"
if [[ ! -f "$health" ]]; then
local vitals
vitals="$(_agents_dir)/faculties/vitals/vitals.sh"
if [[ ! -f "$vitals" ]]; then
echo "unknown"
return 0
fi
if [[ "$refresh" -eq 1 ]]; then
bash "$health" tick >/dev/null 2>&1 || true
bash "$vitals" 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
# Heart-less) vitals faculty 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 '
out="$(bash "$vitals" readiness --json 2>/dev/null | python3 -c '
import json, sys
try:
v = json.load(sys.stdin).get("verdict", "unknown")
Expand All @@ -117,3 +124,6 @@ except Exception:
' 2>/dev/null)"
printf '%s\n' "${out:-unknown}"
}

# Back-compat alias for the pre-rename name (faculty: health -> vitals).
consult_health_agent_verdict() { consult_vitals_verdict "$@"; }
22 changes: 13 additions & 9 deletions agents/build/AGENTS.md → agents/conductors/build/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# Build agent

> **Tier: conductor** — a front-door agent you *drive*. It decides *whether/what*
> to build and drives execution, delegating the *building* to PyAutoBuild and the
> *health decision* to the read-only vitals faculty. It acts; it does not measure.

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.
PyAutoBuild and the *health decision* to the vitals faculty.

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

Expand All @@ -20,10 +24,10 @@ 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
vitals faculty**, 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
agents generalise the same way — a Feature Agent asking the vitals faculty 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)
Expand All @@ -39,16 +43,16 @@ later with no churn to build mode.
| `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
Release consults health *more strictly*: it asks the vitals faculty 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.
Heart's surface, reached via `pyauto-brain vitals`).
3. Consult the vitals faculty 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.
Expand Down Expand Up @@ -97,9 +101,9 @@ A future Python `BuildAgent().execute(...)` wrapper can return this same shape.

- 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.
vitals faculty.
- Re-own a health-shim command (`verify_install`, `url_check`, `watch`, `status`,
`tick`, `fix`) — those belong to Heart, reached via `pyauto-brain health`.
`tick`, `fix`) — those belong to Heart, reached via `pyauto-brain vitals`.
- Mix release-specific reasoning into generic build execution — keep it in
release mode.

Expand Down
Loading