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
26 changes: 19 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ humans invoke identically, so behaviour isn't re-derived from prose each time.
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/bug/`** — the organism's **immune system**: recognises a
pathogen (bug, regression, failing test or PyAutoHeart finding), tells it from
benign self, classifies it (severity/scope/type/confidence), consults PyAutoMemory
as immune memory, and mounts a *targeted* response — deciding **where the fix
belongs** (source-first; never degrading a user-facing workspace script, the
autoimmune failure mode) and emitting a `BugDecision` the `start_dev → ship_*`
workflow consumes. Health mode reads two inputs: the live vitals verdict **and**
the filed PyAutoHeart issues. Reuses the Feature Agent's core; consults the vitals
faculty, never Heart directly. It reasons; it never edits source. (Organism-facing
name: *Immune 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
Expand Down Expand Up @@ -155,8 +165,9 @@ humans invoke identically, so behaviour isn't re-derived from prose each time.
> 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, cost/risk faculties, …). When adding one, **place it by tier**:
More specialist agents are expected over time (Refactor / Documentation / Research
agents, a `diagnosis` faculty split from the Bug Agent, 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
Expand Down Expand Up @@ -194,16 +205,17 @@ to the right agent; normal usage never says "PyAutoBrain".
| Command | Routes to | Tier |
|---------|-----------|------|
| `/feature` | Feature Agent → `start_dev` | real conductor |
| `/bug` | Bug Agent → `start_dev` (health mode → vitals + Heart issues) | real conductor |
| `/build` | Build Agent → vitals → Heart → PyAutoBuild | real conductor |
| `/health` | Health Agent loop → vitals → Heart | real conductor |
| `/bug` `/refactor` `/docs` `/research` | `start_dev` pre-tagged with the work-type | work-type entry* |
| `/refactor` `/docs` `/research` | `start_dev` pre-tagged with the work-type | work-type entry* |
| `/route <text>` | infers the work-type and dispatches to one of the above | NL router |
| `/brain <agent>` | raw `bin/pyauto-brain` passthrough | debug door |

\* No dedicated Bug/Refactor/Docs/Research conductor exists yet — those verbs
route through the Brain dev-flow with their PyAutoMind work-type fixed (still
through the Brain, nothing bypassed), until each earns promotion to its own
conductor. Every command routes **through** the Brain; none replaces it.
\* No dedicated Refactor/Docs/Research conductor exists yet — those verbs route
through the Brain dev-flow with their PyAutoMind work-type fixed (still through the
Brain, nothing bypassed), until each earns promotion to its own conductor (as `/bug`
now has). Every command routes **through** the Brain; none replaces it.

The command bodies live in `skills/<verb>/<verb>.md` (thin; installed as flat
commands by `bin/install.sh`); the shared architecture prose is in
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ faculties multiply behind them.

- **`agents/conductors/feature/`** — the growth function: reasons over PyAutoMind
`feature/*` intent and plans how the organism grows.
- **`agents/conductors/bug/`** — the immune system: recognises a bug / regression /
failing test / PyAutoHeart finding, classifies it, decides where the fix belongs
(source-first, never degrading a user-facing script), and plans the repair.
- **`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.
Expand Down Expand Up @@ -108,11 +111,11 @@ natural language) and it routes to the right agent — normal usage never says

> **Users speak in short commands; PyAutoBrain performs the routing.**

- **Real conductors:** `/feature` → Feature Agent, `/build` → Build Agent,
`/health` → Health Agent (each → vitals/Heart/Build as needed).
- **Work-type entries:** `/bug` `/refactor` `/docs` `/research` route through the
Brain dev-flow (`start_dev`) with their PyAutoMind work-type fixed — honest
interim doors until each earns its own conductor.
- **Real conductors:** `/feature` → Feature Agent, `/bug` → Bug Agent, `/build` →
Build Agent, `/health` → Health Agent (each → vitals/Heart/Build as needed).
- **Work-type entries:** `/refactor` `/docs` `/research` route through the Brain
dev-flow (`start_dev`) with their PyAutoMind work-type fixed — honest interim
doors until each earns its own conductor.
- **Router + debug:** `/route <text>` infers the work-type and dispatches;
`/brain <agent>` is the raw passthrough. Every command routes **through** the
Brain; none replaces it.
Expand Down
140 changes: 140 additions & 0 deletions agents/conductors/bug/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Bug agent

> **Tier: conductor** — a front-door agent you *drive*. The organism's
> **immune system**: it recognises a pathogen (a bug, regression, failing test or
> PyAutoHeart finding), tells it from benign self, types the threat, recalls whether
> it has met it before, and mounts a *targeted* response — neutralising the defect at
> its source without harming healthy tissue. It *consults* the read-only vitals
> faculty (`--check-health`), never queries Heart directly, and never wields the
> scalpel itself. (Organism-facing name: *Immune Agent*.)

The **immune response** of PyAutoBrain. Where the Feature Agent grows the organism and
the Health conductor keeps it in homeostasis, the Bug Agent answers a *specific threat*:
it detects and classifies a defect, tells a real pathogen from benign self (an expected
failure, a flaky test, a mis-filed feature), consults immune **memory** (PyAutoMemory)
for prior/recurring/flaky cases, and produces a precise repair plan the `start_dev →
ship_*` workflow executes. It reasons; it does not edit source.

```
report / failing test / issue / PyAutoHeart finding
→ Bug Agent → start_dev → start_library / ship_library
→ start_workspace / ship_workspace
consults ↘ ↙ consults
vitals faculty PyAutoMemory (recurring failures, prior fixes, flaky tests)
```

## Fundamental principle — a precise response, no autoimmunity

A healthy immune response neutralises the pathogen at its source and spares healthy
tissue. The most delicate tissue here is the **user-facing workspace scripts — they are
documentation.** A fix that injects test env-vars, hard-codes a path, mutates
`os.environ`, or drops a silent guard into a tutorial script is an **autoimmune
reaction** — it damages what it exists to protect. So before proposing any patch the Bug
Agent asks *where the fix belongs*, and strongly prefers a **general fix in library
source**. It edits a workspace script only when the defect truly lives there, never in a
way that reduces clarity; sanctioned knobs go through `config/build/env_vars.yaml` /
`no_run.yaml`, not inline edits. This surfaces as the `Fix locus:` field of every
decision. See [`BUG_TAXONOMY.md`](./BUG_TAXONOMY.md) for the full fix-locus rules.

## It reasons; it does not build

The Bug Agent never edits source, opens PRs, or runs builds — that is the existing
`start_dev` / `ship_*` workflow (and PyAutoBuild at release). It never *runs* tests or
health checks either: reproduction means **identifying** the repro command or the Heart
check, and validation is delegated to the vitals faculty. It emits a `BugDecision`; the
workflow acts on it.

## Four modes

| Mode | Trigger | What it does |
|------|---------|--------------|
| **specific** | a `bug/…md` path (or a report) is given | Classify (severity/scope/type/confidence), locate the owner, decide the fix locus + strategy, and produce a `start_dev`-ready plan. |
| **selection** | nothing given | Scan `bug/**`, rank **severity-first** (a bug list is a triage queue), down-rank in-flight work (`active.md`/`planned.md`), and recommend the next bug — with the reason. |
| **difficulty-constrained** | `--difficulty` / `--model` / `--budget` / `--ambitious` / `--impact` | Estimate difficulty per bug and select to match (easy/weak/limited-token → small; ambitious → large; impact → highest severity). |
| **health** | `health` subcommand | Read **two** health inputs — the live **vitals verdict** and the **filed PyAutoHeart GitHub issues** — and route real defects to `bug/health_fixes/`. |

## Classification

Every decision types the threat (heuristic first pass — the reasoning layer refines it):

- **severity:** `critical | high | medium | low`
- **scope:** `single-file | single-repo | multi-repo | ecosystem`
- **type:** `test-failure | runtime-error | wrong-result | docs-error | workflow-error | config-error | release-error | flaky | unknown`
- **confidence:** `high | medium | low`

If a `bug/` prompt is really a feature, refactor, docs or research task, the agent says
so (`rehome_suggestion`) instead of planning a fix.

## Health mode — two inputs, one router

The bug can come from PyAutoHeart. `bug.sh health` gathers both signals and hands them
to `_bug.py`, which emits a first-pass **category hint** per finding (real-bug / config /
flaky / expected) that the reasoning layer confirms before deciding whether the fix
belongs in the affected repo, PyAutoHeart, PyAutoBuild or PyAutoBrain:

1. the **live vitals verdict** — via the vitals faculty (never Heart directly);
2. the **filed PyAutoHeart issues** — `gh issue list --repo PyAutoLabs/PyAutoHeart`
(`$PYAUTO_HEART_REPO` overridable), the durable findings Heart authored.

Findings hinted as real defects become `PyAutoMind/bug/health_fixes/<name>.md` prompts
(its README already cites Heart issue #27); flaky/expected findings are left to the
Health conductor.

> **Boundary with the Health conductor.** The Health conductor drives the assess →
> triage → dispatch loop toward GREEN — its cut is *validation + recommend, no edit-in
> fixes*. The Bug Agent is that deferred edit-in-fix arm: Health hands it a red that is a
> genuine *code* failure, and the Bug Agent turns it into a repair plan. No duplicated
> triage, no re-implemented Heart checks.

## BugDecision (the structured return)

```
Bug · Mode · Classification (severity / scope / type / confidence) · Likely owner
Reproduction (known / unknown / PyAutoHeart check) · Relevant context (PyAutoMemory)
Fix locus (library-source-first · workspace-config · workspace-script[justified] · infra)
Fix strategy (direct · investigate-first · split-into-phases · defer/re-home)
Recommended workflow (library | workspace | combined | infrastructure)
Health validation (vitals checks required before shipping) · Risks · Next action
```

`--json` returns the same shape (JSON-consistent with the Feature Agent's
`FeatureDecision`, plus `classification` and `fix_locus`), so a future Python
`BugAgent().decide(...)` can return it verbatim.

## Run

```bash
bin/pyauto-brain bug # selection mode (severity-first)
bin/pyauto-brain bug bug/autoarray/rect_adapt.md # specific mode
bin/pyauto-brain bug select --difficulty easy # easy bug for limited tokens
bin/pyauto-brain bug select --impact # highest-severity bug
bin/pyauto-brain bug health # vitals verdict + Heart issue scan
bin/pyauto-brain bug --json bug/autofit/x.md # machine-readable BugDecision
bin/pyauto-brain bug --check-health bug/autolens/x.md # also annotate with the vitals verdict
```

Exit codes mirror the Feature Agent: `0` produced a decision · `4` no prompts /
could-not-resolve mind · `5` bad usage. The analysis core (`_bug.py`) is stdlib-only,
does no network/Git, and never writes — `bug.sh` feeds it the verdict + Heart issues.

## Faculties (a seam, not yet built)

The Bug Agent ships as a **conductor only**, consulting the existing `vitals` faculty.
Its pure, side-effect-free reasoning — classify + locate + fix-locus — is the shape of a
future read-only **`diagnosis` faculty** (reusable by the Feature Agent's re-homing and
the Health conductor). Keeping the conductor set small, that split is deferred with a
clean seam, exactly as Release stayed a mode of Build. See
[`BUG_TAXONOMY.md`](./BUG_TAXONOMY.md).

## What this agent must never do

- Edit source, open PRs, or run builds — that is `start_dev` / `ship_*` / PyAutoBuild.
- Run tests or health checks, or re-implement a PyAutoHeart check — consult the vitals
faculty (`--check-health`) and let Heart measure.
- Query PyAutoHeart directly — only the vitals faculty talks to the Heart organ.
- **Degrade a user-facing workspace script** to mask a symptom (the autoimmune failure
mode) — prefer a general library-source fix.
- Just pick the first bug in selection mode — rank severity-first and explain the choice.

See [`BUG_TAXONOMY.md`](./BUG_TAXONOMY.md) for the classification taxonomy, the fix-locus
rules, the two health inputs, and the reuse of the Feature difficulty heuristic.
Loading