Skip to main content

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:

  1. Loads configuration and connects to Postgres.
  2. Runs the shared SQL migration stream.
  3. Starts the Hyperliquid agent monitor.
  4. Starts the OpenCode sub-agent scheduler.
  5. Starts the deterministic indicator scheduler.
  6. 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​

SubsystemResponsibility
agentsAgent registry, API keys, OpenCode workspaces, selected instruments, and sub-agent-targeted prompt revisions. User-owned encrypted Hyperliquid signing material lives with authentication records.
harnessPersisted 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 characters
  • AGENTS_ENCRYPTION_KEY_ID: identifier stored alongside encrypted keys
  • WORKSPACE_CONTROL_API_KEY: shared credential for the workspace controller
  • database configuration through DATABASE_URL, or the POSTGRES_* 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.