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
72 changes: 46 additions & 26 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,32 +90,52 @@ For the full workflow narrative, conventions, and registry schemas, read
loosely-related changes, split into separate prompt files before issuing.
4. **`tmp/` is scratch.** Never commit anything under it.

## Running tests in a remote (web/mobile) session

Two facts, both measured, both worth one line each:

1. **Run the suite in parallel.** A remote container has 4 cores and the suites
are subprocess-heavy with no single slow test: PyAutoBrain's 554 tests take
96s on one core and 28s on four. `pytest-xdist` is installed by the
session-start hook, so the command is just:

```
python3 -m pytest -q -n auto
```

2. **If `python3 -m pytest` or `pytest` misbehaves, the environment is stale,
not the code.** A session holding several organs registers no SessionStart
hook (Claude Code reads hooks from the project directory, which is the
repos' *parent*). Knock on the door directly, once, in the first turn:

```
bash PyAutoMind/scripts/session_bootstrap.sh # fix it
bash PyAutoMind/scripts/session_bootstrap.sh --check # report only
```

The symptom to recognise: collection `ImportError`s naming `yaml`, or
`No module named pytest`. Both are the session resolving a pytest that is not
this workspace's — never a broken test module.
<!-- repos_sync:remote:begin -->
## Remote sessions (Claude Code on web and mobile)

Three facts, all measured in a web/mobile container, where this file is loaded
and little else is. They ride in every organ because a session may hold any
subset of them — and the session that needs this most is the one holding
several, which is exactly the session no hook fires in.

- **Bootstrap in the first turn, unconditionally** — before the first test
command, not as a remedy once something looks wrong:

```
bash PyAutoMind/scripts/session_bootstrap.sh # ~10s cold, ~1s warm
bash PyAutoMind/scripts/session_bootstrap.sh --check # report only
```

A session holding several organs registers no SessionStart hook — Claude Code
reads project hooks from the project directory, which in that layout is the
repos' *parent*, not a repo — so nothing has set this session up. It was once
phrased as a remedy keyed to `No module named pytest` or collection
`ImportError`s naming `yaml`; that symptom stopped appearing when the
container image moved to Python 3.12, while the environment is still wrong in
ways that read like a bad command rather than a stale session (`pytest -n
auto` → `unrecognized arguments: -n`). The bootstrap also **unshallows the
clones**: a remote session clones shallow, and `git merge-base --is-ancestor`
then answers "not an ancestor" for a commit whose ancestry is merely absent —
the answer the ship and close-out procedures act on when proving a branch
merged.

- **Then run the suite in parallel.** 4 cores, subprocess-heavy suites, no
single slow test: about 3.5x. `python3 -m pytest -q -n auto`, with
`pytest-xdist` supplied by the bootstrap above.

- **There is no `gh`, and installing one does not help.** A remote session
reaches GitHub through the `mcp__github__*` tools, already scoped to the
session's repos. `gh` installs in two seconds and is a trap: it authenticates,
then 403s every repo-scoped call, because the egress proxy serves neither the
REST repo paths nor GraphQL beyond a pinned set of PR-review operations — a
binary that looks healthy and fails everything that matters. It also defeats
the surface probe, which keys off `gh auth status`. Read
`PyAutoBrain/skills/GITHUB_ACCESS.md` at the top of any run that touches
GitHub; it maps each `gh` operation onto its MCP tool. Spell that path from
the workspace root, as written: a multi-organ session is cwd'd at the repos'
*parent*, so a bare `skills/…` reads as a missing file rather than a missing
repo prefix.
<!-- repos_sync:remote:end -->

## When you are asked to add a new prompt

Expand Down
16 changes: 16 additions & 0 deletions active.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Active Tasks

## board-github-data-seam
- issue: https://github.com/PyAutoLabs/PyAutoBrain/issues/303 (issued 2026-08-27)
- issued: 2026-08-27
- prompt: active/board_without_gh_phase1_seam.md
- status: library-dev — not started; routed by /start_dev, no worktree claimed yet
(this session is remote: no ~/Code/PyAutoLabs-wt, so /start_library runs on the
machine that picks the task up).
- worktree: ~/Code/PyAutoLabs-wt/board-github-data-seam/ (to be created by /start_library)
- repos: PyAutoBrain
- phase: 1 of 2 — phase 2 is draft/feature/pyautobrain/board_without_gh_phase2_legs.md,
blocked-by this one; parent design + probe evidence in
draft/feature/pyautobrain/board_without_gh.md
- why: the board is the morning door and eleven legs are dark on the surface it is
read from. The 2026-08-27 probe closed the two cheaper options — $GH_TOKEN 403s
every repo path — so the injection seam is the design.

## transformed-message-factor-gradient-unpack
- issue: https://github.com/PyAutoLabs/PyAutoFit/issues/1501 (issued 2026-08-19)
- issued: 2026-08-19
Expand Down
47 changes: 47 additions & 0 deletions active/board_without_gh_phase1_seam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Board phase 1: the injection seam, proven on the overnight legs

Type: feature
Target: pyautobrain
Repos:
- PyAutoBrain
Difficulty: medium
Autonomy: supervised
Priority: normal
Status: formalised
Filed: 2026-08-27
Issued: 2026-08-27
Parent: draft/feature/pyautobrain/board_without_gh.md

Phase 1 of the board's gh-less work. The parent prompt holds the design, the
measurements and the 2026-08-27 probe that selected this option; read it first
and do not re-derive them.

## Scope

Build the seam and prove it on **one** leg family — the seven `overnight:
could not read <repo>/<workflow>` rows, the largest block of the eleven.

- `board/_board.py` accepts pre-fetched GitHub JSON (`--github-data <file>`),
and `gh_json()` reads from it when present. The `gh` path is untouched, so a
dev box behaves exactly as today.
- The `/board` skill — which *is* the agent, and so is the only thing that can
call `mcp__github__*` — gathers that JSON when `command -v gh` fails, writes
it, and invokes the renderer with the flag. `_board.py` stays a pure
renderer; a subprocess cannot reach MCP tools and this is the whole reason
the seam exists.
- The file's shape is a documented contract in `board/AGENTS.md` (extend
"Reading the board in a remote session"), because it outlives whoever writes
it.

## Guards

- Tests drive the seam from a **fixture file**, never a live call.
- A leg with no injected data still reports `could not read` — the invariant
from the 2026-08-26 work: no leg may substitute an empty answer for an
unasked question. A green badge still requires a render that read everything.

## Done when

The overnight rows are live in a remote render, the degraded count drops by
seven, the dev-box path is byte-identical, and `tests/test_board_degraded.py`
plus the new fixture tests pass.
Loading
Loading