Skip to content

Persistence and local models

Thibaut Rey edited this page Sep 7, 2026 · 1 revision

💾 Persistence

Mount /data to preserve state:

Default path Contents
/data/accounts.json Accounts, aliases, dashboard API keys, application policies, webhooks, and settings
/data/oauth-state.json In-progress OAuth state
/data/requests-trace.jsonl Recent retained traces
/data/requests-stats-history.jsonl Lightweight long-term usage history
/data/anonymous-usage-state.json Mode-0600 anonymous daily retry envelope without a stable installation ID
/data/provider-agent-selection.json Mode-0600 explicit local provider model selection
/data/provider-agent-runtime-endpoints.json Mode-0600 loopback endpoints and optional runtime bearers
/data/provider-agent-device-identity.json Mode-0600 Ed25519 device identity and relay-shadow sequence
/data/provider-agent-cloud-enrollment.json Mode-0600 submitted Cloud shadow node view; never the enrollment grant
/data/codex-projects.json Codex session/project registry
/data/v1-edge-jobs.json Native Rust jobs, results, retries, and webhook delivery state
/data/jobs.sqlite Legacy/control-plane jobs and pre-Rust migration source

The Compose deployment mounts ./data:/data. Recent trace retention defaults to 1,000 entries. Persistent state is not encrypted at rest: accounts.json can contain provider access/refresh tokens, proxy keys, and webhook secrets; oauth-state.json can contain temporary OAuth verifiers; traces and the native job file or legacy database can contain request and response payloads. Files created by MultiVibe use restrictive permissions, but the volume and its backups should still be encrypted, access-controlled, and excluded from public shares.

Job content delivered by webhook or consumed by a client receives a one-hour grace period; unretrieved content is purged after 30 days. For a consistent backup, stop the service cleanly, copy the entire data/ directory (including v1-edge-jobs.json, the *.pre-rust-backup.sqlite migration copy, and any SQLite -wal or -shm files), then start it again. Restore the complete directory only while the service is stopped.

Embedded provider-agent preview

Set PROVIDER_AGENT_ENABLED=true to let Core supervise the packaged provider agent. PROVIDER_AGENT_BINARY selects its absolute binary path and PROVIDER_AGENT_STATE_PATH selects the clean absolute local selection file; by default the file is placed beside STORE_PATH as provider-agent-selection.json. PROVIDER_AGENT_RUNTIME_STATE_PATH selects the separate protected manual-runtime file and defaults to provider-agent-runtime-endpoints.json beside STORE_PATH. The admin APIs can inventory the reviewed loopback candidates, configure one literal loopback endpoint per manual adapter, and persist an explicit model selection locally. Runtime bearers are accepted only through the local authenticated admin path, never returned by either API, and retained when an update omits the secret field.

PROVIDER_AGENT_DEVICE_KEY_PATH selects the separate mode-0600 Ed25519 device identity. The agent exposes only its public key and key ID in the local manifest. Its authenticated relay-shadow endpoint signs Cloud-compatible 30-second session-open envelopes with a persisted monotonic sequence and fixed non-commercial locks. This endpoint cannot carry customer content, open a socket to a relay, enable routing, or create compensation eligibility. PROVIDER_AGENT_ENROLLMENT_STATE_PATH selects the separate submitted-node state. The authenticated Cloud-shadow enrollment route sends only the exact selected-model consent manifest to PROVIDER_AGENT_CLOUD_API_URL, which is restricted to https://auth.multivibe.cloud (or literal loopback HTTP in tests), signs the returned challenge, persists no grant or proof, freezes the submitted selection, and keeps routing and compensation false.

The autonomous host archive also pins PROVIDER_AGENT_MANAGED_ROOT, PROVIDER_AGENT_BUNDLED_OLLAMA_ROOT, PROVIDER_AGENT_DEPENDENCY_MANIFEST_PATH, PROVIDER_AGENT_MANAGED_PLANNER_STATE_PATH and PROVIDER_AGENT_MODEL_CATALOG_PATH to its private data directory and signed bundle layout. Managed demand reconciliation is enabled only when an operator also supplies MULTIVIBE_PROVIDER_DEMAND_TRUSTED_KEYS to the host launcher. That value is an explicit Ed25519 public-key trust root; the repository's RFC interop test key is never used as a packaged Cloud key. Without a configured production trust root, Core still starts but signed demand and managed Ollama remain unavailable.

The local-account Share models · Preview experience exposes the same inventory and revisioned selection without requiring a separate agent UI. It does not submit automatically: enrollment requires an explicit one-time grant and exact manifest. Submission does not advertise capacity, accept community workloads, or enable earnings and payouts.

If the marketplace is later activated after every production gate passes, the announced commercial split for eligible, cleared community-workload revenue is 85% to the host operator and a 15% MultiVibe service fee. Applicable taxes, reserves, disputes and reversals are handled after that split and may reduce or delay the amount payable. The separate 5% fee applies only to customer purchases or top-ups; it is not an additional deduction from the host operator's 85% share. This repository currently implements no payable, settlement or compensation activation.

The multiarchitecture Core container build compiles the Go agent for the same target OS and architecture as the final image, runs its complete Go test suite on the build platform, and installs the static executable at the default /opt/multivibe/bin/multivibe-provider-agent path with no separate download. The binary remains inert unless PROVIDER_AGENT_ENABLED=true; enabling it does not bypass any of the shadow-only routing or compensation locks above.

Provider Host container (Docker Compose and Unraid)

The ordinary docker-compose.yml runs Core as a gateway. The separate packaging/container/docker-compose.host.yml runs the complete security-bounded MultiVibe Host bundle for Linux amd64 systems with a supported NVIDIA GPU. Official tagged Host releases publish the exact verified Linux bundle as ghcr.io/thibautrey/multivibe-host:<version> and update the latest tag only after the image has started and reported the expected Host version.

Set the exact URL used by browsers, then start the Host:

MULTIVIBE_HOST_PUBLIC_URL=http://192.168.1.20:1455 \
  docker compose -f packaging/container/docker-compose.host.yml up -d

Use an HTTPS reverse-proxy origin instead when applicable. Container mode sets MULTIVIBE_HOST_BIND=0.0.0.0, but a non-loopback bind fails closed unless MULTIVIBE_HOST_PUBLIC_URL is an explicit path-free HTTP(S) origin. Core uses that origin for its OAuth callback. Native Host installs retain the secure 127.0.0.1 default and need no additional setting.

Only Core port 1455 is published. The provider-agent bearer endpoint and the managed Ollama listener remain on literal loopback inside the same container. The image uses a read-only root filesystem, prepares only the two declared mount roots, then drops to fixed uid/gid 10001:10001 with no capabilities. Random admin and proxy credentials remain in /data/host-credentials.json and are never Compose or Unraid parameters.

/data contains small private application state. /models is a separate large persistent volume; the managed runtime uses /models/runtime. When the operator explicitly creates the local capacity policy, use /models/weights as its model storage path. MultiVibe does not silently create that policy, enable downloads, enroll the device, accept Cloud work, or activate compensation.

packaging/unraid/multivibe-host.xml and packaging/unraid/ca_profile.xml follow the official Unraid Community Applications v2 layout. The template is deliberately marked beta, requires the Unraid Nvidia Driver runtime, keeps the app unprivileged, and mounts application state separately from models. The files are ready for validation and a later Community Applications submission; their presence in this source repository does not mean the app has already been accepted or listed in the Unraid catalog.

Provider-agent admin endpoints:

  • GET /admin/provider-agent/adapters
  • GET /admin/provider-agent/manifest
  • GET/PUT /admin/provider-agent/runtime-endpoints
  • GET /admin/provider-agent/detected-models
  • GET/PUT /admin/provider-agent/selection
  • GET /admin/provider-agent/cloud-shadow/enrollment
  • POST /admin/provider-agent/cloud-shadow/enroll
  • POST /admin/provider-agent/relay-shadow/session-open
  • GET /admin/provider-agent/managed-ollama/status
  • POST /admin/provider-agent/managed-ollama/install
  • POST /admin/provider-agent/managed-ollama/start
  • POST /admin/provider-agent/managed-ollama/stop
  • POST /admin/provider-agent/managed-ollama/reconcile

Anonymous model-demand sharing

Anonymous sharing is enabled by default for new and upgraded installations and can be changed immediately in the Tracing tab. The activation timestamp is materialized during upgrade, so historical usage from before activation is never backfilled. Re-enabling creates a new activation timestamp.

For each completed UTC day, Core first downloads the public hosted-inference allowlist. It then reads the lightweight local trace history and prepares at most 50 contributions containing only an exact allowlisted canonical model ID and output-token volume rounded down to thousands, capped at one billion tokens per model. The envelope also contains the UTC-day window and a random event UUID used only to retry that day safely.

Before each send, Core obtains a short-lived, single-use Cloud admission ticket and solves a bounded computational challenge. This limits mass submission without an installation ID; it does not prove the reported usage. Cloud labels these volumes self-reported and excludes them from popularity ranking and billing. Admission requires the corresponding updated Cloud deployment and migration; failed admission retains the pending envelope for a later retry.

Core never shares prompts, responses, input-token volumes, projects, accounts, emails, hardware, hostnames, request headers, fine-grained timestamps, or a stable installation ID. If the allowlist or Cloud API is unavailable, the cycle fails closed and inference continues normally. Unchecking the control aborts future sends and deletes any unsent envelope immediately.

Clone this wiki locally