GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - getpipher/armory-fleet: The armory suite's subagent orchestrator for the pi coding agent — a cross-harness, superpowers-native fleet where every agent is armory-native from birth.

BranchesTags
Open more actions menu

Latest commit

 

History

456 Commits
456 Commits

Folders and files

NameName
Last commit message
Last commit date
.github/workflows
.github/workflows
 
 
agents
agents
 
 
assets
assets
 
 
docs
docs
 
 
lifecycles
lifecycles
 
 
plans
plans
 
 
research
research
 
 
scripts
scripts
 
 
specs
specs
 
 
src
src
 
 
test
test
 
 
.gitignore
.gitignore
 
 
AGENTS.md
AGENTS.md
 
 
LICENSE
LICENSE
 
 
PRD.md
PRD.md
 
 
README.md
README.md
 
 
package.json
package.json
 
 
pnpm-lock.yaml
pnpm-lock.yaml
 
 
tsconfig.json
tsconfig.json
 
 

Repository files navigation

@getpipher/armory-fleet

@getpipher/armory-fleet

The armory suite's subagent orchestrator for the pi coding agent — a cross-harness, superpowers-native fleet where every agent is armory-native from birth.

npm version npm downloads pi compatibility license tests release platform

Why · Features · Quick start · Architecture · The fleet panel · Workflows-as-code · Cost-aware tiers · Roadmap · Ecosystem


Why

The pi-subagent ecosystem is crowded — nicobailon/pi-subagents (2688⭐), tintinweb/pi-subagents (702⭐), QuintinShaw/pi-dynamic-workflows (287⭐), kky42/pi-flow (66⭐), teelicht/pi-superagents (54⭐). Three structural gaps remain open, and armory-fleet owns all three — then reaches parity on the rest to be the best pi-subagent package in the ecosystem.

Gap Status quo armory-fleet
Armory-native integration No external package can integrate with the armory suite; they don't own it. Agents that sync to armory-todo, hydrate from armory-memory, see via vision, and edit via cursor by default — uncopyable.
Cross-harness peers Only one early attempt runs Claude Code + Pi as peer backends, foreground-only. First-class dual-arsenal topology — pi and Claude Code spawn as sibling backends from one fleet.
Superpowers-native lifecycle Only one attempt wraps the superpowers skill pipeline, synchronous-only. The full superpowers lifecycle (brainstorm → plan → implement → review → finish) with checkpoints, quality gates, and lifecycle hooks baked in.

Beyond those: a fleet TUI, cron/interval scheduling, git worktree isolation, cost accounting, quality gates, workflows-as-code, and a journaled event-bus — all in one package.

Vision, spine, and the 7-SPEC roadmap live in PRD.md. The landscape deep-read (11+ packages mapped, 5 contenders deep-read) is in research/.


Features at a glance

Capability What you get
🧬 Armory-native agents Every child syncs to armory-todo, hydrates from armory-memory, sees via vision, edits via cursor — by default, from birth. No bolt-on.
🏛️ Cross-harness backends Spawn pi and Claude Code sessions as peer backends from one fleet. Auto-detect Claude; hook-parity keeps both on equal footing.
🦸 Superpowers lifecycle brainstorm → plan → implement → review → finish, checkpoint-driven, skill-loaded per phase. /fleet-implement <task> runs the whole pipeline.
🎚️ Cost-aware tiers economy / standard / frontier model tiers with cost caps + context floors. Route cheap work to cheap models, escalate when it matters. Live cost $ + context % per run.
🚦 Quality gates verification-before-completion, completeness-check, gate, verify — built-in. Register your own. Composite helpers: judgePanel, loopUntilDry, retry.
🧩 Workflows-as-code Author multi-phase workflows in a JS DSL with agent(), pipeline(), phase(), checkpoint(). 5 builtins ship: adversarial-review, code-review, codebase-audit, deep-research, multi-perspective. Journaled + resumable.
🖥️ Fleet TUI /fleet opens an interactive panel: Runs, Tiers, Lifecycle, Workflows, Conversation viewer. Live widget, mid-run Steer/Stop, edit-resume, save-as.
⏱️ Scheduling Cron expressions, intervals, one-shot ISO datetimes. PID-locked scheduler, session-scoped (no catch-up). Background runs on isolated git worktrees.
🔒 Worktree isolation Background runs get isolated git worktrees (in-place fallback for non-git cwds). Foreground runs share the session cwd.
📒 RunLog + journaling Every run is journaled; interrupted workflows recover on restart. A results inbox lets the model pull completed background runs.
🔄 Edit-and-resume Re-run a workflow by replaying the unchanged prefix and re-running only the edited suffix.
📡 Vision built-in describe_image tool is wired into child sessions — agents can see screenshots and diagrams without leaving the fleet.

Quick start

Install

armory-fleet is a pi extension — it loads inside pi, no build step.

# 1. Add to your pi packages (~/local-dev/arsenal or your package dir)
pnpm add @getpipher/armory-fleet

# 2. Register in ~/.pi/agent/settings.json
// ~/.pi/agent/settings.json
{
  "packages": [
    "@getpipher/[email protected]"
    // + its armory siblings: armory-todo, armory-memory, vision, cursor
  ]
}
# 3. Reload pi (/reload) and open the panel
pi
# inside pi → /fleet

Your first subagent (model-callable tool)

The subagent tool is what the model calls to delegate a focused task. Every child is armory-native by default.

// the agent calls this — not you
subagent({
  agent: "general-purpose",
  task: "Audit src/auth/ for token-handling bugs; report findings.",
  // optional: model, lifecycle, todoId, background, isolation, schedule, maxTurns
});
Param Effect
agent Agent definition to spawn (from agents/ or discovered).
task The prompt handed to the child.
model Override the session model. Tip: omit to inherit the session model, or use Ollama/... when the session is on Ollama — don't cross providers.
lifecycle Run the task through a superpowers lifecycle (e.g. default) instead of a single delegate.
todoId Link the run to an existing armory-todo entry.
track Default true (syncs to armory-todo). Pass false only for throwaway lookups.
background Fire without awaiting — run goes to the async pool on an isolated git worktree.
isolation worktree (default for bg in a git repo) · none (in-place) · auto.
schedule Cron (0 9 * * 1-5), interval (30m), or one-shot ISO datetime. Session-scoped, no catch-up.
maxTurns Per-run turn budget (default 20). Raise for complex multi-step tasks.

Your first workflow

Workflows are plain JS files evaluated in a sandboxed vm realm. The orchestration primitives — agent, parallel, pipeline, phase, gate, judgePanel, loopUntilDry, retry, checkpoint, verify, workflow, log — are injected globals (no imports). The only thing you export is meta.

// ship-feature.js — drop into a workflows/ dir discovered by WorkflowRegistry
export const meta = {
  name: 'ship-feature',
  description: 'Plan → implement → 3 parallel review angles with a gate',
  phases: [{ title: 'Plan' }, { title: 'Implement' }, { title: 'Review' }],
}

phase('Plan')
const plan = await agent('Plan this feature: ' + args.task, { tier: 'economy' })

phase('Implement')
const impl = await agent(`Implement the plan:\n${plan}`, { tier: 'standard' })

phase('Review')
const angles = ['security', 'performance', 'correctness']
const reviews = await parallel(
  angles.map((a) => () => agent(`Review the implementation for ${a} issues.`, { tier: 'economy' })),
)

// gate: revise the synthesis until it passes a validator
const synthesis = await gate(
  async (_feedback, n) => n === 0
    ? agent(`Synthesize ${reviews.length} reviews.`, { tier: 'economy' })
    : agent('Revise synthesis per feedback.', { tier: 'economy' }),
  (v) => typeof v === 'string' && v.length > 200 ? { ok: true } : { ok: false, feedback: 'more detail' },
  { attempts: 3 },
)

return { plan, impl, reviews, synthesis }

Open /fleet → Workflows, pick ship-feature, run it. The panel shows live phase progress; mid-run you can Steer (inject a message) or Stop. The realm also exposes args, cwd, and a budget object ({ total, spent(), remaining() }) so workflows can self-limit.

Your first lifecycle run

/fleet-implement Refactor the auth module to use the new session API --auto

Runs brainstorm → plan → implement → review → finish autonomously. Drop --auto for checkpointed mode (pauses at each checkpoint; continue/revise/abort from /fleet → Lifecycle).


Architecture

                        ┌─────────────────────────────────────────────┐
                        │              pi host session                 │
                        │   (loads @getpipher/armory-fleet extension)  │
                        └───────────────────────┬─────────────────────┘
                                                │
        ┌───────────────────────────────────────┼───────────────────────────────────────┐
        ▼                                       ▼                                       ▼
  subagent tool                          fleet tool                           /fleet panel
  (model-callable)                  (workflow runner)                    (FleetView TUI)
        │                                       │                                       │
        ▼                                       ▼                                       ▼
  createAgentSession()                WorkflowController                  Runs · Tiers · Lifecycle
  (pi SDK child)                      + ConcurrencyPool                   Workflows · Conversation
        │                             + adapters                            + live widget
        ├─→ armory-todo sync          + journal/resume
        ├─→ armory-memory hydrate           │
        ├─→ vision (describe_image)         ▼
        ├─→ lifecycle + gates          backend registry
        └─→ tier routing               (pi | Claude Code)

Core engine

  • Engine primitive: createAgentSession() from the pi SDK — child Pi sessions, in-memory or file-backed SessionManager, ResourceLoader. Each child is wrapped to emit session_init on subscribe so the fleet can track it from the first event.
  • Child loader: buildChildLoader() threads armory-todo, armory-memory, and vision into every child's resource + tool set — armory-native from birth, cwd-agnostic.
  • Concurrency: a single-slot lock for foreground runs + a ConcurrencyPool for parallel workflow branches.
  • Turn budget: engine/turn-budget.ts caps each child's run; the subagent tool surfaces exhaustion as a structured status (not a silent truncation).

Armory integration (the uncopyable layer)

Sibling What the fleet wires in Where
armory-todo Every run syncs to the cross-session TODO store. Pass todoId to link. src/todo-sync/
armory-memory Children hydrate project memory on spawn. Shared port, cwd-agnostic. src/memory-hydrate/
vision describe_image tool is wired into child sessions. src/vision/
cursor Children edit through the cursor extension when present. (via child loader)

Cross-harness backends

src/backend/ ships a backend registry with pi (default) and Claude Code as peer backends. detectClaude() auto-discovers Claude; PI_HOOK_PARITY / CLAUDE_HOOK_PARITY tables keep both backends on equal footing. hook-parity.ts normalizes lifecycle/event hooks across harnesses. A ResumeStore persists backend session IDs so cross-harness runs can resume.

Superpowers lifecycle

The default lifecycle (src/lifecycle/default.ts) is the superpowers-native 5-phase pipeline:

Phase Skills loaded Checkpoint? Gates
brainstorm brainstorming ✅ —
plan writing-plans ✅ completenessCheck
implement executing-plans, test-driven-development, verification-before-completion ❌ verification-before-completion, completenessCheck, gate
review requesting-code-review, receiving-code-review ✅ —
finish finishing-a-development-branch — —

Custom lifecycles: drop a YAML file in your lifecycles/ dir, register via discoverLifecycles(). Gates are registered on a GateRegistry (fleet-register-gate command for runtime extensibility).

Quality gates

Built-in (src/lifecycle/gates/): verification-before-completion, completeness-check, gate, verify.

Composite helpers (src/workflows/helpers/) — usable from any workflow:

Helper What it does
judgePanel Run N judge agents; majority/weighted verdict.
loopUntilDry Re-run an agent until a dry-run gate passes.
retry Retry an agent with backoff on failure.
checkpoint Pause a workflow for human review.
completeness-check / gate / verify Gate wrappers for workflow use.

Cost-aware tiers

src/tiers/ ships three built-in tiers:

Tier Models Cost cap Context floor
economy inherit — —
standard inherit — —
frontier inherit — 200k ctx

The shipped defaults use the inherit sentinel — each tier resolves to your active session model, so tier routing works on any provider out of the box. To route across models, override a tier by name with a concrete provider/id chain in ~/.pi/agent/fleet/tiers.json (global) or <project>/.pi/fleet/tiers.json (project):

[
  { "name": "economy",  "models": ["Ollama/minimax-m3:cloud"] },
  { "name": "standard", "models": ["Ollama/glm-5.2:cloud", "inherit"] },
  { "name": "frontier", "models": ["anthropic/claude-sonnet-4"], "costCap": 5, "contextFloor": 200000 }
]

Models are an ordered fallback chain (primary first; a spawn retries the next candidate if model creation is rejected); the inherit sentinel (case-insensitive) may appear anywhere in the chain as a provider-agnostic fallback and always resolves to the session model without catalog or floor checks. contextFloor skips catalog models below the window size; costCap aborts a run whose live cost exceeds the cap (a no-op on flat subscriptions). Tier routing applies to pi-backend agents — backend: "claude" agents receive the resolved string via --model and the claude CLI expects its own model names, so route those by model: instead.

Live cost $ and context % are tracked per run and surfaced in the Tiers view. Override per-run with model, or let the tier registry route based on the task class.

Fleet settings (v1.1.0)

~/.pi/agent/fleet/settings.json (global) and <project>/.pi/fleet/settings.json (project — wins per-field) hold fleet-wide defaults that aren't env-shaped. Currently one field:

{
  "defaultSubagentThinking": "high"
}

defaultSubagentThinking (#78) sets the thinking level for every subagent whose frontmatter does not pin thinkingLevel — so a controller can think at max while the fleet runs at high, without replacing builtin agents (agent-frontmatter overrides still win; per-dispatch overrides are not exposed yet). Valid values: off | minimal | low | medium | high | xhigh | max. On flat subscriptions (z.ai/GLM coding plans, Ollama) this is the quota lever — thinking tokens on every cheap subagent call are pure waste.

Invalid values and unknown keys produce a startup warning naming the file, the field, and the bad value — never a silent no-op. Absent files are normal.

Agent frontmatter thinkingLevel is validated with the same strictness (#90): an invalid value (typo'd level, wrong type) fails that agent's load with an actionable warning naming the file, the bad value, and the valid levels (off | minimal | low | medium | high | xhigh | max) — never a silent no-op. A YAML-empty value (thinkingLevel: with nothing after it) counts as absent.

Operational runtime

src/runtime/ — the async/scheduling spine:

  • async-runner.ts — background dispatch (fire-and-forget).
  • run-journal.ts + run-log.ts — durable run records; reconcile.ts reattaches orphaned runs on restart.
  • concurrency-pool.ts — bounded parallel branches.
  • results-inbox.ts — the model pulls completed background runs via the fleet_results tool.
  • resume.ts — scan for resumable runs + workflows.

Scheduling + worktree

src/scheduling/ — cron expressions (expressions.ts), a Scheduler with PID-locking (pid-lock.ts), session-scoped (no catch-up). src/worktree/ — WorktreeService for isolated bg-run worktrees + DiffService for reviewable diffs.


The fleet panel

/fleet opens an interactive TUI panel (TUI-only; in non-interactive modes use the subagent tool).

View What it shows
Runs Running + recent subagents; status, cost, context %, agent, model. Action submenu: Steer, Stop, View conversation.
Tiers Per-tier model lists, cost caps, context floors. Configure routing.
Lifecycle Active lifecycle runs; Continue/Revise/Abort at checkpoints.
Workflows Registered workflows + live runs. Run, edit-resume, save-as, view result, checkpoint.
Conversation The full message timeline for any selected run.

A live FleetWidget can render in the pi footer/overlay for at-a-glance fleet status while you work.

Slash commands

Command Purpose
/fleet Open the interactive fleet panel (TUI).
/fleet-implement <task> [--lifecycle <name>] [--auto] Run a task through the superpowers lifecycle.
/fleet-register-gate Register a custom gate on the fleet gate registry (extensibility).

Model-callable tools

Tool Purpose
subagent Delegate a focused task to a child agent (sync foreground or async background).
fleet Run + control fleet workflows (JS orchestration: agent, pipeline, phase, checkpoints).
fleet_results Pull completed background run results from the inbox.

Workflows-as-code

Workflows are authored in a JS DSL (src/workflows/source.ts parses; vm-realm.ts evaluates). 5 builtins ship in src/workflows/builtin/:

Workflow Description Phases
adversarial-review Red-team + blue-team review with judge panel Attack → Defend → Judge
code-review 7 parallel review angles plus verification Review → Verify
codebase-audit File-tree scan with completeness check Scan → Audit
deep-research 3-round discovery loop with de-duplication Discover → Synthesize
multi-perspective 4 personas review the same artifact Review → Merge

Every workflow run is journaled (workflows/journal.ts) and resumable. edit-resume replays the unchanged prefix from cache and re-runs only the edited suffix. runtime/controller.ts orchestrates; runtime/pause-gate.ts handles checkpoints; runtime/adapters.ts binds the controller to the fleet's spawn + accounting.

Full JS DSL API reference: docs/workflows.md — export const meta, agent()/parallel()/pipeline()/phase(), the 7 helpers, the script context, worked examples, and the error surface.


Migration (v0.13.0 — SPEC-6-5 cwd isolation)

  • cwd param on the subagent tool (default = the session cwd, backward-compat). Pass it to scope a child's working dir + context (AGENTS.md cascade, skills, memory) to a dispatch target outside the session cwd — the #20 confabulation fix. Cross-cwd dispatches surface a ↗<basename> glyph in the fleet widget + a spawn-time notify.
  • userMemory default flip: the global cross-project user memory scope (/__armory-fleet-user__) is no longer hydrated by default. If you populated that dir + relied on it, add userMemory: true to the agent frontmatter (only meaningful with memoryHydrate: true). TS consumers constructing AgentDef literals must now include userMemory: boolean (required field; use false for the old default behavior).
  • Lifecycle cwd field: lifecycles accept an optional cwd frontmatter field to pin a target repo; absent → the entry-point cwd (the panel's chosen cwd, or the dispatching subagent tool's cwd/session cwd). When present, it overrides the entry-point cwd for all phases.
  • Panel Run-action: a 3rd cwd input step (task → name → cwd), prefilled with the session cwd; Enter accepts, Escape cancels.
  • bg/scheduled + worktree cwd-isolation (#62): the cwd param now scopes background and scheduled runs too — in-place bg runs pass it as the lifecycle entry cwd, and isolation: 'worktree'/'auto' resolve isolation (and create the worktree) against the dispatch cwd's repo, not the session's. Cross-cwd bg worktrees land in <child-cwd>/.pi/fleet/worktrees/.

Event bus + RPC (v1.0)

armory-fleet publishes every run on pi's cross-extension event bus and answers an RPC verb set — so your own extensions can spawn, steer, observe, and abort subagents programmatically.

Event stream (broadcast, pi.events)

Two tiers, every event enveloped as { runId, seq, ts, ...payload } (seq = per-run monotonic, one space per source store):

Channel Payload
fleet:run:started { agent, model?, cwd?, sessionCwd?, mode: foreground|background|scheduled|workflow, task }
fleet:phase:started / completed / failed { phase, … } (lifecycle runs)
fleet:run:ended { status: completed|failed|aborted, result?, error?, filesTouched?, toolCallCount?, durationMs? }
fleet:child:message { role, text } (journal excerpts)
fleet:child:tool { toolName, args, result, isError } (one per completed tool call)

RPC (fleet:rpc → fleet:rpc:result)

Emit { id, verb, params }, get exactly one reply { id, ok, data } or { id, ok: false, error: { code, message } }. Verbs: spawn (returns { runId } immediately; result arrives via fleet:run:ended), schedule (#83 — returns { scheduleId, nextFire }; schedules run lifecycles, not single delegates), status, observe (replay dump — subscribe to the broadcast channels + dedupe by (channel, runId, seq) for the live tail), steer, abort.

spawn params: agent, task, background?, lifecycle? (named lifecycle — with background: true routes through the bg runner; without it runs as a detached foreground-semantics lifecycle), modelFallback? (per-request retry-once on a retryable provider failure — the retry mints a fresh runId and relinks the primary's todo), cwd?, isolation?, maxTurns?, model?, skills?, readOnly?, track?, todoId?.

schedule params: task, expression (cron or interval), lifecycle?, auto?, isolation?, cwd? — no agent: the scheduler runs lifecycles only. Registration emits no run events; on fire, the normal fleet:* stream flows with mode: "scheduled".

Error codes: E-CONTROL-DISABLED, E-RUN-NOT-FOUND, E-RUN-FINISHED, E-BAD-VERB, E-BAD-PARAMS, E-STEER-UNSUPPORTED, E-INTERNAL.

Client helper (~15 lines)

type FleetReply = { id: string; ok: true; data: any } | { id: string; ok: false; error: { code: string; message: string } };
let n = 0;
export function fleetRpc(pi: { events: { emit(c: string, d: unknown): void; on(c: string, h: (d: unknown) => void): () => void } }) {
  return <T = any>(verb: string, params?: Record<string, unknown>): Promise<T> => {
    const id = `fleet-${Date.now().toString(36)}-${++n}`;
    return new Promise<T>((resolve, reject) => {
      const unsub = pi.events.on("fleet:rpc:result", (raw) => {
        const r = raw as FleetReply;
        if (r.id !== id) return;
        unsub();
        r.ok ? resolve(r.data as T) : reject(new Error(`${r.error.code}: ${r.error.message}`));
      });
      pi.events.emit("fleet:rpc", { id, verb, params });
    });
  };
}
// const rpc = fleetRpc(pi); const { runId } = await rpc("spawn", { agent: "scout", task: "look" });

Control gate

spawn/steer/abort/schedule are on by default. Set ARMORY_FLEET_RPC_CONTROL=0 (or false) to reject them with E-CONTROL-DISABLED; read-only observe/status stay available. Honest threat model: in-process extensions already have full system access through pi itself — the switch guards accidents, not adversaries.

Live conversation viewer

/fleet → Runs → open a running run: the timeline overlay streams the child's conversation as it happens (tail-follows; scroll up to read, back to the bottom to re-pin). Finished runs replay from the journal exactly as before.

The #62 tail of SPEC-6-5: subagent({ cwd }) now scopes background and scheduled runs too, not just foreground —

  • bg/scheduled cwd — in-place bg runs pass the dispatch cwd as the lifecycle entry cwd (full context scoping: cascade, skills, memory); schedules persist the pinned cwd and honor it on every fire.
  • Per-dispatch worktrees — isolation: 'worktree' / 'auto' resolve against the dispatch cwd's repo, not the session's; cross-cwd worktrees land in <child-cwd>/.pi/fleet/worktrees/ and are cleaned up via the same service.
  • bg lifecycle parity — the bg adapter now honors the lifecycle cwd chain (lifecycle.cwd → dispatch cwd), which also fixes a pre-existing mismatch where bg isolated runs spawned phases in the session cwd but committed in the worktree.

RPC parity + fleet settings (v1.1.0)

Post-v1.0 batch (issues #78/#83):

  • fleet.defaultSubagentThinking (#78) — a fleet-dir settings home (~/.pi/agent/fleet/settings.json global, <project>/.pi/fleet/settings.json project override) whose first field sets the thinking level for every subagent that doesn't pin its own — the quota lever for flat subscriptions. See Fleet settings.
  • RPC spawn parity (#83) — spawn gains lifecycle (bg routing, or a detached foreground-semantics lifecycle run) and modelFallback (per-request retry-once; the retry mints a fresh runId and relinks the primary's todo).
  • New schedule verb (#83) — { task, expression, lifecycle?, auto?, isolation?, cwd? } → { scheduleId, nextFire }. Schedules run lifecycles only, so spawn's uniform { runId } reply stays unbranched; the frozen surface needed zero renames and zero new error codes.

Provider-agnostic tiers (v0.15.0)

Small-backlog batch (issues #57/#63/#64/#65):

  • Tier inherit sentinel (#64) — builtin tiers no longer hardcode a provider: economy/standard/frontier now resolve to your active session model out of the box (frontier keeps its 200k context floor; the $5 cost cap moved to the override example — a no-op on flat subs). Override by name in tiers.json with concrete provider/id chains for real multi-model routing; inherit can appear mid-chain as a provider-agnostic fallback. See Cost-aware tiers.
  • Self-correcting model errors (#57) — dispatching with a model the runtime doesn't have now lists the session's available (authed) models in the error, so the orchestrating model can pick a valid one on the retry instead of guessing.
  • Panel Escape semantics documented + dead code removed (#63) — Escape always cancels the active panel flow; defaults are accepted via Enter-on-blank. (Also fixed: ctrl+c could trigger the never-documented "escape accepts default" callbacks.)
  • README example tier names fixed (#65) — the ship-feature example now uses real tier names (economy/standard).

MCP governance (armory-gateway integration)

When armory-gateway is resolvable, fleet registers an MCP governance provider at session start: every MCP call made through the gateway passes fleet's mcpDeny policy before it executes.

~/.pi/agent/fleet/settings.json (global) and <cwd>/.pi/fleet/settings.json (project, wins per-field):

{
  "mcpDeny": [
    "github__delete_repo",
    "internal-tools"
  ]
}
  • Entries: bare server (deny the whole server) or server__tool (deny one exact tool).
  • Invalid entries produce an actionable warning and are dropped; valid entries stay enforced.
  • Policy is re-read per call — edits take effect immediately.
  • Gateway absent (the default for public fleet installs)? Nothing changes: registration is skipped silently and fleet behaves exactly as before. Check the gateway's status output — interceptors governance=✗ means standalone.
  • Deliberately deferred to later slices: per-call cost accounting, per-agent/per-run policy scoping, and child-session MCP access (see docs/SPEC-1b-2-fleet-governance-adapter.md §15 for the rationale and revival conditions).

Dogfood reliability (v0.14.0)

Four fixes from dogfooding the fleet on itself (issues #58–#61):

  • ARMORY_FLEET_MODEL_FALLBACK=auto — resolve the global fallback per session from the configured+available model snapshot: a different provider than the session model is preferred, else a different model id; unresolvable (single-model setup) stays off with a one-time warning. Non-auto env values are used verbatim; per-dispatch modelFallback still wins.
  • No-fallback hint — a retryable provider failure (stopReason error) with neither a per-dispatch modelFallback nor the global default surfaces no modelFallback configured — pass modelFallback or set ARMORY_FLEET_MODEL_FALLBACK so silent no-retry failures are visible.
  • Masked primary errors fixed — when a fallback retry also fails, the surfaced error now names both attempts (primary '<model>' failed: …; fallback '<model>' failed: …) instead of only the fallback's.
  • Zero-tool-call flag (#61) — a run that "completes" without a single executed tool call (the premature-return shape: narrate a plan, end) is prefixed with [FLEET] zero-tool-call run — likely a premature return in the tool result; details.toolCallCount exposes the count. Verify (git status/log) before trusting such a result.
  • Richer run journal — run:ended now carries error (failure reason), filesTouched (#49 parity in the durable journal — real SDK args are captured from tool_execution_start; the end event has none), and toolCallCount.

Model-quality drift signals (v1.2.0)

Cheap, additive signals for the output-quality drift observed on flat/cheap model tiers (issues #88/#89). Both are flagging, not blocking — findings were sound every time; the controller decides.

  • Language-drift flag (#88) — when a completed run's final report is majority CJK-family script (Han/Hiragana/Katakana/Hangul ≥ 30% of letters, min 40 letters), the tool result is prefixed with [FLEET] language drift — final report is N% CJK-family script (#88)… and details.languageDrift/languageDriftRatio are set. Observed: glm-5.3-flash drifted into Chinese in 4/7 dispatches, even with an explicit English-only instruction in the prompt. Quoted CJK content inside an English report stays clean; run:ended journals the flag for post-hoc diagnosis. Latin-script non-English (fr/de/…) is deliberately not detected (see the spec's non-goals).
  • Reviewer cross-domain references (#89, guidance) — reviewer subagents on cheap tiers sometimes fabricate plausible-sounding process references (briefs, roll-ups, sibling-repo fixes) while their verdicts and code findings remain verifiable. Rule for controllers: treat any reviewer reference to an artifact outside the provided brief/report/diff as suspect — verify findings by git + file contents, never by report prose. The fleet's structured result fields (details.*) and the journal are the trustworthy surface; the narrative tail is not.

Roadmap

armory-fleet follows a PRD → SPEC-N (brainstorm → spec → plan → implementation) pipeline. 16/16 phases done through v0.12.0.

SPEC Headline Status Artifact
PRD Master PRD ✅ done PRD.md
RESEARCH Landscape research (11+ packages, 5 deep-reads) ✅ done research/
SPEC-1 Core engine + armory-todo sync ✅ done PR #1 · 547319b
SPEC-2 Deep armory integration (memory/vision/cursor) ✅ done · @0.2.0 PR #2 · c6e727c
SPEC-3 Cross-harness peers (pi + Claude Code) ✅ done · @0.3.0 PR #4 · 5bb75fb
SPEC-4 Superpowers-native lifecycle ✅ done · @0.4.0 PR #5 · 67ff9b4
SPEC-5a Operational runtime (async/scheduling/worktree) ✅ done · @0.5.2 PR #6 · 52e3477
SPEC-5b-1 RunLog seam + Runs view ✅ done · @0.6.0 PR #7 · 54b1b10
SPEC-5b-2 Live widget + FleetView + Q9 ✅ done · @0.7.0 PR #8 · 9266a7
SPEC-5b-3 Conversation viewer + timeline fix ✅ done · @0.8.0 PR #9 · adc0034
SPEC-5b-4 Mid-run steering (Steer) + Stop ✅ done · @0.9.1 PR #10 + #11 + #12
SPEC-6-1 Cost-aware tiers + cost $ + context % + Tiers view ✅ done · @0.10.x PR #15/#16/#17
SPEC-6-2 Quality gates + lifecycle hooks ✅ done · @0.11.0 PR #18 · cda5e2b
v0.11.1 bg dispatch isolation split (non-git cwd fix) ✅ done · @0.11.1 PR #19 · 51956e0
SPEC-6-3 Workflows-as-code (release-gate completion) ✅ done · @0.12.0 PR #21 · 9986ad1
SPEC-6-4 Event-bus RPC + live conversation viewer → v1.0 🚧 next —

See the full release history and the PRD §8 for the roadmap rationale.


Ecosystem

armory-fleet is the orchestrator in the getpipher armory suite — the default substrate it runs agents on:

Package Role
armory-todo Global cross-session TODO store (the fleet syncs every run to it).
armory-memory Project memory hydration for child agents.
vision The describe_image tool, wired into fleet children.
cursor Custom editor component for the pi TUI.

Conventions

  • No build step — extensions ship raw .ts via tsx at pi runtime. pnpm typecheck + pnpm test:run before release.
  • Tests — node:test via tsx in test/*.test.mts, importing from ../src/.... 593 passing.
  • Publish — CI on v* tags using the getpipher NPM_TOKEN org secret (release.yml mirrors armory-todo: idempotent npm publish + GitHub Release).
  • Interactive-first UX — every capability lands as a /fleet panel tab/view + action submenu first, then the model-callable tool action.

Verify locally

pnpm install
pnpm typecheck
pnpm test:run --test-timeout=30000   # 593/593

Release-gate smoke (mandatory before any release)

pi --no-extensions -e ./src/index.ts --no-session --approve
# inside: /fleet → Workflows → verify the 5 builtins render + a workflow runs end-to-end

Compatibility

  • pi ^0.81.1
  • Node >=22 (tsx runtime)
  • Platform: macOS, Linux, WSL

License

MIT — see LICENSE. © RECTOR (@rz1989s).

Built with Ihsan · Maintained by RECTOR · getpipher

## Presentation surface (unreleased — #104)

The redesign unifies the three fleet surfaces under one visual language: your pi theme's tokens only (accent/text/muted/dim/warning/success/error), a single glyph vocabulary (▶ ⏸ ✓ ✗ ⏳, braille spinners, box-drawing cards), and the usage — honesty rule (missing data renders —, never an estimate).

Glyph presets. Set ARMORY_FLEET_GLYPHS=ascii for a fully glyph-free fallback (dumb terminals — +---+ cards, - spinner, | footer separators), or =nerd for FontAwesome PUA icons (Nerd Font required). Default is unicode. Invalid values fall back to unicode with a one-time stderr warning.

Fleet-tab preview row. With a running run highlighted in the /fleet Fleet tab, a line under the list mirrors the transcript card's state line exactly (same segments, unthemed); it blanks when nothing running is selected.

In-transcript run cards. When a subagent dispatch fires, the tool row becomes a live card — spinner, agent, model, task, and a state line (last event · turn · elapsed · tok · ctx%) driven by the child run's events. On settle it collapses to one honest line:

╰─ ✓ reviewer · 4m12s · 598K tok · $0.30 · ✎3 · verdict: Ship

(Expand — the native tool-expand key — for the full envelope; failed runs show ✗ … · — · — with the reason.)

Orchestration + findings entries. While a burst of runs is live, a TUI-only entry (zero LLM tokens) shows the waiting-on tree, the fleet TODO projection, and the gate state; when the burst settles, a findings block records each run's outcome plus degradations (fallback used, zero-tool flag, language drift):

── findings ────────────────────────────────
✓ reviewer     4m12s  598K tok  $0.30 — Ship
✗ scheduler    —      —         —      worker exited without result (TODO reverted ⚠)

Widget + panel. The above-editor widget is now a colorized component (totals strip when >1 active; one status-token segment per run). The panel gains a totals header, status-colored rows, a state-machine footer (keys that matter now), and capability-aware actions (aborted runs offer re-run, not stop). All existing keybindings are unchanged.

P2 (structure): t lineage tree (Runs+Fleet), real-width overlays, live scroll separator, unified run-card frame (#108).

About

The armory suite's subagent orchestrator for the pi coding agent — a cross-harness, superpowers-native fleet where every agent is armory-native from birth.

Topics

agent-orchestrationai-agentsarmoryclaude-codecross-harnessmulti-agentnpm-packageorchestrationpipi-coding-agentpi-extensionpi-packagesubagentssuperpowerstypescript

Resources

Readme
MIT license
Activity
Custom properties

Stars

2 stars

Watchers

0 watching

Forks

1 fork
Report repository

Releases

Packages

Contributors

Languages

You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.