Domain · Specifications

Bellona Domain — Technical Specifications

Bellona is an Nx domain.

18sections28 minread

On this page

Build Orchestration, Asset Interchange, Engine Bridge, and Remote-Control Platform

This document specifies what the Bellona domain actually implements in the Oshun monorepo. Every schema, field, enum value, command, and event listed below is traceable to source code under libs/bellona/* and apps/bellona/*. Items named in a design backlog but not yet present in code are explicitly labelled (planned).


1. Domain Layout#

Bellona is an Nx domain. It has 34 libraries under libs/bellona/ and 12 applications under apps/bellona/. There is no services/bellona/ directory.

1.1 Libraries (libs/bellona/)#

The following table is the complete, authoritative list of Bellona libraries. Each row shows the directory name, its NPM package identifier, and a brief summary of its role.

Library Package Role
3dsmax @bellona/3dsmax 3ds Max bridge runtime and workflow contracts
adapters @bellona/adapters Engine-adapter infrastructure (BaseBridge, queues, state)
asset-export @bellona/asset-export CGI-scene asset export readiness/conversion planning
audio @bellona/audio Audio processing and transcoding contracts
blender @bellona/blender Blender engine adapter
blender-agent @bellona/blender-agent Blender-native agent runtime (RPC bridge, action schemas, macros)
bridge-core @bellona/bridge-core WebSocket bridge protocol foundation
client @bellona/client TypeScript SDK
cross-dcc-consistency @bellona/cross-dcc-consistency Cross-DCC workflow consistency / compatibility contracts
database @bellona/database Prisma schema and generated client
davinci @bellona/davinci DaVinci Resolve integration
editor-productization @bellona/editor-productization Editor release/onboarding/recovery/diagnostics contracts
event-handlers @bellona/event-handlers Cross-domain event subscriptions
event-publisher @bellona/event-publisher Type-safe cross-domain event publishing
gameplay-systems @bellona/gameplay-systems Engine-agnostic gameplay systems
godot @bellona/godot Godot engine adapter
houdini @bellona/houdini Houdini integration
integration @bellona/integration Cross-domain consumers/compilers (Hathor, Isis)
interchange @bellona/interchange 3D asset format conversion pipeline
interchange-models @bellona/interchange-models Interchange data schemas
maya @bellona/maya Maya bridge runtime and workflow contracts
mcp-gateway @bellona/mcp-gateway Remote-control MCP gateway server and stdio transport
metahuman @bellona/metahuman MetaHuman pipeline contracts
mocap @bellona/mocap Motion-capture streaming, retargeting, frame-snap
openusd @bellona/openusd OpenUSD pipeline
remote-protocol @bellona/remote-protocol Canonical remote-control protocol contracts
sdk-cpp @bellona/sdk-cpp C++ native SDK sources
unity @bellona/unity Unity engine adapter
unity-agent @bellona/unity-agent Unity Editor MCP server package and orchestration wrapper
unreal @bellona/unreal Unreal engine adapter (+ BellonaUnrealEditor plugin)
video @bellona/video Video processing contracts
virtual-production @bellona/virtual-production Virtual production contracts
xr @bellona/xr XR (visionOS, Meta Quest, WebXR) contracts

1.2 Applications (apps/bellona/)#

The following table is the complete, authoritative list of Bellona applications.

App Role
build-api Event-driven build/export orchestration module
build-worker Background job processor (4 worker types)
render-api Render-job caching and output validation module
cli bellona command-line tool (Commander.js)
bridge-unity Unity WebSocket bridge (port 9004)
bridge-unreal Unreal WebSocket bridge (port 9003)
bridge-godot Godot WebSocket bridge (port 9002)
bridge-blender Blender WebSocket bridge (port 9001)
control-room Browser-first remote-control operator UI (React/Vite)
remote-gateway Remote-control gateway service (device/session/approval broker)
remote-host Remote-control host agent (engine + desktop + browser adapters)

1.3 Implementation Status#

All 34 libraries and 11 of 12 apps contain real TypeScript (or C++) source files. libs/bellona/sdk-cpp and apps/bellona/render-api ship without a package.json but contain implementation source. The @bellona/blender-agent and @bellona/unity-agent packages are implemented, not planned — every module in their runtime catalogs carries status: 'implemented'.

The remote-control subsystem (remote-protocol, mcp-gateway, control-room, remote-gateway, remote-host) is a self-described "walking skeleton" / scaffold layer: source and tests exist, and the apps' own package.json descriptions call them walking-skeleton services.


2. Database Schema#

Bellona has a single PostgreSQL database that persists all build jobs, artifacts, bridge sessions, worker registrations, and audit records. The schema is managed by Prisma and lives entirely in the bellona datasource.

Database: PostgreSQL ORM: Prisma (prisma-client-js generator) Schema file: libs/bellona/database/prisma/schema.prisma (673 lines) Generated client output: libs/bellona/database/src/generated/client Datasource env var: BELLONA_DATABASE_URL Preview features: fullTextSearch, fullTextIndex Migration: libs/bellona/database/prisma/migrations/20260416000000_phase_8_bellona_initial/

The schema declares 11 models and 14 enums.

2.1 Models#

Build (builds)#

The central record for a build job. It tracks every aspect of the job's lifecycle: current status, which platforms to target, which assets to include, which worker is processing it, error details if it fails, and timing for performance analysis.

Field Type Default Notes
id String (cuid) auto Primary key, VarChar(25)
projectId String Owning project, VarChar(50)
status BuildStatus PENDING Lifecycle status
priority JobPriority NORMAL Queue priority
progress Int 0 0–100 percentage
targetPlatforms Platform[] [] Target build platforms
optimizationLevel OptimizationLevel BASIC NONE / BASIC / FULL
includeDebugSymbols Boolean false Include debug symbol files
compressionLevel CompressionLevel MEDIUM LOW / MEDIUM / HIGH
incremental Boolean false Incremental build flag
assetIds String[] [] Asset IDs to include
errorMessage String? Failure message (Text)
errorCode String? Failure code (VarChar(50))
retryCount Int 0 Retry attempts made
maxRetries Int 3 Max retry attempts
workerId String? Assigned worker ID
queuePosition Int? Position in queue
userId String Owner user ID
organizationId String? Owner organization
metadata Json {} Arbitrary metadata
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp (@updatedAt)
startedAt DateTime? Processing start
completedAt DateTime? Processing end
estimatedCompletionAt DateTime? ETA
deletedAt DateTime? Soft-delete timestamp
duration Int? Duration in milliseconds

Relations: artifacts (BuildArtifact[]), logs (BuildLog[]), exports (ExportJob[]). Indexes: status, priority, projectId, userId, organizationId, workerId, createdAt, [status, priority], [projectId, status], deletedAt.


BuildArtifact (build_artifacts)#

Output files produced by a build, stored in S3-compatible object storage. The storageBucket and storageKey together form the canonical address for retrieving the artifact. The checksum enables content-addressable cache lookups.

Field Type Default Notes
id String auto Primary key
buildId String FK → Build (onDelete: Cascade)
name String Artifact filename (VarChar(255))
platform Platform Target platform
path String File path (VarChar(500))
size BigInt File size in bytes
checksum String File checksum (VarChar(128))
storageBucket String Object storage bucket
storageKey String Object storage key
mimeType String? MIME type
metadata Json {} Arbitrary metadata
createdAt DateTime now() Creation timestamp
expiresAt DateTime? Artifact expiration
deletedAt DateTime? Soft-delete timestamp

Unique: [storageBucket, storageKey]. Indexes: buildId, platform, createdAt, expiresAt, deletedAt. No updatedAt field.


BuildLog (build_logs)#

Structured log entries emitted during build execution. Each entry captures the emitting component (source), the pipeline step (step), and a severity level alongside the message text, enabling structured querying for debugging.

Field Type Default Notes
id String auto Primary key
buildId String FK → Build (onDelete: Cascade)
level LogLevel DEBUG / INFO / WARNING / ERROR
message String Log message text (Text)
details Json? Structured detail object
source String? Emitting component name
step String? Pipeline step name
timestamp DateTime now() Log timestamp

Indexes: buildId, level, timestamp. No updatedAt field.


ExportJob (export_jobs)#

An export packaging job that wraps build artifacts into a downloadable engine-native format. The format enum selects the packaging strategy; the downloadUrl is a presigned URL provided once the export is COMPLETED.

Field Type Default Notes
id String auto Primary key
projectId String Project reference
buildId String? Optional FK → Build
status ExportStatus PENDING Export lifecycle status
progress Int 0 0–100 percentage
format ExportFormat ZIP / TAR_GZ / UNITYPACKAGE / UASSET / GODOT_PCK
targetEngine EngineType? Target game engine
includeSource Boolean false Include source files
compression CompressionLevel MEDIUM Compression intensity
assetIds String[] [] Asset selection
downloadUrl String? Presigned download URL
size BigInt? Output size in bytes
checksum String? Output checksum
storageBucket String? Object storage bucket
storageKey String? Object storage key
errorMessage String? Failure error message
errorCode String? Failure error code
userId String Owner user ID
organizationId String? Owner organization
metadata Json {} Arbitrary metadata
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp
completedAt DateTime? Completion timestamp
expiresAt DateTime? Download link expiration
deletedAt DateTime? Soft-delete timestamp
duration Int? Duration in milliseconds

Relations: build (Build?). Indexes: status, projectId, buildId, userId, organizationId, format, createdAt, expiresAt, deletedAt.


EngineProject (engine_projects)#

A record of a generated engine project scaffold — the set of files and configurations generated for a specific engine and platform combination. The settings JSON field holds engine-specific configuration that does not fit into the normalized columns.

Field Type Default Notes
id String auto Primary key
projectId String Source project reference
engine EngineType Target engine
engineVersion String Engine version string
modules String[] [] Engine modules to include
plugins String[] [] Engine plugins to include
platforms Platform[] [] Target platforms
outputPath String Output directory path
templateId String? Build template reference
includeAssets Boolean true Include project assets
assetIds String[] [] Specific asset selection
settings Json {} Engine-specific settings
status BuildStatus PENDING Generation status
errorMessage String? Failure error message
fileCount Int? Number of generated files
totalSize BigInt? Total output size in bytes
dependencies String[] [] External dependencies
warnings String[] [] Generation warnings
userId String Owner user ID
organizationId String? Owner organization
metadata Json {} Arbitrary metadata
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp
completedAt DateTime? Completion timestamp
deletedAt DateTime? Soft-delete timestamp
duration Int? Duration in milliseconds

Indexes: projectId, engine, status, userId, organizationId, createdAt, deletedAt.


BridgeSession (bridge_sessions)#

A session record for a live connection between the Bellona platform and a game engine editor. Tracks connection state (via status), sync progress (via syncedAssetCount), and the heartbeat timestamp used to detect dead sessions.

Field Type Default Notes
id String auto Primary key
projectId String Project reference
engine EngineType Connected engine
engineVersion String? Engine version
status ConnectionStatus DISCONNECTED CONNECTED / DISCONNECTED / SYNCING / ERROR
hostname String? Engine hostname
port Int? Engine port
pid Int? Engine process ID
sessionToken String? Session auth token
lastSyncAt DateTime? Last sync timestamp
syncDirection SyncDirection? PUSH / PULL / BIDIRECTIONAL
syncedAssetCount Int 0 Number of synced assets
userId String Owner user ID
organizationId String? Owner organization
metadata Json {} Arbitrary metadata
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp
connectedAt DateTime? Connection established
disconnectedAt DateTime? Connection dropped
deletedAt DateTime? Soft-delete timestamp
lastHeartbeat DateTime? Last heartbeat received

Relations: conflicts (SyncConflict[]). Indexes: projectId, engine, status, userId, organizationId, createdAt, lastHeartbeat, deletedAt.


SyncConflict (sync_conflicts)#

An asset version conflict detected during bidirectional sync, where the same asset was modified independently on both the Oshun side (localVersion) and the engine side (remoteVersion). The resolution field records how the conflict was resolved once a decision is made.

Field Type Default Notes
id String auto Primary key
sessionId String FK → BridgeSession (onDelete: Cascade)
assetId String Conflicting asset ID
assetPath String? Asset file path
localVersion String Local version identifier
remoteVersion String Remote (engine) version identifier
localChecksum String? Local file checksum
remoteChecksum String? Remote file checksum
resolution String? local / remote / manual (VarChar(20))
resolvedAt DateTime? Resolution timestamp
resolvedBy String? User who resolved
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp

Indexes: sessionId, assetId, createdAt.


BuildWorker (build_workers)#

Registration record for a build worker node. Each worker declares its capabilities at registration time (jobTypes, platforms, engines) so the scheduler can route jobs only to workers capable of processing them. The lastHeartbeat timestamp is used to detect dead workers.

Field Type Default Notes
id String auto Primary key
name String Worker display name
hostname String Hostname (unique)
jobTypes JobType[] [] Supported job types
platforms Platform[] [] Supported platforms
engines EngineType[] [] Supported engines
concurrency Int 1 Max concurrent jobs
status WorkerStatus OFFLINE IDLE / BUSY / PAUSED / STOPPING / STOPPED / OFFLINE
currentJobId String? Currently processing job ID
lastHeartbeat DateTime? Last heartbeat timestamp
totalJobsProcessed Int 0 Lifetime job count
successfulJobs Int 0 Successful job count
failedJobs Int 0 Failed job count
averageJobDuration Float? Average duration in ms
version String? Worker software version
metadata Json {} Arbitrary metadata
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp

Unique: hostname. Indexes: status, lastHeartbeat.


AssetCache (asset_cache)#

Cached metadata for assets imported from other domains (Isis, Hathor), scoped per project. Storing this metadata locally avoids round-trips to the upstream domain's asset store for every build. The engineData JSON column holds engine-specific derived data, such as pre-computed import settings.

Field Type Default Notes
id String auto Primary key
projectId String Project reference
assetId String Asset reference
name String Asset name
type AssetType Asset classification
path String Asset file path
size BigInt File size in bytes
checksum String File checksum
tags String[] [] Searchable tags
metadata Json {} General metadata
engineData Json {} Engine-specific cached data
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp
lastAccessedAt DateTime? Last access timestamp

Unique: [projectId, assetId]. Indexes: projectId, type, updatedAt.


BuildTemplate (build_templates)#

A reusable build configuration that captures a complete set of build settings so teams do not need to re-specify platform combinations, optimization levels, and engine settings for every build. Templates can be marked as the organization default with isDefault.

Field Type Default Notes
id String auto Primary key
name String Template name
description String? Template description
platforms Platform[] [] Target platforms
engines EngineType[] [] Target engines
optimizationLevel OptimizationLevel BASIC NONE / BASIC / FULL
includeDebugSymbols Boolean false Include debug symbols
compressionLevel CompressionLevel MEDIUM LOW / MEDIUM / HIGH
settings Json {} Additional settings
isActive Boolean true Template is available
isDefault Boolean false Is the org default
organizationId String? Owning organization
createdBy String Creator user ID
createdAt DateTime now() Creation timestamp
updatedAt DateTime auto Update timestamp

Indexes: isActive, organizationId.


AuditLog (audit_log)#

An immutable audit trail for all entity changes within the Bellona database. Every mutation to a tracked entity produces an audit record that stores the actor, the before state, the after state, and the diff. The requestId correlates an audit entry back to the originating HTTP request.

Field Type Default Notes
id String auto Primary key
action String Action performed (VarChar(50))
entityType String Entity type changed
entityId String Entity ID changed
previousState Json? State before change
newState Json? State after change
changes Json? Diff of changes
userId String? Actor user ID
ipAddress String? Actor IP address (VarChar(45))
userAgent String? Actor user agent string (Text)
requestId String? Correlation request ID
metadata Json {} Arbitrary metadata
createdAt DateTime now() Creation timestamp

Indexes: [entityType, entityId], userId, action, createdAt. No updatedAt field.


2.2 Enumerations#

The 14 enums below define all categorical values used throughout the schema. Every enum value is referenced by at least one model column above.

Enum Values
BuildStatus PENDING, QUEUED, RUNNING, COMPLETED, FAILED, CANCELLED
JobPriority LOW, NORMAL, HIGH, CRITICAL
Platform WINDOWS, MACOS, LINUX, IOS, ANDROID, WEBGL, PLAYSTATION, XBOX, SWITCH
EngineType UNITY, UNREAL, GODOT, BLENDER, WEB
ExportFormat ZIP, TAR_GZ, UNITYPACKAGE, UASSET, GODOT_PCK
ExportStatus PENDING, PROCESSING, COMPLETED, FAILED, EXPIRED
OptimizationLevel NONE, BASIC, FULL
CompressionLevel LOW, MEDIUM, HIGH
LogLevel DEBUG, INFO, WARNING, ERROR
ConnectionStatus CONNECTED, DISCONNECTED, SYNCING, ERROR
SyncDirection PUSH, PULL, BIDIRECTIONAL
AssetType TEXTURE, MODEL, AUDIO, ANIMATION, MATERIAL, PREFAB, SCRIPT, CONFIG, OTHER
JobType ASSET_BAKE, VALIDATE, ENGINE_PROJECT_GENERATE, EXPORT_PACKAGE
WorkerStatus IDLE, BUSY, PAUSED, STOPPING, STOPPED, OFFLINE

2.3 Schema Conventions#

The following conventions apply uniformly across all 11 models, ensuring consistency that simplifies queries and ORM integration.

  • All primary keys use CUID (@default(cuid()), @db.VarChar(25)).
  • Every model has createdAt; eight models have updatedAt (@updatedAt). BuildArtifact, BuildLog, and AuditLog do not have updatedAt.
  • Build, BuildArtifact, ExportJob, EngineProject, BridgeSession carry a deletedAt soft-delete timestamp.
  • size / totalSize use BigInt to support files larger than 2 GB.
  • metadata, engineData, settings, previousState, newState, changes, and details are PostgreSQL jsonb.
  • Array fields (assetIds, modules, plugins, platforms, engines, tags, warnings, dependencies, jobTypes) are PostgreSQL arrays.
  • BuildWorker.hostname is unique; AssetCache is unique on [projectId, assetId]; BuildArtifact is unique on [storageBucket, storageKey].

3. Build / Export Job Lifecycle#

3.1 Build Status State Machine#

The BuildStatus enum drives the complete build lifecycle from submission to final outcome. A build enters PENDING when enqueued, moves to QUEUED when a worker picks it up, and progresses to RUNNING while the worker executes. It then either reaches COMPLETED, FAILED (retryable up to maxRetries), or CANCELLED by user request.

text
PENDING ──> QUEUED ──> RUNNING ──> COMPLETED
                          │
                          ├──────> FAILED      (retryable up to maxRetries)
                          └──────> CANCELLED   (user request)

A build's retryCount increments on transient failure until it reaches maxRetries (default 3). The build-worker job queue (JobStatus: pending, queued, running, completed, failed, cancelled) mirrors this lifecycle at the worker level.

3.2 Export Status State Machine#

Export jobs follow a simpler lifecycle. Once COMPLETED, a presigned download URL is generated that expires at expiresAt, at which point the job status transitions to EXPIRED.

text
PENDING ──> PROCESSING ──> COMPLETED ──> EXPIRED   (after expiresAt)
                              │
                              └────────> FAILED

3.3 Worker Status State Machine#

A build worker's status reflects its current operational mode. Normal operation cycles through OFFLINE → IDLE → BUSY. The PAUSED, STOPPING, and STOPPED states support controlled drains during deployments. Dead workers are identified when their lastHeartbeat becomes stale.

BuildWorker.status transitions across OFFLINE → IDLE → BUSY during normal operation, and PAUSED, STOPPING, STOPPED during controlled drains.

3.4 Job Priority#

The build-worker priority queue (apps/bellona/build-worker/src/queues/job-queue.ts) orders pending jobs by numeric priority: critical=4, high=3, normal=2, low=1. Higher-priority jobs are always dequeued before lower-priority ones regardless of submission order.


4. Build API (apps/bellona/build-api)#

The Build API is a Node.js module, not an HTTP server. It exposes a programmatic lifecycle API and subscribes to cross-domain events. It does not bind a TCP port itself; the 4005 port number is the documented domain assignment (libs/bellona/README.md) used by sibling services.

4.1 Programmatic API#

@bellona/build-api exports the following entry points from index.ts. The initialize() function is the only required setup step — it wires the cache, queues, and event subscriptions. After that, the module stays alive processing events passively.

typescript
import {
  initialize,
  shutdown,
  getCacheService,
  getBuildCacheService,
  isHealthy,
  getHealthStatus,
} from '@bellona/build-api';

await initialize();

const health = await getHealthStatus();
// {
//   status: 'healthy' | 'degraded' | 'unhealthy',
//   cache: boolean,
//   uptime: number,
//   cacheStats?: { hitRate: number, totalEntries: number }
// }

const cache = getCacheService(); // BuildCacheService

await shutdown();

initialize() performs three steps in order:

  1. Constructs the BuildCacheService (Redis-backed content-addressable cache)
  2. Initializes a dedicated Redis connection for job queues
  3. Wires cross-domain event handlers via @bellona/event-handlers

On startup the process logs "Service ready and listening for events" and stays alive to process events; it does not accept HTTP requests.

4.2 Cache Service exports#

@bellona/build-api also exports BuildCacheService, createBuildCacheService, setBuildCacheService, clearBuildCacheService, and the BuildCacheServiceConfig type. The cache service supports content-addressable storage, compression, deduplication, in-memory + Redis tiers, and Redis PubSub invalidation.

4.3 Type surface#

The module re-exports a large typed surface from types.ts. The types are organized into the following groups:

  • Branded IDsBuildJobId, ArtifactId, ProjectId, AssetId, ContentHash (and their constructors createBuildJobId, createArtifactId, createProjectId, createAssetId, createContentHash)
  • Job typesBuildJob, BuildJobType, BuildJobStatus, BuildJobPriority, BuildError, BuildProgress
  • Artifact typesArtifact, ArtifactType, ArtifactMetadata, TargetPlatform, TargetEngine
  • Cache typesCachedArtifact, CachedBuildJob, CacheEntry, CacheEntryMetadata, CacheLookupResult, CacheStats, CacheConfig
  • Build input typesBuildInput, TextureBuildInput, MeshBuildInput, ShaderBuildInput, AudioBuildInput, AnimationBuildInput
  • Dependency typesDependencyNode, DependencyGraph
  • Event typesBuildEvent, BuildEventType
  • Config typesBuildApiConfig, BuildApiHealth

4.4 Job-queue adapters#

main.ts builds a BuildQueueInterface and ExportQueueInterface. When REDIS_URL is set, jobs are persisted in Redis (bellona:queue:* keys: a job hash, a priority-scored :pending sorted set, and a per-project index set). When REDIS_URL is unset, an in-memory Map is used as a fallback. The build queue supports enqueue, getStatus, and cancel; the export queue supports enqueue and getStatus.


5. Build Worker (apps/bellona/build-worker)#

A poll-based background processor. The JobQueue class is a priority queue with poll-based dequeue (pollInterval default 1000 ms, concurrency default 1).

5.1 Worker types#

JobType is the union asset-bake | validate | engine-project-generate | export-package. Each job type has a dedicated worker module under apps/bellona/build-worker/src/workers/:

Job type Worker module Responsibility
asset-bake asset-bake-worker.ts Texture / model / audio / animation baking
validate validation-worker.ts Build-input and output validation
engine-project-generate engine-project-worker.ts Engine project scaffold generation
export-package export-package-worker.ts Package and export build artifacts

5.2 Worker type surface#

build-worker/types.ts declares branded IDs (JobId, WorkerId, ProjectId, AssetId), JobType, JobStatus, JobPriority, and per-job-type request and result types:

  • asset-bakeAssetBakeRequest / AssetBakeResult / AssetBakeJob (with TextureBakeOptions, ModelBakeOptions, AudioBakeOptions, AnimationBakeOptions)
  • validateValidationRequest / ValidationResult / ValidateJob (with ValidationSeverity, ValidationType, ValidationIssue)
  • Format unionsAssetFormat, TextureFormat, ModelFormat, CompressionQuality

6. Render API (apps/bellona/render-api)#

An internal Node.js module (no HTTP port, no package.json) providing render-job caching, GPU queueing, and output validation.

typescript
import {
  initialize,
  shutdown,
  getCacheService,
  getRenderCacheService,
  isHealthy,
  getHealthStatus,
} from '@bellona/render-api';

6.1 Components#

The render-api is composed of three service components, each with factory and singleton accessor functions:

  • RenderCacheService — Redis-backed render cache (createRenderCacheService, setRenderCacheService, clearRenderCacheService, config type RenderCacheServiceConfig).
  • OutputValidator — render output quality validation (createOutputValidator, getOutputValidator, setOutputValidator), with ValidationSeverity, ValidationCategory, ValidationIssue, OutputValidationResult, JobValidationResult, ValidationOptions.
  • GpuRenderQueue — GPU device allocation and queued job management (createGpuRenderQueue, getGpuRenderQueue, setGpuRenderQueue, clearGpuRenderQueue), with GpuDevice, GpuAllocationRequest, GpuAllocation, QueuedJob, GpuQueueStats, GpuQueueEvents, GpuQueueConfig.

6.2 Type surface#

render-api/types.ts declares the following types for render job management:

  • Job and outputRenderJobId, RenderOutputId, RenderJob, RenderOutput, RenderConfig, RenderSettings, RenderProgress, RenderError
  • ClassificationRenderEngine, OutputFormat, QualityPreset, RenderStatus
  • AnimationAnimationSettings, FrameRange, Resolution
  • CacheCachedRenderJob, CachedRenderOutput, RenderCacheMetadata, RenderCacheStats
  • QueueRenderQueueItem, RenderQueueStatus
  • EventsRenderEvent, RenderEventType
  • ConfigRenderApiConfig
  • ID constructorscreateRenderJobId, createRenderOutputId

7. WebSocket Bridge Protocol#

The four engine bridge apps (bridge-blender, bridge-godot, bridge-unreal, bridge-unity) all build on @bellona/bridge-core (createBridgeServer). The protocol follows the same pattern for every engine: a handshake and ping command are registered first (identical across all bridges), followed by engine-specific commands.

7.1 Connection endpoints#

Engine Default endpoint Port env var Host env var
Blender ws://localhost:9001/blender BLENDER_BRIDGE_PORT BLENDER_BRIDGE_HOST
Godot ws://localhost:9002/godot GODOT_BRIDGE_PORT GODOT_BRIDGE_HOST
Unreal ws://localhost:9003/unreal UNREAL_BRIDGE_PORT UNREAL_BRIDGE_HOST
Unity ws://localhost:9004/unity UNITY_BRIDGE_PORT UNITY_BRIDGE_HOST

Ports default to 90019004 and host to localhost in each app's main.ts.

7.2 Common commands#

Every bridge registers these two commands regardless of engine. handshake establishes mutual version identification; ping verifies liveness.

Command Request data Response data
handshake { clientName, clientVersion } { serverName, serverVersion, protocolVersion }
ping {} { timestamp }

The bridge-core server emits connection, disconnection, command, and error events.

7.3 Engine command sets#

The engine-specific commands registered by each bridge app are listed below. Implementation of each command lives in the corresponding engine adapter library.

Engine Command count Commands
Blender 6 getSceneInfo, createObject, importAsset, exportAsset, setFrame, render
Godot 9 scene-tree access, node create/property/method, scene load, resource load, signal emit, GDScript execution, project settings
Unreal 11 world info, level load/unload, actor spawn/destroy/property, Blueprint function call, material parameter, Sequencer control, console command, screenshot
Unity 14 scene info / load / unload, GameObject create/destroy, prefab instantiate, transform set, component add / property set, animation play, animator parameter, physics force, raycast, message send

The Unity, Unreal, Godot, and Blender command implementations live in @bellona/unity, @bellona/unreal, @bellona/godot, and @bellona/blender respectively.

7.4 Blender bridge session tracking#

bridge-blender is the only bridge that publishes cross-domain events. On connection and disconnection it calls BellonaEventPublisher.publishSessionStarted and publishSessionEnded (see §9). The other bridges track sessions in the database but do not emit cross-domain events.


8. Remote-Control Subsystem#

A browser-first remote-control layer for operating engine hosts, desktop applications, and headless browsers from a web operator console. The apps' package.json descriptions identify the gateway and host as "walking skeleton" services.

8.1 @bellona/remote-protocol#

Canonical protocol contracts for the entire remote-control subsystem. This library defines the type system and namespace structure that all three remote apps share.

Exports: BELLONA_REMOTE_PROTOCOL_PACKAGE_NAME, BELLONA_REMOTE_PROTOCOL_VERSION (0.1.0), BELLONA_REMOTE_PROTOCOL_SCHEMA_STATUS (version-negotiation), and createBellonaRemoteProtocolDescriptor(). The library is partitioned into contract modules: actor, audit, blender, browser, command, common, device, desktop, dry-run, logging, namespaces, policy, result, schema-registry, session, state, stream, unreal, version, plus browser-compensating-actions and desktop-compensating-actions.

The REMOTE_COMMAND_NAMESPACE constant defines 13 command namespaces: device, session, stream, agent, state, blender, unreal, browser, desktop, file, process, approval, diagnostic.

8.2 @bellona/mcp-gateway#

Remote-control MCP gateway server and local stdio transport. Ships a bellona-mcp-gateway binary (src/stdio-cli.js). Modules include stdio-server, remote-control-tools, remote-control-resources, auth-session, command-remediation, mcp-composition-rules, and an agent control layer with the following modules: agent-capability-memory, agent-autonomous-stop-criteria, agent-deep-integration-evals, agent-dry-run-cost-time-estimator, agent-dry-run-impact-summary, agent-dry-run-planners, agent-handoff-paths, agent-long-running-jobs, agent-mutation-locking, agent-preflight-checks, agent-tool-selection-policy, agent-visual-verification-policy.

8.3 Remote-control apps#

App Source highlights
remote-gateway Device registry, session lifecycle, approval service, command dispatcher, pairing codes, host tokens, audit log, redaction, telemetry
remote-host Adapter registry with Blender / Unreal / browser / desktop adapters, command executor, gateway connection, pairing client, identity store, macOS permissions
control-room React/Vite operator UI: approval queue, command palette, device list, session timeline, stream preview, WebRTC loopback, mobile approval PWA, first-session tour

The control-room is gated behind the VITE_BELLONA_CONTROL_ROOM_ENABLED environment flag.

8.4 Phase 180 Roadmap Contract#

The remote-control subsystem is governed by the Phase 180 roadmap: the operating checklist is TODOS/phase-180.md (180.C canonical sequential checklist), the expanded requirements live in TODOS/phase-180-reference.md (180.R / 180.0180.20, including the 180.19 acceptance criteria), and the audit of known scope gaps is TODOS/phase-180-gaps.md. The implementation tracker required by 180.C.01 lives at docs/domains/bellona/extras/remote-control/implementation-tracker.md.

Planned target layout not yet present in the repo:

Package Role
libs/bellona/remote-adapters Adapter interfaces for Blender, Unreal, browser, desktop, files, processes
libs/bellona/mac-host-runtime macOS TCC permissions, process launch, window focus, capture, signing/updates
libs/psyche/desktop-fallback Reusable screenshot/click/type/window fallback shared with Psyche Computer Use
testing/bellona/remote-control Integration, e2e, fixture, and network-impairment test suites

Binding protocol rules from Phase 180: command schemas live only in libs/bellona/remote-protocol and are imported by gateway, host, MCP, adapters, tests, and docs (single source of truth); Blender/Unreal/browser debug and control ports remain localhost-only on the host; deep typed adapters must be preferred over desktop fallback; and no privileged path (arbitrary shell, arbitrary Blender Python, Unreal console, desktop control, or real browser profiles) may ship before policy, approval, and audit primitives are complete.


9. Events#

9.1 Events Published#

@bellona/event-publisher exposes BellonaEventPublisher with eight typed publish methods. The event-type string constants are defined in @oshun/contracts (libs/contracts/src/events/bellona.ts).

The table below shows each event, its publish method, and the key fields in its contract Zod schema payload.

Event Publish method Payload key fields (from contract Zod schema)
bellona.session.started publishSessionStarted sessionId, projectId, userId, engine, engineVersion, workerId, connectionType, capabilities
bellona.session.ended publishSessionEnded sessionId, projectId, userId, engine, durationMs, commandsExecuted, assetsTransferred, bytesTransferred, reason, errorMessage?
bellona.build.started publishBuildStarted buildId, projectId, userId, engine, engineVersion, platform, configuration, features?, sourceCommit?, workerId
bellona.build.progress publishBuildProgress buildId, stage, progress, message?, warnings, errors
bellona.build.completed publishBuildCompleted buildId, projectId, userId, engine, platform, configuration, success, durationMs, artifacts[], metrics
bellona.export.started publishExportStarted exportId, projectId, userId, targetFormat, assets[]
bellona.export.ready publishExportReady exportId, projectId, userId, targetFormat, files[], totalSizeBytes, processingTimeMs, expiresAt
bellona.asset.synced publishAssetSynced syncId, projectId, sessionId, engine, direction, assets[], totalSizeBytes, durationMs

The publisher also exports payload types (BellonaSessionStartedPayload, BellonaSessionEndedPayload, BellonaBuildStartedPayload, BellonaBuildProgressPayload, BellonaBuildCompletedPayload, BellonaExportStartedPayload, BellonaExportReadyPayload, BellonaAssetSyncedPayload) and the GameEngine, BuildPlatform, BuildStatus types, plus getBellonaEventPublisher, createBellonaEventPublisher, resetBellonaEventPublisher.

9.2 Events Consumed#

@bellona/event-handlers defines BELLONA_SUBSCRIPTIONS — four cross-domain subscriptions that drive Bellona's automated build reactions. Each handler receives the event payload and enqueues the appropriate build or export job.

Event Source domain Handler Action
hathor.world.published Hathor handleHathorWorldPublished Enqueues a build for the world
isis.asset.generated Isis handleIsisAssetGenerated Enqueues a build for asset baking
yemaya.build.requested Yemaya handleYemayaBuildRequested Enqueues a build job
yemaya.export.requested Yemaya handleYemayaExportRequested Enqueues an export job

setupBellonaEventHandlers accepts an eventBus, a consumerGroup, a BuildQueueInterface, an ExportQueueInterface, an optional logger, and an optional metrics config. Handler execution metrics are collected through @oshun/metrics via withMetrics / HandlerStatsTracker.

9.3 Event Bus Transport#

The event bus is @oshun/event-bus, which is Redis-backed (it imports ioredis). build-api/main.ts constructs the bus with createEventBus({ redisUrl, sourceDomain: 'bellona', keyPrefix: 'oshun:events', persistence: true, eventTtl: 86400, ... }).

Setting Value
Transport Redis
Source domain bellona
Key prefix oshun:events
Event TTL 86400 s (24 hours)
Retry Exponential, max 3 attempts, 1 s–30 s, multiplier 2
Dead-letter Enabled, 7-day retention, max 1000 entries
Consumer group bellona-build-api (for the build-api subscriber)

10. Asset Interchange (@bellona/interchange)#

The interchange library exposes a format conversion pipeline (import → validate → transform → export) under src/{gltf,fbx,usd,transform,validation}. @bellona/interchange-models provides the shared data schemas.

10.1 AssetFormat union#

The AssetFormat type (interchange/src/types.ts) defines 13 3D-asset format values. This is the complete list of formats the interchange pipeline can process on the import side:

gltf, glb, usd, usda, usdc, usdz, fbx, obj, abc (Alembic), ply, stl, dae (Collada), blend.

10.2 ImageFormat union#

The ImageFormat type defines 9 image format values used for texture interchange:

png, jpg, jpeg, webp, exr, hdr, tga, bmp, tiff.

10.3 @bellona/asset-export#

A planning layer that sits on top of the interchange pipeline. Rather than executing conversions, it produces export plans and manifests that describe what conversions are needed and whether each target is ready or blocked.

Exports:

  • BELLONA_ASSET_EXPORT_FORMATS — the supported export target formats: usd, usda, usdc, usdz, gltf, glb, fbx
  • BellonaAssetExportStatus union — ready / needs-attention / blocked
  • Planning functions — evaluateBellonaAssetExportTarget, evaluateBellonaAssetExportPlan, buildBellonaAssetExportManifest, createBellonaAssetExportTarget, createBellonaAssetExportPlan

Plan evaluation produces per-target readiness ratios, blocking/warning issue counts, and a checksum/package manifest.


11. Cross-Domain Integration (@bellona/integration)#

The integration library is the translation boundary between Oshun domain models and engine-native artifacts. It exports four factory functions, each producing a specialized consumer or compiler instance.

  • createHathorConsumer — imports lore content (worlds, quests, dialogue) from Hathor world-publication events, with a configurable default engine and output directory.
  • createLoreCompiler — compiles lore content for a target engine at a configurable optimization level.
  • createIsisConsumer — imports generated assets from Isis, optionally auto-converting them.
  • createAssetConverter — converts raw assets to engine-native formats via the interchange pipeline.

12. CLI (apps/bellona/cli)#

A Commander.js CLI. The program name is bellona (apps/bellona/cli/src/index.ts). Seven top-level commands are registered:

Command Source Aliases Purpose
build commands/build.ts b (top-level), sub-aliases start/ls/get Submit, list, and inspect build jobs
export commands/export.ts e (top-level), sub-aliases ls/get/rm Create and manage export packages
sync commands/sync.ts sub-aliases bidirectional/ls Push / pull / bidirectional asset sync
config commands/config.ts sub-aliases ls, profile subcommand Manage CLI configuration and profiles
health commands/health.ts Check Build API and Render API health
project commands/project.ts Manage engine project configurations
detect commands/project.ts (detectCommand) Auto-detect engine projects in a directory

The global --api-key option and --api-url resolution use the BELLONA_API_KEY / BELLONA_API_URL / BELLONA_BUILD_API_URL environment variables.


13. TypeScript SDK (@bellona/client)#

@bellona/client provides a typed client. The README shows createBellonaClient({ baseUrl }) with namespaced operations (e.g. client.exports.create, client.exports.onProgress, client.exports.waitForCompletion).


14. C++ Native SDK (@bellona/sdk-cpp)#

libs/bellona/sdk-cpp contains C++ SDK sources (no package.json). It targets native engine plugins and build-machine agents that cannot host a Node.js runtime.


15. Configuration and Environment Variables#

15.1 Build API#

Variable Default Description
BELLONA_DATABASE_URL PostgreSQL connection URL
REDIS_URL redis://localhost:6379 Redis URL (cache + queues + bus). When unset, build-api falls back to in-memory job queues.
BUILD_CACHE_MEMORY_SIZE 104857600 (100 MB) In-memory cache size in bytes
BUILD_CACHE_MAX_SIZE 10737418240 (10 GB) Maximum total cache size in bytes

15.2 Render API#

Variable Default Description
REDIS_URL redis://localhost:6379 Redis connection URL

15.3 Bridge Services#

Variable Default Description
BLENDER_BRIDGE_PORT 9001 Blender bridge WebSocket port
BLENDER_BRIDGE_HOST localhost Blender bridge host
GODOT_BRIDGE_PORT 9002 Godot bridge WebSocket port
GODOT_BRIDGE_HOST localhost Godot bridge host
UNREAL_BRIDGE_PORT 9003 Unreal bridge WebSocket port
UNREAL_BRIDGE_HOST localhost Unreal bridge host
UNITY_BRIDGE_PORT 9004 Unity bridge WebSocket port
UNITY_BRIDGE_HOST localhost Unity bridge host

15.4 CLI#

Variable Default Description
BELLONA_API_URL http://localhost:3020 CLI target API base URL
BELLONA_BUILD_API_URL http://localhost:3020 Build API URL (used by health)
BELLONA_RENDER_API_URL http://localhost:3021 Render API URL (used by health)
BELLONA_API_KEY CLI API authentication key

15.5 Control Room#

Variable Default Description
VITE_BELLONA_CONTROL_ROOM_ENABLED unset Feature flag to enable the operator UI

16. Integration Points#

16.1 Upstream Domains That Trigger Bellona#

The event-driven integration model means no upstream domain calls Bellona over HTTP. Instead, each domain publishes an event and Bellona's event handlers react asynchronously.

Domain Trigger event Bellona response
Hathor hathor.world.published Enqueues a world build
Isis isis.asset.generated Enqueues an asset-baking build
Yemaya yemaya.build.requested Enqueues a build job
Yemaya yemaya.export.requested Enqueues an export job

16.2 Shared Infrastructure Dependencies#

Dependency Usage
@oshun/event-bus Redis-backed cross-domain event pub/sub
@oshun/logging Structured logging across apps
@oshun/cache Redis client / cache primitives
@oshun/contracts Event-type constants and Zod payload schemas
@oshun/metrics Event-handler metrics registry
PostgreSQL Bellona schema database
Redis Build/render cache, build/export job queues, event bus
MinIO / S3 Artifact and export package storage

17. V2 Reciprocal Tasks (Backlog)#

The following items are tracked in the Bellona backlog as reciprocal dependencies of the sister-monorepo V2 fighting-game project.

17.1 BellonaUnrealRuntime (planned)#

  • Task ID: BELLONA-UE-RUNTIME-V2-001
  • Owner: Bellona Runtime Integrations
  • ETA: 2026-06-30

Today the Unreal adapter ships an editor-only plugin at libs/bellona/unreal/plugin/BellonaUnrealEditor/. The runtime-shipped companion plugin BellonaUnrealRuntime is not yet implemented — no BellonaUnrealRuntime directory exists under libs/bellona/unreal/plugin/.

When the runtime plugin is built it will live, like its editor sibling, under Bellona ownership at libs/bellona/unreal/plugin/BellonaUnrealRuntime/. This is the single source of truth for the plugin. V2 must not create V2/ue/Plugins/BellonaUnrealRuntime/ as a parallel copy. The V2 monorepo consumes the Bellona-owned plugin once it ships rather than forking a runtime module of its own; a V2-side check-v2-bellona-runtime-gates.py CI check fails the build if a BellonaUnrealRuntime plugin directory appears under V2/ue/Plugins/.

Until the runtime plugin lands, the Editor-time BellonaUnrealEditor remains available and it is the only Bellona Unreal plugin in either tree; all V2 author/cook workflows (including the frame-snap Live Link handoff in §17.2) run through it. V2 runtime-dependent surfaces stay gated by the @oshun/config feature flags ENABLE_V2_BELLONA_RUNTIME_HOT_RELOAD, ENABLE_V2_BELLONA_RUNTIME_ASSET_IMPORT, and ENABLE_V2_BELLONA_LIVE_COSMETIC_DELIVERY (all default false in libs/shared/config/src/features.ts).

Planned scope: a runtime UE module (no editor-only dependencies) that ships in cooked V2 builds for runtime hot-reload of Bellona-cooked artifacts, ad-hoc runtime asset import on non-rollback surfaces, live cosmetic delivery, and provenance metadata handoff — each gated behind the corresponding feature flag above until the Bellona Runtime Integrations team marks the plugin production-ready.

  • Task ID: BELLONA-MOCAP-V2-FRAME-SNAP-001

This task is implemented in @bellona/mocap under src/frame-snap/. That module defines:

  • Constants BELLONA_MOCAP_FRAME_SNAP_ROUTE (@aja -> @bellona/mocap -> @bellona/unreal), BELLONA_MOCAP_FRAME_SNAP_TARGET_FPS (60), and BELLONA_MOCAP_FRAME_SNAP_TOLERANCE_SECONDS (0.0005).
  • Types BellonaFrameSnapClip, BellonaFrameSnapNotifySegmentKind, BellonaFrameSnapNotifySegmentInput, BellonaFrameSnapNotifySegment, BellonaFrameSnapExportRequest, BellonaFrameSnapLiveLinkManifest (with BellonaFrameSnapManifestClip, BellonaFrameSnapManifestFramePolicy, BellonaFrameSnapManifestLiveLink, BellonaFrameSnapManifestQualityGates), and the BellonaFrameSnapError class.
  • Functions createBellonaFrameSnapLiveLinkExport, normalizeBellonaNotifySegments, snapBellonaSecondsToFrame.

@bellona/mocap resamples Aja-retargeted skeleton clips to 60 Hz, assigns integer frame numbers, normalizes notify segments to integer 60 Hz boundaries, and rejects sub-frame segments. @bellona/unreal receives the editor-only Live Link handoff for import/cook.

The contract route, written with the canonical arrow notation used by the V2 docs, is @aja → @bellona/mocap → @bellona/unreal. Every notify segment carries alignment: 'integer-60hz-frame-boundaries', so the manifest's gameplay windows land on deterministic integer frames. The V2 consumer of this manifest is @v2/aja-bellona-livelink-export (Aja spec §11A.1).

Like the rest of the V2 Bellona surface, this path is author/cook-time only: the manifest sets runtimeLiveLinkPluginRequired: false, the handoff is editorOnlyHandoff, and runtime Live Link plugins remain disabled in shipped V2 builds. Gameplay runs against the cooked, frame-snapped AnimSequence, not a live Link stream — consistent with §17.1, where the runtime plugin is gated until BellonaUnrealRuntime ships.


18. Acceptance Criteria#

The Bellona domain meets its specification when all of the following conditions hold. Each criterion maps directly to a testable behavior.

  1. The Prisma schema migrates cleanly via prisma migrate dev / prisma migrate deploy, producing the 11 documented tables with the documented indexes and constraints.
  2. @bellona/build-api initialize() stands up the build cache, the Redis job queues (or the in-memory fallback when REDIS_URL is unset), and the four cross-domain event subscriptions; getHealthStatus() reports healthy.
  3. The build-worker priority queue dequeues jobs by priority and dispatches each JobType to its dedicated worker module.
  4. Each of the four bridge apps starts a bridge-core WebSocket server on its documented port and registers handshake, ping, and the engine-specific command set (6 / 9 / 11 / 14 commands).
  5. bridge-blender publishes bellona.session.started / bellona.session.ended on connect / disconnect.
  6. @bellona/event-publisher publishes the eight bellona.* events with payloads conforming to the @oshun/contracts Zod schemas, over the Redis-backed event bus.
  7. @bellona/event-handlers consumes hathor.world.published, isis.asset.generated, yemaya.build.requested, and yemaya.export.requested, enqueueing builds/exports.
  8. The bellona CLI exposes the seven documented commands.
  9. The interchange pipeline imports, validates, transforms, and exports the 13 AssetFormat values per its export-capability matrix.