@bb84/quailbot-pi

Quailbot Pi -- a Pi agent extension that turns a quantum instrument workspace into a measurement-readback action loop, with experiment logging and a workspace calibrator.

Packages

Package details

extension

Install @bb84/quailbot-pi from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@bb84/quailbot-pi
Package
@bb84/quailbot-pi
Version
0.1.1
Published
Jun 23, 2026
Downloads
not available
Author
bb84
License
ISC
Types
extension
Size
1.3 MB
Dependencies
0 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/src/extension.js"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

Quailbot Pi

A Pi agent extension for operating quantum measurement instruments through a measurement-readback action loop.

Quailbot Pi turns an instrument workspace (Nanonis STM, or any CLI driver that conforms to the workspace contract) into a fixed agent tool surface: parameter reads and writes, action commands, ROI screenshot readback, anchor clicks, planned multi-step programs, and a durable per-experiment evidence log. Mutating actions are gated behind a workspace-aware policy and produce linked-observable readback as a separate observation from the primary tool result.

Quickstart

Prerequisites

  • Node.js >= 20
  • Pi installed globally: npm install -g @earendil-works/pi-coding-agent
  • A workspace JSON file describing your instrument's CLI parameters, actions, ROIs, and anchors. (See "Workspaces" below.)
  • A working CLI driver on PATH whose name appears in your workspace's cli_params.cli_name field. For Nanonis the canonical driver is nqctl.

Install

# Global (recommended for most users):
pi install npm:@bb84/quailbot-pi

# Project-local (recommended for shared lab setups):
cd your-project
pi install -l npm:@bb84/quailbot-pi

If npm is blocked on your network, install from git:

pi install git:github.com/<your-org-or-fork>/quailbot-pi

First run

cd somewhere   # cwd does not affect where Quailbot state lives
pi

A first-run install has no workspace selected. Most Quailbot commands and tools need an active workspace, so the first thing to do is point at one:

/quailbot-workspace load D:/path/to/your-workspace.json

If you don't have a workspace JSON yet, write a minimal one by hand or import from the legacy Quailbot calibration tool, then use load. Once a workspace is active, open the browser calibrator to edit it visually:

/quailbot-workspace open

The calibrator launches in a localhost browser tab where you can refine ROIs, anchors, CLI parameters, and CLI actions over a real screen capture of your instrument GUI, then save back to the workspace path.

Mutating tools (safety gate)

By default Quailbot tools that change instrument state -- cli_set, cli_ramp, cli_action, click_anchor, set_field, and any mutating step inside quailbot_plan_and_execute -- are denied. To enable them, launch Pi with QUAILBOT_ALLOW_MUTATING_TOOLS=1 set in the environment:

# PowerShell
$env:QUAILBOT_ALLOW_MUTATING_TOOLS = "1"; pi

# bash/zsh
QUAILBOT_ALLOW_MUTATING_TOOLS=1 pi

The denial is enforced before any side effects -- a denied step never touches the instrument. The denial reason is recorded in the experiment log so an audit later can prove no mutation occurred.

Where Quailbot state lives

By default, all Quailbot Pi state lives under your user home directory. This is separate from Pi's own ~/.pi/ (which holds Pi-level session and agent infrastructure); the two trees do not overlap.

~/.quailbot-pi/
  settings.json                 # selected workspace path (created on first load)
  workspace.json                # starter workspace path (only present if you
                                #   place or write a workspace here yourself;
                                #   not auto-created)
  workspaces/                   # default landing dir for editor saves
  workspace-capture.png         # current workspace UI screen capture
                                #   (overwrites; no per-captureId snapshots)
  workspace-capture.metadata.json
  memory/                       # named memory MDs (one per domain)
  skills/                       # named skills (one folder per skill)
  knowledge-state.json          # which memory domains are loaded
  experiments/YYYY/MM/DD/exp_*/ # one folder per agent session
    events.jsonl                # append-only event log
    blobs/
      images/                   # ROI captures live here, one PNG per capture,
        roi-<name>-<refhash>-<captureId>.png
                                #   named with the producing ROI's human name;
                                #   events.jsonl references this same path
  observations-orphan/          # ROI captures without an active session
  provider-payloads.jsonl       # optional provider request/response log
                                #   (opt-in via QUAILBOT_PROVIDER_PAYLOAD_LOG=1)

The sha256 of every ROI PNG is recorded on the corresponding events.jsonl artifact entry for integrity verification, but the on-disk filename uses the human-readable form; there are no sha256-named duplicate copies.

The directory is self-contained -- safe to back up, safe to delete if you want a fresh start, safe to inspect with any file browser.

Overriding the state location

Set the QUAILBOT_PI_STATE_DIR environment variable to relocate everything. This is useful for:

  • Sharding state per instrument rig: QUAILBOT_PI_STATE_DIR=~/.quailbot-pi-rig-a pi
  • Keeping a working set on an external/SSD path
  • Development checkouts that prefer repo-local state (see "For developers")

The override is read on every state-path resolution, so each Pi session honors whatever the env had when Pi started.

Workspace files

Workspace JSON files are user-owned and can live anywhere on disk -- your lab repo, a shared drive, the home dir, wherever. Quailbot stores the absolute path to the selected workspace in settings.json; it does not copy the file. To switch workspaces:

/quailbot-workspace load D:/lab/instruments/nanonis-rig-a.json

The calibrator's Save and Save-As targets are constrained by the same allowed-roots policy that gates the workspace UI's file-browser: ~/.quailbot-pi/ and the parent directory of the currently-active workspace are writable; nothing else is.

Commands

  • /quailbot-workspace show -- summarize the active workspace
  • /quailbot-workspace read -- echo the active workspace JSON
  • /quailbot-workspace load <path> -- select an existing workspace JSON
  • /quailbot-workspace validate <path> -- dry-run validate without selecting
  • /quailbot-workspace write <path> -- write a workspace candidate
  • /quailbot-workspace open -- launch the browser calibrator
  • /quailbot-experiments where -- print the experiments root path
  • /quailbot-experiments list -- list local experiments
  • /quailbot-experiments show <id> -- show timeline for one experiment
  • /quailbot-memory list -- list known memory domains
  • /quailbot-memory load <domain> -- load a memory domain into context
  • /quailbot-memory unload <domain> -- unload a memory domain from context
  • /quailbot-skills list -- list known skills
  • /quailbot-skills window <n> -- set the skill-body context window size
  • /quailbot-settings show|cli-window|image-window|skill-window -- runtime windows
  • /quailbot-reload reload -- reload Quailbot extensions/skills/workspace

Run any command with no args to open its interactive menu where supported.

The agent has additional name-only tools for memory and skill content that are not exposed as slash commands: quailbot_memory_save, quailbot_memory_search, quailbot_skill_write, quailbot_skill_edit. These are agent-facing only (the model invokes them); the slash commands above are the user-facing surface.

Experiments

Every Pi session opens an experiment under ~/.quailbot-pi/experiments/YYYY/MM/DD/exp_*/. The session's tool calls, results, plan steps, ROI captures, denied mutations, and lifecycle events are appended to events.jsonl. ROI screenshots written by the observe tool (and inside quailbot_plan_and_execute) land directly inside blobs/images/ in the experiment folder, named roi-<name>-<refhash>-<captureId>.png; events.jsonl references that exact path. The sha256 of each PNG is recorded on the event's artifact metadata for integrity verification, but the on-disk file uses the human-readable name -- there is exactly one file per ROI capture.

Closing a session, switching workspaces (re-load with a different hash), or shutting Pi down all write an experiment_close event with the reason. Crash recovery surfaces unfinished logs as interrupted_unknown.

Upgrading

pi update npm:@bb84/quailbot-pi

Settings, workspaces, memory, skills, and experiments persist across upgrades because they live under ~/.quailbot-pi/, not inside the installed package.

For developers

Local development uses Pi's local-path package source:

git clone <this repo>
cd quailbot-pi
npm install            # installs dev deps (pi/typebox are devDeps for dev)
npm run pi             # runs pi against the local checkout, with state
                       # rooted at <repo>/.quailbot-pi so dev state stays
                       # isolated from your real ~/.quailbot-pi/
npm test               # runs the full vitest suite
npm run test:e2e       # runs the semantic E2E suite
npm run dev:check      # runs the dev-release adoption E2E

The pi and pi:mutating scripts set QUAILBOT_PI_STATE_DIR to the repo's .quailbot-pi/ directory so development never touches your real home-dir state. Each git worktree gets its own state automatically.

.pi/settings.json points pi at the parent directory as a package source ({ "packages": [".."] }), and package.json's pi.extensions points at ./dist/src/extension.js. So you need npm run build before each session; the pi/pi:mutating scripts chain dev:release (which is npm run build) for you.

Reporting bugs

File an issue with the experiment ID and events.jsonl excerpt if the problem is reproducible in a session. For workspace-loading issues, include the workspace JSON and the output of /quailbot-workspace validate <path>.