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
File renamed without changes.
File renamed without changes.
118 changes: 118 additions & 0 deletions .github/workflows/release_board.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: Release Board

# Publishes the release board — WHAT THE HANDS SHIPPED — three ways from one
# renderer (autohands/board.py, the Heart-dashboard pattern):
# * the GitHub Pages page (one-tap 📋 copy prompts for a phone),
# * badge.json (the shields endpoint the README badge reads),
# * the one-line README strip between the hands:begin/end markers.
#
# Past-tense record only: the board never renders a verdict or a gate —
# readiness lives with the Heart's board, which the page links.
#
# Refreshes right after every release-train run (workflow_run), daily as a
# backstop (tags/PyPI can change without a train run — e.g. a yank), and on
# demand.

on:
workflow_run:
workflows: ["PyAuto Release"]
types: [completed]
schedule:
- cron: "30 5 * * *"
workflow_dispatch:

# contents: write → the README strip self-commit; pages/id-token → publish.
permissions:
contents: write
pages: write
id-token: write

concurrency:
group: release-board-pages
cancel-in-progress: false

jobs:
board:
name: Render + publish the release board
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install PyYAML
run: pip install --quiet pyyaml

- name: Collect the snapshot (GitHub + PyPI APIs)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PYTHONPATH="$PWD/autohands" python autohands/board.py --collect board_snapshot.json

- name: Render every surface
run: |
mkdir -p _site
render() { PYTHONPATH="$PWD/autohands" python autohands/board.py --snapshot board_snapshot.json "$@"; }
render --html > _site/index.html
render --badge > _site/badge.json
render --md > board.md
render --md-brief > readme_strip.md

- name: Write the board to the job step summary
run: |
{
cat board.md
} >> "$GITHUB_STEP_SUMMARY"

- name: Update the README strip (own repo only, main only)
if: github.ref == 'refs/heads/main'
run: |
python - <<'PY'
import pathlib, re
readme = pathlib.Path("README.md")
text = readme.read_text()
strip = pathlib.Path("readme_strip.md").read_text().strip()
begin, end = "<!-- hands:begin -->", "<!-- hands:end -->"
block = f"{begin}\n{strip}\n{end}"
if begin in text and end in text:
text = re.sub(re.escape(begin) + r".*?" + re.escape(end), block,
text, flags=re.DOTALL)
readme.write_text(text)
PY
if ! git diff --quiet README.md; then
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add README.md
git commit -m "docs(hands): auto-update release-board strip [skip ci]"
# Rebuild on the tip if a concurrent push landed; the strip is
# regenerated content, so retrying on the new tip is always safe.
for attempt in 1 2 3; do
if git push; then exit 0; fi
git pull --rebase origin main || exit 1
done
echo "::error::could not push the README strip after 3 attempts"
exit 1
else
echo "README strip unchanged — nothing to commit."
fi

# enablement: true creates the Pages site on first run (no manual
# Settings → Pages step) — same shape as the Mind's publisher.
- uses: actions/configure-pages@v5
if: github.ref == 'refs/heads/main'
with:
enablement: true

- uses: actions/upload-pages-artifact@v3
if: github.ref == 'refs/heads/main'
with:
path: _site

- id: deployment
uses: actions/deploy-pages@v4
if: github.ref == 'refs/heads/main'
23 changes: 11 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# PyAutoHands — Agent Guidance

> **Formerly PyAutoBuild.** This repository is being renamed PyAutoBuild →
> PyAutoHands (see [MIGRATION.md](MIGRATION.md)). The `autohands` CLI and Python
> package keep their names for now; only the repository/branding changes. The
> "Build" organ shorthand and the canonical `Brain → Heart (gate) → Build
> (execute)` call chain are updated at their source (`PyAutoBrain/ORGANISM.md`)
> in a later phase.
(The repo was renamed PyAutoBuild → PyAutoHands in 2026-07; the `autohands`
CLI/package name and the *Build* call-chain shorthand were kept — see
[MIGRATION.md](MIGRATION.md) and `PyAutoBrain/ORGANISM.md`.)

PyAutoHands is the **executor** (the Hands) of the PyAuto release ecosystem:
packaging, tagging, notebook generation, and PyPI publication via `release.yml`.
Expand All @@ -27,12 +24,14 @@ deep `verify_install` suite, and URL hygiene all live in PyAutoHeart now;
`autohands verify_install` / `autohands url_check` / `autohands watch|status|
tick|fix` are thin shims that delegate to `pyauto-heart`. Build keeps only the
executor primitives: the build/notebook pipeline (`pre_build`, `generate*`,
`run_all` / `run*`), the navigator catalogue (`navigator` /
`check_navigator` / `regenerate_navigator`), tagging + release
(`tag_and_merge`, `bump_colab_urls`, `release.yml`), the release-notes and
Slack tooling (`generate_release_notes`, `slack_release_notes`), assistant
seeding (`clone_seed`), and `repro_command`. See `docs/internals.md` for the
authoritative, current list.
`run_all` / `run*`), the navigator catalogue (the `navigator.py` /
`check_navigator.py` / `regenerate_navigator.py` modules — workflow-invoked,
not CLI verbs), tagging + release (`tag_and_merge`, `bump_colab_urls`,
`release.yml`), the release-notes and Slack tooling
(`generate_release_notes`, `slack_release_notes`), the release board
(`board`, published by `release_board.yml`), assistant seeding
(`clone_seed`), and `repro_command`. `bin/autohands help` is the registry of
what is a CLI verb; see `docs/internals.md` for the pipeline detail.

See [`docs/internals.md`](docs/internals.md) for the build pipeline, workspace
folder structure, config files, and `release.yml` details. Read it when
Expand Down
2 changes: 1 addition & 1 deletion MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Migrating from PyAutoBuild to PyAutoHands

The **Hands** organ of the PyAuto organism is being renamed at the repository
The **Hands** organ of the PyAuto organism was renamed (2026-07) at the repository
level: **PyAutoBuild → PyAutoHands**. The name change makes the architecture read
as a living organism — *the Brain decides, the Hands do* — so this repo's brand
matches its role: **PyAutoHands executes work on behalf of PyAutoBrain**.
Expand Down
73 changes: 49 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,61 @@

# PyAutoHands

> **Formerly PyAutoBuild.** The repository is being renamed PyAutoBuild →
> PyAutoHands; see [MIGRATION.md](MIGRATION.md). The `autohands` command and
> Python package keep their names for now — only the repository and its
> branding change.

[![PyAutoScientist GitHub](https://img.shields.io/badge/%F0%9F%A7%AA%20PyAutoScientist-GitHub-181717?style=flat-square)](https://github.com/PyAutoLabs/PyAutoScientist) [![PyAutoScientist ReadTheDocs](https://img.shields.io/badge/%F0%9F%93%96%20PyAutoScientist-ReadTheDocs-8CA1AF?style=flat-square)](https://pyautoscientist.readthedocs.io)

PyAutoHands is the **Hands** of the PyAuto organism: the executor that packages,
tags, builds notebooks, and releases the PyAuto libraries (PyAutoNerves, PyAutoFit,
PyAutoArray, PyAutoGalaxy, PyAutoLens) and their workspaces to PyPI. **PyAutoHands
executes work on behalf of PyAutoBrain** — the Brain decides, the Hands do. It
runs no readiness checks and makes no gate decisions — those belong to
[PyAutoHeart](https://github.com/PyAutoLabs/PyAutoHeart), whose verdict the
[PyAutoBrain](https://github.com/PyAutoLabs/PyAutoBrain) release agent
reads before dispatching a release here.
[![released](https://img.shields.io/endpoint?url=https://pyautolabs.github.io/PyAutoHands/badge.json)](https://pyautolabs.github.io/PyAutoHands/)

**PyAutoHands is the Hands of the PyAutoScientist** — the executor that ships
the software. When a release is dispatched it packages, tags, regenerates
notebooks, and publishes the PyAuto libraries and their workspaces to PyPI.
It executes on behalf of the Brain and never decides for itself: no readiness
checks, no gate decisions — those belong to the Heart.

See the **[PyAutoHands Release Board](https://pyautolabs.github.io/PyAutoHands/)**
(mobile phone dashboard) for what shipped: the released library versions and
their PyPI status, the release train's recent runs, and the nightly cadence —
each actionable item carrying a one-tap 📋 button that copies a ready-made
Claude command (`/release`, `/release rehearse`, `/release validate`,
`/build`; a failed train run copies a `/bug …` prompt with its run link).

## Latest release

<!-- The line below is auto-updated by .github/workflows/release_board.yml (everything -->
<!-- between the hands:begin/hands:end markers is replaced with the rendered strip). -->
<!-- hands:begin -->
<!-- hands:end -->

Every operation is reachable through one dispatcher:
## How PyAutoHands works

1. **The Brain decides, the Hands execute.** A release is dispatched by the
Brain's release conductor (`/release`, or the nightly driver when there is
new activity) — and only when the Heart's readiness verdict is GREEN.
2. **Rehearse first.** `release.yml` builds the five libraries, publishes to
TestPyPI, installs the wheels, and runs the test + workspace validation
suites against them — a full dress rehearsal before anything is public.
3. **Then ship.** On success the same workflow stamps the build tree, cuts
the `YYYY.M.D.minor` git tag on every library, and releases to PyPI.
4. **The workspaces follow.** Notebooks are regenerated from the workspace
scripts, Colab URLs bumped to the new tag, and every workspace repo is
tagged to match.
5. **The record is published.** Release notes land on the libraries' GitHub
Releases, Slack is told, and the [release board](https://pyautolabs.github.io/PyAutoHands/)
refreshes — a past-tense record of execution, never a verdict.

## CLI examples

Every operation is reachable through one dispatcher, run from this checkout
(no pip install):

```bash
bash bin/autohands help # list every subcommand
bash bin/autohands help <subcommand> # full docstring for one
bash bin/autohands pre_build [minor] # format, generate notebooks, bump, push
bash bin/autohands pre_build [minor] # format, generate notebooks, push, dispatch release.yml
bash bin/autohands run_all # run the workspace validation scripts
bash bin/autohands board --md # the release board (also --html, --badge, --json)
```

The release pipeline (`.github/workflows/release.yml`) packages to
TestPyPI, verifies the install, runs the workspace scripts, and on success
releases to PyPI and tags the workspaces — nightly, when there is new
activity to ship.

Boundary and agent guidance: [AGENTS.md](AGENTS.md). The organism:
[PyAutoBrain/ORGANISM.md](https://github.com/PyAutoLabs/PyAutoBrain/blob/main/ORGANISM.md),
documented in full at <https://pyautoscientist.readthedocs.io>.
Boundary and agent guidance: [AGENTS.md](AGENTS.md); the pipeline internals:
[docs/internals.md](docs/internals.md). The organism this repo is the Hands
of is described once in
[PyAutoBrain/ORGANISM.md](https://github.com/PyAutoLabs/PyAutoBrain/blob/main/ORGANISM.md)
and documented in full at <https://pyautoscientist.readthedocs.io>.
Loading
Loading