-
-
Notifications
You must be signed in to change notification settings - Fork 6
Provider agent
The public extension contract is documented in runtimebackend/CONTRIBUTING.md, RUNTIME_PROFILES.md and RUNTIME_BENCHMARKS.md.
The provider agent is a bounded Go component shipped with MultiVibe Core. Core supervises the packaged binary when PROVIDER_AGENT_ENABLED=true; no separate installer is supported.
The Core container build compiles this module for its target architecture and
installs the static executable at
/opt/multivibe/bin/multivibe-provider-agent. The agent is therefore present
in every supported Core image without a runtime download, while remaining
disabled by default until the operator explicitly enables it.
This foundation exposes loopback health and a consent-bounded manifest containing only explicitly selected model identifiers. It enforces the ordered lifecycle detected -> selected -> submitted -> approved -> online -> compensation-eligible, with independent suspension and terminal revocation. It never scans LAN addresses, mDNS, processes, files, command lines, environment variables, or arbitrary ports.
An empty selection remains detected; only a non-empty, explicit selection is
reported as selected. Selected identifiers are unique, sorted and bounded to
100 entries, and URL-, IP- or filesystem-like values are rejected before they
can enter the consent manifest.
Core persists that explicit selection locally in a schema-versioned mode-0600
JSON document. Updates use an atomic replacement and an expected revision, so a
stale dashboard cannot silently overwrite a newer choice. Selection, runtime,
enrollment and relay-shadow controls are available only through authenticated
loopback routes that Core exposes through its existing authenticated admin API.
The process-local bearer is generated by Core for every child launch, is never
accepted from the parent environment, and is not returned by manifests,
responses or logs. In supervised mode, the child binds a literal loopback port
chosen by the operating system before announcing the exact address to Core over
a dedicated inherited pipe. Core strictly validates and closes that bootstrap
frame before making any bearer-authenticated request; it never probes or falls
back to the fixed standalone port.
GET /v1/adapters exposes the bounded runtime contract embedded in the agent:
protocol, health and catalog paths, capabilities, authentication, measurement
dimensions, limits and reviewed automatic candidates. The registry covers the
full Core runtime list and keeps every adapter manual except the reviewed
literal IPv4/IPv6 Ollama, LM Studio, OMLX, MTPLX and Exo loopback candidates.
Ollama uses only its official default port 11434 and documented
OpenAI-compatible /v1/models surface; the review source is the official
Ollama OpenAI compatibility reference.
OMLX and MTPLX share port 8000 and are accepted only when every returned
model carries the matching owned_by signature. Exo uses its documented
loopback port 52415 and /models catalog path, with the same
owned_by: "exo" signature requirement.
The standalone agent preserves the documented literal 127.0.0.1 or ::1
port 1460. The embedded supervisor instead forces port 0 on one of those
literal loopback addresses and learns the resulting non-zero port only through
the private bootstrap pipe.
GET /v1/detected-models performs an on-demand local inventory through those
reviewed candidates and explicitly configured manual endpoints only. Manual
endpoints must use literal 127.0.0.1 or ::1, HTTP and an explicit port;
userinfo, paths, queries, fragments, LAN names and public addresses are
rejected. Catalog calls are redirect-free, deadline- and size-bounded, and the
response contains only the adapter ID and validated model identifiers.
Unavailable candidates expose no local error or network details. The inventory
remains local and does not select, enroll, advertise or upload a model.
Core manages manual endpoints through authenticated
GET /v1/runtime-endpoints and PUT /v1/runtime-endpoints. The state is a
separate schema-versioned mode-0600 document using atomic revisioned
replacement. Optional local runtime bearers are persisted only in that file,
are sent only to the selected loopback catalog endpoint, and are never present
in API responses or logs. Omitting bearer_token preserves the secret for an
unchanged adapter and endpoint; sending an explicit empty value removes it.
Live provider activation, dedicated-tailnet tsnet transport, mutually
authenticated HTTP/2/WebSocket fallback, signed metering envelopes, and remote
workload handling remain fail-closed until their credentials, protocol and
Cloud gates are implemented and verified. The current binary does not advertise
capacity, accept community work, become routable or create compensation
eligibility.
The agent can execute the existing Cloud enrollment shadow protocol after an
authenticated Core administrator supplies the one-time mve_… grant and the
exact consent manifest. POST /v1/cloud-shadow/enroll accepts the exact 29
runtime families in the embedded adapter registry, requires every submitted
model to exactly match the local explicit selection, derives a stable client-node UUID
from the public device key, and sends the challenge only to
https://auth.multivibe.cloud (literal loopback HTTP is accepted for tests).
It signs the returned challenge with the same local Ed25519 identity under the
multivibe-provider-control-shadow-v1 domain. Redirects, arbitrary origins,
unknown fields, oversized bodies, altered challenges and commercial flags fail
closed.
Only the submitted node view, runtime family, declared concurrency and
non-commercial locks are stored in a separate atomic mode-0600 file. The
enrollment grant, proof, private key and response bodies are never persisted or
returned. After submission the local selection is frozen, the manifest advances
to submitted, and a second enrollment is rejected locally. Approval,
availability, transport, routing and compensation still require later explicit
protocol states; submission cannot skip them.
The agent does implement the transport-independent Cloud relay-shadow
session-open envelope. A local Ed25519 identity is stored in an atomic
mode-0600 document together with its monotonic sequence. The local manifest
contains only the public SPKI and its derived key ID. Authenticated
POST /v1/relay-shadow/session-open generates its own 32-byte nonce, uses a
30-second canonical UTC window and signs the exact
multivibe-provider-relay-shadow-v1 domain. The payload hardcodes
shadowOnly=true and every customer-traffic, routing and compensation flag to
false. It contains no prompt, output, media, usage or price and does not create
a network session by itself.
Core starts the embedded process with a closed environment allowlist containing only its loopback URL, the agent loopback listen address and the optional initial selected-model seed. Core separately supplies the explicit selection and runtime state paths, the device-identity path and its newly generated control bearer. Parent-provided state paths or control tokens, provider credentials, Stripe or OAuth secrets, control-plane tokens, API keys and unrelated variables are never inherited by the agent.
The selection file and the detected inventory remain on the machine. This preview corridor does not submit either one to Cloud, enroll the node, publish capacity, enable routing, or create compensation eligibility.
Agent readiness calls Core's credential-free loopback /health endpoint. It
never receives or forwards the proxy API key merely to prove that the packaged
Core process is reachable.
capacity_policy.go defines the fail-closed capacity contract that a future
host application can present to the machine owner. There are no defaults: the
owner must explicitly choose all of the following values before the policy is
accepted:
- maximum GPU utilization percentage (
1through100); - maximum percentage of GPU-addressable VRAM (
1through100); - maximum bytes occupied in the managed model store;
- the managed model store's clean, absolute, non-root path;
- maximum model download bytes in a rolling 24-hour window;
- a positive minimum active-model residency;
- maximum model-set changes in a rolling 24-hour window; and
- a positive amount of physical disk space that must remain free.
An explicit zero download limit disables new model downloads. An explicit zero model-change limit freezes the current active set. Those values use pointer fields in the operator-facing document so they cannot be confused with an omitted choice. Invalid percentages, missing fields, zero safety values, relative or unclean paths, filesystem roots and overflowing durations are rejected rather than normalized.
model_planner.go is a dependency-free, deterministic and declarative planning
slice. Its caller supplies a capacity snapshot for exactly the configured
storage path, a bounded candidate catalog, the provider agent's managed model
state and a fresh authoritative demand snapshot. The planner never searches a
home directory, mounted volume, process table, runtime, network endpoint or any
other filesystem location. It does not call stat, walk directories, infer
installed models, download or delete model files, or start and stop runtimes.
Its output is only a proposed selected-model list plus proposed download sizes.
For each demanded model, the planner requires the candidate context window to
cover the requested context and ranks utility as demand units × required context tokens. Ties prefer larger requested contexts, existing active and
installed models, smaller artifacts and finally lexical model ID. It greedily
admits candidates only while the sum of their GPU utilization reservations and
VRAM fits the owner's percentages. A not-yet-installed candidate must also fit
the lesser of the remaining managed-store allowance and physical free space
after the owner's reserve, as well as the remaining rolling download budget.
The existing active set itself must fit the policy or planning fails closed.
Active models inside the minimum residency window remain selected even if demand changes. Successful active-set transitions are counted over the rolling 24-hour history supplied by managed state; when the owner's change limit is exhausted the plan preserves the current set and proposes no downloads. This slice never proposes deletion, so existing managed artifacts are not evicted to manufacture room for a more popular model.
The managed runtime is reached through the compiled, process-local backend
contract documented in
runtimebackend/CONTRIBUTING.md. That
contract defines explicit primary/fallback selection, immutable launch and
provenance allowlists, normalized metrics and lifecycle capabilities. The
managed Ollama adapter can execute signed Cloud jobs through the outbound relay
only while the owner has enabled allow_cloud_workloads; runtime registration
alone never grants customer traffic.
POST /v1/cloud-shadow/demand accepts only the bounded
multivibe-provider-demand-envelope-v1 contract. The agent rejects duplicate
JSON keys and unknown fields, canonicalizes the signed payload, verifies an
Ed25519 signature against the explicitly configured trust map, and fences every
accepted generation and digest. Issued, observed and expiry times, privacy
policy, runtime version, catalog artifact digest and model-license assessment
must all match the local policy and approved catalog before a plan can be
persisted. The RFC interoperability key in the tests is not a production trust
root and is never a runtime default.
Managed Ollama configuration is all-or-nothing. It requires the signed-demand service, a persistent capacity policy, the packaged model catalog and dependency manifest, a private managed root, the bundled runtime root and separate planner history. On Linux and Windows, the runtime defaults to the first compatible physical GPU reported by the bounded NVIDIA probe; both that pin and the literal-loopback Ollama port can be changed only through validated configuration. Runtime, HOME, XDG, temporary files, logs and the managed model inventory stay below the private root. The packaged Ollama tree is verified and adopted atomically; the credential-free HTTPS download is only a bounded, SHA-256-pinned fallback.
On macOS arm64 and amd64, the host reads total physical memory only through the fixed
/usr/sbin/sysctl -n hw.memsize probe with a short timeout and strict numeric
bounds. The planner exposes at most 50% of the physical total as compute
capacity, leaving the other half to macOS and CPU pressure; the operator's configured
gpu_vram_percent limit is applied after this conservative cap. A missing,
malformed, zero or implausibly large probe result disables managed compute
capacity instead of guessing.
Authenticated lifecycle routes expose status plus explicit install, start, stop and reconcile actions. Every expanding action carries the current local policy revision; reconciliation additionally carries the exact signed plan generation and envelope digest. The controller serializes operations, cancels work when either fence changes, persists model residency and rolling download and model-change histories, and stops immediately when pause or Cloud workload consent is withdrawn. An expired plan also invalidates the active set and stops the managed runtime even when no further request arrives.
Reconciliation can only install catalog-pinned artifacts and mark a verified
managed manifest active. The reconciliation path never receives a prompt or
output. The separate community outbound worker polls Cloud only after signed
enrollment, inventory admission and workload consent are current. Its local
GET /v1/community-outbound/status route requires the provider control token
and exposes counters and sanitized error categories only; it never exposes
prompts, outputs, bearer tokens or device credentials. The announced commercial
split is 85% to the host operator and a 15% MultiVibe service fee for eligible,
cleared community-workload revenue, before applicable taxes, reserves, disputes
and reversals; the separate 5% fee applies only to customer purchases or
top-ups.
The provider agent, public runtime SDK, extension contracts, examples and documentation in this repository are part of MultiVibe Core and are licensed under Apache License 2.0. See NOTICE for attribution and notices.
That license does not grant rights to MultiVibe Cloud, MultiVibe trademarks, credentials or customer data. Model weights, packaged runtimes and other third-party dependencies remain subject to their own licenses and notices.
Migrated from provider-agent/README.md on 2026-09-07.