agentworkshop
AgentWorkShop
Where AI agent teams meet the production line.
简体中文 · Documentation · Releases · Changelog · Plugin API · SDK
v0.7.70 · 14 engines · 6 field protocols (5 built-in + serial plugin) + MES REST integration (mirror & live) · data-analysis ledger with line-scoped permissions · per-call tool parameter/binding preflight · 86 host tools · 119 runtime settings · bilingual docs (简体中文 / English)
A configuration-driven platform where AI agent teams and an industrial digital twin share one runtime — agents query real telemetry, issue supervisory setpoints through human-approved write control, and every event streams live to a 3D twin.
[!IMPORTANT] Positioning: supervisory layer. AgentWorkShop is a supervisory (SCADA-adjacent) layer for production-line management, digital twins, DAQ and agent orchestration, operating at second-level soft real-time. It is not a hard real-time controller: any time-critical loop (< 10 ms, interlocks, safety, servo) must live inside the PLC. Setpoints written here are advisory — plant-side logic may veto.
FIGURE INDEX
FIG.01 closed loop ·
FIG.02 DAQ console ·
FIG.03 line operations ·
FIG.04 digital twin ·
FIG.05 dashboard ·
FIG.06 responsive
JUMP TO
What is this? · Highlights Interface · Architecture Quick start · Configuration & CLI Industrial stack · Usage Verification · Project layout Tech stack · Development Roadmap · License
AT A GLANCE
Supervisory layer, second-level soft real-time 14 engines · 4 entry points 6 field protocols (5 built-in + serial plugin, read + write) 7-state task machine · root queue + lease fencing Group chat jobs · scheduled tasks · HITL FTS5 + vector memory · hot-reloadable plugins SDK · CLI · TUI · external MCP · ~1100+ acceptance assertions
Documentation
Docs are bilingual — the VitePress site ships a language switcher (简体中文 / English) across every section. Deep-dive pages ship in this repo too, and the CLI copies them into the published tarball:
| Topic | Online | In-repo | What it covers |
|---|---|---|---|
| Getting started | Guide | docs/site/en/guide/ |
install → first run → first agent × line session, configuration, DAQ protocols, DCW read/write, HITL, recipe versioning, multi-harness teams, line permissions, AML |
| Plugin development | Plugin guide | docs/plugins.en.md |
the full extension contract: three scopes, index.mjs manifest, ctx server/browser surface, settings/groups declarations, lifecycle events, i18n, panels, team-scoped switches, a real example |
| SDK | SDK guide | docs/sdk.en.md |
agentworkshop/sdk as a programming client (platform REST client with envelope handling) and as the plugin extension base; TypeScript types; browser-side SDK |
| CLI | CLI manual | docs/cli.en.md |
all 15 aw commands, global options, exit codes, dual-mode path model, the command-registration system, maintainer publish guide |
| AML | AML guide | docs/aml.md |
auto-modeling lab: dataset build, job orchestration, model registry, promotion gates, agent tools |
| TUI | — | docs/tui.md · tui/README.md |
terminal workbench: channels, agents, tasks, live monitor, HITL answering |
| Multi-harness architecture | — | docs/multi-harness-architecture.md |
engine taxonomy, normalized session contract, provider/model catalog, failure modes |
What is this?
AgentWorkShop started as a multi-agent software workshop — channels of coding agents with a lead-agent scheduler, a 7-state task machine, persistent memory, and four interoperable entry points (WebSocket / MCP / A2A / REST).
It grew an industrial half: a full data-acquisition and write-control stack (Modbus TCP / OPC UA), production lines with recipes and batch runs, a 3D digital-twin town, an auto-modeling lab (dataset → training job → leaderboard → gated promotion) — and the bridge that makes it unique: agents can be granted bound, permission-scoped access to real industrial nodes, query their live telemetry with physical semantics attached, and drive write operations through an interlock → human-in-the-loop → readback pipeline.
It is also extensible by design: a self-contained plugin can enhance the server (hooks, routes, agent tools, DAQ drivers, config groups) and the browser (panels, i18n) at the same time, and the same surfaces are available to ordinary programs through the SDK — see docs/plugins.md and docs/sdk.md.
The result: submit a goal like "analyze the melt temperature trend and optimize the setpoint" — and an agent team reads real sensor history, computes statistics, proposes a new setpoint, waits for your approval in the HITL panel, writes it to the PLC, verifies the readback, and reports the numbers back. End to end, verified by automated E2E.
FIG.01 — The closed loop
Goal → read → compute → approve → write → readback → report. Recorded against a running instance: real DAQ history, real write control, real HITL approval.
[!NOTE] Every figure in this README is a recording or screenshot of a running instance — not a mockup. The numbers on screen come from seeded industrial data flowing through the same code paths the product ships.
🎬 Live demo (4 min 11 s, English voice-over & captions)
Click the cover to watch the full demo. Real PLC simulator, real serial-port enumeration, real agent-team execution — no cuts, no fakes.Scenes: dashboard → live DAQ → governed write & read-back → serial protocol plugin → agent team execution → closed-loop trend → 3D digital twin.
Highlights
Agent team runtime
| Capability | Why it matters |
|---|---|
| Lead-agent orchestration | Each channel has one lead: decomposes goals, dispatches to idle workers, reassigns failures, judges goal satisfaction. LLM decisions with a deterministic rule-engine fallback — the system never stalls. |
| Three execution modes | goal (satisfaction judging) · loop (fixed-interval replay) · pipeline (ordered stages). 7-state task machine with progress, artifacts and full history. |
| Harness-agnostic | One AgentInterface, 14 engines in three transport classes: in-process — mock (no LLM), claude (Claude Agent SDK, resident session, same-turn steer); persistent session over a protocol — omp (RPC subprocess), codex (app-server JSON-RPC), dsh / qwen / hermes (ACP), opencode (serve + HTTP/SSE); headless CLI with a structured event stream — gemini (stream-json), copilot (JSONL), cursor (stream-json), crush (non-interactive run), goose (stream-json), pi (-p --mode json). The platform never knows which one runs. |
| Per-channel LLM selection | Each channel picks a harness → provider → model (+effort) triple from the harness's live catalog (e.g. zhipu-coding-plan/glm-5.3-flash on omp). Members inherit it unless they override — mixing harnesses in one team is a first-class setup, not a workaround. |
| Harness availability check | GET /api/workshop/harnesses probes each engine's CLI on PATH. The UI disables not-installed engines, and dispatch is hard-checked at every entry point. |
| Stall-safe supervision & task governance | Submitted goals enter a FIFO root queue with visible queue positions. Queued roots never burn their execution budget while waiting — the budget starts at admission, and a deterministic lead-rescue sweep revives starved entries (stopped/idle lead runtime + fresh assignment) before a human ever notices. A supervision watchdog distinguishes stuck from slow — agent tool invocations count as liveness, so healthy long-running industrial work survives while genuinely stalled tasks surface to the lead. Every assignment carries a generation + execution lease, so events from a superseded worker are dropped by admission, not reconciled by hope. |
| Harness continuity | Engines declare a continuity mode (persistent / per_turn); persistent sessions are reused across turns under a read-only continuity lease (pid / session / reuse count / last restart reason), and a server restart restores what can be restored instead of silently re-forking. |
| Channel group chat & native HITL | The channel timeline is a real group chat: a member's request becomes a trackable job (not a lost message), and engines with a native ask surface (e.g. omp) route HITL questions through the platform — approve once, the engine continues with the receipt. Member permissions and notifications are first-class. |
| Scheduled tasks | Any channel task can run on a schedule — fixed interval (60 s floor) or daily at a set time — managed from /workshop/schedules or the REST API, with per-run history, busy-guard (no overlapping runs of the same schedule) and channel-scoped visibility. |
| Persistent memory & channel process memory | Private + channel-shared domains; FTS5 with CJK segmentation, optional vector hybrid recall, token-budgeted injection. On top sit process memories: deterministic root/child/lead event contracts, a canonical root summary, and a durable outbox (dead-letter + compensation worker) so the story of a goal survives restarts. |
| Four entry points | One manager behind every door: WS (AEP v1 event stream with seq-resume), MCP (25 in-process tools), A2A (JSON-RPC 2.0 + AgentCard), REST. |
Industrial stack
| Capability | Why it matters |
|---|---|
| Six field protocols | Modbus TCP, Modbus RTU-over-TCP (serial gateway), OPC UA, MQTT and HTTP/REST, plus a built-in serial plugin (direct RS-232/485: Modbus RTU + ASCII line) — acquisition and write-control drivers with connection pools, classified error messages and per-driver connection tests. mock covers demos/CI. Protocols are plugins: ctx.daq.registerDriver / ctx.dcw.registerWriteDriver inject straight into the frontend protocol dropdown and dynamic forms (⌁ badge) — when a protocol ships self-describing metadata, the frontend forms render with zero changes. |
| Agent teams, industrial scope | Agents bind to DAQ/DCW nodes and see semantic cards — physical meaning, units, safe range, recipe window — never raw registers. |
| Human-approved write control | DCW writes flow through safe-range ∩ recipe-window interlock → optional HITL approval → PLC write → readback verification → signed write history. |
| Read-write DCW channels | Every control node also reads its PLC value back through the same calibration path it writes with: periodic + on-demand + agent reads surface SET vs ACT side by side — passive observation, never blocked by write interlocks. |
| Recipe versioning & governance | Parameter changes are versioned with attribution (user/agent/system + operator + reason). Roll back to any revision or the last-good batch — non-destructively. Stale-node params are skipped and clearly marked. |
| Recipe-chain optimization loop | Agents optimize through recipe management, the way human process engineers do: recipe_trial batch-dispatches multi-parameter candidates without writing a version → re-measure → progress adopts via recipe_update (same recipe id, version +1) → regression triggers a unified rollback (recipe_rollback with dispatch: true = definition revert + batch restore to the PLC). Single-knob direct dispatch is out of the loop; trials run under four-layer bounds and a per-line cadence. |
| Channel-bound lines (read-only grant) | A channel can bind a line: every member reads that line's ops logs, recipe history and live status without any node binding (tool outputs are tagged "channel-bound, read-only"), while writes still require node authorization. The line brief is injected into member prompts; binding changes hot-recycle member runtimes. |
| Data-analysis ledger (v0.7.62) | Agents persist analysis results as first-class records: native analysis_save / analysis_query host tools write a dedicated analysis_reports table keyed by line + recipe + time window, with conclusions, metrics, data sources and actor attribution. The ledger is append-only for agents; humans revise via REST with editor attribution. A dedicated /analysis page streams new reports live (ops-log WS), filters by line / recipe / time / keyword, and edit/delete are permission-gated (operate line mode; admin-only delete). External analysis plugins integrate through the same ledger — diag_run runs IDD analyses in the background across six intents (deep root-cause diagnosis, line stability report, quick screening, DOE analysis, tuning-experience mining, optimization campaign — scenario prompts injected per intent), returns a task_id immediately, tracks progress via diag_status, and the finished report lands in the ledger via analysis_save. |
| Semantic parameter surface & tuning loop | Every dispatchable write converges on the recipe face (recipe_update / recipe_apply / recipe_trial, each gated by binding → HITL reason → active-run). Writes stay narrowed by the four-layer bound — node safe range ∩ parameter baseline bounds ∩ active product bounds ∩ active recipe window — and each adjustment opens a tuning record that dcw_judge must close (keep / rollback / uncertain), with dcw_rollback executing the undo. (v0.7.63 removed the legacy param_control / param_read / dcw_read direct-node tools — dead surface under permission model v2 — so the agent tool list stays clean.) |
| Line operations | Lines → products → recipes → batch runs. Recipe windows gate acquisition and interlock writes; every sample is tagged product/recipe/run for per-batch isolation. |
| MES REST integration (two data paths) | Production-management data joins the same governed workspace: a mes-rest node maps the MES API's catalog / current / history endpoints through declarative request maps (auth via secretRef → env token, never plaintext; hooks can post-process ingested data). Agents read it two ways — live: mes_fetch issues the mapped request and returns the API response (large windows paginate async into a mesds-* CSV dataset read via mes_datasets / mes_dataset_read; raw rows never enter the prompt); mirrored: an http DAQ node polls the same API into the local TSDB so daq_query serves it like any native node — and keeps serving it when the API is down. mes_catalog is line-scoped and fail-closed. |
| Multi-modal DAQ frame pipeline | Multi-point profiles (thickness/scanner) and CCD image frames flow through template sink pipelines: vectors & metadata into Timescale (daq_frames), pixels into object storage (MinIO, auto disk fallback); derived-metric thresholds ride the existing alarm chain. |
| Production hardening (v0.7.58) | Hold-heartbeat lifecycle fixed — failed writes never occupy the setpoint (no phantom re-dispatch), driver/connection/line changes clear the value, line stop suspends hold automatically; silent mock fallback blocked (unknown protocols fail loudly, plugin unload can't fake success); frame pixel sha256 fingerprints + day-directory object GC (DB cross-check before delete); Timescale daily chunks + columnstore compression (TSL); heap-watermark watch with crash/liveness/watermark auto-respawn; write-hold windows & trial cadence persisted across restarts; runtime grant re-checks include the channel-bound line (revocation takes effect everywhere). |
| Agent self-audit tools | line_context, ops_log, recipe_log, recipe_versions, dcw_journal — agents see exactly which line/product/recipe they control, who did what, and how every value changed. |
Governance, configuration & extension
| Capability | Why it matters |
|---|---|
| Line-level permissions | Industrial data is gated per production line with three states (none / read-only / operate), enforced in the data plane — regular users see no line data until granted. |
| Per-call tool preflight (v0.7.66) | Every industrial tool call is checked before its handler runs: parameter shape, plus reference membership for node_id / line_id / recipe_id / dataset_id and chained dataset/job/model/plan/scene ids (resolved through lineage). References must fall inside the caller's bound face (bound nodes ∪ channel-bound line read-only ∪ nodes on a bound recipe's line). Out-of-scope calls are rejected with the caller's bound face and a concrete next step; authorization denials are audited. |
| Full-operation audit log | Every user / agent / system action lands in one queryable log; operators are attributed to "Channel/Member", distinct from users and the system. Streamed live over WS. |
| Team-scoped plugin switches | Each team (channel) keeps an independent plugin switch set (channel_plugins): a disabled plugin's tools are not injected into that team's agents. Plugins themselves are hot-managed via aw plugin and the /plugins page. |
| Plugin extension API | A self-contained directory under plugins/<name>/ enhances both halves at once: index.mjs (server: hooks, routes, agent tools, DAQ read drivers / DCW write drivers, frame processors, node templates, config groups, KV, timers) and client.mjs (browser: panels injected into named slots, i18n, settings UI). Three scopes — builtin (shipped) > project (checkout) > user (~/.AgentWorkShop) — with ~1 s hot reload on enable/disable and on code edits; a disabled plugin's drivers are removed on hot reload immediately. Built-in example: serial-bridge (serial communication: read/write drivers, serial probe API, frontend panel). Full contract in docs/plugins.md. |
| AML — auto-modeling lab | Dataset build → training job → leaderboard → promotion gates → model reference, all driven from /aml or by agents through 14 aml_* tools. Python runtime bootstrapped with uv into an aml/ asset root inside the config root; artifacts and metadata stay under the config root. Models carry a human-readable identity — label (line · recipe · objective), description and line/objective ids — selectable via aml_model_find. |
| AML hybrid twin × MPC | Grey-box physics core + bounded PyTorch residual, TwinSnapshot / VirtualTrial / RecommendationCertificate with UQ/OOD screening and all-trajectory gates; the hybrid_twin channel profile injects 12 profile tools (scene discovery/compile/freeze, physics-spec draft/validate/compile, snapshot, trial, MPC, gate, provider catalog) plus the general twin_calibration_request. Trials stay virtual (candidateExecuted=false) and writes are recommendation-only until a certificate is certified. |
| Two-mode optimization loop | Dedicated channel templates split the loop structurally: an aml-training channel gets the modeling face (datasets, jobs, scene compile, physics specs, training plans — no plant writes, no MPC) and an aml-optimization channel gets the acting face (snapshots, trials, gate, MPC, Bayesian search twin_bayes_optimize, governed micro-writes optimization_explore) — training-while-optimizing is impossible by construction. Exploration mode writes through the governed chain with response read-back pairing (every write lands in an optimization_explorations ledger); production mode requires a bound model that cleared the twin gates (aml mode, boundModelId at instantiate time). |
| Runtime observability | GET /api/system/monitor exposes the agent-team internals as numbers: root queue depth, watchdog interventions, harness session reuse, pending memory outbox — each guarded by a documented rollback switch, so new machinery can be turned off without a redeploy. |
Line operations feed (/operations) |
One page for every touch on the plant: a live operation feed (REST snapshot + WS stream) classifies writes, DAQ, AML, recipe, rollback, alarm, line, manual and system actions into nine categories, renders structured before → after diff badges on write rows (failures marked red), and infers the closed-loop phase (monitor → exploration · small-step → recommendation search → shadow verification → production) straight from the event stream. The same feed powers a line-operations panel inside the workshop console. |
| External MCP gateway | aw mcp starts a zero-dependency stdio MCP server (38 tools) that discovers a running instance automatically (env → lock file → config file) and exposes lines, recipes (incl. mark-good), governed DCW writes, semantic parameter mapping, DAQ queries, channels, team provisioning, model promotion, judge/rollback and plugin management to any MCP client — gated by the mcp.enabled runtime setting, with --doctor and --print-config helpers. |
| Fully config-driven runtime | Every runtime knob (memory budgets, compaction, rollback guardrails, retention, backups, log level, system timezone, MCP gate…) is declared once in the settings descriptor registry with precedence config.yml < runtime-settings < env — 119 settings across 18 groups (40 live / 79 restart), no hardcoded defaults in code. |
| Configurable system timezone | One time.timeZone setting (IANA id, live-applied) drives human-facing timestamps — logs, chat, audit, agent records and schedules — through a single formatter; machine timelines (DAQ samples, timestamptz) stay absolute. |
| Configurable cadences | Sampling and query defaults/floors are live settings (daq.sampling.*, daq.query.*): hot-reloaded, clamped on node create/patch, and agent tool descriptions always carry the current values. |
Digital twin
| Capability | Why it matters |
|---|---|
| 3D digital twin | Three.js town: place line equipment and channel territories, watch device health, alarms and live values — driven by the same event bus. An adaptive quality ladder (DPR / shadow / bloom tiers, wall-clock FPS budget) matches the machine, and window.__townStats exposes real render metrics for perf probes. |
The interface
Every panel below is the real UI, at 1440×900, recorded from a running instance.
FIG.02 — DAQ console
Acquisition, end to end. Node inventory and health under a live gauge band, trends that fill as samples land, an alarm strip that only holds what is actually unacknowledged, and a tailing event stream.
FIG.03 — Line operations
Lines, products, recipes, batches. Starting a line gates acquisition through its recipe window and tags every sample with product/recipe/run; control nodes expose SET vs ACT through the same calibration path they write with.
FIG.04 — Digital twin
The twin is the same event bus, rendered. Equipment, channel territories, alarms and live values — an adaptive quality ladder (DPR / shadow / bloom, wall-clock FPS budget) keeps it honest on modest hardware.
FIG.05 — Dashboard
One screen for the whole workshop. Channels, agents, tasks, DAQ throughput and alarms — read from the same state the API serves, not a separate metrics store.
FIG.06 — Responsive
Desktop → tablet → phone. The instrument rail collapses to an icon rail, then to an off-canvas drawer; page headers stack, dense tables become scrollable ledgers with a pinned identity column.
Architecture
flowchart TB
subgraph FE["Frontend — Nuxt 4 / Vue 3"]
UI["Workshop UI · 3D Twin · Dashboards"]
WS["AEP client — seq resume"]
end
subgraph SRV["Server — Nitro / h3"]
REST["REST /api/workshop/**"]
HUB["WS Hub — AEP v1"]
A2A["A2A JSON-RPC"]
MCP["MCP Server"]
subgraph RT["Runtime"]
MGR["AgentChannelManager"]
SCH["SchedulerLoop — lead supervision"]
TE["TaskEngine — 7-state machine"]
AR["AgentRuntime × N"]
MEM["AgentMemory — FTS5 + vector"]
BUS["Event bus (ManagerBus) — per-channel seq + ring"]
end
subgraph IND["Industrial"]
DAQ["DAQ gateway — per-node edge runtimes"]
DCW["DCW gateway — write control"]
BR["Bus — inproc / MQTT"]
TSDB["TSDB — SQLite / Timescale"]
end
subgraph HB["Harness adapters — 14 engines"]
MOCK["mock · claude — in-process"]
OMP["omp — RPC subprocess"]
CDX["codex — app-server"]
DSH["dsh · qwen · hermes — ACP"]
OC["opencode — serve"]
FAM["gemini · copilot · cursor · crush · goose · pi — headless CLI"]
end
DB[("SQLite — channels · agents · tasks
messages · memories (FTS5) · events")]
end
UI <--> WS
WS --> BUS
REST & A2A & MCP --> MGR
MGR --> SCH & TE & AR
AR --> MEM
AR --> MOCK & OMP & CDX & DSH & OC & FAM
MGR & TE & MEM & BUS --> DB
DAQ <--> BR --> TSDB
DCW --> BR
DAQ & DCW --> BUS
The agent × machine bridge (the part worth reading the source for):
agent ──binds to──▶ node (daq: auto / dcw: manual)
│ │
│ my_industrial_nodes ◀── semantic card: meaning · unit · safe range · recipe window
│ daq_query ◀── TSDB history, stats + physical semantics
│ dcw_control ──▶ interlock (safe range ∩ recipe window)
│ ──▶ HITL approval (manual mode, 180 s timeout)
│ ──▶ PLC write → readback check → ACK + write history
◀── result text with numbers the agent can cite
Quick start
Prerequisites
node -v # ≥ 23.4.0 (needs built-in node:sqlite)
Real-agent harnesses require their CLI on PATH —
omp,codex,dsh,opencode,gemini,qwen,copilot,cursor,crush,goose,piorhermes(any subset; each channel can mix harnesses).mockandclaude(SDK) run in-process and need no PATH CLI. The dashboard "execution engines" panel shows per-engine readiness with a green/grey dot; entries for uninstalled engines link to their official install pages. Optional DAQ infrastructure (MQTT broker + TimescaleDB) auto-starts via Docker when reachable (docker compose up -d).
Option A — install from npm (recommended)
npm install -g agentworkshop # → `aw` / `agentworkshop` on PATH
aw start # → http://localhost:3001
The published tarball ships a prebuilt production bundle (.output/), so an npm install boots straight away — no build step, no build tools. On first launch everything initializes into the config root ~/.AgentWorkShop: the default config.yml, a generated .env holding a random session secret, runtime-settings.json, a docker-compose seed, prompts/, commands/, plugins/ (seeded from the SDK examples, disabled by default) and an empty data/ directory. All runtime data (SQLite, JSON repos, backups, logs) lives there too — config and data stay with the install, not the working directory.
Prefer a one-off run without installing globally?
npx agentworkshop start # no global npm install required
npxstill creates~/.AgentWorkShop— running without a global install is not the same as leaving no trace on disk.
Option B — from source
git clone https://github.com/kingdol666/AgentWorkShop.git && cd AgentWorkShop
pnpm install
pnpm dev # → http://localhost:3000 (port from config.yml)
Production from source:
pnpm build # nuxt build → .output/
pnpm start # port from config.yml → server.prod.port
In a source checkout the config root is the project's
.AgentWorkShop/folder (runtime overrides, data, project-level commands), whileconfig.yml/.envstay at the checkout root, version-controlled as the factory defaults.
Updating
aw update # check + self-update the global install
aw update --check # only report; nothing is installed
npm install -g agentworkshop@latest # manual equivalent
Releases follow semver. aw start verifies the config root on every launch and migrates the legacy pre-home data/ layout into it (newest file wins), so data survives upgrades. SQLite schema migrations run server-side at boot. Current version: v0.7.70 — see Releases.
Your first agent × line session (~2 minutes)
- Sign in — register in the sidebar (or
POST /api/users/register). - Build a line —
Line Operations→ create a line, add DAQ nodes (e.g.daq-temp-tc) and control nodes (e.g.dcw-temp-sp), create a product + recipe, hit Start. Live values start flowing. - Create a team —
Agent Workshop→ pick a lead + workers, deploy into a channel. - Bind nodes — open the agent's detail panel → bind the DAQ node (auto) and the control node (manual = needs your approval).
- Submit the goal — "Analyze the last 5 minutes of melt temperature; if deviation from 182 °C exceeds 1 °C, correct the setpoint (wait for my approval)."
- Approve — the agent reads real history, computes the mean, requests the write → approve in the HITL panel → watch the setpoint change and the goal close with a numeric report.
Configuration & CLI — config-driven by design
One runtime, one source of truth. config.yml declares defaults; runtime-settings.json inside the config root carries runtime overrides; environment variables and CLI flags sit on top. Every editable key is described once in shared/config/schema.json (type, range, enum, live-vs-restart) and surfaced through the same descriptors in both the UI and the CLI.
config.yml (defaults) < .AgentWorkShop/runtime-settings.json (runtime) < env vars / CLI flags
The config root is ~/.AgentWorkShop for a global install (npm i -g) — wherever you run aw from — and <repo>/.AgentWorkShop in a source checkout (with config.yml / .env staying at the checkout root as version-controlled factory defaults). AW_HOME redirects it; AW_MODE=home forces the global shape.
Live settings, persisted, hot-reloaded
- The Settings → Runtime config tab renders every editable key from the descriptors — change server ports, theme, API timeouts, locale or the approval gate, hit save.
livekeys apply instantly (theme, title, timeouts, approval gate, DAQ sampling cadences, TSDB query buckets…) over a server-sent event stream — no reload, no restart.restartkeys (ports, hosts) persist to disk and take effect on the next launch of the matching mode (aw dev/aw start).- One channel for every writer: the UI, the CLI and the server's file watcher all converge on the same settings file, so a change made anywhere shows up everywhere.
Example — retune the acquisition and query cadences live:
aw config set daq.sampling.defaultIntervalMs 2000 # new nodes sample every 2 s
aw config set daq.sampling.minIntervalMs 500 # per-node floor (create/patch clamp)
aw config set daq.query.defaultBucketMs 3000 # TSDB reads default to a 3 s bucket
aw config set daq.query.minBucketMs 500 # query floor (samples/line query/agent tool)
Agent tool descriptions are re-rendered with the current values on every injection, so an LLM always sees the floor and default that will actually apply to its daq_query calls.
The aw CLI
| Command | What it does |
|---|---|
aw start · aw dev · aw build |
Production server / dev server / build — ports from the effective config; first start builds once |
aw stop |
Stop a running aw service instance via the single-instance lock |
aw config list · get · set · unset · reset |
Read & write runtime settings (validated against the schema, atomic writes) |
aw plugin list · create · enable · disable |
Manage plugins across all three scopes: inspect, scaffold (project scope; --global for user scope), enable/disable (state file, ~1 s hot reload on the running server) |
aw mcp |
Industrial MCP stdio server (38 tools over the platform REST: lines, recipes, DCW writes, parameter mapping, DAQ, channels, teams, model promotion, plugins) — auto-discovers the running instance; --doctor diagnoses discovery/health/auth, --print-config emits a ready-to-paste MCP client config |
aw home |
Inspect / initialize the config root .AgentWorkShop |
aw init <dir> |
Scaffold a runnable project (full config system + CLI included) |
aw register <path|url|npm:pkg> |
Register a new command — project-local or --global |
aw update |
Check npm for the latest release and self-update the global install |
aw doctor |
Environment + project health check (node, config, ports, keys) |
aw status |
Live overview: mode, config sources, running server, command table |
aw tui |
Terminal workbench: channel/agent management, task submission, live monitor pane, HITL answering (see docs/tui.md · tui/README.md) |
aw version |
Print the CLI/package version (alias v) |
Global flags: --help/-h · --version/-v · --json (machine-readable) · --root <dir> · --debug.
Exit codes: 0 success · 1 runtime error · 2 usage error. With --json, failures come back as an envelope carrying { ok: false, error: 'unknown-command' \| 'no-project' \| 'usage' \| 'internal' \| … }, so automation can branch without parsing stderr.
Command registration
Commands are plain modules exporting { meta, run }. Drop one into a scanned directory and it's live on the next invocation — no registry bookkeeping, convention over configuration:
| Scope (highest wins) | Directory |
|---|---|
| project | <root>/.AgentWorkShop/commands/ |
| user | ~/.AgentWorkShop/commands/ |
| built-in | packaged with the CLI (cli/commands/) |
aw register <file|url|npm:pkg> copies a command into the right scope (--global for user scope); aw help lists everything that's registered.
// ~/.AgentWorkShop/commands/hello.mjs
export const meta = { name: 'hello', group: 'Custom', summary: 'Say hi', usage: 'aw hello [--name <n>]' }
export async function run(argv, ctx) {
console.log(`Hi ${argv.flags.name ?? 'AW'} — mode: ${ctx.mode}`)
}
The industrial stack in detail
Data acquisition (DAQ)
- Six protocol drivers: Modbus TCP, Modbus RTU-over-TCP (serial gateway), OPC UA, MQTT, HTTP/REST, plus the serial-bridge built-in plugin (direct RS-232/485: Modbus RTU framing + ASCII line protocol, write side with same-address readback verification, serial enumeration/probe API and a frontend panel) — connection pools, classified error messages, per-driver connection tests; the driver registry accepts plugin-registered protocols of any kind (with self-describing metadata, the frontend forms render with zero changes).
- Per-node edge runtimes: independent sampling cadence, publish cadence, in-flight mutex per node — one slow driver never blocks its neighbors. Sampling and query defaults/floors are driven by the live
daq.sampling.*/daq.query.*settings. - Pipeline: driver → queue (in-process or MQTT, offline buffer on disconnect) → consumer with out-of-order defense → three-way fan-out: WS live push (gated), TSDB batch write, device-twin writeback.
- Robustness: TSDB single-in-flight writes with bounded retries, buffer backpressure with drop counters, real loss metrics exposed on
daq.controllerframes. - Alarms: recipe-scoped monitoring windows with 2% hysteresis + 3-tick debounce; alarm/offline transitions are instant (safety first).
- Querying is batch-scoped by default:
daq_queryresolves the node's active run and filters by that batch'srun_id+recipe_id, so an agent reading evidence always sees the recipe currently running — never a mix of the previous batch. The effective scope (run=<id> 配方「name」(recipe_id)) is printed in the result header and restated per node at the end, and the same ids can be fed straight back intodaq_queryoraml_dataset_build; passscope: 'all'(or an explicitrecipe_id/run_id/product_id) for cross-recipe comparison and history review. Lines that are not running stay unfiltered, so historical data remains queryable.
Write control (DCW)
- Engineering-unit writes:
linearcalibration (scale/offset) PLC↔physical, readback verification with deadband tolerance, ACK states and write history. - Interlock: with a line running, the active recipe's parameter window replaces the node's global safe range for that node.
- HITL:
manual-mode bindings suspend the write for user approval (deduped per agent+node; re-validation at approval time — permission is re-checked when you click approve).
Recipe & batch
Line → Product → Recipe → Run. Starting a run applies recipe params node-by-node (each write verified), gates acquisition per line, and tags every sample with line/product/recipe/run — per-product data isolation with five-dimension queries (line × product × recipe × time × node).
AML — auto-modeling lab
The modeling half of the loop: /aml builds datasets out of tagged telemetry, submits training jobs to a uv-managed Python runtime, ranks runs on a leaderboard, and promotes a model only when it clears the configured gates (NRMSE, rollout NRMSE, validation/test gap, minimum rows and runs). Promoted models are referenced by id, so an MPC or shadow-twin controller can consume a versioned artifact instead of a vague "latest".
- Agents do the same work through 14 tools (
aml_dataset_build,aml_job_submit,aml_job_status,aml_leaderboard,aml_model_promote,aml_model_find,aml_training_plan_*, …) — submit a goal and let the team train and report. - The Python runtime bootstraps itself with
uvinto an./amlasset root inside the config root; dataset/artifact/metadata paths, disk quota, job timeout, concurrency and retention are all settings (16 in theamlgroup), not constants. - Governance defaults are conservative: cross-recipe datasets are refused unless explicitly allowed, and every job is attributed.
- Hybrid twin × MPC core: AML also owns the hybrid twin plane —
SceneContract/PhysicsModelManifest/TwinSnapshot/ObjectiveProfile/VirtualTrial/RecommendationCertificateon top of a grey-box physics core with a bounded PyTorch residual, UQ/OOD screening and all-trajectory hard-constraint gates. Channels opt in through thehybrid_twinprofile, which injects twelve profile agent tools (twin_provider_catalog,twin_scene_discover/compile/freeze,twin_physics_spec_draft/validate/compile,twin_scene_read,twin_snapshot_create,twin_trial_run,mpc_optimize,twin_gate_evaluate) plus the generaltwin_calibration_request; a trial is virtual by design (candidateExecuted=false) and a recommendation is only certified when gates and benefit pass. Server-side strategies aresafe_small_step(insufficient data) andprecise_search(model cleared gates). Plan + acceptance record:docs/aml-hybrid-twin-mpc-integration-plan.md,docs/aml-hybrid-twin-implementation-acceptance.md. - Any-scene modeling loop: the loop is not tied to a bundled scene. Bind nodes →
twin_scene_discoverinfers control/state/disturbance/target/guard semantics with evidence →twin_scene_compiledrafts aSceneContract→ you confirm →twin_scene_freezefreezes it (immutable versions) →twin_physics_spec_draftproposes a skeleton PhysicsSpec (one first-order relaxation equation per state, τ/gain as calibratable prior-boxed parameters) that you refine → validate/compile (whitelisted AST, no arbitrary code) →aml_job_submit { job_kind: 'hybrid_residual' }runs without any code: the built-in reference trainer calibrates physics parameters (stage A), fits a 3-member bounded residual ensemble (stage B) and reports conformal q90 coverage (stage D) — the calibrated spec is written back and shared by evaluation, prediction and trials. - Model-backed twin & continuous calibration:
twin_trial_run/mpc_optimizeaccept amodel_id— the rollout is then driven by the trained hybrid model (calibrated physics + residual-ensemble ONNX,ModelBackedHybridProvider) with UQ coverage and member disagreement coming from training artifacts, and a dataset whose line/product/recipe doesn't match the scene is rejected (TWIN_MODEL_SCENE_MISMATCH). Calibration requests are consumed by a 60 s worker that re-submitshybrid_residualretraining candidates automatically; promotion still goes through HITL + Twin Gate (AML_TWIN_WORKER_DISABLED=1turns the worker off). - Two-mode optimization loop:
awships two channel templates —chtpl-aml-training-default(modeling face: 22 tools, no plant writes, no MPC) andchtpl-aml-optimization-default(acting face: snapshot/trial/gate/MPC/Bayesian search plusoptimization_explore, the governed micro-write that pairs every setpoint with its response read-back in anoptimization_explorationsledger). The faces are mutually exclusive per channel; optimization channels instantiate either in exploration mode (governed small steps, no model required) or aml mode (boundModelIdrequired — a gate-cleared model must be bound before the acting face unlocks). - Twin provider plugin SDK (hot-loaded): an industrial scene's physics core / scene packs / objectives / solvers register through
ctx.twininto the Twin Provider Registry (registerPhysicsProvider/registerScenePack/registerObjectiveProfile/registerTrainingAdapter/registerSolverAdapter, pluslistProviders/getProviderHealth/resolveProvider/validateProvider/retireProvider/isRegistryAvailable). Twin tools resolve providers viaSceneContract.physicsProfileId(falling back to the bundledtwin-injection-default), so swapping scenes changes neither tools nor channels; a hot reload stages a new generation and drains the old one while trials and MPC hold leases, so in-flight work is never invalidated andretireProvideronly unloads at zero references. The bundled injection provider ships through that same external contract (server/plugins-builtin/twin-injection-default/), and plugins live in the usual scopes with no restart for disable/reload. Field tables and a runnable example:docs/plugins.md→ "Hybrid-twin provider plugins"; SDK surface:docs/sdk.md§4.10.
Usage
Authentication
Email + password login issues a bearer token (multiple tokens per user, individually revocable).
# register
curl -X POST http://localhost:3000/api/users/register \
-H 'content-type: application/json' \
-d '{"email":"you@example.com","password":"secret","name":"you"}'
# every workshop call
curl http://localhost:3000/api/workshop/channels \
-H 'authorization: Bearer <token>'
Line-level permissions
Industrial data is gated per production line with three states, managed by an admin
in the built-in Permissions page (/permissions, admin-only in the sidebar):
| State | DAQ nodes | DCW (write) nodes | Visibility |
|---|---|---|---|
| none (default for regular users) | hidden | hidden | line data withheld server-side — invisible in Line Ops, DAQ center and the digital twin |
| read-only | read | ✕ | line visible, values stream, no writes / dispatch / device binding |
| operate | read | read + write | full access incl. setpoint writes, dispatch, binding |
admin/editorroles are unrestricted (operations roles).- Regular users default to none — they see no line data until granted.
- Enforcement lives in the data plane: list endpoints filter by grant, write/dispatch endpoints return a human-readable 403, and Agent↔node bindings validate the line grant (DAQ needs read-only+, DCW needs operate).
- Plugins get the same surface via
ctx.permissions(lineMode/visibleLineIds/listGrants/setGrants) plus apermissions:changedlifecycle hook; the SDK REST client exposesclient.permissions.overview()/client.permissions.set(...).
Execution modes
Prefix the task description (or pick in the composer UI):
| Mode | Semantics | Config |
|---|---|---|
goal |
lead decomposes → workers deliver → lead judges satisfaction; unmet → more subtasks; met → parent completes. | goalCriteria |
loop |
replay the same task on a fixed interval. | intervalMs (default 60000), maxIterations (default ∞) |
pipeline |
ordered stages; stage N+1 consumes stage N's output. | stages: [{name, description, assigneeId?}] |
Scheduled tasks
Any task can also be attached to a schedule so a channel keeps working when nobody is watching:
| Aspect | Behavior |
|---|---|
| Modes | interval — fixed cadence (intervalMs, 60 s floor) · daily — once per day at HH:MM local time |
| Management | /workshop/schedules page, or POST/PATCH /api/workshop/schedules |
| Guard rails | busy-guard (a fire is deferred while the channel still has active tasks), per-run history with status, and a consecutive-failure circuit breaker (maxConsecutiveFailures) that auto-disables a misbehaving schedule |
| Typical use | nightly line patrol (daq_query + report to memory), periodic drift check with auto-judge, daily KPI digest |
# create a schedule: patrol the line every 30 minutes
curl -X POST http://localhost:3000/api/workshop/schedules \
-H 'authorization: Bearer <token>' -H 'content-type: application/json' \
-d '{"channelId":"<id>","name":"line-patrol","title":"Line patrol","description":"Read all DAQ nodes on line 1 and post a drift summary to channel memory.","mode":"interval","intervalMs":1800000}'
The four entry points
| Entry | Endpoint | Audience |
|---|---|---|
| WS | /api/workshop/ws?channelId=… |
Dashboards / UI — AEP v1 envelopes, per-channel monotonic seq, 5000-event ring, lastSeq resume, snapshot fallback. |
| MCP | in-process server, 25 tools | Agents (omp host tools) — management + job-face tools, channel-scoped. |
| A2A | POST /api/workshop/a2a/:agentId/rpc |
External agents — JSON-RPC 2.0, AgentCard at /card, tasks/sendSubscribe SSE. |
| REST | /api/workshop/** |
Humans / scripts — full management face. |
Task state machine
SUBMITTED ─▶ ASSIGNED ─▶ WORKING ─▶ WAITING ─▶ COMPLETED
│ │ │ │
└────────────┴───────────┴──▶ CANCELED / FAILED ─▶ (retry ≤ 3 or cancel)
Verified end-to-end
Every claim above is backed by a suite you can re-run. The acceptance suites drive a
production instance over real simulated plant protocols (Modbus TCP/RTU, OPC UA, MQTT,
HTTP + an MQTT/Timescale pipeline) with real engine CLIs, and assert on the database,
the event stream and the HTTP API — not on mocks. Two 2026-09-24 waves are archived:
the baseline matrix (~1100+ real assertions, v0.7.45 production build, isolated AW_HOME,
real browser) in docs/audit/e2e-2026-09-24-full-coverage.md,
and the follow-up feature wave (real PLC node simulator + injection-molding AgentTeam
closed loop, FIFO multi-goal, scheduled tasks, collaboration; the report records each result,
including environment- or credential-limited failures and SKIPs)
in docs/audit/e2e-2026-09-24-all-features.md.
| Suite | Latest result | What it covers | Reproduce |
|---|---|---|---|
real-injection-closed-loop.mjs |
2 goals COMPLETED / 0 failed (2026-09-24, real PLC simulator + real omp team) |
injection line provisioned from the simulator (11 DCW + 14 DAQ nodes) → real AgentTeam lead/analyst/optimizer → governed writes with a 65.8 s gap ≥ 60 s policy → DAQ re-measurement → qualityOk, verdict keep |
AW_BASE=<base> SIM_BASE=http://127.0.0.1:4010 AW_TOKEN=<token> node scripts/real-injection-closed-loop.mjs |
_run-real-injection-fifo-goals.mjs |
exit 0 (2026-09-24) | FIFO root queue with multi-task serialization: goal 2 dispatched only after goal 1 closed, role gate flip, two governed writes 65.04 s apart, two judged records, 4-anchor ledger | AW_BASE=<base> SIM_BASE=… AW_TOKEN=<token> node scripts/_run-real-injection-fifo-goals.mjs |
e2e-plc-plugin-closedloop.mjs |
core stages A–D all green (2026-09-24) | PLC simulator supply over Modbus 16040 → DAQ cross-check (AW sample 197 vs simulator register 197.37) → HITL closed-loop write to 3 zones (registers 40021/40023/40025 = 210, verified write-through) → dcw_judge keep; plugin stages E–H need the external diagnosis service and are reported as SKIP |
AW_BASE=<base> KB_BASE=http://127.0.0.1:8771 AW_E2E_USERS_DB=<home>/data/users.sqlite node scripts/e2e-plc-plugin-closedloop.mjs |
_dbg-schedule-e2e.mjs |
35 / 0 (2026-09-24) | scheduled tasks: plan CRUD + validation, next_run_at, scheduledCount, busy guard 409 CHANNEL_BUSY, in-flight duplicate 409 SCHEDULE_RUNNING, cancel reconciliation (run FAILED + failure counters), timer auto-fire (trigger_kind=timer), disable/enable state machine, 404 after delete |
SCHED_E2E_BASE=<base> node scripts/_dbg-schedule-e2e.mjs |
e2e-crash-cycle.mjs |
5 / 5 phases (2026-09-24) | watch → hard kill → persistence check → restart → redelivery → auto-resume → consumption-gap replay, each phase in its own process | node scripts/e2e-crash-cycle.mjs --port 3300 --home .e2e-home-full |
e2e-full-closedloop.mjs |
98 / 0 (2026-09-24, v0.7.45 production build) | 11 stages: registration → line/product/recipe modeling → DAQ sampling → frame pipeline → DCW write + readback → rollback ledger → agent-node authorization → bridge privilege boundaries → plugins → data-root isolation | node scripts/e2e-full-closedloop.mjs <base> |
| Protocol matrix, real protocols | 46 / 0 (2026-09-24) | MQTT · Modbus TCP · Modbus RTU · OPC UA · HTTP — acquisition, governed write + readback, recipe-window interlock and a real agent closed loop per protocol | node scripts/_dbg-protocol-matrix.mjs |
| Production API live | 60 / 0 (2026-09-24) | persistence across restart, template CRUD, task assign/complete/cancel/loop/pipeline, A2A + mailbox, WS broadcast, MCP endpoint, cascade delete | AW_E2E_TOKEN=<token> node scripts/api-live-e2e.mjs |
| AgentTeam chat + native HITL | 112 passed / 0 failed / 1 blocked (2026-09-24, real omp) |
group-chat request → trackable job; omp native ask → HITL approval → engine resumes with the receipt |
node scripts/e2e-agentteam-chat.mjs --phase=all |
| Terminal mirror + prompt composition | 26 / 0 and 16 / 0 (2026-09-24, real omp) |
terminal mirror frames, input/abort/ui_response injection, native ask round-trip; five-section prompt assembly (scenario → profile → memory → manual → assignment) observed on the wire |
node scripts/test-terminal-e2e.mjs · node scripts/test-prompt-system.mjs |
| Real-engine collaboration | task-flow real PASS, e2e-omp-workspace 13 / 13, group-chat real PASS, multi-user HIL PASS (2026-09-24) |
real omp lead + workers: decomposition, dispatch, progress, artifacts, workspace-scoped file reads, unload; multi-user HITL visibility; multi-harness team 14/18 (omp + dsh green) |
npx tsx scripts/e2e-agentteam-task-flow-real.ts · npx tsx scripts/e2e-omp-workspace.ts |
| Front-end acceptance | responsive gate 16 / 16 routes, nav drawer 10 / 10 (2026-09-24, real Chromium) | the 16 gated routes (of 22 page components) incl. the 3D town render at the gate thresholds; drawer interaction, scroll lock, route change, zero page errors | node scripts/ui/verify-responsive.mjs --routes all · node scripts/ui/verify-nav.mjs |
_aw0746-stage12.mjs |
10 / 0 (2026-09-25, globally installed v0.7.49 packaged build) | health gate (version=0.7.49) → admin login/role surface → channel creation with a real omp lead → group chat opened → real omp reply → omp child process visible in monitoring |
AW_BASE=<base> node scripts/_aw0746-stage12.mjs |
_aw0746-stage34.mjs |
13 / 0 (2026-09-25, v0.7.49 packaged build + PLC simulator) | line provisioned from the simulator (11 DCW + 14 DAQ) → product/recipe triple → every sample tagged with recipe_id/run_id while running → daq_query defaults to the active batch (scope=all opts out, measured 1 vs 4) → Hybrid Twin template instantiated (lead + 3 workers; that run injected 6 twin tools / 57 total — the profile now injects 12) |
AW_BASE=<base> node scripts/_aw0746-stage34.mjs |
_aw0746-stage6b-train-sweep.mjs |
gates all green (2026-09-25, v0.7.46 packaged build, real torch training) | 1 s grid dataset (1724 rows / 10 runs) → inline-code job trained for real → G1 one-step 0.0992 (≤0.10) / G2 rollout 0.1092 (≤0.25) / G3 generalisation 14.6% (≤20%) / G4 rows+runs → model registered and promoted to production | AW_BASE=<base> AW_DATASET_ID=<ds> node scripts/_aw0746-stage6b-train-sweep.mjs |
_aw0746-stage7-twin.mjs |
17 / 0 (2026-09-25, v0.7.49 packaged build, real DAQ + real model) | real samples → TwinSnapshot fresh=true → 65 real VirtualTrials (12 safe candidates, candidateExecuted=false) → 12-check recommendation gate write_eligible → verdict written back to the model as twinEligibility → mpc_optimize upgrades to precise_search → 0 DCW writes throughout |
AW_BASE=<base> AW_REQUIRE_MODEL=1 node scripts/_aw0746-stage7-twin.mjs |
_aw0746-stage6c-jobsmoke.mjs |
5 / 0 (2026-09-25, v0.7.49 packaged build) | AML job path: inline code accepted (no workspace/train.py required) → job reaches a terminal state → training logs/ONNX traces → experiment plus per-check gates persisted |
AW_BASE=<base> node scripts/_aw0746-stage6c-jobsmoke.mjs |
_aw0748-failclosed-probe.mjs |
7 / 0 (2026-09-25, v0.7.49 packaged build) | hard-constraint fail-closed regression: auto_daq builds a snapshot from real bindings → a mappable weight constraint evaluates normally → an unmappable part_weight constraint is judged not passed with a precise detail (v0.7.47 passed it falsely) → an empty trajectory is also judged not passed |
AW_BASE=<base> node scripts/_aw0748-failclosed-probe.mjs |
_aw0748-mock-closedloop.mjs |
13 / 0 (2026-09-25, v0.7.49 packaged build, in-process mock, no quota) |
scheduler closed-loop regression: create a mock channel → the root task is genuinely dispatched and closed → [mock:complex] forces delegation into child tasks → the parent closes after they finish → the second and third root tasks are dispatched too (before the fix the lead was unloaded while idle, cr.scheduler became null and later root tasks only landed in the DB, sitting in SUBMITTED until ROOT_TIMEOUT) → the tool bridge explicitly rejects host tools for mock |
AW_BASE=<base> node scripts/_aw0748-mock-closedloop.mjs |
| Industrial bench — integrated | 77 / 77 checks (current baseline contract, bench/PIPELINE.md; an earlier 2026-09-21 run recorded 83/83) |
five-protocol five-line bench: connectivity, sampling into Timescale, governed writes, governance, agent closed loop, semantic parameter layer | node bench/pipeline.mjs --profile integrated |
| Multi-scenario closed loop | 4 scenarios · closed loops reached (2026-09-21) | injection-molding weight-window tuning · A²/O wastewater compliance with energy minimum · continuous-annealing quality window vs throughput · BOPET line mission | node bench/scenarios.mjs --scenarios injection,wwtp,anneal |
| Line permissions / audit-negative | 21 / 21 + 9 / 9 (2026-09-12) | three-state line grants with human-readable 403s, binding-subject validation, revocation convergence, unauthenticated WS receives zero telemetry | node scripts/_dbg-perms-e2e.mjs <base> <adminPass> · node scripts/_dbg-audit-neg-e2e.mjs <base> <adminPass> |
| Render regression | 30 / 30 (2026-09-12) | DAQ table integrity (row count aligned with the API), WS-driven row updates, filters, detail page, 3D town + model library, 7-page smoke, zero page errors | node scripts/_dbg-render-regression.mjs <base> <email> <pass> |
| AML auto-modeling | 25 / 0 (2026-09-24, deterministic trainer) | dataset build → cross-recipe refusal → job submit → gates → promotion guards → prediction guards → audit; --real adds the uv/torch runtime |
node node_modules/tsx/dist/cli.mjs --tsconfig .nuxt/tsconfig.server.json scripts/e2e-aml.ts |
| Offline unit/property suites | all green | AEP event index (test-events-index), LRU, data-root split (test-data-root), log flooding, rollback index, plugin hardening, task lease fencing (test-task-lease-fencing), CLI exit codes (test-cli-exit), SDK surface (test-sdk-surface) |
node scripts/test-<name>.mjs (TS suites via tsx) |
The historical v0.7.20 acceptance baseline — 156 assertions, 0 failures — is archived in
docs/audit/e2e-2026-09-07.md. Perf probing:
scripts/_dbg-render-perf.mjs.
Project layout
AgentWorkShop/
├── bin/ · cli/ # aw CLI — command registry · built-in commands · config engine
├── app/ # Nuxt 4 frontend (srcDir)
│ ├── pages/ # / · /workshop · /workshop/agents · /workshop/teams
│ │ # /workshop/channel-templates · /workshop/schedules · /workshop/w/:id
│ │ # /town · /daq · /daq/:id · /dcw · /dcw/:id
│ │ # /aml · /operations · /monitor · /logs · /permissions
│ │ # /plugins · /users · /tokens · /settings
│ ├── components/workshop/ # timeline · lanes · task board · memory panel · 3D town
│ └── stores/composables/ # Pinia + AEP client
├── server/
│ ├── api/ # REST + WS + A2A + MCP routes
│ ├── services/workshop/
│ │ ├── runtime/ # manager · scheduler-loop · task-
Version History
| Version | Released | License |
|---|---|---|
| 0.7.70 | Apache-2.0 | |
| 0.7.66 | Apache-2.0 | |
| 0.7.65 | Apache-2.0 | |
| 0.7.64 | Apache-2.0 | |
| 0.7.63 | Apache-2.0 | |
| 0.7.62 | Apache-2.0 | |
| 0.7.61 | Apache-2.0 | |
| 0.7.60 | Apache-2.0 | |
| 0.7.59 | Apache-2.0 | |
| 0.7.58 | Apache-2.0 | |
| 0.7.54 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.53 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.52 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.51 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.50 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.49 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.48 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.47 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.46 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.44 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.41 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.40 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.39 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.38 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.37 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.34 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.33 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.27 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.24 | PolyForm-Noncommercial-1.0.0 | |
| 0.7.23 | PolyForm-Noncommercial-1.0.0 |
Showing the latest 30 of 69. See every release on npm