A multi-model agent-orchestration kernel, in Rust.
· 简体中文
Vyane is one kernel — and one CLI over it — for dispatching, broadcasting and failing over tasks across both coding-agent harnesses (Claude Code, Codex CLI, …) and raw HTTP model endpoints. Point it at a task and a target and it runs it; point it at several targets and it fans out or fails over. Whether a run happens inside a coding CLI with a filesystem and tools, or as a plain chat completion over HTTP, is one field on the target — not a different tool, a different config file, or a different mental model.
The differentiator is the four-layer target model. Provider, protocol, harness and model are independent axes and are never conflated. A provider is who supplies the endpoint, key and billing; a protocol is the wire format; a harness is the execution shell (or none, for direct chat); a model is the inference model. So: a relay is not a protocol (it is a provider that happens to speak one), a coding CLI is not a provider (it is a harness that still needs one), and a model id is only valid within one provider. These stay four separate fields from configuration all the way into the run ledger, which is what lets Vyane do the correct thing at the boundaries where lazier tools quietly break.
Concretely, that buys you: clean-env subprocess spawning by construction —
child agents are launched from a scrubbed baseline environment, so the calling
session's credentials and base-URL overrides never leak into them; failover
chains that never leak a model id across providers — each element of a chain
is resolved fully and independently, so a fallback always uses the model that
belongs to the provider it runs against; whole-chain capability admission —
Write/Full cannot silently run on a chat-only target, and Linux mutating
runs retain the admitted directory object across child spawn; and an
append-only JSONL run ledger that records prompt digests (not prompt
bodies), the full attempt
trail of every dispatch, and owner-scoped records from day one so
multi-user isolation never needs a schema retrofit.
vyane-rs is the open-source Rust implementation of Vyane, a private personal
AI-OS execution substrate that has been running real multi-model development
pipelines since early 2026. It is being rebuilt here in the open, capability by
capability, tracking the private system as it evolves — so the design reflects
what actually held up in daily use, not a greenfield guess.
This repo is developed by an orchestrated fleet of AI coding agents: different
frontier models write the code, adversarially cross-review each other's work,
and fix what the review turns up, all under a human-owned architecture and
integration gate. Code changes go through tiered independent
review — docs merge on CI
green, standard code gets one independent model review, high-risk surfaces
get adversarial multi-round review — plus the cargo fmt / clippy /
cargo test gates described in CONTRIBUTING.md. No
product change lands on the say-so of the model that wrote it.
The repository-local v0.1 through v0.3 milestones and v0.4 implementation
scope are delivered. External crates.io publication (to Rust's public package
registry) is a deferred distribution action, not a feature milestone, and
requires separate authorization; a tag or registry token is not that
authorization. The manual release workflow additionally requires a protected
crates-io environment approval by a reviewer other than the dispatcher and
requires the supplied release tag, current main, and workflow SHA to identify
one exact commit. The registry token is exposed only to the final publish step.
The 17-crate local package preflight passes, but no crate has
been published. This does not mean full parity with the original private Vyane
system. In the current public integration baseline, the fixed cross-repository matrix
tracks 53 capabilities across eight domains: 7 implemented, 23 partial, 12
missing, 9 deliberately different or awaiting a decision, and 2 planned. It
records substantial native-harness, continuity, collaboration, governance,
observability, and interface work still to do. Unqualified “full parity” means
whole-system capability parity: private credentials and deployment details stay
out of this public repo, but their generic contracts and optional/private
adapter boundaries still need verifiable coverage. Live daemon pause/resume and
automatic restart replay are two explicit daemon limits, not the whole remaining
parity backlog. See the
original-Vyane parity baseline. APIs
remain unstable pre-release; the CLI runs real dispatch/broadcast/failover
today. The public parity manifest now contains 25 sanitized cases across
classifier, failover, and automatic-routing suites; 15 match after their
declared normalization and ten remain explicit open differences or one-sided
Rust scope differences. Run python3 .github/scripts/parity-report.py --format markdown to recompute current Rust behavior, validate the stored sanitized
attestation, and print an offline report. It does not execute the private
reference implementation.
| capability | crate | state |
|---|---|---|
| core type system (four-layer model, traits, errors, env policy, process-local workdir pin) | vyane-core |
[x] includes the non-serializable live native-side-effect authority contract |
| config & profiles | vyane-config |
[x] |
| OpenAI-Chat + Responses + Anthropic-Messages clients | vyane-protocol |
[x] baseline clients; [~] bounded typed tool turns and the per-wire authorized path currently cover non-streaming OpenAI Chat only |
| Claude Code + Codex CLI harnesses, including stdout event streaming | vyane-harness |
[x] additive scoped execution carries the Linux pinned workdir and an optional live spawn authority; the Process AgentRun host constructs that authority for fresh sessionless CLI runs, and gated capture/streaming revalidate before wrapper spawn and real-target release. This remains adapter-delegated rather than a host sandbox |
native permission/tool execution seam (not yet a general Harness implementation) |
vyane-harness + vyane-service |
[~] the resident fresh/sessionless native AgentRun lane combines atomic scope validation, per-wire model authorization, the bounded serial turn driver and durable completion. WP-83 adds descriptor-relative read/search/write/edit built-ins bound to the admitted PinnedWorkdir. WP-84 adds an independently configured structured command tool under a Linux read-only Bubblewrap profile; WP-85 optionally grants that command a bounded HTTPS destination policy without sharing the host network. WP-86 adds a separate hosted web_search tool with a frozen Responses target, domain narrowing, source validation and per-attempt live authority. WP-87 adds a separately configured web_fetch tool with HTTPS/domain, public-address, redirect, content and byte limits. WP-88 composes independent user, project, explicit and operator-managed permission ceilings without letting config grant a tool. WP-90 adds explicit descriptor-bound command writable roots while keeping the rest of the workspace read-only. WP-91 freezes layered per-tool allow/ask/deny decisions, and WP-92 adds bounded failover across frozen direct OpenAI Chat targets before any tool side effect. Session authority, checkpoint/session commit, approval resume, automatic replay and native resume remain open |
| dispatch / broadcast / failover kernel | vyane-kernel |
[x] early execution id, whole-chain trusted capability admission, one-shot prepared dispatch and original-ordinal failover evidence |
| append-only run ledger + owner-isolated session records | vyane-ledger |
[x] direct-HTTP transcript continuation plus strict revisioned V2 snapshots, store-level CAS Reset / ForkFresh / Commit, and an exact local-filesystem execution-period lease; CLI/service control is limited to owner-local list/inspect/reset-native, with no public fork, REST mutation, distributed lease protocol, or production native resume |
| replayable owner-scoped event store | vyane-ledger |
[~] storage/cursors, bounded message and AgentRun lifecycle projection, and owner-bound resident broker/projector assembly in the daemon now exist; delivery lanes, dispatch/workflow producers, subscription, retention and a unified timeline remain |
| durable, secret-free task metadata | vyane-task |
[x] schema v2 keys snapshots, events and CAS by (owner,id) with transactional v1 migration; built-in frontends still select explicit local |
| durable owner-scoped AgentRun queue, worker topology and recovery truth | vyane-agent |
[~] exact leases/deadlines, active permits, bounded tree cancel, body-free completion receipts/outbox, and resident execution/recovery/publication are production-assembled for narrow Linux Process and fresh/sessionless Native lanes with an authenticated loopback submit/status/output/cancel API. Remote, native sessions/resume, distinct principals, live pause/resume, and automatic replay remain absent |
| owner-scoped transactional message/delivery store | vyane-message |
[~] multi-mailbox strict FIFO, delayed/idempotent delivery, fenced leases, TTL, ack/nack, body-free outbox, external-receipt reconciliation, hidden staged completion publication, bounded mailbox pages, and exact mailbox claim exist |
| owner-scoped goal lifecycle and progress truth | vyane-goal |
[~] one SQLite transaction updates the current snapshot and appends an immutable event; WP-68 through WP-75 add bounded verification/evidence, pursuit/checkpoint/daemon composition and explicit approval-gated continuity through reviewed takeover handback. WP-76 adds exact typed quota-reset ingestion whose dependency release is arrival-order independent. WP-77 extends the same durable decision and one-shot dispatch boundary to a ready primary continuation. WP-78 adds observation-identified and sequenced review-check pass/fail evidence plus an approval-gated repair handback; stale replay cannot reopen the gate, repeated failures reopen repair, and resume recursively binds the latest repair/review/takeover evidence. WP-79 adds a read-only, revision-bound operator next-action projection over the current goal and approval evidence. WP-80 exposes only that projection through an opt-in, owner-frozen, bearer-authenticated loopback REST GET with an atomic redacted snapshot. WP-81 adds a separate owner-frozen/source-bound mutation port and one-shot bounded typed watcher poller; it records only existing continuity signals. WP-82 adds a purpose-authenticated, one-shot bounded runner that can invoke separately configured queue and approved-execution ports with an exact projection fence; it has no decision port, so every approval decision remains manual. Concrete ports, daemon scheduling, runtime-native resume and a general authenticated goal service remain future layers |
| bounded platform-neutral upstream quota snapshots | vyane-quota |
[~] closed card/window/balance and error schemas, validated connector identity, stable sorted snapshots, bounded concurrency, whole-operation timeout, failure isolation, redirect-closed HTTP and a body cap; no concrete provider connector, credential loader, durable history, polling daemon, CLI snapshot surface or automatic action |
| bounded replay-safe delivery broker + body-free EventLog projectors | vyane-broker |
[~] fake-adapter contracts, message/AgentRun lifecycle projection with stable source event IDs, and the explicit non-Clone ResidentBrokerSupervisor are assembled into the resident daemon with an intentionally empty delivery lane set; worker/message glue and remote A2A/Channels adapters remain absent |
| declarative workflow engine (DAG + journal/resume/replay) | vyane-workflow |
[x] exact-plan replay creates a new run and reuses a journal-recorded all-success prefix |
| resident workflow plus Process and Native AgentRun daemon (authenticated local control) | vyane-cli |
[x] workflow control plus Linux CLI-harness Process and fresh/sessionless Native AgentRun submit/status/output/cancel; no native session resume, automatic replay or live pause/resume |
detached background runs (--detach + task commands) |
vyane-cli |
[x] |
| CLI (check / dispatch / broadcast / history / session / sessions / workflow / task / daemon / a2a / goal) | vyane-cli |
[x] revision-aware session control, local a2a send/inbox/read, and owner-scoped goal lifecycle/progress commands; legacy sessions remains compatible |
| shared service layer | vyane-service |
[x] OwnerContextFactory authenticates and resolves a reserved-local-safe authority; OwnerScopedService freezes dispatch/stream/query/session/reset. AgentRun components include prepared authorized harness dispatch, paired Process/Native backends, exact message-completion handback, and the generic resident host used by the daemon; ordinary dispatch starts none of them |
REST API (vyane serve — dispatch/broadcast/runs/sessions/health) |
vyane-cli + axum |
[x] per-start bearer capability, loopback Host/Origin enforcement, non-loopback bind rejection, allowlisted views, and one assembly-frozen local service scope; the bearer still is not a distinct principal or hostile same-UID/multi-user boundary |
MCP server (vyane mcp — nine tools) |
vyane-mcp + rmcp 3.3 |
[x] six base tools plus authenticated durable workflow submit/status/cancel; generic success output has a 1 MiB cap; stdio dual-era handshake keeps initialize on 2025-11-25 and can negotiate MCP 2026-07-28 over server/discover |
| pluggable routing | vyane-router |
[x] |
| solution-review workflow (implement → fan-out review → synthesize) | vyane-cli (review module) |
[x] not yet the original system's structured git diff/PR review product |
Capability admission is deliberately narrower than a sandbox. ReadOnly works
with chat or harness targets. Write/Full requires an existing workdir and a
trusted built-in Claude/Codex CLI editing manifest; direct HTTP and unknown
adapters are rejected before executor construction. Mutating dispatch currently
fails closed outside Linux. The pinned descriptor prevents workdir path
replacement, but does not confine a hostile same-UID child or absolute-path
access. The exact NativeSessionDomain storage contract and store-level CAS
transitions now exist, but they are evidence rather than resume authority.
Regular dispatch requires an exact (owner, session_id, execution_id) lease,
acquires it before loading continuity, and retains it through model execution
and a revision-CAS completion update. The filesystem store uses an owner-only
advisory lock, serializes direct control mutations against the same authority,
and prevents same-session runs from overlapping: a competitor either acquires
the lease after a bounded wait or receives Conflict, always before executor
construction. This is a local crash-released fence, not a distributed
generation/TTL protocol; the
post-model session commit also remains best-effort and must not be described as
strict durable continuation. Regular dispatch still rejects legacy-unbound or
domain-bound native harness state before executor construction. Streaming
dispatch rejects any session even earlier, before session-store load,
capability probe, or executor construction. Pure direct-HTTP transcript
continuation remains available only through regular dispatch. The owner-local
CLI/service exposes list, inspect, and revision-checked reset-native; it exposes
no public fork, REST mutation, or production native resume.
The native authority work remains an incomplete integration seam. A separate
OpenAI Chat typed-turn path revalidates immediately before every explicit wire
send; cancellation remains live through authority wait, send, response-body
read and retry backoff. The shared HTTP client follows no redirects and performs
no implicit retries, so one explicit attempt corresponds to one authority
check. ToolRegistry::execute_authorized similarly revalidates only an allowed
call immediately before executor polling; deny/ask/invalid/unknown/cancelled/
expired decisions remain pure and revocation stays outside model-facing tool
text. AgentRunModelToolAuthority is now a concrete bridge for a fresh,
sessionless scope: it owns the permit and scope, revalidates the AgentRun store
on Tokio's blocking pool for each one-based model send or tool operation, and
rejects session-bearing scopes, checkpoint effects, and session commits. The
fresh/sessionless resident Native lane now registers and calls this bridge; it
still does not combine a session lease with an exact native-session domain.
The paired in-process operation can now bind its lifetime-bound effect
authority to one exact fresh, sessionless NativeExecutionScope. Binding first
atomically validates owner/run/generation/lease/deadline/controller plus exact
target, prompt and policy digests; each subsequent one-based model send or tool
operation repeats that full native-scope validation. Session/resume scopes,
checkpoint/session-commit effects, raw store/permit access and cloning or
serialization remain closed. This authority composition seam now underpins the
concrete fresh/sessionless Native operation and result handback from WP-65 and
WP-66; it does not authorize session-aware execution. See
WP-52, WP-65, and
WP-66.
NativeTurnDriver supplies the resident Native lane's bounded serial
model/tool loop. It
defaults to eight model turns with a hard ceiling of 32, permits at most one
tool call per turn, requires the initial advertised tool-name set to equal the
registry-name set, validates every request/response, and preflights the complete
next transcript with a worst-case bounded tool result before any permission or
tool future can run. Model sends and allowed tools use only the authorized
entry points. Refusal, approval-required, parallel calls, tool-choice
violations, cancellation, timeout and budget exhaustion are typed terminal
stops; usage addition saturates, and post-tool model failure becomes a redacted
non-replayable stop rather than an outer failover error. Invalid JSON arguments
produce static non-echo tool text and never execute. Tool descriptions and
schemas are non-authoritative model guidance; each NativeTool must validate
the actual arguments it receives.
The driver's outcome is non-serializable and has redacted Debug. The explicit
fresh/sessionless resident Native lane constructs it with separately authorized
filesystem read/search/write/edit, sandboxed command, command-network,
hosted-search and bounded-fetch tools. Layered configuration can only narrow
explicitly requested tools, and ask remains a terminal approval-required stop.
This is still narrower than a general Harness: checkpoint/session-commit
consumers, approval resume and native resume remain absent. Separately,
AgentProjectionComponents::open provides an
explicit owner-bound path to the one-shot AgentRun projector while keeping the
raw store encapsulated. Ordinary dispatch neither opens that database nor
starts projection or other resident work.
WP-65 provided the original dark composition slice: a private native
spool, exact fresh/sessionless scope, authorized OpenAI Chat client, tool-free
NativeTurnDriver, and exact durable message-completion acceptance path. It is
now production-assembled by the later Native lane. WP-83 through WP-88 and
WP-90 through WP-92 add the separately authorized filesystem, command,
network, search/fetch, layered permission and pre-side-effect failover slices
without claiming session-aware authority, approval resume, automatic replay or
general parity.
vyane-service::AgentRunRecoveryDriver is another explicit fixed-owner,
non-Clone one-shot seam. Construction freezes the owner, injected store,
options and at most one trusted adapter per ControllerKind; recover_once
consumes the driver. Recovery claim and final confirmation run on Tokio's
blocking pool. One pass is capped at 64 tickets and 16 concurrent adapter
calls, each adapter timeout is at most 60 seconds, and the durable operation
lease is at most five minutes and must be strictly longer than the timeout plus
settlement margin. A conservative caller-local monotonic window starts before
the blocking claim, so claim latency is deducted and a custom store's wall
clock cannot extend adapter authority. Only a controllerless ticket or an
affirmative Gone observation for the exact controller can reach
confirm_controller_gone; reports and errors are body-free and recovery
tickets never cross the adapter boundary.
Standing alone this one-shot driver is not a resident worker-health or execution
loop. WP-51 first composed the paired in-process backend; WP-61 uses the generic
supervisor with an exact Linux Process adapter in the workflow daemon, and
WP-66 adds the fresh/sessionless Native lane. There is still no Remote
adapter, session-aware resume, live pause/resume, or automatic replay.
Controller adapters must revalidate the
complete identity before every effect, return Unavailable without an effect
when identity reuse cannot be excluded, and remain safe to repeat after
timeout, drop, or settlement failure. A custom store's blocking call cannot be
forcibly cancelled, and an adapter timeout bounds future polling rather than
proving a non-abortable external effect stopped. See
WP-45 for the exact boundary.
vyane-service::AgentRunExecutionDriver complements recovery with a separate
fixed-owner, non-Clone, consuming one-shot pass over newly due runs. A pass
admits its whole claim on Tokio's blocking pool and is capped at 64 runs, 16
concurrent polls, a five-minute lease, and heartbeat intervals from 100
milliseconds through 60 seconds that must remain below the lease. Its monotonic
base starts before claim. For every admitted item it generates independent
256-bit prospective controller id and fingerprint material, then orders claim,
durable start, permit issue, a pre-effect heartbeat, and only then the first
executor poll. The trusted executor must revalidate the permit at every actual
effect, and custom stores are checked after every transition.
Only a Quiesced closed outcome authorizes the driver to initiate terminal
settlement. A single item future owns and advances the receipt. Before that
proof, cancellation, timeout, panic, drop, Unknown, or heartbeat failure
authorizes no new settlement and may leave Starting or Running for WP-45
exact-identity recovery. Once a blocking settlement call has started it cannot
be interrupted and may outlive a dropped waiter; a custom store can also
mutate-then-error, so a reported settlement failure is uncertain. WP-47 remains
the generic one-shot contract. WP-61 production-assembles it with a fresh
sessionless CLI-harness executor, exact Process controller, and message
handback. That narrow assembly does not add native execution, Remote,
session-aware resume, live pause/resume, or automatic replay. See
WP-47 and WP-61.
InProcessAgentComponents now supplies one concrete pairing for those one-shot
drivers. It admits one live backend per owner process-wide, regardless of store
pointer; that backend binds one store and structured operation and mints both
InProcess executor/recovery drivers. Exact id/fingerprint matching,
Notify-based cancellation/exit observation, and a fail-closed 4096-entry
tombstone bound prevent a late or reused controller from being mistaken for the
one being recovered. Durable confirmation reclaims the exact tombstone; failed
or uncertain confirmation retains it, and a post-reclamation late registration
must revalidate its permit again before operation code runs. Operations receive
a lifetime-bound non-Clone effect authority and must consume a freshly
revalidated permit proof immediately before every effect.
ResidentInProcessAgentSupervisor can consume this exact pairing into separate
execution, recovery, and completion-publication polling loops. It validates poll/backoff bounds, applies
capped exponential backoff to degraded/error/panic cycles, creates no task,
channel, runtime, payload queue or replay policy, and never automatically
enqueues resume. Supervisor cancellation stops new cycles and is forwarded to
an executor already being polled; the Process backend terminates and reaps its
exact group, records the stopped lifecycle, and the driver awaits the item
before the completion loop's final drain. Forced drop still forfeits that
guarantee, and a custom blocking store means drain has no fixed wall-clock
bound. The generic
ResidentAgentSupervisor first consumed a concrete Linux Process backend in
the daemon; WP-66 subsequently production-assembled the fresh/sessionless
in-process Native operation as a second lane. The
generic handback contract is defined in WP-53, the
original resident boundary is in WP-51, and the production
Process and Native scopes are in WP-61 and
WP-66.
ResidentAgentHost is the bounded multi-lane service substrate above those
single-lane facades. It runs one exact durable-backend execution loop per lane
while sharing one validated recovery-adapter union and one completion
projector. Lane failures and backoff are isolated, but store ordering remains
cross-backend. The current daemon installs the Linux Process lane and the
fresh/sessionless Native lane; Remote remains unassembled. See
WP-64 and WP-66.
The WP-61 host accepts authenticated loopback AgentRun requests only through
the workflow daemon. It freezes a private create-only prompt spool together
with the exact resolved target chain, capability plan, canonical workdir,
sandbox, timeout, system text and labels. Only fresh, sessionless CLI harness
targets are admitted. The executor revalidates the active permit and frozen
snapshots before wrapper spawn and every real-target release. A private
controller sidecar is durably reserved before Running, then advanced to the
exact Linux process identity before target release. Sequential
failover stops the old controller before starting the next. Success requires a
quiesced process lifecycle and typed terminal proof; in particular, Claude
exiting zero without a JSON result is a failure. Completion is staged under a
stable key and returned only after exact message publication.
The Native lane freezes a private prompt spool, direct OpenAI Chat target chain, policy digest, workdir identity, timeout and turn limit before durable creation. It re-resolves the complete chain before the first wire request, revalidates live authority at every model/tool effect, and may fail over only for the shared eligible error taxonomy before any tool side effect. Trusted filesystem, command, command-network, hosted-search and bounded-fetch tools remain separately authorized and configuration can only narrow the explicitly requested set. See WP-66 and WP-83 through WP-88, and WP-90 through WP-92.
The daemon exposes POST /v1/agent-runs, status, output and cancel routes under
its existing bearer and loopback restrictions. Startup performs exact stale
backend recovery without replay. Graceful shutdown first closes admission
and drains admitted submit/cancel initialization, then signals the AgentRun
supervisor and awaits it concurrently with workflow-supervisor drain. An active
Process group is cooperatively terminated and reaped before completion's final
drain. This is not a Remote or session-aware native host, does not support
native resume, live pause/resume or automatic replay, and the local bearer still
does not represent distinct principals or hostile same-UID isolation. See
WP-61 and WP-66.
The Process-lane graceful drain and daemon-level Native graceful-shutdown race
are acceptance-covered, including deadline-bound restart settlement without
input replay or output publication. Startup and forced-restart fixture
stabilization are documented in WP-95 and
WP-96.
The service layer also has a principal-derived owner phase-A boundary.
OwnerContextFactory freezes a trusted authenticator and resolver, keeps
AuthenticatedPrincipal construction private, rejects authenticated entry to
the reserved local namespace, and mints a non-serializable redacted
OwnerContext. OwnerScopedService freezes that owner into dispatch,
single-target streaming, history, session inspection, and revision-checked
reset. Existing frontends explicitly retain trusted single-user local
compatibility; REST freezes all of its dispatch/broadcast/run/session/stream
operations into one such local scope at router assembly, but its bearer does
not yet represent distinct principals. See WP-49.
Durable task schema v2 now keys snapshots, events, leases and CAS by
(owner,id), so two owners can safely reuse one task id. Its v1 migration is
transactional and verifies counts, foreign keys, schema and event-sequence high
water before commit. REST outputs use opaque owner/task-qualified artifact
segments with an exact local-UUID legacy read fallback. Built-in task control
still selects only local, and the old detached filesystem scaffold remains a
local compatibility subsystem; this is therefore storage isolation, not a
multi-user REST claim. See WP-50.
vyane-broker::ResidentBrokerSupervisor is a separate explicit, non-Clone
library driver. Its consuming run future concurrently owns disjoint
owner/store-bound delivery lanes, message maintenance, message projection and
AgentEvent projection. Batch sizes, aggregate delivery concurrency and
exponential error backoff are validated and bounded; one lane's error or panic
does not stop unrelated lanes or projectors. The driver creates no detached
task, channel, runtime or second queue: the embedding caller supplies a Tokio
runtime and cancellation token and must await the future. Cancellation is
observed only between cycles, so an operation already in progress drains its
current bounded cycle; dropping the outer future forfeits that graceful-drain
guarantee.
No service, CLI or daemon production assembly constructs this driver yet. It does not execute or recover AgentRuns, provide controller/message handback, implement A2A or Channels, or add live pause/resume or automatic replay. See WP-44 for the exact boundary.
Vyane supports three interchangeable front-ends, all sharing the same
vyane-service layer so dispatch semantics are identical:
| protocol | command | use case |
|---|---|---|
| CLI | vyane dispatch --target prod "task" |
interactive / scripted one-shot runs |
| REST API | vyane serve --addr 127.0.0.1:9721 |
programmatic access from any HTTP client |
| MCP | vyane mcp |
let other agents (Claude, Codex, …) call vyane as a tool |
The production CLI MCP surface contains nine tools: dispatch, broadcast,
history, sessions, vyane_route, vyane_check, and authenticated durable
workflow submit/status/cancel. Generic success payloads have a 1 MiB cap;
the two new diagnostics use stricter, smaller bounds. vyane_route is a
Rust-side deterministic preview extension, not a same-name parity claim
against the fixed reference baseline. vyane_check performs static
configuration analysis only; it does not probe a network endpoint, spawn a
harness, or validate a live credential. Every success result shares the generic
output ceiling, but the legacy execution tools do not yet have the diagnostics'
uniform field-level input budgets. If execution completed but detail exceeded
the ceiling, dispatch/broadcast returns bounded run receipts with
operation_status="completed" and detail_omitted=true; callers must not retry
those receipts as though execution failed.
Workflow callers provide a canonical UUIDv7 plus a bounded self-contained source bundle. The MCP layer cannot provide owner, controller, token, or an execution path. The CLI freezes its own startup directory and re-authenticates the exact resident daemon for every workflow operation. Responses contain only the caller id, lifecycle state, and a closed failure code. Explicit step workdirs and sandboxes above read-only are rejected before daemon contact. This is durable workflow control, not general task, board, collaboration, or multi-principal MCP parity.
The CLI exposes the transactional message store as a same-machine durable inbox:
vyane a2a send reviewer --from builder --kind review "ready for review" --json
vyane a2a inbox reviewer --json
vyane a2a read reviewer <message-id> --jsoninbox is non-mutating. read requires the recipient mailbox as well as the
message id, then uses the existing fenced claim → delivered → acknowledged
state machine. It writes and flushes the full response before acknowledging;
write failure remains reclaimable, while a crash after flush can produce a
duplicate instead of message loss. Its JSON payload is therefore a pre-ack
delivered snapshot; exit status zero confirms the subsequent acknowledgement.
--delay-seconds, --include-future, --include-read,
--limit, --owner (alias --owner-user-id), and --db provide explicit
local control. The default database is the standard messages.sqlite3 below
the Vyane data directory.
This is not an A2A HTTP implementation. It has no Agent Card, discovery,
remote send/get/cancel, SSE, push, or Channels adapter. --owner and --from
are supplied by the caller: the former is a logical storage scope and the
latter is only a sender label, not authenticated principal authority or
identity. Do not expose this CLI directly as a hostile multi-user service.
See WP-59 for the exact boundary.
The CLI exposes an owner-scoped goal lifecycle over one SQLite source of truth:
vyane goal create --title "Ship a release" \
--acceptance 'test-passes:cmd:cargo test --workspace' --json
vyane goal next --auto-start --json
vyane goal progress <goal-id> --stage implementation --detail "tests added" --json
vyane goal verify <goal-id> --workdir . --json
vyane goal claim <goal-id> --worker pursuer --json
vyane goal pursue <goal-id> --worker pursuer --target builder --workdir . --sandbox write --json
vyane goal continuity-next <goal-id> --json
vyane goal done <goal-id> --summary "all checks passed" --jsoncreate/get/list/next/start/claim/progress/verify/pursue/pause/resume/done/fail/cancel share stable
JSON success/error envelopes. Every mutation updates the current query snapshot
and appends an immutable revision event in the same transaction. Queue selection
orders priority ascending, then creation time ascending. The default database is
goals.sqlite3 below the Vyane data directory; --db selects another local
file. --owner (alias --owner-user-id) is a caller-selected storage scope,
not authenticated authority. Foreign and absent ids are intentionally
indistinguishable at the store boundary.
Acceptance KIND:TARGET values remain persisted descriptors. goal verify
executes only explicit local cmd: checks under a canonical workdir, scrubbed
environment, bounded output/time and Unix process-group cleanup, then persists
passing criteria through the existing lease-fenced mutation. The goal must be
in_progress; an active lease requires the matching --worker. It does not
auto-complete or pursue goals, invoke network/board adapters, coordinate quota
handoff, or expose a goal REST/MCP service. See WP-60 and
WP-68 and WP-69. Each verification
attempt is retained as a private, immutable, digest-checked artifact and is
returned by goal get --json; it is evidence, not completion authority.
goal pursue is the explicit bounded outer loop: verify, dispatch one fresh
sessionless segment through the ordinary target/failover kernel, then reverify.
It requires and renews the exact active worker lease. A schema-v4 checkpoint
atomically preserves lifetime segment/failure counters, runtime/workdir identity,
and the last run and verification ids with each progress event. After pause and
database restart, an explicitly resumed goal can be claimed by a new worker and
continues from that checkpoint; stale revisions, workers and lease generations
fail closed. Only the pursuer may
complete after all criteria pass. Missing/manual criteria,
budgets, cancellation and repeated failures pause; external lifecycle changes stop. The
manual command does not auto-start a goal, resume a runtime-native session, or
perform quota/approval handoff. The resident daemon can separately opt in to the
same pursuer as described below.
The production CLI currently accepts only the local single-user owner so goal
and dispatch ledger authority cannot silently diverge.
See WP-70, WP-71,
WP-72, and WP-73.
goal continuity-next is a read-only operator projection over the exact current
goal revision, quota boundary, handoff steps, and durable approval evidence. It
returns one closed action such as queue, decide, execute, record a signal, wait,
resolve a blocked execution, or continuity complete. It never performs that
action and never invents required workdir, decision, or signal evidence. See
WP-79.
The REST assembler explicitly opts into the goal read component and exposes the
same projection as GET /v1/goals/{id}/continuity-next on the
bearer-authenticated loopback server. That REST instance of GoalReadService
freezes the local owner at construction, observes the goal and its approval
evidence in one read transaction, and returns only an allowlisted redacted DTO. A request cannot
select an owner. The component has no goal list/get, MCP, queue, decision,
execution, signal or runner surface and cannot complete a goal. The bearer is
not a distinct principal and does not provide hostile multi-user or same-UID
isolation. This fresh continuity view is also not runtime-native session
resume. See WP-80.
GoalObservationIngress is a separate opt-in mutation component. It freezes an
authority-supplied owner, binds a trusted non-secret watcher identity as the
signal source, and accepts only typed quota-reset or sequenced review-check
observations for an exact current quota/primary-target boundary. The one-shot
GoalObservationRunner bounds watcher count, concurrency, timeout and batch
size, isolates failures, and applies accepted batches in deterministic watcher
order. It has no HTTP/MCP/CLI endpoint, concrete connector, periodic loop,
approval or execution authority; it cannot complete a goal. See
WP-81.
GoalContinuityRunner consumes that closed next-action view for a bounded goal
set. Read, queue and execute credentials are authenticated through separate
purpose policies and must resolve to one owner. Each port retains that same
opaque owner context, and assembly rejects a mismatched binding. Queue and
approved-execution ports receive only the exact goal revision, quota boundary,
step and approval fence; there is no decision port, raw dispatch input, retry or periodic loop.
The crate supplies no concrete queue/execution adapter, so assembly remains
explicit. See WP-82.
vyane serve exposes a JSON HTTP API with streaming (SSE) and async task
support:
| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/health |
health check |
POST |
/v1/dispatch |
dispatch a task (synchronous, blocks until done) |
POST |
/v1/dispatch/stream |
dispatch with SSE streaming (deltas as they arrive) |
POST |
/v1/broadcast |
fan out to multiple targets concurrently |
POST |
/v1/tasks |
submit async dispatch, returns task id immediately |
GET |
/v1/tasks |
list durable REST task metadata |
GET |
/v1/tasks/:id |
get one task's durable status and ledger link |
GET |
/v1/tasks/:id/output |
read a successful task's separate mode-0600 output artifact |
POST |
/v1/tasks/:id/cancel |
cancel a running task |
GET |
/v1/runs |
query the run ledger (filter by status/provider) |
GET |
/v1/sessions |
list saved sessions |
SSE streaming events (POST /v1/dispatch/stream):
data: {"type":"delta","text":"Here is "}
data: {"type":"tool_use","name":"Read","summary":"{\"path\":\"src/lib.rs\"}"}
data: {"type":"delta","text":"a function..."}
data: {"type":"finished","record":{...},"output":"Here is a function..."}
Async task lifecycle (POST /v1/tasks → poll GET /v1/tasks/:id):
# Use the exact mode-0600 token path printed by `vyane serve`. Feeding this
# header through curl config stdin keeps the bearer out of argv and the process
# environment. The token is removed after a clean shutdown.
TOKEN_FILE='<path printed by vyane serve>'
rest_auth() {
printf 'header = "Authorization: Bearer %s"\n' "$(<"$TOKEN_FILE")"
}
# Submit
rest_auth | curl --config - -X POST http://localhost:9721/v1/tasks \
-H 'Content-Type: application/json' \
-d '{"task":"write tests","target":"openai/gpt-4o"}'
# → {"id":"0195...","state":"running","task_digest":"...",...}
# Poll
rest_auth | curl --config - http://localhost:9721/v1/tasks/0195...
# → {"id":"0195...","state":"succeeded","ledger_run_id":"0195...",...}
# Read the result body after success
rest_auth | curl --config - http://localhost:9721/v1/tasks/0195.../output
# → {"output":"..."}Cancellation first reports the non-terminal cancelling state; keep polling
until the kernel records cancelled, succeeded, failed, timed_out, or
interrupted after process cleanup and ledger settlement. Task responses never
embed the prompt, output, or raw error; use ledger_run_id to correlate the
bounded task record with the run ledger.
The server rejects non-loopback bind addresses and every endpoint requires a
fresh 256-bit bearer capability published to the private serve.token path
printed at startup (mode 0600 inside a mode-0700 data directory on Unix).
It also rejects non-loopback Host/Origin values and
cross-site browser requests. Run and session responses use allowlisted public
views rather than serializing internal storage records. This blocks remote
browser rebinding and other unauthenticated callers, but malicious code running
under the same OS identity can read the token; this remains a local single-user
control surface, not a hostile same-UID or multi-user boundary. On non-Unix
systems, keep VYANE_DATA_DIR under a platform-managed user-private directory;
Vyane does not replace the platform ACL on a caller-selected shared directory.
The local-only workflow daemon is a separate control surface from vyane serve.
It keeps an admitted workflow running after the submitting CLI exits:
vyane daemon start # detached, waits for readiness
vyane daemon start --goal-auto-pursue \
--goal-target builder --goal-workdir . --goal-sandbox write
vyane daemon status --json
vyane workflow submit workflow.toml --var env=dev
vyane workflow status <uuidv7> --json
vyane workflow cancel <uuidv7>
vyane daemon stopdaemon run keeps the same supervisor in the foreground. The listener accepts
only loopback addresses, and every endpoint — including /health — requires a
per-start 256-bit bearer token stored separately from the owner-only daemon
descriptor. The control API is POST /v1/workflows, GET /v1/workflows/:id,
and POST /v1/workflows/:id/cancel. On Linux it also exposes
POST /v1/agent-runs, GET /v1/agent-runs/:id,
GET /v1/agent-runs/:id/output, and POST /v1/agent-runs/:id/cancel for the
fresh/sessionless Process and Native lanes described in
WP-61 and WP-66. There is no
permissive CORS layer. This
protects against accidental browser and cross-process access, but is not a
sandbox against hostile code running as the same OS user.
The client authenticates the exact recorded daemon before reading local
workflow sources. It sends the workflow TOML plus every declared prompt_file
as an in-memory source bundle; the daemon never resolves those source paths on
its own filesystem. The semantic limits are 1 MiB for the TOML, 4 MiB per
prompt, 16 MiB total, 128 prompt entries, and 4,096 bytes per bundle path.
Variables are limited to 128 entries, 256 bytes per key, 1 MiB per value, and
4 MiB total. The canonical submission working directory is also carried in the
request (maximum 4,096 bytes): a missing or relative step workdir is resolved
from it, while an absolute step workdir is preserved.
The client generates a canonical UUIDv7 by default and prints it to stderr
before the request is sent. --id <uuidv7> reuses an id for reconciliation or
an idempotent retry: the same daemon workflow scope, normalized source, working
directory, and variables returns the existing task; any mismatch is a conflict
and never replays the earlier payload. The task id and workflow journal id are
identical. On daemon restart, abandoned daemon-owned rows are cleaned by exact
controller identity and marked interrupted; they are not automatically
resumed or replayed. Foreground workflow resume remains an explicit,
journal-oriented command.
Goal pursuit is disabled by default. --goal-auto-pursue requires one explicit
target and canonical workdir; sandbox and verifier/segment/invocation limits
remain bounded flags. The daemon handles one local goal at a time, first
adopting eligible in_progress work and then atomically claiming the next
queued goal. A daemon replacement can continue its still-live stable-worker
lease and WP-71 checkpoint; an expired lease is reclaimed through the normal
generation fence. Semantic pauses, terminal goals, and goals under another
live worker are never auto-resumed or stolen. Shutdown cancels the fresh
runtime effect while leaving a running checkpoint, rather than recording a
false business pause. This adds no goal HTTP API, quota/approval handoff,
runtime-native session resume, remote owner, or parallel goal scheduler.
vyane route "task text" previews a decision. vyane dispatch --target auto
executes the same decision and records the selected profile/provider/model,
tier, effort, score, intent, and tag on the ledger record. The router scores task complexity from structural signals
(changed files, dependency edges, retry count, prompt length, inferred
tags) and maps to an economy / mainline / frontier tier, then resolves
a preference based on profile tier and tags metadata:
vyane route "write an ADR for the system architecture" --changed-files 20
vyane route "simple task" --tier frontier
vyane dispatch "fix the parser" --target auto
vyane dispatch "review auth" --target auto --no-frontier
Routing hints can also be supplied as routing.stage, routing.tier,
routing.tags, routing.candidates, and routing.allow_frontier labels.
Decision fields such as routing.provider and routing.effort are reserved so
callers cannot forge audit metadata. A literal profile named auto remains
addressable as profile:auto; target:<provider>/<model> explicitly selects a
provider/model pair when a provider id begins with the reserved profile:
prefix. Workflow steps may use a
deferred auto target after prompt rendering:
[[step]]
id = "review"
target = "auto"
prompt = "Review {{steps.implement.output}}"
[step.route]
stage = "review"
tags = ["security"]
allow_frontier = false
effort = "high"[step.route].effort is a closed typed value (low, medium, high, or
xhigh) available only on a deferred single target. Route hints on an explicit
target or fan_out fail before dispatch instead of being ignored. Effective
effort precedence is workflow explicit effort, then the selected profile's
configured effort, then the decision tier default. The resulting canonical
routing.effort is applied to every failover leg and frozen for recorded,
detached, daemon-idempotent, and journal-resume execution. Invalid values are
rejected without echoing their input, and an ordinary effort label cannot
forge the reserved decision field. See WP-46.
WorkflowPlan schema v1 is now the bounded, strict, filesystem-independent
execution payload shared by compile, prepare, run, and resume. It freezes the
materialized DAG, typed targets and route hints, lossless timeouts, requested
capability summary, source claim, and a canonical plan checksum. The payload is
not a safe public view, and its checksum is not authentication, provenance, or
execution authority. Plan-only continuation fails closed unless the journal has
the exact checksum; only the source-bearing compatibility API may migrate an
older journal after validating the exact source hash. See
WP-54.
WP-58 adds explicit exact-plan replay/fork. It reads a terminal source journal, creates a new UUIDv7 journal, reuses only the dependency-closed, journal-recorded all-success prefix, and executes the remaining suffix live. The source remains unchanged; daemon restart still never implies replay.
This closes the repository-local shared typed-plan prerequisite, not workflow parity. Dynamic control flow, nested workflows, shared budgets, a compatibility frontend, changed-plan call matching, CLI/REST/MCP plan transport, sanitized cross-implementation fixtures, and a production-complete model-tier policy remain open.
The frontier guard is fail-closed across the selected profile and its failover chain. Detached auto-routed jobs send a secret-free target snapshot once over a private worker stdin pipe and refuse to start if config changes would make the worker execute a different provider/model/protocol/harness/parameter chain. The snapshot is not persisted. Endpoint URLs, provider-specific extra values, and harness env-injection values are represented only by safe digests/shape metadata; raw credentials are never copied.
vyane review runs a three-step solution-review workflow on the existing
workflow engine: implement → fan-out review → synthesize. It is not yet the
original system's structured git diff/PR review, finding-artifact, verifier,
and publication pipeline.
vyane review 'implement a sorting function' \
--implementer sonnet \
--reviewers opus,gpt \
--synthesizer opus
CLI REST API MCP
vyane dispatch vyane serve vyane mcp
│ │ │
└──────────┬───────┴──────────┬───────┘
▼ ▼
vyane-service (shared facade)
│
▼
┌─────────────┐
│ kernel │ early execution id,
│ dispatch / │ whole-chain admission,
│ broadcast │ attempts + RunRecord
└──────┬──────┘
┌────────────┴────────────┐
▼ ▼
direct-http protocol cli-wrap harnesses
clients (ChatClient) (Harness, scrubbed env)
OpenAI Chat / Responses, Claude Code, Codex CLI, …
Anthropic Messages │
└────────────┬──────────────┘
▼
append-only JSONL ledger
(digests, attempt trail)
+ session store
SQLite transactional message store
(messages, deliveries, receipt/outbox state)
SQLite goal lifecycle store
(snapshot + immutable events in one transaction)
bounded delivery broker
(replay-safe adapters + body-free EventLog projection)
SQLite AgentRun / worker store
(leases, topology, recovery, tree cancel, body-free outbox)
The kernel depends only on the traits and types in vyane-core; the concrete
clients, harnesses and ledger are assembled behind those traits in the service
layer. Seventeen crates:
| crate | responsibility |
|---|---|
vyane-core |
four-layer target model, capability traits, error taxonomy, env policy, process-local workdir pin, and live native-side-effect authority vocabulary — the shared types everything else speaks |
vyane-config |
TOML config + profiles; resolves a profile (and its failover chain) to a BoundTarget |
vyane-provider |
provider registry; endpoints, auth styles, per-provider env-injection rules |
vyane-protocol |
ChatClient implementations for the HTTP protocols (OpenAI Chat / Responses, Anthropic Messages), a separately authorized OpenAI Chat typed-turn path, and the shared HTTP base validator and secret-free endpoint-routing digest |
vyane-harness |
Harness implementations wrapping coding CLIs headlessly, with additive scoped execution, pinned-workdir handoff and process-group control; also owns the guarded native tool registry, bounded turn driver, descriptor-relative filesystem tools, and sandboxed command/network tools used by the resident Native lane |
vyane-kernel |
early execution identity, whole-chain capability admission, prepared streaming/dispatch, failover gating and run-record assembly |
vyane-ledger |
JSONL Ledger + filesystem SessionStore, including strict revisioned native-session snapshots and atomic CAS transitions; cost estimation |
vyane-task |
SQLite-backed, secret-free task lifecycle snapshots and CAS event history |
vyane-agent |
SQLite-backed, owner-scoped AgentRun queue, worker topology, fenced two-stage recovery admission, active permits and atomic native-scope revalidation, bounded tree cancellation, and body-free lifecycle outbox |
vyane-message |
SQLite-backed, owner-scoped transactional message and delivery truth, fenced leases, external receipts, and per-projector body-free outbox |
vyane-goal |
SQLite-backed, owner-scoped goal snapshots plus immutable lifecycle/progress events and persisted acceptance descriptors |
vyane-broker |
bounded owner-bound delivery pumps, replay-safety admission, fenced settlement, maintenance, and body-free message/AgentRun EventLog projection |
vyane-router |
target selection / routing policy (grows into pluggable routing) |
vyane-workflow |
declarative DAG execution, templates, atomic journals, and resume |
vyane-service |
shared construction and operation layer used by front-ends; also exports principal-derived owner scope, the fresh/sessionless Native authority bridge, explicit AgentRun projection assembly, one-shot recovery/execution drivers, paired Process/Native backends, and the generic multi-lane resident host used by the daemon |
vyane-mcp |
six base MCP tools plus an injectable, credential-free workflow-control port; the CLI exposes nine tools over stdio |
vyane-cli |
the assembler and entry point: wires the crates together behind a command-line UI |
Configuration is a TOML file (a platform config directory for user defaults —
e.g. ~/Library/Application Support/vyane/config.toml on macOS — merged with
.vyane/config.toml for project overrides). See
profiles.example.toml for the full shape; a
provider and a profile look like:
Native AgentRun permissions remain explicit request opt-ins. Optional
[native_permissions] sections in user, project, explicit, and
operator-managed config files only impose independent ceilings; see
WP-88. Command execution remains read-only unless its
request and every ceiling list exact pre-existing writable_roots; see
WP-90. Non-empty command writable roots additionally
require /usr/bin/bwrap --help to advertise --bind-fd FD DEST; current
Ubuntu 24.04 security updates provide that capability. Roots must be
directories; regular files are rejected so atomic editor replacement is not
misrepresented as supported. Granting a root also grants aggregate storage
consumption within that subtree: per-file and process/time ceilings remain,
but WP-90 does not provide a backing-filesystem byte or inode quota.
CLI-harness requests keep the common read-only / write / full sandbox
vocabulary. Optional [harness_permissions] max_sandbox sections in every
config layer impose independent ceilings across an entire Claude Code / Codex
CLI failover chain; the strictest ceiling wins and an over-broad request fails
before REST/workflow task identity, journal or dispatch persistence, and
subprocess spawn. Vyane does not accept raw vendor permission flags. Operator policy should use
VYANE_MANAGED_PERMISSION_CONFIG; the older
VYANE_MANAGED_NATIVE_CONFIG name remains a compatibility alias. See
WP-93.
vyane check and the MCP vyane_check tool report a redacted effective
permission summary. The CLI-harness row shows the strictest configured sandbox
ceiling. Native/Canto capability rows distinguish unrestricted_by_config,
bounded, and disabled; these are configuration upper bounds, not grants,
and never include raw paths, domains, commands, environment names, or tool
rules. See WP-94.
vyane daemon start keeps its 500 ms per-attempt control-lock budget while
using the existing 30 second readiness window to retry typed, transient lock
contention after the child has spawned. Startup filesystem, permission, and
control-data failures remain fatal; see WP-95.
[providers.anthropic]
base_url = "https://api.anthropic.com"
api_key_env = "ANTHROPIC_API_KEY" # names an env var; no key material in config
auth_style = "x_api_key" # bearer | x_api_key
protocol = "anthropic_messages"
default_model = "a-capable-anthropic-model"
# A named bundle of provider + protocol + harness + model → one BoundTarget.
[profiles.review]
provider = "anthropic"
protocol = "anthropic_messages"
harness = "none" # "none" = direct HTTP chat, no workspace
model = "a-capable-anthropic-model"Then, from the shell:
# Validate config, resolve every profile, probe harness binaries and env vars.
vyane check
# Dispatch one task to one target (a profile name).
vyane dispatch "review this diff" --target myprofile
# Broadcast the same task to several target chains, concurrently.
vyane broadcast "compare approaches" --targets a,b,cSample vyane check output against a config with two providers and three
profiles (one profile's required env var deliberately left unset, to show
what a missing-key warning looks like):
config files:
.vyane/config.toml (loaded)
providers:
anthropic: anthropic_messages default_model=a-capable-anthropic-model
openai: openai_chat default_model=a-fast-openai-model
profiles:
builder: anthropic/a-capable-anthropic-model via claude-code (anthropic_messages)
codex: warning: provider requires environment variable `OPENAI_API_KEY` for its API key, but it is not set
review: anthropic/a-capable-anthropic-model (anthropic_messages)
harnesses:
claude-code: available
codex-cli: available
profile environment:
builder: ANTHROPIC_API_KEY present
codex: OPENAI_API_KEY missing
review: ANTHROPIC_API_KEY present
- Boring dependencies. Widely-used, well-understood crates; no clever infrastructure where a plain file will do.
- Secrets never serialize. Credential types are non-serializable by construction; config stores the name of an env var, never the value.
- Declaration and evidence are not authority. Capability manifests and scopes are serializable audit data; prepared plans, pinned directory handles and active permits stay process-local and fail closed across provenance drift.
- The ledger stores digests, not prompts. New run accounting records a prompt digest and never copies a preview or prompt body by default.
- Scrubbed child environment by default. Harnesses spawn from a minimal baseline env plus an explicit per-target injection set; inheriting the full parent environment is opt-in.
- No hidden timeouts. Long agentic runs legitimately take hours; timeouts are opt-in per task, never a silent default.
- Owner-aware records. Every run and session carries an owner field from day one, so multi-user isolation is never a retrofit.
- Architecture — the four-layer model, crate map, dispatch lifecycle, env policy, failover and ledger semantics.
- Architecture decisions — accepted product differences and their still-open acceptance gates.
- Roadmap — milestones for v0.1 through v0.4.
- Original-Vyane parity baseline — fixed cross-repository capability matrix and acceptance gates.
- Contributing — toolchain, checks, and PR conventions.
- AGENTS.md — public-repo rules for coding agents (no private paths or credentials).
Licensed under either of MIT or Apache License, Version 2.0 at your option. Unless you explicitly state otherwise, any contribution you submit for inclusion is dual-licensed as above, with no additional terms or conditions.