diff --git a/AGENTS.md b/AGENTS.md index 86b4736..00b2851 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -126,12 +126,12 @@ humans invoke identically, so behaviour isn't re-derived from prose each time. leg → re-judge — until Heart goes GREEN. Delegates all dispatch to the release conductor. Current scope is *validate + recommend*, checkpointing every dispatch; edit-in fixes are an explicit follow-up. (Skeleton.) -- **`agents/conductors/clone/`** — the *Mitosis Agent* (**design only** — see - its `DESIGN.md`; no CLI yet): will reproduce a mature domain assistant +- **`agents/conductors/clone/`** — the *Mitosis Agent* (**analysis-only v0** — + see its `DESIGN.md`): analyzes how to reproduce a mature domain assistant (reference: `autolens_assistant`) into a new specialised assistant cell — domain analysis, template-boundary partition, a `CloneDecision` with an exact-clone/sibling/seed question, generation delegated to Build, newborn - validation by Heart. + validation by Heart. Its current CLI emits the decision and writes nothing. ### Faculties @@ -203,9 +203,9 @@ it resolves the sibling `pyauto-heart` and `autobuild` binaries from PATH or the ## The command surface (Brain implicit) The `bin/pyauto-brain ` CLI above is the machinery; humans drive it through -short verb commands installed into `~/.claude/commands/`. The Brain stays -**implicit** — you type a verb (or plain natural language) and the Brain routes it -to the right agent; normal usage never says "PyAutoBrain". +short verb commands in Claude Code or discoverable skills in Claude and Codex. +The Brain stays **implicit** — you type a verb (or plain natural language) and +the Brain routes it to the right agent; normal usage never says "PyAutoBrain". > **Users speak in short commands; PyAutoBrain performs the routing.** @@ -228,10 +228,11 @@ never for symmetry — the Refactor Agent earned its promotion via the `ideas.md backlog bullet, the skill's own recorded follow-up, and the autonomy series. Every command routes **through** the Brain; none replaces it. -The command bodies live in `skills//.md` (thin; installed as flat -commands by `bin/install.sh`); the shared architecture prose is in -[`skills/COMMANDS.md`](skills/COMMANDS.md). The work-type taxonomy the router and -work-type entries use is `PyAutoMind/ROUTING.md`. +The command bodies live in `skills//.md`; thin `SKILL.md` wrappers +make the same canonical workflows discoverable to skill-aware harnesses. +`bin/install.sh` installs both surfaces without duplicating their bodies. Shared +architecture prose is in [`skills/COMMANDS.md`](skills/COMMANDS.md). The +work-type taxonomy the router and work-type entries use is `PyAutoMind/ROUTING.md`. ## Never rewrite history diff --git a/bin/README.md b/bin/README.md index 09a42f8..8ad3696 100644 --- a/bin/README.md +++ b/bin/README.md @@ -3,7 +3,7 @@ Executable tooling for the PyAuto organism. - **`pyauto-brain`** — the PyAutoBrain CLI (reasoning-layer entry point). -- **`install.sh`** — the cross-organ Claude skill/command **installer**. +- **`install.sh`** — the cross-organ Claude/Codex skill and command installer. - **`check_skill_line_counts.sh`** — the skill line-count **guard** (primary skill `.md` files must stay < 200 lines). @@ -14,7 +14,8 @@ admin_jammy hosts no skills and is slated to leave `PyAutoLabs/`. ## install.sh Auto-discovers (no hardcoded skill list) by scanning each organ repo's -`skills/` dir for `*/` subdirs, then symlinks each into `~/.claude/`: +`skills/` dir for `*/` subdirs, then symlinks each supported surface into its +harness home: - **`PyAutoMind/skills/`** — registry-coupled skills (`create_issue`). - **`PyAutoBrain/skills/`** — development-workflow skills (`start_dev`, @@ -32,15 +33,17 @@ Auto-discovers (no hardcoded skill list) by scanning each organ repo's - **`admin_jammy/skills/`** — vestigial: hosts no skills; scanned only so an old checkout still resolves, auto-skipped once admin_jammy leaves. -Discovery rule per root: +Discovery rules per root are independent, so a directory may expose both: -- A directory with `SKILL.md` → **skill**, symlinked to `~/.claude/skills//`. -- A directory with `.md` (and no `SKILL.md`) → **command**, symlinked to - `~/.claude/commands/.md`. +- `SKILL.md` → skill directory symlinked to Claude under its source-directory + name and to Codex under the hyphenated frontmatter `name`. +- `.md` → command symlinked to `~/.claude/commands/.md`. Roots that aren't checked out are skipped. It is idempotent — existing symlinks are replaced, non-symlink files are left alone, and broken symlinks pointing into -a PyAuto root are pruned. Re-run it after pulling updates. +a PyAuto root are pruned. `CLAUDE_HOME` and `CODEX_HOME` may override the +destinations for isolated tests or non-default installations. Re-run it after +pulling updates. ## Bootstrap on a new machine diff --git a/bin/check_skill_line_counts.sh b/bin/check_skill_line_counts.sh index e745021..b879fde 100755 --- a/bin/check_skill_line_counts.sh +++ b/bin/check_skill_line_counts.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Report any *primary* skill .md file over the line limit (default 200). # -# Claude skill guidance keeps primary skill files short; long background, +# Agent skill guidance keeps primary skill files short; long background, # templates and examples belong in supporting docs (`reference.md`, shared # `WORKFLOW.md`), which are exempt here. A "primary" file is a skill's `SKILL.md` # or its command body `.md`. diff --git a/bin/install.sh b/bin/install.sh index cdcb866..74c8c61 100755 --- a/bin/install.sh +++ b/bin/install.sh @@ -1,10 +1,11 @@ #!/usr/bin/env bash -# Bootstrap Claude Code skills/commands into ~/.claude/ from every PyAuto -# organism repo that hosts skills. +# Bootstrap Claude Code commands and Claude/Codex skills from every PyAuto +# organism repo that hosts them. # # This installer lives in PyAutoBrain (the reasoning/orchestration organ). It -# scans every organ repo's skills/ dir and symlinks their skills+commands into -# ~/.claude/. Roots that aren't checked out are simply skipped. +# scans every organ repo's skills/ dir and symlinks skills into both harnesses; +# Claude-only command files remain available as slash commands. Roots that +# aren't checked out are simply skipped. # # Discovery roots (scanned in order): # - admin_jammy/skills/ — vestigial: admin_jammy hosts no skills and is @@ -19,10 +20,10 @@ # (PyAutoBuild's root is for its own release/packaging-execution skills only — it # owns NO dev-workflow skills; the ship_* skills merely call its release step.) # -# Auto-discovers skills in each root: -# - A directory with SKILL.md → installed as ~/.claude/skills// -# - A directory with .md (and no SKILL.md) → installed as a flat -# command at ~/.claude/commands/.md +# Auto-discovers surfaces in each root independently: +# - SKILL.md → installed in both the Claude and Codex skill roots +# - .md → installed as a flat Claude command +# A directory may contain both; neither surface suppresses the other. # # Safe to re-run — existing symlinks are replaced, non-symlink files are skipped. # @@ -32,13 +33,16 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -PYAUTO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +DEFAULT_PYAUTO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +PYAUTO_ROOT="${PYAUTO_ROOT:-$DEFAULT_PYAUTO_ROOT}" ADMIN_SKILLS_DIR="$PYAUTO_ROOT/admin_jammy/skills" MIND_SKILLS_DIR="$PYAUTO_ROOT/PyAutoMind/skills" BRAIN_SKILLS_DIR="$PYAUTO_ROOT/PyAutoBrain/skills" HEART_SKILLS_DIR="$PYAUTO_ROOT/PyAutoHeart/skills" BUILD_SKILLS_DIR="$PYAUTO_ROOT/PyAutoBuild/skills" PROFILING_SKILLS_DIR="$PYAUTO_ROOT/autolens_profiling/skills" +CLAUDE_HOME="${CLAUDE_HOME:-$HOME/.claude}" +CODEX_HOME="${CODEX_HOME:-$HOME/.codex}" # ---------- Execution-environment note ---------- # @@ -53,7 +57,7 @@ else fi echo "" -mkdir -p "$HOME/.claude/skills" "$HOME/.claude/commands" +mkdir -p "$CLAUDE_HOME/skills" "$CLAUDE_HOME/commands" "$CODEX_HOME/skills" # ---------- Prune stale symlinks ---------- # @@ -76,8 +80,9 @@ prune_stale_symlinks() { done } -prune_stale_symlinks "$HOME/.claude/skills" -prune_stale_symlinks "$HOME/.claude/commands" +prune_stale_symlinks "$CLAUDE_HOME/skills" +prune_stale_symlinks "$CLAUDE_HOME/commands" +prune_stale_symlinks "$CODEX_HOME/skills" # ---------- Install one source dir's skills/commands ---------- @@ -101,17 +106,27 @@ install_from_dir() { # Skip the install.sh dir itself, or any non-skill dirs [ "$name" = "skills" ] && continue + local found=0 if [ -f "$entry/SKILL.md" ]; then - # Skill — symlink the directory - local dst="$HOME/.claude/skills/$name" - _link_symlink "$entry" "$dst" "skill" + _link_symlink "$entry" "$CLAUDE_HOME/skills/$name" "Claude skill" installed_count=$((installed_count + 1)) - elif [ -f "$entry/$name.md" ]; then - # Command — symlink the flat .md file - local dst="$HOME/.claude/commands/$name.md" - _link_symlink "$entry/$name.md" "$dst" "command" + found=1 + + local skill_name + skill_name="$(sed -n 's/^name:[[:space:]]*//p' "$entry/SKILL.md" | head -1)" + if [ -z "$skill_name" ] || [[ "$skill_name" == *[!a-z0-9-]* ]]; then + echo " SKIP $name (Codex skill name invalid or missing: ${skill_name:-})" + else + _link_symlink "$entry" "$CODEX_HOME/skills/$skill_name" "Codex skill" + installed_count=$((installed_count + 1)) + fi + fi + if [ -f "$entry/$name.md" ]; then + _link_symlink "$entry/$name.md" "$CLAUDE_HOME/commands/$name.md" "Claude command" installed_count=$((installed_count + 1)) - else + found=1 + fi + if [ "$found" -eq 0 ]; then echo " SKIP $name (no SKILL.md or $name.md found)" fi done @@ -149,4 +164,4 @@ install_from_dir "$PROFILING_SKILLS_DIR" "autolens_profiling/skills/ — science # ---------- Summary ---------- -echo "Done. Restart Claude Code to pick up changes." +echo "Done. Restart Claude Code and Codex to pick up changes." diff --git a/skills/COMMANDS.md b/skills/COMMANDS.md index d775fde..2d8436b 100644 --- a/skills/COMMANDS.md +++ b/skills/COMMANDS.md @@ -61,11 +61,18 @@ symmetry. The taxonomy they tag is `PyAutoMind/ROUTING.md`. - **`/brain [args]`** — explicit, un-veneered passthrough to `bin/pyauto-brain` for debugging. Free-text `/brain` defers to `/route`. +Codex skills also expose the remaining public CLI agents directly: the +analysis-only `clone` conductor, the `release` conductor, and the read-only +`vitals`, `review`, `memory`, and `samplers` faculties. They do not gain new +slash commands; `brain` remains Claude's low-level passthrough. + ## How these are installed -Each command is a directory `skills//` containing only `.md` (no -`SKILL.md`). `bin/install.sh` turns that into a flat `~/.claude/commands/.md` -symlink — a typed slash command, not an auto-triggered skill. This file -(`COMMANDS.md`) sits at the `skills/` root, so the installer's directory scan -skips it: it is reference-only. Keep command bodies short and this file the single -place architecture prose lives (guarded by `bin/check_skill_line_counts.sh`). +Each command directory keeps `.md` as its canonical command body and may +add a thin `SKILL.md` discovery wrapper. `bin/install.sh` treats the two files +independently: it installs the command into `~/.claude/commands/` and the skill +into both `~/.claude/skills/` and `~/.codex/skills/` (using the skill's +hyphenated frontmatter name for Codex). This file (`COMMANDS.md`) +sits at the `skills/` root, so the directory scan skips it; it is reference-only. +Keep wrappers and command bodies short and keep shared architecture prose here +(guarded by `bin/check_skill_line_counts.sh`). diff --git a/skills/WORKFLOW.md b/skills/WORKFLOW.md index a2d0f8a..133c997 100644 --- a/skills/WORKFLOW.md +++ b/skills/WORKFLOW.md @@ -75,15 +75,13 @@ file and `PyAutoBrain/AGENTS.md`, and note that the agent was emulated. ## Model delegation (judgment tier plans, execution tier ships) -The workflow skills split work across **model tiers**, not named models — the -doctrine survives model access changing: +The workflow skills split work across **capability tiers**, not named models or +harness-specific tool names, so the doctrine survives model access changing: -- **Judgment tier** — the strongest model available to the session (currently - **Fable 5**; previously, and as fallback, **Opus**). Planning, orchestration, - risk judgment, anything user-facing. -- **Execution tier** — a fast, cheap model (currently **Sonnet**) for - mechanical shell/git phases, delegated as subagents (`Agent` tool, - `model: "sonnet"`). +- **Judgment tier** — the strongest reasoning model available to the session. + Planning, orchestration, risk judgment, and anything user-facing. +- **Execution tier** — a fast, lower-cost model for mechanical shell/git phases, + delegated through the harness's subagent mechanism when available. The main session stays on the judgment tier; bulk execution moves to the execution tier — no manual model toggling. @@ -170,8 +168,8 @@ the vitals faculty rather than re-deriving pass/fail criteria in the skill. - If the user gives a development task with **no** PyAutoMind prompt path, first write a concise prompt under the right `//` folder (original request verbatim), then continue with that path. -- Where a body delegates mechanical execution to an execution-tier subagent, a harness - without subagents performs the same steps directly, preserving the +- Where a body delegates mechanical execution to an execution-tier subagent, a + harness without subagents performs the same steps directly, preserving the judgment/mechanical split above. ## Execution environments diff --git a/skills/brain/SKILL.md b/skills/brain/SKILL.md new file mode 100644 index 0000000..025319f --- /dev/null +++ b/skills/brain/SKILL.md @@ -0,0 +1,10 @@ +--- +name: brain +description: Run a named PyAutoBrain conductor or faculty directly through bin/pyauto-brain. Use for low-level agent invocation, agent help, or debugging the Brain router. +--- + +# Brain + +Follow [`brain.md`](brain.md) exactly. Use [`../COMMANDS.md`](../COMMANDS.md) +for the shared command-surface contract. Keep agent behavior in the deterministic +CLI and its adjacent `AGENTS.md`; do not reimplement it here. diff --git a/skills/brain/brain.md b/skills/brain/brain.md index 73690dd..3bf7035 100644 --- a/skills/brain/brain.md +++ b/skills/brain/brain.md @@ -8,8 +8,8 @@ Shared routing context: `PyAutoBrain/skills/COMMANDS.md`. ## Do -- `/brain [args...]` where `agent ∈ {feature, build, release, health, - vitals}` → run `bin/pyauto-brain [args...]` and report the output - verbatim. +- `/brain [args...]` where `agent ∈ {intake, feature, bug, refactor, + profiling, clone, build, release, health, vitals, review, memory, samplers}` → + run `bin/pyauto-brain [args...]` and report the output verbatim. - `/brain help [agent]` → run `bin/pyauto-brain help [agent]`. - `/brain ` with no known agent → defer to **`/route`**. diff --git a/skills/bug/SKILL.md b/skills/bug/SKILL.md new file mode 100644 index 0000000..fcc9e32 --- /dev/null +++ b/skills/bug/SKILL.md @@ -0,0 +1,10 @@ +--- +name: bug +description: Classify and plan PyAutoLabs bugs, regressions, failing tests, incorrect output, or PyAutoHeart findings through the PyAutoBrain Bug Agent before starting development. +--- + +# Bug + +Follow [`bug.md`](bug.md) exactly. Use [`../COMMANDS.md`](../COMMANDS.md) for +shared routing. Let `bin/pyauto-brain bug` produce the decision; do not bypass +the Brain or implement the repair inside this skill. diff --git a/skills/bug/bug.md b/skills/bug/bug.md index 2f13c21..9288208 100644 --- a/skills/bug/bug.md +++ b/skills/bug/bug.md @@ -24,9 +24,9 @@ Shared routing context: `PyAutoBrain/skills/COMMANDS.md`. carrying forward). Then tell the user it is **safe to `/clear` before the next `/bug`**: the transcript now holds only disposable investigation scratch (file reads, repro runs, tool output), so a fresh session loses nothing and context - stays lean across many bugs in one sitting. Claude cannot self-clear — this is a - deliberate one-keystroke user step, and the externalised state above is what makes - it lossless. + stays lean across many bugs in one sitting. An agent cannot clear its own host + transcript — this is a deliberate one-keystroke user step, and the externalised + state above is what makes it lossless. The Bug Agent **reasons; it never edits source**, and its first question is always *where the fix belongs*: prefer a general library-source fix, and **never degrade a diff --git a/skills/build/SKILL.md b/skills/build/SKILL.md new file mode 100644 index 0000000..f73b7a4 --- /dev/null +++ b/skills/build/SKILL.md @@ -0,0 +1,9 @@ +--- +name: build +description: Coordinate PyAuto build, deploy, or release execution through the PyAutoBrain Build Agent, including its vitals consultation and PyAutoBuild delegation. Use when the user asks to build, publish, deploy, or release. +--- + +# Build + +Follow [`build.md`](build.md) exactly. Preserve the Brain -> vitals -> Heart -> +Build boundary and all human release gates. diff --git a/skills/clone/SKILL.md b/skills/clone/SKILL.md new file mode 100644 index 0000000..95a70d5 --- /dev/null +++ b/skills/clone/SKILL.md @@ -0,0 +1,10 @@ +--- +name: clone +description: Analyze how a mature PyAuto domain assistant should be reproduced as an exact clone, sibling, or seed through the PyAutoBrain Clone Agent. Use for assistant-cell cloning decisions; the current agent is analysis-only and must not generate files. +--- + +# Clone + +Read [`../../agents/conductors/clone/AGENTS.md`](../../agents/conductors/clone/AGENTS.md) +completely, then run `bin/pyauto-brain clone` with the documented arguments. +Return its `CloneDecision` and preserve the agent's no-write boundary. diff --git a/skills/clone/agents/openai.yaml b/skills/clone/agents/openai.yaml new file mode 100644 index 0000000..597d25d --- /dev/null +++ b/skills/clone/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Clone Agent" + short_description: "Analyze assistant cloning boundaries" + default_prompt: "Use $clone to analyze how a PyAuto domain assistant should be cloned." diff --git a/skills/docs/SKILL.md b/skills/docs/SKILL.md new file mode 100644 index 0000000..b1f26fa --- /dev/null +++ b/skills/docs/SKILL.md @@ -0,0 +1,9 @@ +--- +name: docs +description: Start PyAutoLabs documentation, tutorial, notebook, example, or narrative-prose work through the Brain development workflow with the docs work type fixed. +--- + +# Docs + +Follow [`docs.md`](docs.md) exactly. Route the task through `start-dev`; this is +a work-type entry, not a separate documentation conductor. diff --git a/skills/docs/docs.md b/skills/docs/docs.md index 73e2973..b5e0cf7 100644 --- a/skills/docs/docs.md +++ b/skills/docs/docs.md @@ -13,4 +13,5 @@ Treat the request as PyAutoMind work-type **`docs/`** — documentation, example notebooks, or tutorial prose. If no prompt path exists, create one under `PyAutoMind/docs//.md` (original request verbatim), then run **`/start_dev`** on it. `start_dev` routes through the Brain, and the tutorial -Opus/Sonnet split in `../WORKFLOW.md` applies. Taxonomy: `PyAutoMind/ROUTING.md`. +The judgment/execution tier split in `../WORKFLOW.md` applies. Taxonomy: +`PyAutoMind/ROUTING.md`. diff --git a/skills/feature/SKILL.md b/skills/feature/SKILL.md new file mode 100644 index 0000000..b9fc7d5 --- /dev/null +++ b/skills/feature/SKILL.md @@ -0,0 +1,9 @@ +--- +name: feature +description: Select, size, phase, or plan a PyAutoLabs feature through the PyAutoBrain Feature Agent, then route an approved task into start-dev. Use for new capabilities and next-task selection. +--- + +# Feature + +Follow [`feature.md`](feature.md) exactly. Let `bin/pyauto-brain feature` +produce the structured decision before development starts. diff --git a/skills/health/SKILL.md b/skills/health/SKILL.md new file mode 100644 index 0000000..c4a6a38 --- /dev/null +++ b/skills/health/SKILL.md @@ -0,0 +1,9 @@ +--- +name: health +description: Use the single PyAuto health door for readiness assessment, validation sweeps, active-work status, release-run status, or worktree status through the Brain and Heart-owned procedures. +--- + +# Health + +Follow [`health.md`](health.md) exactly. Keep health judgment in PyAutoHeart and +dispatch through the documented Brain conductor or reference leg. diff --git a/skills/intake/SKILL.md b/skills/intake/SKILL.md new file mode 100644 index 0000000..f2cc879 --- /dev/null +++ b/skills/intake/SKILL.md @@ -0,0 +1,9 @@ +--- +name: intake +description: Turn raw PyAutoLabs ideas, bug reports, or loose requirements into classified and sized PyAutoMind prompt files through the PyAutoBrain Intake Agent. Use before start-dev when intent is not yet formalized. +--- + +# Intake + +Follow [`intake.md`](intake.md) exactly. Run the deterministic intake agent as a +dry run first and apply only after reviewing its decision. diff --git a/skills/memory/SKILL.md b/skills/memory/SKILL.md new file mode 100644 index 0000000..45a6197 --- /dev/null +++ b/skills/memory/SKILL.md @@ -0,0 +1,10 @@ +--- +name: memory +description: Recall cited PyAuto scientific, architectural, assistant, or task-history context through the read-only PyAutoBrain Memory Faculty. Use before substantial planning when prior decisions or domain knowledge could change the approach. +--- + +# Memory + +Read [`../../agents/faculties/memory/AGENTS.md`](../../agents/faculties/memory/AGENTS.md) +completely, then run `bin/pyauto-brain memory ""`. Read only the cited +pages needed for the task and preserve the documented privacy boundary. diff --git a/skills/memory/agents/openai.yaml b/skills/memory/agents/openai.yaml new file mode 100644 index 0000000..e981642 --- /dev/null +++ b/skills/memory/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Memory Faculty" + short_description: "Recall cited PyAuto knowledge" + default_prompt: "Use $memory to recall cited PyAuto architectural or scientific context for this task." diff --git a/skills/profiling/SKILL.md b/skills/profiling/SKILL.md new file mode 100644 index 0000000..a0daf7a --- /dev/null +++ b/skills/profiling/SKILL.md @@ -0,0 +1,9 @@ +--- +name: profiling +description: Plan PyAutoLens performance campaigns, ingest fresh profiling results, or triage profiling drift through the PyAutoBrain Profiling Agent without running sweeps directly. +--- + +# Profiling + +Follow [`profiling.md`](profiling.md) exactly. Keep measurement execution in the +profiling workspace and use the Brain agent for campaign decisions. diff --git a/skills/refactor/SKILL.md b/skills/refactor/SKILL.md new file mode 100644 index 0000000..cd5e28b --- /dev/null +++ b/skills/refactor/SKILL.md @@ -0,0 +1,9 @@ +--- +name: refactor +description: Plan behavior-preserving PyAutoLabs restructuring through the PyAutoBrain Refactor Agent, including invariant checks, candidate mining, and safe-autonomy routing. +--- + +# Refactor + +Follow [`refactor.md`](refactor.md) exactly. Re-route any intended behavior or +public API change instead of treating it as a refactor. diff --git a/skills/register_and_iterate/SKILL.md b/skills/register_and_iterate/SKILL.md new file mode 100644 index 0000000..4e900bf --- /dev/null +++ b/skills/register_and_iterate/SKILL.md @@ -0,0 +1,9 @@ +--- +name: register-and-iterate +description: Register and execute a resumable sequence of PyAutoLabs tasks using PyAutoMind state and the PyAutoBrain autonomous queue contract. Use for ordered multi-task series rather than a single development task. +--- + +# Register And Iterate + +Follow [`register_and_iterate.md`](register_and_iterate.md) exactly. Read +[`reference.md`](reference.md) when the body routes to its detailed procedure. diff --git a/skills/register_and_iterate/reference.md b/skills/register_and_iterate/reference.md index 575b99a..b46690e 100644 --- a/skills/register_and_iterate/reference.md +++ b/skills/register_and_iterate/reference.md @@ -55,7 +55,7 @@ check. Stage changes (do **not** commit). Then hit the ship-approval gate. ## Delegation (local-dev) -Delegate the mechanical run-and-register cycle to a Sonnet subagent; the outer +Delegate the mechanical run-and-register cycle to an execution-tier subagent; the outer skill keeps cross-task context and handles judgement gates. ``` diff --git a/skills/register_and_iterate/register_and_iterate.md b/skills/register_and_iterate/register_and_iterate.md index 53ee3a2..5f74e1c 100644 --- a/skills/register_and_iterate/register_and_iterate.md +++ b/skills/register_and_iterate/register_and_iterate.md @@ -69,7 +69,7 @@ classifying and registering each offending type. Full pattern, the three-step assertion, and the classification heuristic are in [`reference.md`](reference.md) → "Scaffold", "Registration loop", "Classification heuristic". In local-dev, delegate the mechanical run-and-register -cycle to a Sonnet subagent (reference.md → "Delegation"). +cycle to an execution-tier subagent (reference.md → "Delegation"). ### 4. After PASS — gate: ship approval diff --git a/skills/release/SKILL.md b/skills/release/SKILL.md new file mode 100644 index 0000000..53d3c49 --- /dev/null +++ b/skills/release/SKILL.md @@ -0,0 +1,11 @@ +--- +name: release +description: Coordinate PyAuto release readiness, rehearsal, validation, nightly-driver inspection, or a human-authorized release through the PyAutoBrain Release Agent. Use for release operations while preserving Heart gates and human-required manual release approval. +--- + +# Release + +Read [`../../agents/conductors/release/AGENTS.md`](../../agents/conductors/release/AGENTS.md) +completely, then run `bin/pyauto-brain release` in the documented mode. Apply +[`../../AUTONOMY.md`](../../AUTONOMY.md); never convert a manual release into the +scheduled-nightly exception. diff --git a/skills/release/agents/openai.yaml b/skills/release/agents/openai.yaml new file mode 100644 index 0000000..0b6d270 --- /dev/null +++ b/skills/release/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Release Agent" + short_description: "Coordinate gated PyAuto release workflows" + default_prompt: "Use $release to assess or drive the requested PyAuto release workflow." diff --git a/skills/repo_cleanup/SKILL.md b/skills/repo_cleanup/SKILL.md index 2f9a55b..95d2b52 100644 --- a/skills/repo_cleanup/SKILL.md +++ b/skills/repo_cleanup/SKILL.md @@ -1,5 +1,5 @@ --- -name: repo_cleanup +name: repo-cleanup description: Periodic hygiene sweep across PyAuto repos and worktrees — audit stale feature branches, tracking refs, stashes, and dirty checkouts, then execute per-bucket cleanups after confirmation. Use for end-of-week tidying or unwieldy branch lists. --- diff --git a/skills/research/SKILL.md b/skills/research/SKILL.md new file mode 100644 index 0000000..466080c --- /dev/null +++ b/skills/research/SKILL.md @@ -0,0 +1,9 @@ +--- +name: research +description: Start exploratory scientific, algorithmic, architectural, or prior-art investigation through the PyAutoBrain development workflow with the research work type fixed. +--- + +# Research + +Follow [`research.md`](research.md) exactly. This is a work-type entry through +the Brain, not a dedicated research conductor. diff --git a/skills/review/SKILL.md b/skills/review/SKILL.md new file mode 100644 index 0000000..6c452fb --- /dev/null +++ b/skills/review/SKILL.md @@ -0,0 +1,10 @@ +--- +name: review +description: Prepare a PyAuto feature branch ReviewSurface and apply an independent CLEAN, FINDINGS, or BLOCKED judgment for the autonomous ship gate. Use for dev-workflow branch review, not release readiness or implementation fixes. +--- + +# Review + +Read [`../../agents/faculties/review/AGENTS.md`](../../agents/faculties/review/AGENTS.md) +completely, then run `bin/pyauto-brain review --task `. Judge the returned +surface independently and never fix findings inside the faculty invocation. diff --git a/skills/review/agents/openai.yaml b/skills/review/agents/openai.yaml new file mode 100644 index 0000000..7278413 --- /dev/null +++ b/skills/review/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Review Faculty" + short_description: "Prepare a PyAuto branch review surface" + default_prompt: "Use $review to prepare the active PyAuto task branch for an independent review verdict." diff --git a/skills/route/SKILL.md b/skills/route/SKILL.md new file mode 100644 index 0000000..f611bb2 --- /dev/null +++ b/skills/route/SKILL.md @@ -0,0 +1,9 @@ +--- +name: route +description: Infer the appropriate PyAutoBrain command or development work type from a free-form PyAutoLabs request. Use when the request is actionable but does not name intake, feature, bug, refactor, health, build, docs, or research explicitly. +--- + +# Route + +Follow [`route.md`](route.md) exactly. Use [`../COMMANDS.md`](../COMMANDS.md) as +the authoritative map and dispatch through the selected Brain surface. diff --git a/skills/run_queue/SKILL.md b/skills/run_queue/SKILL.md new file mode 100644 index 0000000..222afbe --- /dev/null +++ b/skills/run_queue/SKILL.md @@ -0,0 +1,9 @@ +--- +name: run-queue +description: Run the generic PyAutoBrain task queue with explicit --auto activation, per-task autonomy caps, checkpoint-and-continue behavior, and durable PyAutoMind state. +--- + +# Run Queue + +Follow [`run_queue.md`](run_queue.md) exactly. Apply +[`../../AUTONOMY.md`](../../AUTONOMY.md) without weakening any gate. diff --git a/skills/sampler_pipeline/SKILL.md b/skills/sampler_pipeline/SKILL.md index 13811ab..f126781 100644 --- a/skills/sampler_pipeline/SKILL.md +++ b/skills/sampler_pipeline/SKILL.md @@ -1,5 +1,5 @@ --- -name: sampler_pipeline +name: sampler-pipeline description: Trial a new non-linear sampler through the ingest → prototype → profile → promote pipeline — point it at a sampler's GitHub repo, get it running on the standard problem and on a likelihood the user owns (MLTracker diagnostics, benchmark comparison), then (if warranted) the full PyAutoFit implementation. Use when the user wants to try, benchmark, or promote a sampler / search / MCMC / nested-sampling / HMC method, or gives a sampler repo URL. --- diff --git a/skills/samplers/SKILL.md b/skills/samplers/SKILL.md new file mode 100644 index 0000000..847fd34 --- /dev/null +++ b/skills/samplers/SKILL.md @@ -0,0 +1,10 @@ +--- +name: samplers +description: Inspect PyAuto sampler script tiers, PyAutoFit search coverage, benchmark records, and tier gaps through the read-only PyAutoBrain Samplers Faculty. Use for sampler selection or pipeline planning without running samplers. +--- + +# Samplers + +Read [`../../agents/faculties/samplers/AGENTS.md`](../../agents/faculties/samplers/AGENTS.md) +completely, then run `bin/pyauto-brain samplers` in the documented mode. Use the +returned `SamplerSurface` as advice and keep execution in the sampler pipeline. diff --git a/skills/samplers/agents/openai.yaml b/skills/samplers/agents/openai.yaml new file mode 100644 index 0000000..2ca857d --- /dev/null +++ b/skills/samplers/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Samplers Faculty" + short_description: "Inspect PyAuto sampler capabilities" + default_prompt: "Use $samplers to inspect the PyAuto sampler surface and recommend the appropriate tier." diff --git a/skills/ship_library/reference.md b/skills/ship_library/reference.md index a4fd724..979765f 100644 --- a/skills/ship_library/reference.md +++ b/skills/ship_library/reference.md @@ -49,7 +49,7 @@ See full details below. -🤖 Generated with [Claude Code](https://claude.com/claude-code) +Generated by the PyAutoLabs agent workflow. ``` ## Validation checklist (--auto) @@ -96,7 +96,7 @@ Build/release step. Per repo, after the vitals faculty / Heart verdict is GREEN: 5. Return a structured summary: one line per repo with test pass/fail counts, commit SHA, and PR URL. -In local-dev this is delegated to a Sonnet subagent (mechanical execution); the +In local-dev this is delegated to an execution-tier subagent (mechanical execution); the reasoning model drafts the commit/PR text first and consumes the subagent's result. In other environments run the same steps directly. diff --git a/skills/ship_library/ship_library.md b/skills/ship_library/ship_library.md index 23449f8..041d248 100644 --- a/skills/ship_library/ship_library.md +++ b/skills/ship_library/ship_library.md @@ -67,7 +67,7 @@ On GREEN, run the dev workflow's own test → commit → push → feature-PR ste worktree, confirm the branch is `feature/` (never auto-switch), commit, push, `gh pr create --label pending-release`, and verify the label landed. This is feature-development git work, not a Build/release step. In -local-dev delegate the mechanical part to a Sonnet subagent; elsewhere run it +local-dev delegate the mechanical part to an execution-tier subagent; elsewhere run it directly. If any step fails, stop and report — do not proceed. **Under `--auto`:** all four legs of the autonomous-ship gate must pass (step diff --git a/skills/ship_workspace/reference.md b/skills/ship_workspace/reference.md index 904edc9..d893f57 100644 --- a/skills/ship_workspace/reference.md +++ b/skills/ship_workspace/reference.md @@ -21,7 +21,7 @@ The PR body **MUST** include a `## Scripts Changed` section. ## Test Plan - [ ] Smoke tests pass for all affected workspaces -🤖 Generated with [Claude Code](https://claude.com/claude-code) +Generated by the PyAutoLabs agent workflow. ``` Omit `## Upstream PR` entirely if there is no linked library PR. @@ -49,7 +49,7 @@ step. Per workspace repo, after the readiness gate is GREEN: commit SHA, PR URL, and confirmation of the cross-reference comment. Only edit files in `scripts/`; notebooks are regenerated, never hand-edited. In -local-dev delegate this to a Sonnet subagent; elsewhere run it directly. +local-dev delegate this to an execution-tier subagent; elsewhere run it directly. ## Library-first merge gate diff --git a/skills/ship_workspace/ship_workspace.md b/skills/ship_workspace/ship_workspace.md index 54194ae..1a5a627 100644 --- a/skills/ship_workspace/ship_workspace.md +++ b/skills/ship_workspace/ship_workspace.md @@ -64,7 +64,7 @@ cross-reference step per auto-switch), regenerate notebooks from scripts (never edit `notebooks/` directly), `gh pr create --label pending-release`, verify the label, and cross-reference the upstream library PR if linked. In local-dev delegate to a -Sonnet subagent; elsewhere run directly. Any failure → stop and report. +execution-tier subagent; elsewhere run directly. Any failure → stop and report. **Under `--auto`:** all four legs of the autonomous-ship gate must pass (step 3 note); ship without interactive sign-off, add the `## Validation checklist` diff --git a/skills/start_dev/reference.md b/skills/start_dev/reference.md index 6afee6d..371fe54 100644 --- a/skills/start_dev/reference.md +++ b/skills/start_dev/reference.md @@ -126,7 +126,7 @@ PyAutoMind. Shared organ boundary and the execution-environment model are in If a repo is on a non-main/non-master branch or has uncommitted changes, flag it with a warning — this may indicate another task or agent is active there. -3. **Check for active Claude agents, recent branches, and worktree claims** +3. **Check for active agents, recent branches, and worktree claims** Source the worktree helper and list anything already claimed by another task: diff --git a/skills/start_dev_for_user/SKILL.md b/skills/start_dev_for_user/SKILL.md new file mode 100644 index 0000000..5e037f6 --- /dev/null +++ b/skills/start_dev_for_user/SKILL.md @@ -0,0 +1,9 @@ +--- +name: start-dev-for-user +description: Start a PyAutoLabs development task for another contributor, including plan, issue, branch, and handoff preparation without claiming the local implementation worktree. +--- + +# Start Dev For User + +Follow [`start_dev_for_user.md`](start_dev_for_user.md) exactly. Read +[`reference.md`](reference.md) only when the body routes to its detailed format. diff --git a/skills/update_issue/SKILL.md b/skills/update_issue/SKILL.md index c61d9f0..863806c 100644 --- a/skills/update_issue/SKILL.md +++ b/skills/update_issue/SKILL.md @@ -1,7 +1,6 @@ --- name: update-issue description: Post a progress update to a GitHub issue from the current CLI session — commits, summary, and remaining work. -user-invocable: true --- Post a progress summary from the current session to a GitHub issue. diff --git a/skills/vitals/SKILL.md b/skills/vitals/SKILL.md new file mode 100644 index 0000000..58b197f --- /dev/null +++ b/skills/vitals/SKILL.md @@ -0,0 +1,10 @@ +--- +name: vitals +description: Read and explain the authoritative PyAutoHeart readiness verdict through the read-only PyAutoBrain Vitals Faculty. Use when a conductor or user needs current GREEN, STALE, YELLOW, or RED reasons without dispatching work. +--- + +# Vitals + +Read [`../../agents/faculties/vitals/AGENTS.md`](../../agents/faculties/vitals/AGENTS.md) +completely, then run `bin/pyauto-brain vitals` in the documented mode. Return +the verdict and reasons without mutating or bypassing Heart. diff --git a/skills/vitals/agents/openai.yaml b/skills/vitals/agents/openai.yaml new file mode 100644 index 0000000..d066895 --- /dev/null +++ b/skills/vitals/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Vitals Faculty" + short_description: "Read and explain organism readiness" + default_prompt: "Use $vitals to read and explain the current PyAutoHeart readiness verdict." diff --git a/tests/test_skill_install.py b/tests/test_skill_install.py new file mode 100644 index 0000000..899fa3e --- /dev/null +++ b/tests/test_skill_install.py @@ -0,0 +1,134 @@ +"""Cross-harness discovery and installer coverage.""" + +import os +import re +import subprocess +from pathlib import Path + + +BRAIN_HOME = Path(__file__).resolve().parents[1] +DISPATCHER = BRAIN_HOME / "bin" / "pyauto-brain" +INSTALLER = BRAIN_HOME / "bin" / "install.sh" +MARKDOWN_LINK = re.compile(r"\[[^]]+\]\(([^)]+)\)") + + +def public_agents() -> set[str]: + result = subprocess.run( + [str(DISPATCHER), "help"], + check=True, + capture_output=True, + text=True, + ) + return set(re.findall(r"^ ([a-z][a-z0-9_-]+)\s+", result.stdout, re.MULTILINE)) + + +def test_every_public_agent_has_a_skill_wrapper(): + agents = public_agents() + assert agents + missing = [ + name + for name in sorted(agents) + if not (BRAIN_HOME / "skills" / name / "SKILL.md").is_file() + ] + assert missing == [] + + +def test_local_skill_links_resolve(): + broken = [] + for skill in sorted((BRAIN_HOME / "skills").glob("*/SKILL.md")): + for target in MARKDOWN_LINK.findall(skill.read_text()): + path = target.split("#", 1)[0] + if not path or "://" in path: + continue + if not (skill.parent / path).resolve().exists(): + broken.append(f"{skill.relative_to(BRAIN_HOME)} -> {target}") + assert broken == [] + + +def test_installer_keeps_commands_and_installs_both_skill_homes(tmp_path): + claude_home = tmp_path / "claude" + codex_home = tmp_path / "codex" + env = os.environ | { + "HOME": str(tmp_path / "home"), + "CLAUDE_HOME": str(claude_home), + "CODEX_HOME": str(codex_home), + } + + subprocess.run( + ["bash", str(INSTALLER)], + cwd=BRAIN_HOME, + env=env, + check=True, + capture_output=True, + text=True, + ) + + for name in ("intake", "start_dev"): + assert (claude_home / "skills" / name).is_symlink() + assert (claude_home / "commands" / f"{name}.md").is_symlink() + + assert (codex_home / "skills" / "intake").is_symlink() + assert (codex_home / "skills" / "start-dev").is_symlink() + assert not (codex_home / "skills" / "start_dev").exists() + + assert (claude_home / "skills" / "release").is_symlink() + assert (codex_home / "skills" / "release").is_symlink() + assert not (claude_home / "commands" / "release.md").exists() + + +def test_installer_preserves_non_symlink_destinations(tmp_path): + claude_home = tmp_path / "claude" + codex_home = tmp_path / "codex" + protected = codex_home / "skills" / "intake" + protected.mkdir(parents=True) + marker = protected / "user-owned.txt" + marker.write_text("keep\n") + env = os.environ | { + "HOME": str(tmp_path / "home"), + "CLAUDE_HOME": str(claude_home), + "CODEX_HOME": str(codex_home), + } + + result = subprocess.run( + ["bash", str(INSTALLER)], + cwd=BRAIN_HOME, + env=env, + check=True, + capture_output=True, + text=True, + ) + + assert marker.read_text() == "keep\n" + assert "SKIP intake (Codex skill" in result.stdout + + +def test_invalid_codex_name_does_not_suppress_claude_surfaces(tmp_path): + pyauto_root = tmp_path / "PyAutoLabs" + skill = pyauto_root / "PyAutoBrain" / "skills" / "legacy_skill" + skill.mkdir(parents=True) + (skill / "SKILL.md").write_text( + "---\nname: legacy_skill\ndescription: Legacy test skill.\n---\n" + ) + (skill / "legacy_skill.md").write_text("# Legacy command\n") + claude_home = tmp_path / "claude" + codex_home = tmp_path / "codex" + env = os.environ | { + "HOME": str(tmp_path / "home"), + "PYAUTO_ROOT": str(pyauto_root), + "CLAUDE_HOME": str(claude_home), + "CODEX_HOME": str(codex_home), + } + + result = subprocess.run( + ["bash", str(INSTALLER)], + cwd=BRAIN_HOME, + env=env, + check=True, + capture_output=True, + text=True, + ) + + assert (claude_home / "skills" / "legacy_skill").is_symlink() + assert (claude_home / "commands" / "legacy_skill.md").is_symlink() + assert not (codex_home / "skills" / "legacy_skill").exists() + assert "Codex skill name invalid" in result.stdout