---
name: prl-research-loop
description: Use PRL for reproducible research phases, reusing one Git worktree per hypothesis and implementation route while creating a new run for each experiment.
---

# PRL research loop

## Fast submit, explain later (default)

Read the current context once; reuse known context and batch independent necessary checks. Make the minimal change and necessary validation, then submit immediately. Do not require long STATE.yaml/hypothesis prose, reports, repeated preflight checks, or optional remote tracking before submission. Update explanatory notes asynchronously after the receipt, or at the next useful phase boundary.

Submission must first pin an immutable code snapshot and atomically persist owner/session, commit, argv/config (including seed), checkpoint identity, explicit GPU IDs/resource policy, logs/events and termination policy. Never launch bare training and add Git/identity afterward. Put required CPU tests in a dependency Run so the worker gates computation without an Agent round trip. Required checks still finish before computation; non-required services cannot gate it.

A queued receipt means submitted, NOT process started or first update completed. Inspect performance only when useful: preparation, dependency wait, checksum, GPU wait, process spawn and trainer first progress are separate phases. Mark the first update with an event's `milestone: first_update` (or a progress watchdog); do not infer it from the first arbitrary log line.

1. Call `prl_context` before acting. Read the active tasks, hypothesis, project goal, current state, and active Runs owned by this Pi session.
2. Treat one Task/worktree as one implementation route. If an active Task already matches the hypothesis and route, reuse its worktree; do not call `prl_task_start` again for each phase.
3. Call `prl_task_start` only when no compatible active Task exists. A new worktree is exceptional: use `new_worktree_reason` only for `stable_baseline`, `concurrent_agents`, or `disposable_experiment`. Different hypotheses naturally use different Tasks.
4. Make phase changes in the existing worktree. Use `prl_task_checkpoint` for a named phase commit when there is no experiment to launch. `prl_run_launch` also checkpoints the current code before every experiment.
5. Launch every experiment as a new PRL Run with an argv array. Declare only useful event listeners; `process.exit` is automatic. The Run and its notifications are bound to the current Pi session.
6. For a GPU handoff or other mandatory continuation, enqueue the successor before the parent finishes with `prl_run_enqueue`. Pin a `durable_complete` artifact/checksum whenever a checkpoint is required and explicitly allow `checkpointed_stop` when appropriate. The worker—not the LLM—must wait for the dependency and launch the successor.
7. Use `prl_run_fork` for a variant of an existing experiment instead of rebuilding its full argv and protocol. Apply only the requested override diff; structural changes require weights-only or fresh start.
8. Never inspect, terminate, retry, or react to a Run owned by another Pi session. Use `prl_run_claim` only for an unbound legacy Run. If the original owner session is lost, use `prl_run_transfer` only after explicit user confirmation and record a reason.
9. Do not poll a process or log. When this session receives a `[PRL EVENT]`, call `prl_run_inspect` with a bounded mode; inspection acknowledges delivery. Handle each notification_id once; ignore acknowledged/delayed duplicates and inspect a batch once per Run, not once per progress line. Update accumulated state when useful and decide: inspect, modify, retry, or stop. Do not use `wake_agent` as a dependency scheduler.
10. Use `prl_run_control` for termination/retry. For long training, provide a reason and use checkpoint-first termination; never request `force` unless the user explicitly accepts SIGKILL risk. Retry creates a new session-owned Run, marks the parent superseded, and never overwrites it. Do not act on delayed events from superseded Runs.
11. Trust the Pi PRL monitor widget/status line for this session's queued and running experiments; use `prl_run_inspect` for details rather than repeatedly restating a completed Run.
12. Every Run executes from an immutable snapshot. Use absolute output/checkpoint/cache paths outside all worktrees; do not assume relative files appear in the mutable Task worktree.
13. Update `research/STATE.yaml` and the hypothesis note with concise accumulated conclusions. Finish the Task only after active Runs stop and the route is complete. Review and merge the finished branch to `main` once, explicitly and separately; PRL never pushes or merges automatically.

Useful event types: `log.regex`, `timer.timeout`, and `file.created`. Actions are `record`, `terminate`, and `wake_agent`.

A PRL GPU lease coordinates PRL-managed Runs and checks `nvidia-smi`, but cannot reserve a GPU against unmanaged external jobs. Use a real scheduler such as Slurm for hard reservations.
