Releases: Xateh/maestro
Release list
v0.4.2
The second 0.4.x train stop for SP12 (ephemeral, agent-authored workflows). It lands
the two governance prerequisites that gate an ephemeral run before SP12e ships the
run core: the safety policy (SP12b) and budget & resource governance (SP12c).
Everything here is preflight/primitive — validators, limiters, and accounting that an
operator configures and the future run core (SP12e, 0.4.3) enforces. Nothing in this
release executes an ephemeral workflow.
Added
- Ephemeral safety policy — default-closed
server.ephemeralconfig + validators
(src/ephemeral-policy.mjs,src/setup/server-config.mjs). A new
server.ephemeralblock, disabled unlessenabled: true, declares the safety
envelope for agent-authored runs:command_allowlist,provider_allowlist,
max_fanout(default 4),sandbox(required/optional), andgate_relaxation
(forbid/allow).validateEphemeralPolicychecks a workflow against the policy
and returns structured codes (ephemeral_disabled,command_not_allowlisted,
provider_not_allowlisted,fanout_exceeds_cap,gate_relaxation_forbidden).- Command allowlist matcher. Exact, prefix (
cmd *), and regex (re:…) entries;
whitespace-normalized; fails closed (an invalid regex never matches). Every
declaredcommands[].runis gated regardless of role kind, so an agent role
cannot smuggle a shell command past the allowlist. - Gate-relaxation comparator (
gatesAreWeaker). Whengate_relaxation: forbid,
an ephemeral workflow may not disable a baseline boolean gate
(require_distinct_reviewer,output_schema_conformance) or drop a numeric floor
(min_coverage) below baseline. - Fan-out cap fails closed: a non-finite/absent
max_fanoutpermits no fan-out
rather than silently disabling the check.
- Command allowlist matcher. Exact, prefix (
- Budget & resource governance (SP12c). Operator-side caps and accounting
primitives, with the breach kill-switch explicitly deferred to SP12e:- Per-run budget validators + ceiling clamp (
src/budget.mjs).validateBudget
checkstokens/usd/wall_clock_msare positive and not below an operator floor
(bad_budget_spec,budget_below_floor);clampBudgetclamps a requested budget
down to the operator ceiling. - Bounded async pool (
src/async-pool.mjs,runPool) caps concurrent work, and
parallel-group execution now runs through it so a group cannot exceed the limit. agent.max_concurrent_rolesconfig (default 4) bounds concurrent role
execution.- Per-provider rate limiter (
src/provider-rate-limit.mjs) over a shared token
bucket, configured viaserver.providers.<name>.rate_limit(capacity,
refill_per_sec; refill may be fractional). - Live cost accounting (
src/cost-accounting.mjs,accumulateCost) plus a
best-effort USD price table (src/provider-pricing.mjs) for cost estimates. A
cost_updatestage-event primitive exists; per-role emission is deferred to the
run core.
- Per-run budget validators + ceiling clamp (
Fixed
- Security — polynomial-ReDoS code-scanning alerts. Resolved
js/polynomial-redos
alerts flagged by code scanning. - herdr — leftover terminal pane. A completed task no longer leaves an empty root
terminal pane behind.
v0.4.1
The first 0.4.x train stop for SP12 (ephemeral, agent-authored workflows). It lands
the two prerequisites that have no SP7 dependency — the authoring surface (SP12a)
and the provider registry (SP12d). Both are authoring/preflight primitives: they
let an agent write and check a workflow before any ephemeral run core exists. Nothing
in this release executes a workflow; that is SP12e (0.4.3).
Added
- Published workflow JSON Schema —
schema/workflow.schema.json. The full
workflow document is now described by a canonical JSON Schema, exposed to MCP
clients as a resource atmaestro://schema/workflow.json. An authoring agent can
fetch the schema, generate a workflow against it, and validate locally before
submission. maestro_validate_workflowMCP tool. Validates a workflow either inline (a
JSON document passed directly) or from disk (a path), returning structured
validation codes so an agent can run a repair loop. Bounded by a
max_validate_attemptsguard with an explicit recovery path.maestro_list_providersMCP tool + provider registry
(src/provider-registry.mjs). Enumerates configured providers with capability
flags (src/adapters/capabilities.mjs) and best-effort auth preflight, so an
authoring agent can target only providers that are actually available. The
registry/preflight primitives land here; the run-time enforcement of provider
validation codes arrives with the ephemeral run core (SP12e).- Exemplar workflow library —
examples/. Canonical, schema-valid workflows an
agent (or a human) can copy from:default,parallel-group,github-tracker,
andfull-audit-sweep.
Fixed
- herdr provider-alias resolution. Aliases (e.g.
xcodex) are now resolved via
bash -icso the alias expands from the interactive shell; previously the runner
exited 127 because the alias was not onPATHin a non-interactive shell.
v0.4.0
Added
- Parallel groups — concurrent role execution as a single compiled node. A
workflow may declareparallel_groups(an array of arrays of role names, each
group with>= 2members). The members run concurrently
(Promise.allSettled) as one compiled group node. They must not depend on each
other (no sibling edges), cannot bekind: "scoring", and must share the same
donesuccessor — all validated, with abad_parallel_grouperror on
violation. If any member emits an interrupt/terminal event
(error/question/waiting/needs_review) or fails hard, that event
propagates and halts the run (highest-precedence wins) rather than being
swallowed.run-manifest.jsonrecords theresolved_parallel_groups. - Coverage ingestion — structured coverage from command roles. A command
role'sparser.coverage.formatacceptsc8-json,lcov,jest-json,
cobertura,clover, orregex(theregexformat requires apctcapture
pattern). After the command exits, the runner reads the declared coverage file
(path-confined, 4 MB cap) and fillsevaluation.coverageas
{ overall_pct, by_command }—overall_pctis the arithmetic mean across
contributing commands. An unknown format is rejected at validation
(bad_command_spec). - GitHub issue tracker backend. Set a tracker
kind: "github"with
owner/repo/token(plus an optionallabel, defaultmaestro). It polls
the REST API for labeled open issues and performs write-backs (comment, close,
add-label), staying rate-limit aware. - Inbound webhooks.
POST /api/v1/webhook/:kindacceptsgithub
(HMAC-SHA256 signature viawebhook_secret, verified timing-safe) and
generic(bearer token viawebhook_bearer_token, verified timing-safe).
The body is capped at 1 MB. Awebhook_template(with{{payload.path}}
interpolation) renders the dispatched task title; the task is created against
the configuredworkflow. - Outbound lifecycle notifications. A
notifyconfig
{ on: [...events], url, format }(format: "slack" | "generic") fires
best-effort POSTs oncompleted,halted, andapproval_needed. It never
throws and makes one attempt per event. - Real mid-run cancellation. Cancelling a task now aborts the in-flight run
at the next step boundary (viaAbortController), sets statuscancelled, and
stampscancelled_atinrun-manifest.json. Previously cancellation only
updated bookkeeping.
Changed
- Correctness scoring now blends coverage. When a workflow produces
evaluation.coverage.overall_pct,correctness_scorebecomes the mean of
pass_rateandoverall_pct / 100(waspass_ratealone). MIGRATION NOTE:
workflows that opt into coverage parsing may seecorrectness_scoredrop even
at a 100% pass rate — check anymin_correctnessgate. Workflows without
coverage parsing are unaffected. require_distinct_revieweris now default-on. When absent it behaves as
true, but for this release it emits a WARNING (non_distinct_reviewer)
rather than an error; it becomes a hard error in v0.5.0.
Deprecated
experimental_per_edge_contextgraduated to the stable key
per_edge_context. The old key still works but emits a deprecation warning —
rename it.require_distinct_reviewer: falseis deprecated. The check defaults on in
v0.4.0 and becomes required in v0.5.0.
Notes
- Role Convention doc no longer pitches Maestro as the
plan → execute → reviewpipeline.docs/role-convention.mdnow frames that flow as just the
stock graph, consistent with the README's positioning. Documentation only — no
behavior or API change.
v0.3.0
Added
- Per-edge context contract — experimental prototype (item A, headline). A
workflow may opt in withexperimental_per_edge_context: trueplus an
edge_contextmap ("<from>:<event>"or per-source"<from>"→
"full"|"scoped"|["role", …]) to declare, per inbound edge, which
prior handoffs the destination node's prompt sees. Off by default — default
workflows are byte-identical. New pure modulelanggraph/context-contract.mjs;
wired into the LLM node path (only the prompt's view is narrowed, never the
durable handoff record). Falsification verdict: KEEP — per-edge context
provably expresses what per-role static config cannot, demonstrated on the
stockfull-audit-sweep, whereimplementationre-entered via different
critics resolves different input views. output_schema_conformanceworkflow gate (item B). Promotes per-node soft
schema_validationevidence into an auditable run verdict — "every handoff
that declared a schema conformed to it." Declarable ingates:(validated in
workflow-validate.mjs), enforced inscoring.enforceGatesfrom per-handoff
metadata; any non-conforming handoff blocks and names the offending role(s).require_distinct_revieweropt-in assertion (item C). Whentrue,
workflow-validateerrors (non_distinct_reviewer) if any verifier role
(verifies: true) shares a provider with an implementation entry role — so a
model never reviews its own work. Opt-in; the default-on flip is deferred.
Notes
- Report-back determinism probe (item D) — feasibility write-up returning a
verdict: report-back is not expressible on the single-active-node engine,
and even on a future concurrent engine output-reproducible determinism cannot
survive it. The
North-Star wording stays auditable / replayable; "deterministic" is confined
to DAG traversal/wiring, never outputs.
v0.2.1
Fixed
- Local LLM provider alignment.
maestro doctorand the CLI/config docs
(docs/cli.md,docs/configuration.md,docs/local-llm.md) now match the
experimental local providers actually shipped in the adapter registry, so
doctor no longer reports drift against providers it doesn't recognize.
v0.2.0
Added
- Schema contract closeout (v0.2.0, AUDIT F4) —
output_schema_refis now a
first-class, enforceable contract end to end.- One shared validator. The five duplicated
resolve→validatebranches in
langgraph/nodes.mjs(stub / command / regression / scoring + the LLM
handoff) collapse into a singlevalidateRolePayload(roleDef, payload)helper
inschemas/index.mjs, returning the same{ ok, errors, schema }evidence
(ornullwhen nothing is declared). - Opt-in strict enforcement. A role may set
enforce_output_schema: trueto
promote soft validation to a hard halt — a non-conforming payload routes to
$haltwith a typedoutput_schema_violationblocker instead of recording
soft evidence and continuing. Soft validation stays the default; the flag is
type-checked inworkflow-validate.mjs(warns when set without a schema). - TUI round-trip guard.
writeWorkflowstrips a ref-derivedoutput_schema
before persisting, so editing a ref-declared workflow keepsoutput_schema_ref
authoritative and never bakes the inline schema onto disk.
- One shared validator. The five duplicated
full-audit-sweep-gatedworkflow template — the documented gated example
(ratifies the default-workflow gate decision): the leanfull-audit-sweep
shipsscoringwith no gates (informational), whilefull-audit-sweep-gated
opts in to exactly oneno_high_severity_findingsgate (reviewer-severity →
$halt).npm run test:terminal— a named lane that runs the full suite under
MAESTRO_BACKEND=terminal, pinning the zero-dependency terminal backend (the
default) as a first-class tested configuration in CI. README/CONTRIBUTING now
document the terminal backend as the default andherdras optional
acceleration.maestro servemulti-service management —servebecomes a service
manager: register, run, and supervise multiple tracker-backed services from a
single state dir. Each service is a named definition (serve add <name> --slug … [--port --workflow --var --workspace --shared-state]) backed by an
owner-checked0600definition + pid-record store. Lifecycle is
identity-verified against the recorded pid via/proc(liveness,stop,
pause,resume) with a detached worker spawn under an exclusive start lock,
so a stale pid can't be killed or double-started.serve list/status
derive live state;serve logs <name> [-f] [-n N]tails a bounded worker log;
serve adoptmaterializes a legacy single-tracker config as adefault
service. Service overlays resolve theserverconfig block with a var
denylist and port/api-key validation, failing fast at start on an unset
api-key var or a port collision.- Portable roles — Maestro Role Convention (MRC) — author a role once and
reuse it across workflows, and consume Claude Code subagents and skills
directly. A role loader normalizes.claude/agents,SKILL.md, and native
.maestro/rolesunits into oneRoleDef; a role'ssourceplus inline
overrides compose (nosource⇒ unchanged behavior). Per-role
tools/deny_toolsallowlists thread through the adapter seam — claude
hard-enforces via--allowedTools/--disallowedTools, codex folds Bash scope
into--sandbox, other providers record advisory scope in the run manifest.
Shipstriage(classifier branch) andresearch(gather→synthesize) demo
workflows,maestro role list|show|lint+import-agentCLI,
classification/research schemas, anddocs/role-convention.md. - Per-alias env for multi-account CLIs — provider aliases may now be objects
{name, command?, env?}, so multiple accounts of the same CLI (e.g. two
Claude logins on differentCLAUDE_CONFIG_DIRs) work purely through
config.jsoninstead of hand-written shell aliases. Alias env merges over
provider env (alias wins) with~/$VARexpansion; the resolved binary is
spawned directly (nobash -ic) while the account name stays the routing
identity. Bare-string aliases are unchanged. New modulesrc/providers.mjs
plus a full TUI account manager (add/edit/delete + env editor with denylist
rejection). - Opt-in autonomous claude write mode — a write-permission role may set
MAESTRO_CLAUDE_WRITE_MODE(e.g.acceptEdits,bypassPermissions) so a
non-interactive claude applies edits without a human at the CLI, matching
codex'sapproval_policy=never. Unset preserves the legacy permission mode. - TUI & CLI authoring —
maestro setup trackerwizard writes
server.tracker(Linear) and chains theLINEAR_API_KEYprompt; the
full-screen TUI gains workflow editing (switch / new / delete / remove-role /
apply-template / validate) and detail-screen actions (run / edit /
approve-substitution / skip-role / switch-provider). Role detail and footer
keybinds wrap (ANSI-aware) instead of clipping.
Changed (BREAKING)
maestro serveis now a subcommand group, not a one-shot foreground
server. The v0.1.1maestro serve [--config] [--state-dir] [--port]
invocation no longer starts a server (maestro serve --config …errors with
unknown serve subcommand). Usemaestro serve start <name>afterserve add, or start a server directly with the flag-first formmaestro [--config <path>] [--port <n>](noserveword).
Changed
- Bare
maestroprints help (like git/docker/npm) instead of defaulting to
server mode, which previously died with a cryptic
unsupported_tracker_kind: missing. Flag-first invocations (maestro --port 4100) still start the server.
Fixed
- Engine — robust agent failure handling. Failure classifiers
(isUsageLimitFailure/isContextWindowFailure) now read only the error
channel (message + stderr + genuine stream-json error lines), so an agent that
merely discusses "rate limits" or "context windows" no longer false-trips a
retry. A claude run that emits a terminalsubtype:"success"is salvaged
instead of discarded asagent_failedon a non-zero exit (e.g. after gated
tool denials). A custom event routed to$completenow finalizes the run as
succeeded instead of stranding it as running. F7: SIGTERM timeouts escalate to
SIGKILL after a 2s grace. F8: stream tails decode through aStringDecoderso
a multibyte codepoint split across chunks reassembles. - Persistence — data-integrity + resource bounds. F5:
updateTaskreads
synchronously so concurrent updates to one id can't interleave and drop a
patch. F6: SQLite opens with WAL +busy_timeout=5000. F9: the rate-limiter
evicts the LRU bucket pastmaxBuckets. F4 (base):output_schema_refexpands
to an inline schema at workflow-load time (guarded byassertInsideDir) — the
foundation the schema-contract closeout above completes. - Project cleanup tolerates out-of-band-removed worktrees — a vanished
worktree path is no longercd'd into (which failed with an opaquespawn git ENOENT); cleanup clears git metadata best-effort and stays idempotent.
Security
- Dashboard XSS (F1) — the inlined snapshot JSON neutralized only lowercase
</script>; every<is now escaped, closing mixed-case</Script>and
<!--breakouts via attacker-influenced issue titles/descriptions. - Symlink-escape read boundary (F2/F3) —
assertInsideDirReal/
isInsideDirReal(realpath both ends) gate the MCP read tools, so a symlink
planted in an agent-writable run dir can't exfiltrate arbitrary files; the
assertInsideDirdocstring is corrected to state it is lexical-only. - Role
sourcepath-escape — the engine's source-resolution loop now guards
role.sourcewithisSafeRelativeRefbeforeloadRole(a../absolute
source becomes abad_role_sourceblocker), the sole enforceable gate since
composeRolestripssourcebefore the non-blocking validator. An
imported/shared workflow could otherwise read an arbitrary file into the agent
prompt and the run-manifest. - Secret handling (F10/F11) — stored secrets skip
ENV_KEY_DENYLISTkeys on
load (noLD_PRELOAD/NODE_OPTIONSpromotion intoprocess.env); KDF
N/r/pread from the secret envelope are bounds-checked before scrypt, so
a tampered envelope can't drive a decrypt-time CPU/memory DoS. servehardening — service overlays apply a var denylist and reject name
traversal; start fails fast on an unset api-key var or a port collision.- Dependency — bump the transitive
honopin to 4.12.25
(GHSA-wwfh-h76j-fc44, path traversal);npm audit --omit=devreports 0
vulnerabilities.
v0.1.1
v0.1.0
Initial release.
Added
- Plan → execute → review pipeline driven by a LangGraph state graph, with
typed handoffs between roles (raw agent logs never re-enter prompt context). - Six provider backends: claude, codex, copilot, gemini, antigravity, and a
built-in ollama adapter for fully local models. - Herdr terminal integration: one tab per task, agents run in visible panes.
Tabs close automatically on success, persist as a conversation trail while a
task waits on the user, and are reused when the task resumes
(herdr.close_tab_on:success|terminal|never). - Dual-backend persistence — SQLite task store (
node:sqlite) by default,
or PostgreSQL whenDATABASE_URL=postgres://…is set.openStore()routes to
PostgresTaskStore(pgpool) automatically; both backends share an
identical schema and a uniform async store interface. JSON-file mirror kept
for legacy readers. - Encrypted secret store —
maestro setup keys --encryptmigrates
.maestro/secrets.local.jsonto an encryptedsecrets.local.enc.json
(scrypt + AES-256-GCM, zero new deps) and shreds the plaintext. Unlock with
MAESTRO_SECRET_PASSPHRASEor an interactive prompt; real env vars still win.
maestro doctorreports the store mode.maestro setup hardeninstalls a
Claude Code guardrail (PreToolUse hook + deny rules) so only maestro reads its
secrets. Seedocs/configuration.md§ Secrets. - OpenTelemetry tracing — set
OTEL_EXPORTER_OTLP_ENDPOINTto export
traces and spans via OTLP/HTTP proto. Auto-instrumentshttp,pg, and
dns. Completely zero-overhead (no imports, no SDK init) when the env var
is absent. Override the service name withOTEL_SERVICE_NAME. - MCP server exposing eight
maestro_*tools for agent callbacks. - Interactive TUI (
maestro tui) for reviewing, approving, and answering tasks. - Interactive web dashboard — the HTTP server (
maestro serve) serves a
Linear-inspired browser UI at/:- Live task board polling
/api/v1/stateevery 5 s (active) or 30 s (idle)
with surgical DOM updates — no page reloads. - Filter tabs: All / Running / Retrying / Completed.
- Click any row to open a slide-in detail panel that fetches
/api/v1/<identifier>: shows issue state, attempt, timestamps,
description, priority, assignee, and full JSON. Actions: Copy JSON,
Raw endpoint link. - Trigger Refresh button (POST
/api/v1/refresh) with loading spinner;
Force-Poll button for immediate state sync. - Toast notifications and a live pulse indicator in the toolbar.
- Live task board polling
- Security model: host-command denylist, env secret stripping, path-traversal
guards, config redaction. - HTTP endpoint hardening — the dashboard/API server (
maestro serve)
applies a per-IP token-bucket rate limit (reads ~120/min, writes ~12/min;
429+Retry-Afterwhen exceeded) and validates input on every route:
issue identifiers are length-capped and charset-restricted (malformed input
→400instead of500), and oversizedPOSTbodies are rejected (413).
Disable withMAESTRO_HTTP_RATELIMIT=off. MCP tool inputs (ids, prompt,
status, mode) gained matching length/type validation. - Headroom context compression for prior-output pipelines.
- Linear tracker integration (server mode).
- GitHub Actions CI: lint (Biome), test matrix (Node 22/24 on Linux plus a
macOS leg), coverage (c8) with an enforced threshold gate, dependency
audit; Dependabot for npm and Actions updates. maestro init --workflow <name>workflow templates:default(planner →
executor → reviewer) andextended, which adds a read-only System
Evaluator role — the reviewer can escalate hard cases via
MAESTRO_HANDOFF: {"event":"escalate",...}, and
maestro task --mode evaluateruns a standalone principal-level audit.- Two more workflow templates:
local(every role on ollama, zero cloud) and
solo(executor only, fastest loop). maestro workflow use <name>— switchworkflow.jsonto any built-in
template; the previous file is always backed up toworkflow.json.bak.maestro doctor [--json]— read-only preflight: node version, provider CLI
presence + versions, herdr availability, and state-dir health (config,
workflow validation, db, secret store mode). Exit 1 on any failing check.- Automatic herdr → terminal backend fallback: when the herdr binary isn't on
PATH, tasks run on the terminal backend with a one-line notice instead of
failing (MAESTRO_BACKEND=terminalstill forces/silences it). - End-of-run summary: after
maestro task/run-task, a per-role table
with duration, stdout size, and status; steps now persiststarted_at
alongsidecompleted_at. - npm publish metadata (
repository,license,author,keywords,
prepublishOnly) and aRELEASING.mdrelease checklist. - Tag-triggered GitHub Release workflow: pushing
vX.Y.Zlints, tests,
verifies the tag againstpackage.json, and publishes a Release with the
matching changelog section and the packed tarball (npm publish stays
manual). - Community health files: issue forms, Contributor Covenant 2.1 code of
conduct, CODEOWNERS, and a documented platform policy (Linux/macOS;
Windows via WSL2).
Changed
- Project renamed from Symphony to Maestro.
maestro task --plan-onlynow errors withunknown_modewhen the workflow
defines noplan-onlymode (previously it silently fell back to
workflow.initialand ran a full write-enabled pipeline).- The init wizard prints a one-line explainer before each setup question.
- Full-screen TUI (
maestro tuion a real terminal): keyboard-driven task
board with filter views and live refresh, task detail with one-keystroke
approve/deny/message/retry/cancel/mark-done/resume/extend, a settings
editor, and a workflow graph screen that renders roles, handoff arrows, and
event transitions as a responsive grid (vertical stack on narrow
terminals). The classic prompt-driven TUI remains the fallback for non-TTY
use and viaMAESTRO_TUI_CLASSIC=1. --help/-h/helpCLI usage output.bin/maestro.mjsis now a thin entry shim; the CLI implementation lives in
src/cli/modules (no behavior or public-surface change).
Fixed
- MCP server no longer throws at import time when no
.maestrodirectory
exists up-tree; root discovery is lazy and errors surface on first tool call. - The
node:sqliteExperimentalWarning is no longer printed on every CLI and
MCP server run; other process warnings still pass through. - Captured agent stdout/stderr are stripped of ANSI/VT control sequences before
entering handoff payloads and the console (on-disk logs stay raw), so CLIs
that redraw streaming progress no longer leak cursor-move escapes. scripts/is now included in the published package, somaestro setup harden
(which installs a hook backed byscripts/secret-guard.mjs), the
agent:ocr/agent:evalexample agents, andheadroom:setupwork from an
installed package instead of only from a git clone.- The
agent:ocr/agent:evalscripts fail fast with an install hint when the
Ollama binary is absent, instead of surfacing a raw spawn error mid-run.