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
21 changes: 16 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ Each agent is a directory under `agents/<name>/` with:

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
Expand All @@ -117,16 +124,20 @@ Current agents:
> 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, 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).
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).

## 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 --dry-run # reason + plan only (emit the BuildDecision)
bin/pyauto-brain release # reason about readiness, then release on green
Expand Down
29 changes: 29 additions & 0 deletions agents/_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,35 @@ resolve_autobuild() {
_resolve_bin autobuild "$PYAUTO_ROOT/PyAutoBuild/bin/autobuild"
}

# _resolve_dir <env-var-name> <repo-name> — echo the path to a sibling PyAuto
# *repository checkout* (not a binary), or print a hint to stderr and return 1.
# Organs like PyAutoMind and PyAutoMemory are markdown knowledge bases with no
# CLI: the Brain reasons over their files directly. Resolution order: an explicit
# env override (e.g. PYAUTO_MIND), then $PYAUTO_ROOT/<repo>, then a couple of
# common dev layouts ($HOME/<repo>, $HOME/Code/<repo>).
_resolve_dir() {
local var="$1" repo="$2" override="${!1:-}" c
if [[ -n "$override" && -d "$override" ]]; then printf '%s' "$override"; return 0; fi
# The parent of this PyAutoBrain checkout is the most reliable sibling root
# (organs are typically cloned side by side), so check it first.
local brain_parent
brain_parent="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/../.." && pwd)"
for c in "$brain_parent/$repo" "$PYAUTO_ROOT/$repo" "$HOME/$repo" \
"$HOME/Code/$repo" "$HOME/Code/PyAutoLabs/$repo"; do
if [[ -d "$c" ]]; then printf '%s' "$c"; return 0; fi
done
echo "pyauto-brain: '$repo' checkout not found (set $var, or clone it beside PyAutoBrain / under $PYAUTO_ROOT)" >&2
return 1
}

# resolve_mind — locate the PyAutoMind checkout (the organism's intent store).
resolve_mind() { _resolve_dir PYAUTO_MIND PyAutoMind; }

# resolve_memory — locate the PyAutoMemory checkout (the organism's long-term
# scientific/architectural knowledge). Optional: the Feature Agent degrades
# gracefully when memory is absent rather than inventing context.
resolve_memory() { _resolve_dir PYAUTO_MEMORY PyAutoMemory; }

# readiness_verdict — run `pyauto-heart readiness --json` and echo the verdict
# string (green/yellow/red). Returns non-zero if Heart can't be resolved/run.
readiness_verdict() {
Expand Down
116 changes: 116 additions & 0 deletions agents/feature/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Feature agent

The **growth function** of PyAutoBrain. It reasons over the feature *intent*
stored in PyAutoMind and decides **how the organism should grow** — which feature
task to work on, how hard it is, whether it must be phased, what scientific
context applies, and which development path to take. It does **not** implement
code: it produces a structured `FeatureDecision` that the existing development
workflow consumes.

```
Mind (PyAutoMind feature/*) → Feature Agent → start_dev
→ start_library / ship_library
→ start_workspace / ship_workspace
consults ↘ ↙ consults
Health Agent PyAutoMemory (scientific / architectural context)
```

> Long term this is the organism-facing **Growth Agent**; *Feature Agent* is the
> engineering-facing name and the safe first implementation.

## Fundamental principle

**The Feature Agent reasons; it does not build.** It never edits source. It reads
intent, consults memory, estimates difficulty, decides phasing, and emits a plan
that `start_dev` / `ship_*` execute. Implementation only happens when the plan is
handed to the existing workflow.

## Brain agents consult one another

Like the Build Agent, the Feature Agent is a citizen of the society of agents.
For risky / multi-repo / release-bound work it **consults the sibling Health
Agent** (`--check-health`) rather than querying the Heart organ directly — only
the Health Agent talks to Heart. It also consults **PyAutoMemory** for scientific
and architectural context, and **never invents science** when memory has
material. See [`MIND_TAXONOMY.md`](./MIND_TAXONOMY.md) for the PyAutoMind taxonomy
it reasons over and the PyAutoMemory routing it uses.

## Three modes

| Mode | Trigger | What it does |
|------|---------|--------------|
| **specific** | a task path is given | Read the named prompt, classify repos, consult memory, size it, decide phasing, and produce a `start_dev`-ready plan. |
| **selection** | no task given | Scan `feature/**`, rank candidates, and recommend the best next task — **not** merely the first in a list; down-ranks in-flight work (from `active.md` / `planned.md`). |
| **difficulty-constrained** | `--difficulty` / `--model` / `--budget` / `--ambitious` / `--impact` | Estimate difficulty per task and select to match the constraint (easy/weak-model/limited-token → small; ambitious/strong-model → large; impact → high-leverage). |

## Difficulty & sizing

Difficulty is a transparent heuristic (`small | medium | large | too-large`) over
repos affected, prompt size, scientific complexity, architectural risk, test
burden, and whether memory context / human judgement is required. The factor
breakdown is in every decision so the reasoning layer can adjust.

Sizing then drives the **phase decision**:

- **direct** — small/medium; one PR.
- **split-into-phases** — large/too-large; prefer several small shippable PRs over
one fragile PR. For *too-large* it emits phase stubs, e.g.
`feature/<target>/<name>_phase_1_design.md … _phase_4_docs.md`.
- **research-first** — ambiguous, no repo resolved; open a `research/` task first.
- **defer / re-home** — if the prompt is mis-filed (a bug, refactor, research or
experiment), it says so and suggests the correct PyAutoMind category.

## Run

```bash
bin/pyauto-brain feature # selection mode
bin/pyauto-brain feature feature/autofit/sbi.md # specific mode
bin/pyauto-brain feature select --difficulty easy # easy task
bin/pyauto-brain feature select --model strong --limit 5 # ambitious shortlist
bin/pyauto-brain feature select --impact # highest-leverage
bin/pyauto-brain feature --check-health feature/autolens/x.md # also consult Health
bin/pyauto-brain feature --json select # machine-readable
```

A bare path is treated as `specific`; nothing given is `selection`. `--json`
emits the full `FeatureDecision` (with a `shortlist` in selection modes).

Exit codes: `0` produced a decision · `4` no prompts / could-not-resolve mind ·
`5` bad usage (unknown task / flag).

## FeatureDecision (the structured return)

Mirrors the spec's required fields:

```
Selected task · Mode · Work-type/target · Repos affected · Difficulty (+score)
Recommended workflow (library|workspace|combined|research|experiment|refactor|bug)
Relevant context (PyAutoMemory sub-wikis to consult) · Phase decision (+stubs)
Execution plan (start_dev / start_library / ship_library / start_workspace / …)
Health considerations · Risks · Next action (one concrete step)
```

`--json` returns the same shape for programmatic use (a future Python
`FeatureAgent().decide(...)` can return it verbatim).

## Workflow mapping

- **library** → `start_dev` → `start_library` → `ship_library`
- **workspace** → `start_dev` → `start_workspace` → `ship_workspace`
- **combined** → library PR first (so the workspace consumes its `## API Changes`
summary), then the workspace PR; ship both in order.

Library vs. workspace is decided from the `@RepoName` references in the prompt
body, not the folder (per PyAutoMind `ROUTING.md`).

## What this agent must never do

- Edit source, open PRs, or run builds itself — that is the Build Agent /
PyAutoBuild via `start_dev` / `ship_*`.
- Query PyAutoHeart directly — consult the Health Agent (`--check-health`).
- Invent scientific or architectural context when PyAutoMemory has material —
cite the sub-wiki instead.
- Just pick the first prompt in selection mode — rank, and explain the choice.

See [`MIND_TAXONOMY.md`](./MIND_TAXONOMY.md) for the PyAutoMind work-type taxonomy,
the PyAutoMemory sub-wiki routing, and the difficulty heuristic in detail.
116 changes: 116 additions & 0 deletions agents/feature/MIND_TAXONOMY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# PyAutoMind & PyAutoMemory surface known to the Feature Agent

This audit records the **intent surface** (PyAutoMind) the Feature Agent reasons
over and the **knowledge surface** (PyAutoMemory) it consults. Both are markdown
knowledge bases with no CLI — the Brain reasons over their files directly. The
agent must treat these as inputs to reason about, never as logic to reimplement.
Sources of truth: `PyAutoMind/ROUTING.md`, `PyAutoMind/README.md`,
`PyAutoMemory/index.md`.

## PyAutoMind taxonomy (intent → work-type)

Prompts live at `<work-type>/<target>/<name>.md`. The **work-type** (first
folder) declares the kind of thinking required; the **target** (second folder)
names the affected repo or domain. The Feature Agent owns `feature/` and helps
keep it organised — re-homing mis-filed prompts.

| Work-type | Intent | If a `feature/` prompt is really this → re-home as |
|-----------|--------|-----------------------------------------------------|
| `feature/` | new user-facing / scientific capability | (stays) |
| `bug/` | incorrect behaviour, crash, regression | `bug/` |
| `refactor/` | internal restructuring, no behaviour change | `refactor/` |
| `research/` | unclear science → investigate before building | `research/` |
| `experiment/` | proof-of-concept / spike | `experiment/` |
| `docs/` `test/` `release/` `maintenance/` `triage/` | docs / tests / release / hygiene / unclear | matching folder |

The agent classifies a prompt's intent and, when it does not match `feature/`,
states the better category in `rehome_suggestion` rather than planning code.

## Targets → library vs. workspace

The `/start_library` ↔ `/start_workspace` split is decided from the `@RepoName`
references in the **prompt body**, not the folder (per `ROUTING.md`).

- **Libraries** (source): PyAutoConf, PyAutoFit, PyAutoArray, PyAutoGalaxy,
PyAutoLens (`autoconf`, `autofit`, `autoarray`, `autogalaxy`, `autolens`;
aliases `aa`/`af`/`ag`/`al`). API paths like `@aa.decorators.transform`
resolve by their head token (`aa` → `autoarray`).
- **Workspaces / tutorials / examples**: `autolens_workspace`(`_test`),
`autogalaxy_workspace`(`_test`), `autofit_workspace`(`_test`), `HowToLens`,
`HowToGalaxy`, `HowToFit`, `autolens_assistant`, `autolens_profiling`, and the
`workspaces` bucket.

`@`-mentions that resolve to neither (e.g. `@z_projects`, `@jax`) are dropped so
the repo count reflects real affected repos. Workflow mapping:

- library only → `start_dev → start_library → ship_library`
- workspace only → `start_dev → start_workspace → ship_workspace`
- both → library PR first (workspace consumes its `## API Changes` summary), then
the workspace PR; ship in order.

## Workflow state the agent reads

- `active.md` — in-flight tasks (sessions, worktrees, claimed repos).
- `planned.md` — filed-but-not-started tasks.
- `queue.md` — ordered processing queues.

In **selection** mode the agent extracts `feature/...md` paths referenced in
`active.md` / `planned.md` and **down-ranks** them, so it surfaces genuinely new
next work rather than resurfacing what is already moving. Priorities and
inter-task dependencies are applied by the reasoning layer on top of the ranking.

## PyAutoMemory routing (scientific / architectural context)

Before planning substantial scientific or architectural work, the agent maps the
task to the relevant PyAutoMemory sub-wiki and **cites it** — it does not invent
context when memory has material. Sub-wikis (source: `PyAutoMemory/index.md`):

| Sub-wiki | Domain | Triggered by (examples) |
|----------|--------|--------------------------|
| `lensing_wiki/` | strong gravitational lensing | lens, deflection, source reconstruction, subhalo, time delay, cosmography, SLACS/TDCOSMO |
| `smbh_wiki/` | supermassive black holes | black hole, SMBH, binary, recoil, NANOGrav |
| `cti_wiki/` | charge-transfer inefficiency | CTI, trap, arctic, VIS calibration |
| `methods_wiki/` | statistical / computational methods | Bayesian, sampler, JAX, NUFFT, SBI, graphical models, deep learning |
| `galaxies_wiki/` | galaxy formation & evolution | bulge/disk, MGE, morphology, IFU, kinematics |

Library targets also pull a default sub-wiki (`autolens`→lensing,
`autogalaxy`→galaxies, `autofit`/`autoarray`/`autoconf`→methods). PyAutoMemory is
**optional**: if the checkout is absent the agent still names the sub-wikis to
read, degrading gracefully rather than failing.

## Difficulty heuristic (transparent by design)

`_feature.py` scores each task and the score appears in every decision:

| Signal | Contribution |
|--------|--------------|
| repos affected | `(count − 1) × 2` — the dominant driver |
| library **and** workspace | `+2` (coordination cost) |
| prompt size | `+min(words/150, 4)` |
| scientific complexity | `+min(#keywords, 3)` |
| architectural / API risk | `+min(#keywords × 2, 4)` |
| test burden (JAX, smoke, parity, …) | `+1` |
| memory context required | `+1` |

Thresholds: `≤2 small · ≤5 medium · ≤9 large · >9 too-large`. These are a
**v1 heuristic**: the factor breakdown is exposed precisely so the reasoning
layer can override the bucket (e.g. a pre-phased prompt that scores "too-large"
is already a single phase). When the keyword lists or thresholds drift, update
them here and in `_feature.py` together; do not encode them anywhere the agent
must re-derive at runtime.

## Boundary audit — reasoning vs. intent vs. knowledge vs. execution

```
intent → PyAutoMind (feature/* prompts, active/planned/queue state)
reasoning → PyAutoBrain (Feature Agent — this)
knowledge → PyAutoMemory (via direct file reads; cited, never invented)
health → PyAutoHeart (via the Health Agent, never queried directly)
execution → PyAutoBuild (via start_dev / ship_* — never run by this agent)
```

No execution, health-checking, or knowledge-authoring logic lives in the Feature
Agent. It reads intent, consults knowledge and (optionally) health, reasons, and
hands a plan to the existing workflow. If intent-shaping logic ever creeps in
here, it belongs back in PyAutoMind; if knowledge authoring creeps in, it belongs
in PyAutoMemory.
Loading