Skip to content

feat: /dispatch setup — first-run wizard, deployment pointer, and detection (issue #92) - #93

Merged
edgehero merged 3 commits into
mainfrom
feat/dispatch-setup-wizard
Aug 4, 2026
Merged

feat: /dispatch setup — first-run wizard, deployment pointer, and detection (issue #92)#93
edgehero merged 3 commits into
mainfrom
feat/dispatch-setup-wizard

Conversation

@edgehero

@edgehero edgehero commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes #92. The final UX on top of the #80#82 ladder: an operator whose only install is pi install npm:@edgehero/pi-dispatch-admin types /dispatch in a repo, and the console takes them from nothing to a working deployment — with a consent per action — then lands in the panel.

Three commits:

1 — worker: SKILL_NAME_RE exported from flow-gate

The traversal-choke charset was duplicated in materialize.mjs with a keep-in-sync comment, and the wizard becomes a third reader. One export, two imports, one vector-pin test.

2 — the deployment pointer (INT-DEPLOYMENT-POINTER-CONTRACT)

~/.pi/agent/pi-dispatch-deployment.json (override PI_DISPATCH_DEPLOYMENT_FILE): an allowlisted, absolute-paths-only env map layered under the operator's env once at extension load — env wins key by key, the worker/receiver never read it, and PI_DISPATCH_RUN_ROOTS or credential-shaped keys in the file have no effect by construction (a pointer that widened the AI-run allowlist would be a second, unreviewed door to a gated capability). A broken or newer file degrades to exactly the pre-pointer behavior with a one-line surfaced notice — never a throw; the contract records this as the deliberate reconciliation of fail-loud-on-newer with the read-model's never-throw doctrine. resolvePaths stays env-only and untouched. This is what makes a wizard-built deployment visible to /dispatch from any directory — and it replaces the README's "hand-mirror five env vars into your pi session" paragraph.

3 — the wizard, detection, and the nudge

  • Detection on bare /dispatch (cheapest-first): valid pointer or explicit env ⇒ panel exactly as before; cwd scaffold quadruple or a reachable queue ⇒ panel plus one hint; nothing anywhere and the queue unreachable ⇒ the offer. An exported VALKEY_URL is probed, never trusted — a dead URL still reaches the offer, and an ops outage on a configured deployment keeps today's banner, never a wizard prompt. Missing logs/settings dirs prove nothing (lazy OS-temp defaults) and are never consulted.
  • /dispatch setup — dialogs-first, overlay-per-handoff (pi's tui suspend handle exists only inside a ctx.ui.custom factory; dialogs can't run under a capturing overlay; stdin belongs to the attached child): deploy dir (default ~/pi-dispatch, never the repo) → consented npm install @edgehero/pi-dispatch@0.1.0 under import-pi's spawn doctrine (bare npm, win32 npm.cmd+shell:true only there, no filesystem path in argv, --ignore-scripts, post-install version assertion that stops the wizard loudly) → the terminal handed to pi-dispatch up, whose own y/N gates are the host-mutation consents (--yes is forwarded to nothing) → optional user-level service install → the pointer written with its JSON shown verbatim, then re-applied in-process so the panel opens against it without restarting pi → provider key printed, never written → optional setup github hand-off → optional first trigger for the repo the session sits in: folder pre-filled, flow picked from that repo's .pi/skills/ through the shared SKILL_NAME_RE, the in-place-edit warning printed, and the ai-trigger: allow line printed for the operator to commit — the wizard never writes into a repo. Then the panel.
  • Once-ever session_start nudge: reason: "startup" only, hasUI only, sync-only checks (no queue probe at startup), marker-file latch, notify-only.
  • Every step individually declinable; declines continue converge-style; headless refuses; USED_API is unchanged (spawns via node:child_process); RUNTIME_VERSION is pinned to the worker's version by an anti-drift test so release bumps stay atomic.

Specs

New DES-FIRST-RUN-SETUP-WIZARD (with the recorded rejections: long-lived wizard overlay, clone reuse, detached worker, credential dialogs, auto-writing the repo's opt-in — two keys stay two keys) and INT-DEPLOYMENT-POINTER-CONTRACT; REQ-ADMIN-VIA-PI-EXTENSION amended (setup is operator-typed only — deliberately no model-callable tool; the skill's new chapter tells the model to ask the operator to type it); REQ-DEPLOYMENT-BOOTSTRAP Scope carve-in (the wizard is a driver, not a power). Revision History rows in interfaces/design/requirements; DES-TRIGGER-OUTSIDE-PI (bootstraps, never hosts), DES-CLI-SURFACE, CONST-BUDGET-BEFORE-TOKENS (no wizard path spends — setup ends at the panel, not at a job) — unchanged, checked.

Tests

Full suite: 1843 tests, 1827 pass, 0 fail, 16 pre-existing skips (+46 over main: 31 wizard, 12 pointer, wiring/pinned-api/flow-gate additions). Admin bundle rebuilt and smoke-loaded (both new modules inlined; factory registers resources_discover + session_start). CI greps clean.

…ource of truth (issue #92)

materialize.mjs imported nothing and kept a keep-in-sync copy; the admin's
setup wizard is about to become a third reader. A traversal-choke charset
duplicated three ways drifts exactly where it must not — one export, two
imports, one vector-pin test.

Signed-off-by: Rob Boerman <robboerman@live.nl>
… elsewhere (issue #92)

INT-DEPLOYMENT-POINTER-CONTRACT: <agent dir>/pi-dispatch-deployment.json
(override PI_DISPATCH_DEPLOYMENT_FILE), an allowlisted absolute-paths-only env
map layered UNDER the operator's env once at extension load. Env wins key by
key; the worker and receiver never read it; PI_DISPATCH_RUN_ROOTS and
credential-shaped keys in the file have no effect by construction -- the
pointer resolves paths, never grants capabilities. A broken or newer file
degrades to exactly the pre-pointer behavior with a one-line surfaced notice,
never a throw (the recorded reconciliation of fail-loud-on-newer with the
read-model's never-throw doctrine). Reapply (post-wizard-write) updates only
keys the pointer itself set and never unsets -- a half-typed hand edit cannot
yank paths from a live panel. resolvePaths stays env-only and untouched;
12 new tests, admin suite 306/306.

Signed-off-by: Rob Boerman <robboerman@live.nl>
…ce-ever nudge (issue #92)

- bare /dispatch now detects where the deployment is: valid pointer or explicit
  env -> panel exactly as before; cwd scaffold or a reachable queue -> panel
  plus one hint; nothing anywhere AND queue unreachable -> the offer. An
  exported VALKEY_URL is probed, never trusted -- a dead URL still reaches the
  offer, and an ops outage on a configured deployment keeps the banner, never
  the wizard
- /dispatch setup: dialogs-first, overlay-per-handoff (the tui suspend handle
  exists only inside a ctx.ui.custom factory; dialogs cannot run under a
  capturing overlay; stdin belongs to the attached child) -- pick a deploy dir,
  consented npm install of @edgehero/pi-dispatch@RUNTIME_VERSION under
  import-pi's spawn doctrine (no path in argv, --ignore-scripts, post-install
  version assertion that stops the wizard loudly), hand the terminal to
  pi-dispatch up (its own y/N gates ARE the host-mutation consents; --yes is
  forwarded to nothing), optional user-level service install, pointer written
  with the JSON shown verbatim then reapplied in-process, provider key printed
  never written, optional setup github hand-off, optional first trigger for the
  repo the session sits in (folder pre-filled, flow picked from its .pi/skills
  via the shared SKILL_NAME_RE, the in-place-edit warning printed, and the
  ai-trigger: allow line PRINTED for the operator to commit -- the wizard never
  writes repo files), then the panel
- session_start nudge: reason startup only, hasUI only, sync-only checks, a
  marker file makes it once-ever, notify-only
- every step individually declinable; declines continue converge-style;
  headless refuses; USED_API unchanged (spawns via node:child_process)

Specs: new DES-FIRST-RUN-SETUP-WIZARD (incl. the recorded rejections);
REQ-ADMIN-VIA-PI-EXTENSION amended (setup, the detection tree, the nudge,
declined-offer acceptance); REQ-DEPLOYMENT-BOOTSTRAP scope carve-in (the wizard
is a driver, not a power); Revision History rows in design.md + requirements.md;
DES-TRIGGER-OUTSIDE-PI, DES-CLI-SURFACE, CONST-BUDGET-BEFORE-TOKENS unchanged,
checked. operate-pi-dispatch SKILL.md gains the setup chapter (operator-typed
only; the model asks the operator to type it). README first-run story; cli/init
next-steps mention the wizard.

Signed-off-by: Rob Boerman <robboerman@live.nl>
@edgehero
edgehero merged commit a3d634a into main Aug 4, 2026
8 checks passed
@edgehero
edgehero deleted the feat/dispatch-setup-wizard branch August 4, 2026 08:15
birhantprkc pushed a commit to birhantprkc/pi-dispatch that referenced this pull request Aug 6, 2026
The first-run wizard (issue edgehero#92, PRs edgehero#93 + edgehero#94): admin 0.4.0 ships
/dispatch setup, the deployment pointer, the no-deployment detection, and
the once-ever startup nudge. worker 0.1.1 ships the SKILL_NAME_RE export
and the setup cross-references in the CLI help; RUNTIME_VERSION follows it
(the anti-drift test makes the pair atomic). Both READMEs compacted.

Signed-off-by: Rob Boerman <robboerman@live.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

First-run setup from inside pi: /dispatch detects a missing deployment, offers guided setup, lands in the panel

1 participant