Tutorial: Experimental Workflows with Exploop
=============================================
This tutorial shows how to use **FermiLink exploop mode** for iterative
laboratory or instrument-driven experimental workflows.
The key idea is that ``exploop`` connects an agent workflow with **PID
polling**. The agent can start a long measurement as a detached process,
print ``PID``, and return control immediately.
**FermiLink** then polls that PID, waits until the measurement finishes,
records new artifacts, refreshes ``projects/memory.md``, and only then starts
the next agent reasoning turn. This lets very long iterative agent workflows
run without keeping the agent blocked inside one tool call.
The complete flow is:
1. Install **FermiLink** with ``pip``.
2. Configure the Codex agent policy (tested under both Windows and MacOS environments).
3. Install remote experimental skills from a GitHub repository.
4. Initialize a local workspace from that installed repository.
5. Run ``fermilink exploop goal.md`` until the experiment is complete.
This tutorial is self-contained. You can follow it from a fresh shell.
Prerequisites
~~~~~~~~~~~~~
You need:
- Python ``>= 3.11``
- ``git`` on ``PATH``
- OpenAI Codex CLI installed and authenticated
- Access to a GitHub repository that contains your experimental skills
- A lab workstation or control computer that can safely run the instrument
scripts referenced by those skills
``exploop`` is designed for Windows-oriented lab workflows and uses native
Windows PID polling through ``tasklist``, as most experimental devices are Windows-based. It also works for
development and testing on macOS/Linux.
.. warning::
Experimental workflows can interact with real hardware. Do not let the agent modify hardcoded hardware safety limits
unless you explicitly ask for that change.
Step 1. Install **FermiLink**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A clean Python environment is recommended:
.. code-block:: bash
conda create -n fermilink-exploop python=3.11 -y
conda activate fermilink-exploop
pip install fermilink
Quick check:
.. code-block:: bash
fermilink --help
Step 2. Configure the Codex agent policy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Install and authenticate Codex CLI if you have not done that already:
.. code-block:: bash
npm i -g @openai/codex
codex login
Then set **FermiLink** to use Codex with a high-reasoning model and optionally relaxed
sandboxing (``--bypass-sandbox`` or enforcing sanboxing ``--sandbox``) for direct command execution:
.. code-block:: bash
fermilink agent codex --model gpt-5.5 --reasoning-effort xhigh --bypass-sandbox
Confirm the active policy:
.. code-block:: bash
fermilink agent --json
.. warning::
``--bypass-sandbox`` allows the agent to run local measurement commands and
instrument-control scripts. Use it only on a trusted experimental control
machine. For dry runs or mock hardware, prefer ``--sandbox``.
Step 3. Install remote experimental skills from GitHub or local path
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An experimental skills repository can be any GitHub repository that contains a
``skills/`` directory with one or more ``SKILL.md`` files. The repository can
also contain scripts, notebooks, instrument documentation, calibration notes,
or templates that the skills reference.
Example repository layout:
.. code-block:: text
lab-experiment-skills/
|-- skills/
| `-- laser-scan/
| `-- SKILL.md
|-- scripts/
| `-- run_scan.py
`-- docs/
`-- instrument_notes.md
Install the repository as a **FermiLink** package knowledge base:
.. code-block:: bash
fermilink install https://github.com/your-org/lab-experiment-skills --workflow-type experiment
The option ``--workflow-type experiment`` is necessary as **FermiLink** by default expects simulation workflows.
If the repository is private, make sure your GitHub SSH key has access. The
package id is derived from the GitHub repository name. In the example above,
the package id is ``lab-experiment-skills``.
Confirm that the package is registered:
.. code-block:: bash
fermilink list
Step 4. Initialize a local experimental workspace
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a workspace for one experimental campaign and initialize it from the
installed GitHub repository name:
.. code-block:: bash
mkdir -p ~/experiments/laser_scan_demo
cd ~/experiments/laser_scan_demo
fermilink init lab-experiment-skills
What ``fermilink init `` does here:
- Copies the package ``skills/`` directory into the workspace.
- Overlays the installed repository contents so the agent can inspect scripts,
docs, and examples.
- Writes ``AGENTS.md`` plus ``CLAUDE.md`` / ``GEMINI.md`` aliases for local
agent guidance.
- Records a manifest so ``fermilink clean`` can safely remove the overlay
later.
After initialization, the workspace is the place where measurements, logs,
figures, and memory will accumulate.
Step 5. Write ``goal.md``
~~~~~~~~~~~~~~~~~~~~~~~~~
Create a concise goal file in the workspace. The exact content depends on your
instrument and skills, but a good experimental goal states the objective,
safety constraints, allowed scripts, expected artifacts, and done criteria.
Example:
.. code-block:: markdown
# Goal: Laser power sweep
Use the local experimental skills to run a small laser power sweep on the
mock or lab instrument controller.
## Objective
Measure detector response at 5, 10, 15, and 20 mW. Save raw logs and a
summary plot under `projects/YYYY-MM-DD-laser-power-sweep/`.
## Safety constraints
- Do not exceed 20 mW.
- Do not modify hardware safety limits.
- If the instrument reports an interlock, stop and summarize the condition.
## Execution guidance
- Read `skills/*/SKILL.md` before choosing scripts.
- Start long measurements as detached processes.
- When a long measurement starts, emit `PID` for
the final detached measurement process, not a launcher or wrapper.
- Update `projects/memory.md` after each step with parameters, commands,
PIDs, output paths, and pending work.
## Done criteria
- Raw data for all four powers are saved.
- A summary CSV and plot are saved.
- The final response includes `DONE` only after all
measurement and analysis work is complete.
Step 6. Run ``exploop``
~~~~~~~~~~~~~~~~~~~~~~~
Start the iterative experimental workflow:
.. code-block:: bash
fermilink exploop goal.md
For very long measurements, tune the iteration and polling limits:
.. code-block:: bash
fermilink exploop --max-iterations 50 --wait-seconds 10 --max-wait-seconds 172800 goal.md
Useful options:
- ``--max-iterations``: maximum agent turns before stopping.
- ``--wait-seconds``: PID polling interval and fallback sleep between turns.
- ``--max-wait-seconds``: hard cap for one PID wait window.
- ``--sandbox``: per-run sandbox override if you do not want to use the global
``fermilink agent`` policy.
What happens during an ``exploop`` run
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each iteration follows the same control loop:
1. ``exploop`` writes the local ``AGENTS.md`` experimental guide and prepares
``projects/memory.md``.
2. It discovers local ``skills/*/SKILL.md`` files and lists newly observed
artifacts.
3. It prompts the configured agent with the goal, memory, skills, and artifact
summary.
4. If the agent emits ``12345``, **FermiLink** polls
that process instead of immediately asking the agent to continue.
5. When the PID exits, **FermiLink** snapshots new or modified files under
``projects/`` and starts the next agent turn with updated context.
6. When the agent emits ``DONE``, ``exploop`` exits
successfully.
Typical PID-polling output looks like this:
.. code-block:: text
[exploop] instructions: AGENTS.md
[exploop] memory: projects/memory.md
[exploop] iteration 1/30
24816
[exploop] measurement running; polling PID(s) every 10.0s and showing status every 60s: 24816
[exploop] still waiting for measurement PID(s) after 60.1s: 24816
[exploop] measurement PID polling complete after 312.4s
[exploop] iteration 2/30
This PID boundary is the main difference between ``exploop`` and a normal
interactive agent session. The agent does not need to remain inside a blocking
tool call for hours. It launches a measurement, emits the PID, and **FermiLink**
handles the waiting before the next reasoning turn.
Files created in the workspace
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After ``fermilink init`` and ``fermilink exploop``, you should expect:
- ``skills/``: copied experimental skills from the GitHub repository.
- ``AGENTS.md``: local exploop guidance for the agent.
- ``CLAUDE.md`` / ``GEMINI.md``: aliases for agents that read those filenames.
- ``projects/memory.md``: persistent campaign memory, pending work, commands,
PIDs, and artifact inventory.
- ``projects/YYYY-MM-DD-short-name/``: recommended location for measurement
outputs.
- ``fermilink-exploop/state.json``: artifact-tracking state used by
``exploop``.
Do not edit the managed ``skills/`` copy directly unless you intend local-only
changes. For reusable improvements, update the GitHub skills repository and
reinstall it.
Cleanup
~~~~~~~
When the campaign is finished and you no longer need the overlaid skills in
the workspace, run:
.. code-block:: bash
fermilink clean
``fermilink clean`` removes the managed overlay files and leaves your
measurement outputs under ``projects/`` untouched. The installed GitHub package
stays under **FermiLink**'s package store, so you can initialize another
workspace from it later.
Troubleshooting
~~~~~~~~~~~~~~~
- **The agent does not see my experimental skills**: confirm that
``skills/*/SKILL.md`` exists in the workspace after ``fermilink init``.
- **Private GitHub install fails**: confirm your SSH key has repository read
access; **FermiLink** registers GitHub repositories through SSH-backed clone
metadata.
- **PID is immediately reported as finished or not found**: the agent likely
emitted a launcher/wrapper PID instead of the final detached measurement PID.
Update the skill to redirect stdin/stdout/stderr and emit the child process
PID.
- **``exploop`` reaches ``--max-wait-seconds``**: the measurement is still
running after the configured cap. Inspect the instrument state, then resume
from the same workspace when safe.
- **``fermilink init`` reports a conflict**: move the conflicting local file or
rerun with ``--force`` only if you are sure the managed overlay may replace
it.