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
76 changes: 76 additions & 0 deletions agents/conductors/hygiene/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Hygiene agent

> **Tier: conductor** — a front-door agent you *drive*. The *maintenance
> function* — the organism's sense of its own upkeep: it owns the code-quality
> debt that neither proves the organism works (that is Heart) nor measures the
> speed of modelling (that is profiling). It consults the read-only vitals
> faculty like every conductor, reasons over the quality signals, and emits a
> `HygieneDecision` the human/session executes — delegating the actual fixes to
> the dev-flow conductors. It never issues health verdicts and never releases.

Grown from demonstrated need: the hygiene reasoning already exists, scattered —
the `repo_cleanup` skill (whose SKILL.md explicitly foreshadowed this "Cleanup
Agent"), `cli_noise_clean`, `dep_audit` and `audit_docs` — plus recurring manual
perf-hygiene work (slow unit tests, slow integration-mode scripts, import cost).
This conductor unifies and prioritises them. Design decision (conductor, **no
paired repo**, boundaries) recorded in PyAutoMind
`research/pyautobrain/hygiene_agent_decision.md` and the founding prompt
`feature/pyautobrain/hygiene_agent.md`.

## Modes

| Mode | Question | Emits |
|------|----------|-------|
| `perf` | Which unit tests / integration-mode workspace scripts / imports are slow, and what is the cheapest win? | timing findings + route (refactor/bug; JAX-adapt only on a clear win) — *phase 3* |
| `tidy` | What git debris (stale branches, stashes, `[gone]` refs, dirty checkouts) is safe to remove? | the `repo_cleanup` sweep — *phase 2* |
| `noise` | What CLI noise (warnings, stray prints, library chatter) do tests/scripts emit? | the `cli_noise_clean` audit — *phase 2* |
| `deps` | Which dependency caps drift behind PyPI, and at what risk? | the `dep_audit` summary — *phase 2* |
| `docs` | Which `docs/api/*.rst` module paths are stale? | the `audit_docs` findings — *phase 2* |
| *(default)* | Across all of the above, what is the single most useful hygiene action now? | a prioritised `HygieneDecision` worklist |

```
pyauto-brain hygiene # audit across modes → prioritised worklist
pyauto-brain hygiene perf # dev-loop timing (staged: phase 3)
pyauto-brain hygiene tidy # git debris (staged: phase 2)
pyauto-brain hygiene noise # CLI noise (staged: phase 2)
pyauto-brain hygiene deps # dependency-cap drift (staged: phase 2)
pyauto-brain hygiene docs # stale API docs (staged: phase 2)
pyauto-brain hygiene <mode> --json
```

> **Staged.** This is the phase-1 scaffold: the conductor is real, routable and
> bounded, but the modes are stubs — each prints its staged notice. Phase 2
> absorbs `repo_cleanup` (`tidy`) and `cli_noise_clean` (`noise`) and consults
> `dep_audit` (`deps`) / `audit_docs` (`docs`); phase 3 builds `perf` and any
> PyAutoHeart observation legs.

## Fundamental principles

- **Find and prioritise; delegate the fix.** Hygiene surfaces quality debt and
ranks it; the actual repair is ordinary dev-flow work routed to `refactor`
(restructure), `bug` (regression-shaped), or a `feature` — shipped through
`ship_library` / `ship_workspace`. The conductor never reinvents fix machinery.
- **Measurement lives in Heart; hygiene acts.** Heart already observes and tracks
the dev-loop timing signals (`script_timing`, `test_run`); hygiene reads them
and acts, the same split the health conductor follows. New standing signals
(import cost, CLI noise) become Heart *legs*, not a new repo — hygiene has no
persistent artifact lifecycle of its own to house (the reason it is a
conductor with no paired organ).
- **Stdlib / bash only** in the conductor itself — like profiling, it must never
drag the JAX stack into the Brain.

## Boundaries

- **vs profiling** — split by *what is measured*. Profiling owns the product's
modelling / compute speed (likelihood on the science grid, GPU tiers, vram,
A100, baselines/pins); hygiene owns the *developer loop's* cost (unit tests,
`PYAUTO_TEST_MODE` / `PYAUTO_SMALL_DATASETS` integration scripts, import time).
Hunting generally-slow functions flagged by integration tests is hygiene's
`perf` mode (moved here from profiling's staged future modes). JAX-adaptation
is shared: hygiene flags a dev-loop function and delegates; a likelihood on the
science grid is profiling's call.
- **vs health** — Heart observes and verdicts; hygiene acts on the observations.
Consults the vitals faculty; never issues a health verdict.
- **vs bug / refactor** — hygiene finds and prioritises debt and *delegates* the
fix to them; they own the repair.
- **vs build** — hygiene is upkeep, not release; it never touches PyAutoBuild.
98 changes: 98 additions & 0 deletions agents/conductors/hygiene/hygiene.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/usr/bin/env bash
# agents/conductors/hygiene/hygiene.sh — the Hygiene Agent (a PyAutoBrain
# reasoning conductor). The maintenance function — the organism's sense of its
# own upkeep: the code-quality debt that neither proves it works (that is Heart)
# nor measures the speed of modelling (that is profiling).
#
# Owns code-quality upkeep across the organism and emits a HygieneDecision the
# human/session executes, delegating the actual fixes to the dev-flow conductors
# (refactor/bug/feature) via ship_*. It reasons; it never edits source itself,
# and (like profiling) it stays stdlib/bash so it never drags the JAX stack into
# the Brain.
#
# Usage:
# hygiene.sh # audit across modes -> prioritised worklist (default)
# hygiene.sh perf # dev-loop timing: unit tests / integration scripts / imports (phase 3)
# hygiene.sh tidy # git debris: the repo_cleanup sweep (phase 2)
# hygiene.sh noise # CLI noise: the cli_noise_clean audit (phase 2)
# hygiene.sh deps # dependency-cap drift: dep_audit vs PyPI (phase 2)
# hygiene.sh docs # stale API docs: audit_docs over docs/api/*.rst (phase 2)
# hygiene.sh <mode> --json # machine-readable HygieneDecision
#
# PHASE 1 SCAFFOLD: the conductor is real, routable and bounded, but the modes
# are staged stubs — each reports where it lands. Per-mode behaviour and
# exit-code semantics arrive with the modes (phases 2-3).

set -uo pipefail

HERE="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
source "$HERE/../../_common.sh"

MODE_ORDER=(perf tidy noise deps docs)
declare -A MODE_PHASE=(
[perf]="phase 3" [tidy]="phase 2" [noise]="phase 2" [deps]="phase 2" [docs]="phase 2"
)
declare -A MODE_DESC=(
[perf]="dev-loop timing — unit tests / integration-mode scripts / import cost; route to refactor/bug"
[tidy]="git debris — the repo_cleanup sweep"
[noise]="CLI noise — the cli_noise_clean audit"
[deps]="dependency-cap drift — dep_audit vs PyPI"
[docs]="stale API docs — audit_docs over docs/api/*.rst"
)

mode="default"
json=0
for arg in "$@"; do
case "$arg" in
perf|tidy|noise|deps|docs) mode="$arg" ;;
default) mode="default" ;;
--json) json=1 ;;
-h|--help|help) mode="help" ;;
*) echo "hygiene: unknown argument '$arg' (modes: ${MODE_ORDER[*]}, --json)" >&2; exit 2 ;;
esac
done

if [[ "$mode" == "help" ]]; then
# Print the "# Usage:" block from this script's own header (robust to the
# header moving — no hard-coded line numbers).
awk '/^# Usage:/{u=1;next} u{ if($0 ~ /^# /){sub(/^# /," "); print} else exit }' "$HERE/hygiene.sh"
exit 0
fi

# --- JSON footing (staged): a HygieneDecision shell the Brain session can read.
if [[ "$json" -eq 1 ]]; then
if [[ "$mode" == "default" ]]; then
printf '{"decision":"HygieneDecision","status":"staged-phase-1","mode":"default","modes":['
sep=""
for m in "${MODE_ORDER[@]}"; do
printf '%s{"mode":"%s","status":"staged","lands":"%s"}' "$sep" "$m" "${MODE_PHASE[$m]}"
sep=","
done
printf ']}\n'
else
printf '{"decision":"HygieneDecision","status":"staged-phase-1","mode":"%s","lands":"%s"}\n' \
"$mode" "${MODE_PHASE[$mode]}"
fi
exit 0
fi

# --- Human footing.
echo "== HygieneDecision (phase-1 scaffold — modes staged) =="
echo "The hygiene conductor owns code-quality upkeep: developer-loop cost and repo"
echo "tidiness, distinct from Heart (proof-of-works) and profiling (modelling speed)."
echo "It finds and prioritises debt, then delegates the fix to refactor/bug/feature."
echo
if [[ "$mode" == "default" ]]; then
printf ' %-6s %-9s %s\n' "MODE" "LANDS" "SCOPE"
for m in "${MODE_ORDER[@]}"; do
printf ' %-6s %-9s %s\n' "$m" "${MODE_PHASE[$m]}" "${MODE_DESC[$m]}"
done
echo
echo "Run 'pyauto-brain hygiene <mode>' for a mode once it lands; --json for the"
echo "machine footing. Design: PyAutoMind research/pyautobrain/hygiene_agent_decision.md."
else
echo " mode: $mode"
echo " scope: ${MODE_DESC[$mode]}"
echo " lands: ${MODE_PHASE[$mode]} — not yet implemented (phase-1 scaffold)."
fi
exit 0
17 changes: 11 additions & 6 deletions agents/conductors/profiling/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,19 @@ pyauto-brain profiling <mode> --json
`profiling_drift` leg, PyAutoHeart#38); this agent runs the measurement
lifecycle. Heart never dispatches campaigns; this agent never issues health
verdicts.
- **vs hygiene** — performance measurement ≠ repo hygiene (the hygiene split:
Heart observes noise / Brain `repo_cleanup` mutates).
- **vs hygiene** — split by *what is measured*: profiling owns the product's
modelling / compute speed (likelihood on the science grid, GPU tiers, A100);
the **hygiene conductor** (`agents/conductors/hygiene/`) owns the developer
loop's cost (unit-test time, `PYAUTO_TEST_MODE` / `PYAUTO_SMALL_DATASETS`
scripts, import time) and repo tidiness. Hunting generally-slow functions
flagged by integration tests is hygiene's `perf` mode, not profiling's.
- **vs build** — campaigns are not releases; `profile.yml`'s on-release runs
stay CI/Build territory.

## Future modes (staged in the founding prompt)

JAX compilation-time profiling of likelihood functions; hunting
generally-slow functions flagged by integration tests. A read-only profiling
*faculty* (opine on regressions / optimization targets) splits out only on
demonstrated consult demand.
JAX compilation-time profiling of likelihood functions. (Hunting
generally-slow functions flagged by integration tests moved to the hygiene
conductor's `perf` mode — that is developer-loop cost, not modelling speed.)
A read-only profiling *faculty* (opine on regressions / optimization targets)
splits out only on demonstrated consult demand.
5 changes: 4 additions & 1 deletion bin/pyauto-brain
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# pyauto-brain feature [args] (conductor) reason over PyAutoMind tasks, plan growth
# pyauto-brain refactor [args] (conductor) plan behaviour-preserving restructuring (default-safe)
# pyauto-brain profiling [args] (conductor) campaign/ingest/triage plans over the profiling workspace
# pyauto-brain hygiene [args] (conductor) code-quality upkeep: perf/tidy/noise/deps/docs — HygieneDecision (modes staged)
# pyauto-brain clone [args] (conductor) v0: analyze a library+workspace against the reference assistant — CloneDecision (writes nothing)
# pyauto-brain build [args] (conductor) coordinate execution: consult vitals, run Build
# pyauto-brain release [args] (conductor) release door → Build Agent release mode (gate + pre_build)
Expand Down Expand Up @@ -49,6 +50,7 @@ declare -A AGENT_SCRIPT=(
[bug]="$CONDUCTORS_DIR/bug/bug.sh"
[refactor]="$CONDUCTORS_DIR/refactor/refactor.sh"
[profiling]="$CONDUCTORS_DIR/profiling/profiling.sh"
[hygiene]="$CONDUCTORS_DIR/hygiene/hygiene.sh"
[clone]="$CONDUCTORS_DIR/clone/clone.sh"
[build]="$CONDUCTORS_DIR/build/build.sh"
[release]="$CONDUCTORS_DIR/release/release.sh"
Expand All @@ -64,6 +66,7 @@ declare -A AGENT_DESC=(
[bug]="The immune system: classify a bug/regression/Heart finding, locate the fix, plan the repair"
[refactor]="The renewal function: plan behaviour-preserving restructuring — RefactorDecision; default-safe under --auto"
[profiling]="The proprioceptive function — the organism's sense of its own effort: campaign/ingest/triage plans over the autolens_profiling workspace — ProfilingDecision"
[hygiene]="The maintenance function — the organism's sense of its own upkeep: code-quality debt (dev-loop cost + tidiness), delegating fixes — HygieneDecision"
[clone]="The Mitosis Agent (v0: decision only): partition the reference assistant, analyze the domain, emit the CloneDecision — never writes"
[build]="Coordinate execution: consult the vitals faculty, then delegate to PyAutoBuild"
[release]="Release door → the Build Agent release mode (single gate); 'release rehearse'/'release validate' drive release validation; 'release nightly' is the scheduled-nightly driver"
Expand All @@ -75,7 +78,7 @@ declare -A AGENT_DESC=(
)
# Conductors are the front doors a human drives; faculties are consulted (and
# runnable read-only). Both are dispatchable, but the menu groups them by tier.
CONDUCTOR_ORDER=(intake feature bug refactor profiling clone build release health)
CONDUCTOR_ORDER=(intake feature bug refactor profiling hygiene clone build release health)
FACULTY_ORDER=(vitals review memory samplers)
AGENT_ORDER=("${CONDUCTOR_ORDER[@]}" "${FACULTY_ORDER[@]}")

Expand Down
3 changes: 2 additions & 1 deletion skills/COMMANDS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# PyAutoBrain command surface — shared reference

The short verb commands (`/intake`, `/feature`, `/build`, `/health`, `/bug`,
`/refactor`, `/profiling`, `/docs`, `/research`, `/route`, `/brain`) are a thin, human-friendly **veneer**
`/refactor`, `/profiling`, `/hygiene`, `/docs`, `/research`, `/route`, `/brain`) are a thin, human-friendly **veneer**
over the PyAutoBrain router (`bin/pyauto-brain`). This file is the shared context
every command file points at, so each command body stays a few lines long.

Expand Down Expand Up @@ -34,6 +34,7 @@ readiness gate, or execution — those belong to the organs.
| `/bug` | Bug Agent | `bin/pyauto-brain bug` → `start_dev` → `ship_*` (health mode → vitals + Heart issues) |
| `/refactor` | Refactor Agent | `bin/pyauto-brain refactor` → `start_dev [--auto]` → `ship_*` (behaviour-preserving; default-safe) |
| `/profiling` | Profiling Agent | `bin/pyauto-brain profiling` → campaign/ingest/triage plans over the autolens_profiling workspace |
| `/hygiene` | Hygiene Agent | `bin/pyauto-brain hygiene` → perf/tidy/noise/deps/docs upkeep plans; delegates fixes to refactor/bug/feature (modes staged) |
| `/build` | Build Agent | `bin/pyauto-brain build` → vitals faculty → Heart → PyAutoBuild |
| `/health` | Health Agent | `bin/pyauto-brain health` loop → vitals faculty → Heart → GREEN |

Expand Down
11 changes: 11 additions & 0 deletions skills/hygiene/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
name: hygiene
description: Audit and prioritise the organism's code-quality upkeep — slow tests/scripts/imports, CLI noise, dependency-cap drift, stale API docs, git debris — through the PyAutoBrain Hygiene Agent, which reasons and delegates fixes without editing source itself.
---

# Hygiene

Follow [`hygiene.md`](hygiene.md) exactly. The Hygiene Agent finds and
prioritises code-quality debt (developer-loop cost + repo tidiness) and
delegates the fix to the dev-flow conductors — it never edits source directly.
Keep measurement in Heart and modelling-speed work in the Profiling Agent.
26 changes: 26 additions & 0 deletions skills/hygiene/hygiene.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# /hygiene — keep the organism's code clean (via the Brain Hygiene Agent)

Route code-quality upkeep — the debt that neither proves the organism works
(that is `/health`) nor measures modelling speed (that is `/profiling`) —
through PyAutoBrain's **Hygiene Agent**. You never name the Brain; this command
is the door.

Shared routing context: `PyAutoBrain/skills/COMMANDS.md`.

## Do

1. Run `bin/pyauto-brain hygiene [perf | tidy | noise | deps | docs]` (no arg =
audit across modes → a prioritised worklist). This is a **dry run** — it emits
a `HygieneDecision`. Nothing is executed.
2. Execute the emitted plan through the normal dev workflow: hygiene *finds and
prioritises* quality debt and *delegates the fix* — restructuring to
`/refactor`, regressions to `/bug`, larger changes to `/feature` — shipped via
`ship_library` / `ship_workspace`.

The Hygiene Agent **reasons; it never edits source.** Measurement lives in Heart
(the `script_timing` / `test_run` signals); hygiene acts on it.

> **Staged (phase 1):** the conductor is real and bounded but its modes are
> stubs. `tidy` / `noise` / `deps` / `docs` land in phase 2 (absorbing
> `repo_cleanup` + `cli_noise_clean`, consulting `dep_audit` + `audit_docs`);
> `perf` in phase 3.
12 changes: 7 additions & 5 deletions skills/repo_cleanup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ Cleanup is not release work, so it never touches PyAutoBuild. It reads the
PyAutoMind registry (`active.md`) to know what's claimed. Organ boundary +
execution-environment model: [`../WORKFLOW.md`](../WORKFLOW.md).

> **Future Cleanup Agent.** This skill is the inline form; the natural home for
> the reasoning is a dedicated PyAutoBrain **Cleanup Agent** (alongside the
> Feature / Build / Health agents) that generalises hygiene across the organism.
> Until it exists, run the reasoning here per this file and record the agent as a
> follow-up — the same pattern WORKFLOW.md describes for the other skills.
> **The hygiene conductor.** This skill is the inline form; its reasoning is now
> owned by the PyAutoBrain **Hygiene Agent** (`agents/conductors/hygiene/`),
> which generalises hygiene across the organism and absorbs this sweep as its
> `tidy` mode. That conductor's phase-1 scaffold exists and documents the
> boundary; the `tidy` mode itself lands in phase 2. Until it does, run the
> reasoning here per this file — this remains the working form for git-debris
> cleanup.

**Distinct from:** `/health worktrees` (Heart read-only diagnostic — consulted here,
but this also mutates); post-merge cleanup in `CLAUDE.md` (once per shipped task —
Expand Down