Overview
import autocti hard-requires arcticpy, which is not a pip dependency: its sdist is source-only C++ (needs libgsl-dev + a toolchain + Cython) and its own requirements downgrade numpy below 2.0. Every CTI repo that runs CI therefore carries its own copy of the install recipe, there is no single owner, and the documented recipe is incomplete for a clean environment. This task makes one canonical arcticpy install step owned by PyAutoHeart (the organ that owns the reusable CI workflows), repoints every consumer at it, and fixes the human/agent docs so they match CI.
Audit result (this supersedes the prompt's site list)
The prompt flagged PyAutoCTI's own lib-tests CI as UNREAD. Audited:
PyAutoCTI/.github/workflows/main.yml is a thin caller of PyAutoHeart/.github/workflows/lib-tests.yml@main. It contains no arcticpy recipe of its own.
- That reusable workflow carries two further copies, one per job:
unittest (L81–90) and unittest-nojax (L180–186).
So there are four shell copies, not two:
| # |
Site |
setuptools wheel? |
| 1 |
PyAutoHeart/.github/workflows/lib-tests.yml — job unittest |
yes |
| 2 |
PyAutoHeart/.github/workflows/lib-tests.yml — job unittest-nojax |
yes |
| 3 |
autocti_workspace_test/.github/scripts/smoke_install.sh |
no |
| 4 |
autocti_assistant/.github/workflows/wiki-currency.yml |
yes |
autocti_workspace has no .github/ directory at all — it is a docs-only consumer.
Correction to the "latent failure" framing
The prompt says smoke_install.sh "relies on the runner image's ambient setuptools" and is one runner-image change from breaking. That is not accurate as written. PyAutoHeart's smoke-tests.yml runs
- name: Install (base + the workspace's own epilogue)
run: |
pip install --upgrade pip setuptools wheel
pip install pyyaml
bash workspace/.github/scripts/smoke_install.sh
so setuptools is present when the epilogue runs. The real defect is weaker but still worth fixing: the epilogue's correctness depends implicitly on a preceding step in a different repository's workflow, with nothing stating the dependency. Reordering or trimming that Heart step would silently break CTI smoke. Making the canonical step self-contained removes the coupling.
Docs are worse than CI
PyAutoCTI/AGENTS.md §arcticpy — the note both other repos cite as canonical. Says "install it after numpy is in place" and then the bare pip install arcticpy line. Omits both Cython and setuptools.
autocti_workspace/AGENTS.md §arcticpy — "install it after numpy". Omits Cython and setuptools.
autocti_workspace_test/AGENTS.md — "after numpy+cython". Omits setuptools.
autocti_assistant/skills/ac_setup_environment.md — numpy + cython, no setuptools.
Plan
- Add a canonical composite action
install-arcticpy to PyAutoHeart, version-pinned in one place, ending in an import assertion.
- Give it a self-test workflow in PyAutoHeart so a change to the recipe is proven to build before it can break four repos.
- Repoint all four shell copies at it and delete the local recipes.
- Fix the four documented recipes so humans and agents get the same working commands CI uses.
- Leave the build-cache idea unimplemented; record it as a measured follow-up rather than guessing.
Detailed implementation plan
Affected Repositories
- PyAutoHeart (primary)
- autocti_workspace_test
- autocti_assistant
- PyAutoCTI
- autocti_workspace
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./PyAutoHeart |
main |
clean |
| ./autocti_workspace_test |
main |
clean |
| ./autocti_assistant |
main |
clean |
| ./PyAutoCTI |
main |
clean |
| ./autocti_workspace |
main |
clean |
Suggested branch: feature/arcticpy-install-standardisation
Shape: composite action, not a shell script
PyAutoHeart has no .github/actions/ today, so this is a new convention for the repo. It is the right one:
- PyAutoHeart is public, so
uses: PyAutoLabs/PyAutoHeart/.github/actions/install-arcticpy@main resolves from any consumer repo with no checkout of Heart required — the same reach the reusable workflows already have, and the same @main reference style every caller already uses.
- A shell script in Heart would need each consumer to fetch it first (curl or a checkout), which is more machinery and a worse pin.
smoke_install.sh is a bash script and cannot uses: an action. Rather than leave copy #3 in place, the arcticpy install moves out of the workspace epilogue and into Heart's smoke-tests.yml as a gated step. This matches the existing precedent inside Heart: lib-tests.yml already gates its arcticpy step on if: inputs.package == 'autocti'.
Implementation Steps
-
PyAutoHeart/.github/actions/install-arcticpy/action.yml (new) — composite action:
- input
version, default 2.6 (the single pin).
- input
sudo, default true, so a container without sudo can opt out of the apt leg.
sudo apt-get update && sudo apt-get install -y libgsl-dev
python -m pip install --upgrade pip setuptools wheel — self-contained, no reliance on a caller's preceding step.
python -m pip install numpy cython
python -m pip install "arcticpy==${version}" --no-build-isolation --no-deps
python -c "import arcticpy; print(arcticpy.__version__)" — the assertion. Today a broken arcticpy surfaces much later as a confusing import autocti failure in an unrelated job.
-
PyAutoHeart/.github/workflows/arcticpy-action.yml (new) — self-test. Runs on PRs touching the action or the workflow, plus workflow_dispatch. Uses the local path ./.github/actions/install-arcticpy so it exercises the branch's version, then asserts add_cti produces a trail on a single bright pixel. Without this, a @main reference means a recipe change cannot be validated before merge.
-
PyAutoHeart/.github/workflows/lib-tests.yml — replace both inline blocks (jobs unittest, unittest-nojax) with the action, keeping the if: inputs.package == 'autocti' gate.
-
PyAutoHeart/.github/workflows/smoke-tests.yml — add an arcticpy boolean input (default false); when true, run the action after Python setup and before the workspace epilogue. Default-false keeps every non-CTI workspace caller byte-identical.
-
autocti_workspace_test — caller .github/workflows/smoke_tests.yml passes arcticpy: true; delete the recipe from .github/scripts/smoke_install.sh, leaving it to do only what is genuinely workspace-specific (the chain install and the autonerves re-pin).
-
autocti_assistant/.github/workflows/wiki-currency.yml — replace the inline recipe in "Install the stack" with the action, and delete the "Recipe mirrors …smoke_install.sh" comment that acknowledged the copy-paste.
-
Docs — fix all four, each to the verified-complete recipe, and point them at the canonical action so the CI/doc link is explicit:
PyAutoCTI/AGENTS.md §arcticpy (the cited canonical note; keep the no-root header workaround)
autocti_workspace/AGENTS.md §arcticpy
autocti_workspace_test/AGENTS.md
autocti_assistant/skills/ac_setup_environment.md (note: the assistant's .claude/skills/*.md are symlinks into skills/, git mode 120000 — one edit covers both surfaces)
Verified recipe (measured 2026-08-24, clean Ubuntu container, Python 3.12 venv)
apt-get install -y libgsl-dev # g++/gcc/make already present on the image
pip install numpy scipy setuptools wheel Cython matplotlib
pip install arcticpy==2.6 --no-build-isolation --no-deps
Each missing build dep failed the build naming the next one: setuptools → Cython → builds. matplotlib is a runtime import (arcticpy/read_noise.py) needed only because --no-deps suppresses it; the CTI stack installs it anyway, so it is not a build dep and does not belong in the canonical step.
Deliberately not done
Caching the built wheel (actions/cache keyed on arcticpy version + Python version + runner image). arcticpy compiles from source on every CI run in every CTI repo, so there is real time to reclaim — but the prompt asks for a measured proposal with before/after timings rather than an assumed win, and cache-invalidation complexity is a genuine cost. Filed as a follow-up, not guessed at here.
Key Files
PyAutoHeart/.github/actions/install-arcticpy/action.yml — new canonical step
PyAutoHeart/.github/workflows/arcticpy-action.yml — new self-test
PyAutoHeart/.github/workflows/lib-tests.yml — copies 1 and 2
PyAutoHeart/.github/workflows/smoke-tests.yml — new gated step for copy 3
autocti_workspace_test/.github/scripts/smoke_install.sh — copy 3
autocti_assistant/.github/workflows/wiki-currency.yml — copy 4
Original Prompt
Click to expand starting prompt
PyAutoMind/draft/maintenance/ci/arcticpy_install_standardisation.md, filed 2026-08-24 — reproduced verbatim:
Standardise the arcticpy CI install across every CTI repo
Type: maintenance / Target: pyautoheart / Difficulty: medium / Autonomy: supervised / Priority: normal
import autocti hard-requires arcticpy, which is not a pip dependency: its sdist is source-only (needs libgsl-dev + a C++ toolchain + Cython) and its own requirements downgrade numpy below 2.0. Every CTI repo that runs CI therefore carries its own copy of the install recipe. There is no single owner, the copies have already diverged in a way that matters, and the recipe as documented is incomplete for a clean environment.
Make one canonical arcticpy install step, owned by the organ that owns the reusable CI workflows, and have every CTI repo consume it.
Work: (1) put the canonical step in PyAutoHeart alongside the reusable workflows the CTI repos already call — check PyAutoHeart's actual layout and conventions before choosing the shape; (2) add the missing setuptools wheel; (3) assert the install worked with python -c "import arcticpy; print(arcticpy.__version__)"; (4) repoint every consumer and delete the local copies; (5) fix the documented recipe in autocti_workspace/AGENTS.md, autocti_assistant/skills/ac_setup_environment.md and PyAutoCTI/AGENTS.md; (6) single pin — bumping arcticpy==2.6 should become a one-line change.
Optional, decide deliberately: caching the built wheel. Raise it as a measured proposal with before/after timings rather than assuming it is worth the cache-invalidation complexity.
Why now: two tasks in the preceding sequence were deferred on the belief that arcticpy could not be built outside a prepared machine — a belief that turned out to be false, and cost real work. A canonical, documented, CI-owned install is what stops that assumption forming again.
Unblocks draft/test/autocti/phase5_smoke_reenable_ordered_trap_scripts.md (CTI epic Phase 5) and helps draft/bug/autocti/wiki_currency_baseline_drift.md, whose baseline regeneration needs the same stack.
Overview
import autoctihard-requires arcticpy, which is not a pip dependency: its sdist is source-only C++ (needslibgsl-dev+ a toolchain + Cython) and its own requirements downgrade numpy below 2.0. Every CTI repo that runs CI therefore carries its own copy of the install recipe, there is no single owner, and the documented recipe is incomplete for a clean environment. This task makes one canonical arcticpy install step owned by PyAutoHeart (the organ that owns the reusable CI workflows), repoints every consumer at it, and fixes the human/agent docs so they match CI.Audit result (this supersedes the prompt's site list)
The prompt flagged PyAutoCTI's own lib-tests CI as UNREAD. Audited:
PyAutoCTI/.github/workflows/main.ymlis a thin caller ofPyAutoHeart/.github/workflows/lib-tests.yml@main. It contains no arcticpy recipe of its own.unittest(L81–90) andunittest-nojax(L180–186).So there are four shell copies, not two:
setuptools wheel?PyAutoHeart/.github/workflows/lib-tests.yml— jobunittestPyAutoHeart/.github/workflows/lib-tests.yml— jobunittest-nojaxautocti_workspace_test/.github/scripts/smoke_install.shautocti_assistant/.github/workflows/wiki-currency.ymlautocti_workspacehas no.github/directory at all — it is a docs-only consumer.Correction to the "latent failure" framing
The prompt says
smoke_install.sh"relies on the runner image's ambientsetuptools" and is one runner-image change from breaking. That is not accurate as written. PyAutoHeart'ssmoke-tests.ymlrunsso
setuptoolsis present when the epilogue runs. The real defect is weaker but still worth fixing: the epilogue's correctness depends implicitly on a preceding step in a different repository's workflow, with nothing stating the dependency. Reordering or trimming that Heart step would silently break CTI smoke. Making the canonical step self-contained removes the coupling.Docs are worse than CI
PyAutoCTI/AGENTS.md§arcticpy — the note both other repos cite as canonical. Says "install it after numpy is in place" and then the barepip install arcticpyline. Omits bothCythonandsetuptools.autocti_workspace/AGENTS.md§arcticpy — "install it after numpy". Omits Cython and setuptools.autocti_workspace_test/AGENTS.md— "after numpy+cython". Omits setuptools.autocti_assistant/skills/ac_setup_environment.md— numpy + cython, no setuptools.Plan
install-arcticpyto PyAutoHeart, version-pinned in one place, ending in an import assertion.Detailed implementation plan
Affected Repositories
Branch Survey
Suggested branch:
feature/arcticpy-install-standardisationShape: composite action, not a shell script
PyAutoHeart has no
.github/actions/today, so this is a new convention for the repo. It is the right one:uses: PyAutoLabs/PyAutoHeart/.github/actions/install-arcticpy@mainresolves from any consumer repo with no checkout of Heart required — the same reach the reusable workflows already have, and the same@mainreference style every caller already uses.smoke_install.shis a bash script and cannotuses:an action. Rather than leave copy #3 in place, the arcticpy install moves out of the workspace epilogue and into Heart'ssmoke-tests.ymlas a gated step. This matches the existing precedent inside Heart:lib-tests.ymlalready gates its arcticpy step onif: inputs.package == 'autocti'.Implementation Steps
PyAutoHeart/.github/actions/install-arcticpy/action.yml(new) — composite action:version, default2.6(the single pin).sudo, defaulttrue, so a container without sudo can opt out of the apt leg.sudo apt-get update && sudo apt-get install -y libgsl-devpython -m pip install --upgrade pip setuptools wheel— self-contained, no reliance on a caller's preceding step.python -m pip install numpy cythonpython -m pip install "arcticpy==${version}" --no-build-isolation --no-depspython -c "import arcticpy; print(arcticpy.__version__)"— the assertion. Today a broken arcticpy surfaces much later as a confusingimport autoctifailure in an unrelated job.PyAutoHeart/.github/workflows/arcticpy-action.yml(new) — self-test. Runs on PRs touching the action or the workflow, plusworkflow_dispatch. Uses the local path./.github/actions/install-arcticpyso it exercises the branch's version, then assertsadd_ctiproduces a trail on a single bright pixel. Without this, a@mainreference means a recipe change cannot be validated before merge.PyAutoHeart/.github/workflows/lib-tests.yml— replace both inline blocks (jobsunittest,unittest-nojax) with the action, keeping theif: inputs.package == 'autocti'gate.PyAutoHeart/.github/workflows/smoke-tests.yml— add anarcticpyboolean input (defaultfalse); when true, run the action after Python setup and before the workspace epilogue. Default-false keeps every non-CTI workspace caller byte-identical.autocti_workspace_test— caller.github/workflows/smoke_tests.ymlpassesarcticpy: true; delete the recipe from.github/scripts/smoke_install.sh, leaving it to do only what is genuinely workspace-specific (the chain install and the autonerves re-pin).autocti_assistant/.github/workflows/wiki-currency.yml— replace the inline recipe in "Install the stack" with the action, and delete the "Recipe mirrors …smoke_install.sh" comment that acknowledged the copy-paste.Docs — fix all four, each to the verified-complete recipe, and point them at the canonical action so the CI/doc link is explicit:
PyAutoCTI/AGENTS.md§arcticpy (the cited canonical note; keep the no-root header workaround)autocti_workspace/AGENTS.md§arcticpyautocti_workspace_test/AGENTS.mdautocti_assistant/skills/ac_setup_environment.md(note: the assistant's.claude/skills/*.mdare symlinks intoskills/, git mode 120000 — one edit covers both surfaces)Verified recipe (measured 2026-08-24, clean Ubuntu container, Python 3.12 venv)
apt-get install -y libgsl-dev # g++/gcc/make already present on the image pip install numpy scipy setuptools wheel Cython matplotlib pip install arcticpy==2.6 --no-build-isolation --no-depsEach missing build dep failed the build naming the next one:
setuptools→Cython→ builds.matplotlibis a runtime import (arcticpy/read_noise.py) needed only because--no-depssuppresses it; the CTI stack installs it anyway, so it is not a build dep and does not belong in the canonical step.Deliberately not done
Caching the built wheel (
actions/cachekeyed on arcticpy version + Python version + runner image). arcticpy compiles from source on every CI run in every CTI repo, so there is real time to reclaim — but the prompt asks for a measured proposal with before/after timings rather than an assumed win, and cache-invalidation complexity is a genuine cost. Filed as a follow-up, not guessed at here.Key Files
PyAutoHeart/.github/actions/install-arcticpy/action.yml— new canonical stepPyAutoHeart/.github/workflows/arcticpy-action.yml— new self-testPyAutoHeart/.github/workflows/lib-tests.yml— copies 1 and 2PyAutoHeart/.github/workflows/smoke-tests.yml— new gated step for copy 3autocti_workspace_test/.github/scripts/smoke_install.sh— copy 3autocti_assistant/.github/workflows/wiki-currency.yml— copy 4Original Prompt
Click to expand starting prompt
PyAutoMind/draft/maintenance/ci/arcticpy_install_standardisation.md, filed 2026-08-24 — reproduced verbatim: