Architecture
HyperVibes is one Rust application process. It runs the Axum web server, Postgres migrations, the Hyperliquid monitor, and the OpenCode scheduler in a single Tokio runtime.
Runtime
Startup performs the following work:
- Loads configuration and connects to Postgres.
- Runs the shared SQL migration stream.
- Starts the Hyperliquid agent monitor.
- Starts the OpenCode sub-agent scheduler.
- Starts the deterministic indicator scheduler.
- Serves the web interface, static files, SSE streams, and the agent JSON API.
The main process owns graceful shutdown. The first SIGINT or SIGTERM stops
new scheduled work and lets in-flight agent dispatches drain. A second signal
ends that grace period. The API remains available during the normal drain so an
in-flight OpenCode MCP server can finish its API calls.
Subsystems
| Subsystem | Responsibility |
|---|---|
agents | Agent registry, API keys, OpenCode workspaces, selected instruments, and sub-agent-targeted prompt revisions. User-owned encrypted Hyperliquid signing material lives with authentication records. |
harness | Persisted unified sub-agents/runs, provider-reload maintenance, recovery of orphaned runs, and OpenCode dispatch. |
Harness sub-agents
harness_sub_agents is the single configuration record for every OpenCode
sub-agent and harness_sub_agent_runs is its durable execution queue. The
durable roles are many analysis jobs plus singleton trading and review
jobs. Candle sub-agents use the candle_closed trigger, which the scheduler
owns and advances at UTC candle boundaries after the configured settling delay.
Review keeps its daily schedule. harness_maintenance_tasks remains separate
for provider configuration reloads.
Sub-agents can be deleted only while their runs and OpenCode sessions are idle.
Deletion first removes terminal sessions through the OpenCode API, then deletes
the sub-agent and cascades its runs. Conversations remain separate from harness
sub-agents and runs.
| opencode | OpenCode HTTP client, session persistence access, and generated agent workspaces. |
| memory | Append-only, agent-owned scoped records, source-run provenance, and links between records. |
| indicators | Validated PineScript-subset definitions, immutable versions, server-fetched closed-candle execution, and durable result provenance. |
| hyperliquid | Instrument reference data, account-history journal, live account state, signed order gateway, and order reconciliation. |
| web | Askama-rendered web interface, HTMX/SSE updates, static assets, and /api/v1 agent endpoints. |
| settings | Global application settings, including the base OpenCode system prompt. |
Postgres is the durable system of record. The application uses the public
schema for registry and orchestration tables, and memory, hyperliquid, and
opencode schemas for their respective data. All migrations live in
migrations/ and run at application startup.
Hyperliquid account history powers the Trades and Activity views. Users and authorized agents can add notes to trades and individual transactions, with each note showing its author and time.
Agent Execution
A user first configures and approves one user-owned Hyperliquid trading signer on the Account page. Agent creation then selects an exclusive main or sub-account, creates an agent API key, creates default prompts and schedules, and is ready to create isolated run or conversation workspaces when needed.
The scheduler polls every 10 seconds. It claims due work transactionally and uses independent analysis, review, and trading lanes per agent, while allowing work for different agents to run concurrently. Built-in work includes:
- scheduled Analysis jobs, Trading, and Review
For a dispatch, the OpenCode backend creates a session in the isolated run
workspace and invokes the appropriate OpenCode command. The initial prompt
contains the agent and sub-agent context, selected instruments, the sub-agent's
current prompt revision, the latest agent_learnings memory, the global prompt,
and a live account snapshot for Trading work. That snapshot includes per-stream
data authority and monitor health; unavailable data is never represented as an
empty account. The order gateway rejects new agent exposure until the
clearinghouse and open-orders streams are current, while reduce-only orders
remain available for risk reduction.
Analysis jobs use approved data tools for research and publish discoverable
memories with agent-wide or instrument-targeted scope. They do not author or
execute reusable analysis code. Trading owns research synthesis and execution: it
reads fresh context for an instrument from each enabled Analysis producer,
records a trading_decision memory when possible, and manages orders. Missing,
stale, or failed analyst output is context rather than a scheduler or
order-gateway block.
Enabled indicators execute the cross-product of their one to eight explicit
timeframes and selected Analysis instruments. Definitions own configuration,
immutable versions own Pine source and one shared input-value set, and each run
records one version, instrument, timeframe, canonical closed-candle
boundary, normalized candle input, numeric plots, versioned visual_data, and
diagnostics. Visual-data version 1 stores compact marker events for
plotshape(), plotchar(), and plotarrow() against source candle indices;
the chart boundary resolves their offsets and timestamps without changing the
immutable run output. Before an Analysis dispatch, a durable dependency set
freezes active versions and the target intersection. Each dependency uses the
greatest canonical indicator boundary not later than the Analysis boundary, so
finer Analysis cadences reuse slower indicator runs. The persisted deadline
survives restarts; unfinished dependencies freeze as timed_out. V6 contexts
record exact timeframe, indicator boundary, run ID, and frozen status, while V5
contexts remain readable. Analysis credentials can read only their frozen exact
results. Trading has no direct indicator scope.
Indicator workers are bounded per process, claim work with expiring token-fenced leases, and retry temporary infrastructure failures at most three times with persisted backoff. Creating or updating an enabled definition queues the latest canonical boundary for every timeframe/instrument target. Reconciliation does not perform historical backfill. Queue and completion notifications reduce latency, with periodic database polling as the correctness fallback. Definitions are archived rather than deleted, and dependency-referenced runs are excluded from retention cleanup.
Run state is persisted. On startup and periodically thereafter, the scheduler resumes queued runs and recovers stale running runs so interrupted dispatches do not block subsequent work. A due daily Review whose review lane is occupied keeps its scheduled boundary and retries on subsequent ticks instead of losing the daily review window.
After a run becomes terminal, workspace cleanup checks that its OpenCode session is inactive before scrubbing runtime secrets and disposing that run directory's cached OpenCode instance. The run's session record and workspace artifact remain available under their normal retention policies; disposal releases in-memory plugin and workspace state. A failed probe or disposal leaves the artifact pending for the scheduler's periodic recovery sweep rather than releasing an active session's resources. Session creation has a 30-second HTTP deadline; the outer run deadline is configured independently per sub-agent. Terminal run workspaces are retained for two hours after successful secret scrubbing and OpenCode instance disposal. A periodic sweep deletes expired workspaces only after checking that their sessions are inactive; failed checks are retried. Run records and mirrored transcripts remain in Postgres after workspace deletion, but run-local scratch files do not. Conversation workspaces remain available across turns and are removed when the conversation is deleted. Previously assigned workspace expiration timestamps are not changed by a new retention setting.
Isolated Workspace Foundation
The runtime persists a versioned run-context snapshot and run-artifact lifecycle
record before isolated dispatch is enabled. The snapshot carries only run input
and capability identity; validation rejects sensitive gateway and credential
fields, including normalized field-name variants and known runtime credential
forms. Schema version two is a closed, typed JSON contract; adding a nested
input or capability requires a reviewed schema version rather than an opaque
metadata field.
Artifact paths are never stored in Postgres. The workspace controller
derives them from the owned agent key and run ID as
/workspaces/runs/<agent-key>/<run-id>/workspace.
The controller can idempotently create, inspect, scrub the root runtime .env,
and delete run workspaces. Equivalent state and controller paths exist for an
internal conversation UUID at
/workspaces/conversations/<agent-key>/<conversation-id>/workspace; external
channel keys are not filesystem identities. The scheduler and conversation
service still use the active workspace during this foundation phase. Phase 3
and Phase 4 respectively adopt these isolated directories for dispatch and
conversation turns.
Notifications may record a system-supplied run or conversation provenance and capability-schema binding. A scoped source must be owned by the agent and have the relevant durable notification authority. Provenance never stores a gateway token or destination, and deleting a source run or conversation preserves the notification record.
Agent conversations are separate from scheduled sub-agents and harness_sub_agent_runs. Each
agent_conversations row maps one user or future-gateway conversation to
one OpenCode session. Chat transcript, tool activity, errors, and context
telemetry are mirrored from OpenCode and delivered to the browser as complete
HTMX SSE partial snapshots. Future channels use the same mapping with their
channel and external conversation key.
Boundaries
OpenCode performs LLM and tool execution. HyperVibes retains authority over agent identity, scheduling, memory, account state, and exchange execution. The workspace MCP server uses the agent API key to call HyperVibes; it does not receive the user's Hyperliquid private key. Exchange orders are signed by the owner's trading signer and target the agent's stored trading account.
The agent API is authenticated with a Bearer API key. The resolved agent_key
is the data-ownership boundary for account, memory, and order operations.
OpenCode is the sole execution backend. Its HTTP endpoint is configured at the
application level with OPENCODE_BASE_URL, rather than being assigned through
database runtime rows.
Configuration
Required configuration:
AGENTS_ENCRYPTION_KEY: 32-byte key encoded as 64 hexadecimal charactersAGENTS_ENCRYPTION_KEY_ID: identifier stored alongside encrypted keysWORKSPACE_CONTROL_API_KEY: shared credential for the workspace controller- database configuration through
DATABASE_URL, or thePOSTGRES_*variables
Operational configuration includes APP_BIND_ADDR or APP_HOST and
APP_PORT, APP_CACHE_DIR, workspace root settings, the API base URL visible
inside OpenCode workspaces, OPENCODE_BASE_URL, and OpenCode Basic Auth credentials. See
.env.example for the complete local-development configuration.
Indicator execution uses INDICATOR_MAX_CONCURRENT_EXECUTIONS (1..=32) or a
CPU-derived default of logical CPUs minus one, clamped to 1..=32. This is a
per-process limit. INDICATOR_ANALYSIS_WAIT_TIMEOUT_SECONDS (1..=300, default
30) bounds Analysis waiting for applicable indicator work.
The application defaults to 127.0.0.1:3003. The workspace-facing API URL is
configured separately with HYPERVIBES_AGENT_API_BASE_URL; it must resolve
from the OpenCode container or runtime.
Frontend
The web interface is server-rendered with Askama. HTMX handles partial
updates and SSE publishes live account, memory, and database-notified agent run
changes. The shared Postgres notification listener fans harness_sub_agent_runs changes
out to both run-detail streams and the Sub-agents tab's Recent Runs section; session
notifications are used only by run-detail transcript and summary streams.
Frontend source is in assets/; build.rs builds the Tailwind and esbuild
output when application assets or templates change.
Workspace Controller And Volumes
The HyperVibes service never mounts or accesses agent workspace files. The
OpenCode container owns the agent_workspaces named volume at /workspaces and
runs the workspace-controller HTTP process alongside OpenCode. The HyperVibes
service calls its private Compose-network /v1 API with
WORKSPACE_CONTROL_API_KEY for workspace lifecycle operations and bounded,
read-only workspace-browser requests. This controller is not an agent MCP tool;
agents cannot create, delete, inspect, promote, or browse workspaces through it.
Set WORKSPACE_CONTROL_API_KEY for both the HyperVibes and OpenCode services.
In production, the controller is private to the Compose network at
http://opencode:14097 and has no host port. The development stack publishes
it only at 127.0.0.1:${WORKSPACE_CONTROL_PORT:-14097}. Do not expose it
publicly or place the key in an agent workspace, prompt, MCP configuration, or
agent .env.
Back up the agent_workspaces volume with Podman volume tooling. Preserve the
opencode_data volume independently because it contains global provider
credentials and OAuth state. Back up the production .env with the database
because it contains the agent-encryption key and database password.
A rollout uses a fresh agent_workspaces volume. Back up the database, retain
the legacy host workspaces/ directory outside normal operation, deploy, and
then recreate required agents. The application does not copy or remove legacy
workspace data.