Skip to content

Anuva Python Server Requirements

Document Status: Draft for engineering implementation
Audience: Codex, Backend Engineers, Unity Engineers, DevOps
Recommended Path: docs/Anuva_Python_Server_Requirements.md
Primary Runtime: Python 3.11+
Primary OS: Windows Server / Windows Desktop
Secondary OS: macOS / Linux where practical


1. Purpose

This document defines the requirements for the Anuva Python Server, a local/VM-side orchestration service responsible for operating the Unity-based video generation worker.

The Python Server acts as the bridge between:

  1. Anuva Web App / Payload CMS backend
  2. Unity Video Generator Windows EXE or Unity Editor Play Mode
  3. Local render-job workspace on the machine
  4. Generated MP4 upload pipeline
  5. Health monitoring and operational dashboard
  6. Local Anuva Web App simulation for development and QA

The document is intended to be detailed enough for Codex to generate the first production-oriented implementation.


2. Source Requirement Summary

The initial requirements for the Python Script are:

  1. Should be cross-platform, with Windows as the primary target and Mac/Linux as secondary targets.
  2. Poll the Anuva Web App to check for render jobs.
  3. Accept a render job and download data/files to an appropriate folder on the Windows local machine.
  4. Control the entire lifecycle of the Unity EXE:
  5. Launch
  6. Monitor
  7. Exit
  8. Heartbeat
  9. Restart
  10. Upload generated MP4 video to the Anuva Web App
  11. Connect to Unity App during Unity Editor Play Mode testing
  12. Communicate with Unity EXE to get status messages using ZeroMQ-based messages between Python and Unity C#.
  13. Monitor Unity EXE health, system performance, and crashes without degrading game frame rates.
  14. Use packages such as psutil, GPUtil, and logging packages.
  15. Create a Windows service using NSSM.
  16. Example:
    nssm install UnityMonitor "C:\Python39\python.exe" "C:\Scripts\monitor.py"
    
  17. Configure the NSSM service to run in the interactive user session, not Session 0, so it can interact with the Unity EXE.
  18. Serve HTTPS servers:
  19. Serve HTML files for Vuplex-based display inside Unity.
  20. Serve an HTML-based GUI for the Python monitoring service.
  21. Support Manual Render Job claiming from the Dashboard web interface.
  22. Support Anuva Web App simulation for complete local testing while the real Web App is still under development.

3. Anuva Product Context

Anuva is a Virtual Studio for businesses to create professional Presentation Videos without filming or video editing.

Users provide intent, business context, documents, images, and videos through the Anuva Web App. The system then generates or compiles:

  • Voiceover scenes
  • Captions
  • Visual assignments
  • Brand, Set, and Bot selections
  • Scene timing
  • Camera shot metadata
  • Renderer-ready Presentation Config JSON

The final video is rendered by a Unity-based Video Generator running on a Windows machine or AWS Windows GPU VM.

The user never edits timelines, camera paths, or layouts directly. The Web App and compiler decide how the presentation should be structured. Unity consumes the compiled config and records the final MP4.


4. High-Level Platform Architecture

Anuva consists of two major runtime surfaces and one worker-side orchestration service.

4.1 Anuva Web App

The Web App is responsible for user-facing creation, asset management, AI generation, compilation, job creation, and result management.

Expected stack:

  • Payload CMS v3 backend
  • Next.js frontend
  • Supabase/Postgres storage layer
  • AWS S3 or compatible object storage for media
  • Mastra-based AI assistant workflows
  • Presentation Config compiler
  • REST APIs for Unity/Python workers

The Web App owns:

  • Users and workspaces
  • Presentations
  • Presentation scenes
  • Media assets
  • RAG sources and chunks
  • Presentation compilations
  • Video generation jobs
  • Render status
  • Final generated media records

4.2 Unity Video Generator

The Unity Video Generator is a Windows EXE, and may also run in Unity Editor Play Mode during development.

It is responsible for:

  • Loading the Presentation Config JSON
  • Loading referenced assets
  • Setting up the 3D Set, Bot, Props, and Virtual Screen
  • Playing voiceover audio
  • Displaying images, captions, HTML, and videos
  • Executing camera shots
  • Capturing the output to MP4
  • Reporting render status back to the Python Server

Unity is the rendering/capture runtime. It should not poll the Web App directly in the preferred V1 architecture. The Python Server handles external orchestration and communicates render commands to Unity.

4.3 Python Server

The Python Server is a persistent orchestration service running on the same machine as Unity.

It is responsible for:

  • Polling Anuva Web App for queued render jobs
  • Listing available render jobs for manual Dashboard claiming
  • Claiming exactly one job at a time per worker instance unless configured otherwise
  • Downloading config and assets
  • Preparing a deterministic local job folder
  • Launching or connecting to Unity
  • Sending job start/config commands to Unity
  • Receiving Unity status via ZeroMQ
  • Monitoring Unity process health
  • Restarting Unity when safe and appropriate
  • Uploading the generated MP4 to the Web App
  • Updating job status, progress, and errors
  • Serving local HTTPS content for Unity Vuplex displays
  • Serving a local monitoring GUI for operators
  • Running a local Web App simulator for development and QA

5. Core Requirements Summary

The Python Server must:

  1. Be cross-platform in structure, with Windows as the primary supported production OS.
  2. Poll the Anuva Web App for queued render jobs.
  3. Claim a render job atomically before processing.
  4. Download all required job data and media files into a local job folder.
  5. Control the Unity EXE lifecycle:
  6. Launch
  7. Monitor
  8. Stop
  9. Heartbeat
  10. Restart
  11. Support connecting to Unity Editor Play Mode for development/testing.
  12. Communicate with Unity using ZeroMQ.
  13. Track Unity health, machine health, GPU health, crashes, and timeouts.
  14. Upload generated MP4 files back to the Anuva Web App.
  15. Run as a Windows service using NSSM.
  16. Be configured to run in an interactive user session, not Session 0, when controlling Unity graphics.
  17. Serve local HTTPS content for Vuplex-powered HTML screens inside Unity.
  18. Serve a local browser-based monitoring dashboard.
  19. Produce structured logs suitable for debugging and future observability.
  20. Support manual render-job discovery from the Dashboard web interface.
  21. Allow an operator/developer to view available Web App render jobs with brief summaries.
  22. Allow an operator/developer to manually claim a selected render job from the Dashboard instead of relying only on automatic polling.
  23. Support automatic polling and manual claiming as separate worker modes.
  24. Provide a local Anuva Web App simulation mode for end-to-end Python Server testing before the real Web App APIs are complete.
  25. Simulate all relevant Web App render job states, API responses, job packages, upload behavior, failure modes, and cancellation flows.

6. Non-Goals for V1

The Python Server must not:

  • Generate voiceover scripts.
  • Generate TTS audio.
  • Run Mastra workflows.
  • Compile Presentation Config JSON.
  • Decide scene visuals.
  • Modify camera shot selection.
  • Edit Presentation Config semantics.
  • Act as a user-facing Web App backend.
  • Replace Payload CMS.
  • Perform video editing after Unity capture, except optional validation or file checks.

The Python Server is an execution worker, not a creative or AI decisioning service.


7. Render Job Lifecycle

7.1 Job States

The Web App is expected to expose render jobs with states similar to:

  • queued
  • claimed
  • inProgress
  • uploading
  • completed
  • failed
  • cancelled

The Python Server should treat the Web App as the source of truth for job state.

7.2 Worker Lifecycle

The Python Server lifecycle should be:

  1. Start service.
  2. Load configuration.
  3. Validate local directories.
  4. Start internal HTTPS servers.
  5. Initialize ZeroMQ sockets.
  6. Optionally launch Unity or wait for Unity Editor connection.
  7. Register heartbeat with Web App if endpoint exists.
  8. Poll for jobs or wait for manual Dashboard claim, depending on configured acquisition mode.
  9. Claim a job.
  10. Download job package.
  11. Prepare local workspace.
  12. Send render command to Unity.
  13. Monitor progress.
  14. Detect completion or failure.
  15. Upload generated MP4.
  16. Mark job completed or failed.
  17. Clean up or archive local files based on retention policy.
  18. Return to polling or manual idle state.

7.3 Single-Job Constraint

V1 should process only one active render job per Python Server instance.

Parallel rendering on one machine is out of scope unless explicitly enabled later.

7.4 Automatic vs Manual Job Claiming Modes

The Python Server must support two job acquisition modes:

  1. Automatic Polling Mode
  2. The worker periodically polls the Web App.
  3. The worker automatically claims the next eligible queued job.
  4. This is the default production mode.

  5. Manual Claim Mode

  6. The worker lists available render jobs in the Dashboard.
  7. The operator/developer selects a job.
  8. The Python Server attempts to claim the selected job atomically.
  9. If claim succeeds, the normal render lifecycle begins.
  10. If claim fails, the Dashboard must show a clear reason.

A third combined mode is also allowed:

  1. Hybrid Mode
  2. The worker polls automatically when idle.
  3. The Dashboard can also manually claim jobs while the worker is idle.
  4. Manual claim must be blocked when another job is active, unless explicitly configured otherwise.

Manual Claim Mode is primarily intended for:

  • Local development
  • QA testing
  • Debugging specific render jobs
  • Controlled render execution on a developer machine
  • Re-rendering selected jobs during Unity integration testing

The Python Server must never bypass Web App job-claim rules. Manual claiming still uses the same atomic claim endpoint as automatic polling.


8. Web App API Contract Assumptions

The exact Payload CMS endpoints may evolve. The Python Server should isolate all Web App communication in a dedicated client module.

Recommended module:

anuva_python_server/webapp/client.py

8.1 Required API Operations

The Python Server needs Web App client methods for:

get_next_queued_job(worker_id: str) -> RenderJob | None
claim_job(job_id: str, worker_id: str) -> RenderJob
get_job_package(job_id: str) -> RenderJobPackage
update_job_status(job_id: str, status: str, progress: float | None, message: str | None) -> None
send_worker_heartbeat(worker_id: str, payload: WorkerHeartbeat) -> None
upload_render_result(job_id: str, file_path: Path, metadata: dict) -> UploadedMedia
complete_job(job_id: str, result_media_id: str) -> None
fail_job(job_id: str, error_code: str, error_message: str, diagnostics: dict | None) -> None
cancel_job(job_id: str, reason: str) -> None

8.1.1 Render Job Listing API Operations

For manual claiming, the Web App client must also support:

list_available_jobs(
    worker_id: str,
    filters: RenderJobListFilters | None = None
) -> list[RenderJobSummary]

get_job_summary(job_id: str) -> RenderJobSummary

manual_claim_job(
    job_id: str,
    worker_id: str
) -> RenderJob

manual_claim_job may internally call the same API endpoint as claim_job, but should remain a separate Python method so the Dashboard flow is explicit and testable.

8.2 Expected Render Job Package

A render job package should contain:

{
  "jobId": "string",
  "workspaceId": "string",
  "presentationId": "string",
  "compilationId": "string",
  "jobType": "preview | finalRender",
  "priority": "standard | priority | fastest",
  "config": {},
  "assets": [
    {
      "assetId": "string",
      "kind": "image | video | audio | html | other",
      "url": "https://...",
      "filename": "string",
      "mimeType": "string",
      "checksum": "optional string",
      "required": true
    }
  ],
  "render": {
    "resolution": "720p | 1080p | 4k",
    "frameRate": 24,
    "aspectRatio": "16:9",
    "format": "mp4",
    "watermark": false
  }
}

8.3 Atomic Claim Requirement

Job claiming must be atomic on the Web App side.

The Python Server must never assume that a job returned by polling or manual listing is safe to process until a claim endpoint succeeds.

If claiming fails because another worker claimed the job, the Python Server should log the claim conflict and resume polling or return to manual idle state.

8.4 Render Job Summary Requirements

For Dashboard listing, each render job summary should include enough information for a developer/operator to confidently choose a job without opening the full Web App.

Recommended fields:

{
  "jobId": "job_001",
  "workspaceId": "workspace_001",
  "presentationId": "presentation_001",
  "presentationTitle": "Product Launch Video",
  "jobType": "preview | finalRender",
  "priority": "standard | priority | fastest",
  "status": "queued",
  "createdAt": "2026-05-14T10:00:00+05:30",
  "requestedBy": {
    "userId": "user_001",
    "displayName": "Demo User",
    "email": "demo@example.com"
  },
  "summary": {
    "useCase": "Product Explainer",
    "sceneCount": 8,
    "targetDurationSec": 75,
    "resolution": "1080p",
    "setVariantName": "Modern Product Studio",
    "botVariantName": "Neutral Professional"
  },
  "readiness": {
    "renderReady": true,
    "blockingIssues": []
  }
}

The Dashboard should display:

  • Job ID
  • Presentation title
  • Job type
  • Priority
  • Created/requested time
  • Use case
  • Scene count
  • Target duration
  • Resolution
  • Render readiness
  • Short status/issue summary

The Dashboard should not display sensitive signed URLs, raw config JSON, or private user data beyond what is necessary for development and operations.


8A. Local Anuva Web App Simulation Mode

The Anuva Web App is still under active development. To unblock Python Server and Unity integration, the Python Server project must include a local Web App simulation mode.

The simulator must behave like a lightweight stand-in for the real Anuva Web App worker API.

It should enable complete local testing of:

  • Job listing
  • Automatic job polling
  • Manual job claiming
  • Job package retrieval
  • Asset download URLs
  • Job status updates
  • Worker heartbeat
  • Render progress reporting
  • Upload success
  • Upload failure
  • Job completion
  • Job failure
  • Job cancellation
  • Web App unavailable behavior
  • Invalid job package behavior
  • Race conditions such as claim conflicts

8A.1 Simulator Modes

The simulator should support at least three usage modes:

  1. In-Process Fake Client
  2. Used by unit tests.
  3. No HTTP server required.
  4. Implements the same Python interface as the real Web App client.

  5. Local HTTP Simulation Server

  6. Runs as a local FastAPI server.
  7. Exposes endpoints shaped like the expected Web App worker API.
  8. Used for integration testing and Dashboard testing.

  9. Scenario-Based Test Harness

  10. Loads predefined render job scenarios from local JSON/YAML files.
  11. Allows deterministic testing of success and failure flows.

The Python Server must be able to switch between real Web App mode and simulation mode using configuration.

8A.2 Simulator Configuration

Example config:

webapp:
  mode: "simulated" # real | simulated
  base_url: "http://127.0.0.1:7090"
  api_token_env: "ANUVA_WORKER_API_TOKEN"

simulator:
  enabled: true
  host: "127.0.0.1"
  port: 7090
  data_dir: "C:\\Anuva\\Worker\\simulator"
  scenario: "happy_path_final_render"
  auto_seed_jobs: true
  simulate_latency_ms: 250

When webapp.mode is simulated, the Python Server should use the local simulator instead of the real Payload CMS backend.

8A.3 Simulator Data Layout

Recommended simulator data layout:

C:\Anuva\Worker\simulator
  scenarios\
    happy_path_final_render\
      jobs.json
      job_packages\
        job_001.json
      assets\
        images\
        videos\
        audio\
        html\
      expected_uploads\
    asset_download_failure\
      jobs.json
      job_packages\
        job_002.json
    claim_conflict\
      jobs.json
      job_packages\
        job_003.json
  uploads\

Each scenario should define:

  • Initial jobs
  • Job packages
  • Asset files
  • Simulated API behavior
  • Upload behavior
  • Expected state transitions

8A.4 Simulated Job State Machine

The simulator must support all relevant job states:

queued
claimed
inProgress
uploading
completed
failed
cancelled

The simulator should track state transitions and reject invalid transitions unless explicitly configured to allow them for testing.

Example valid transition flow:

queued -> claimed -> inProgress -> uploading -> completed
queued -> claimed -> inProgress -> failed
queued -> cancelled
claimed -> cancelled
inProgress -> cancelled

8A.5 Simulator API Endpoints

The simulator should expose endpoints equivalent to the expected real Web App worker API.

Recommended endpoints:

GET  /sim/jobs/available
POST /sim/jobs/{jobId}/claim
GET  /sim/jobs/{jobId}/package
PATCH /sim/jobs/{jobId}/status
POST /sim/jobs/{jobId}/heartbeat
POST /sim/jobs/{jobId}/upload
POST /sim/jobs/{jobId}/complete
POST /sim/jobs/{jobId}/fail
POST /sim/jobs/{jobId}/cancel
GET  /sim/assets/{scenario}/{path}
GET  /sim/state
POST /sim/state/reset
POST /sim/state/load-scenario

The real Web App client abstraction should allow the simulator client and real client to share the same high-level interface.

8A.6 Required Simulation Scenarios

The simulator must include predefined scenarios for:

  1. Happy Path Preview Render
  2. One queued preview job.
  3. Valid config.
  4. All assets downloadable.
  5. Upload succeeds.

  6. Happy Path Final Render

  7. One queued final render job.
  8. Valid config.
  9. All assets downloadable.
  10. Upload succeeds.

  11. Manual Claim Flow

  12. Multiple available jobs.
  13. Dashboard lists jobs.
  14. Operator claims one selected job.
  15. Claimed job is removed from available list.

  16. Claim Conflict

  17. Job appears available.
  18. Claim endpoint rejects it as already claimed.
  19. Dashboard displays claim failure.

  20. Asset Download Failure

  21. Required asset URL returns 404 or simulated timeout.
  22. Python Server fails job before Unity render starts.

  23. Invalid Job Package

  24. Missing config or malformed config.
  25. Python Server fails job with JOB_PACKAGE_INVALID or CONFIG_INVALID.

  26. Unity Render Failure

  27. Job package is valid.
  28. Fake Unity or test harness emits render.failed.

  29. Upload Failure

  30. Unity completes render.
  31. Simulated upload endpoint fails.
  32. Python Server preserves output and marks upload failure/fail state.

  33. Job Cancellation Before Render

  34. Job is cancelled after claim but before Unity starts.

  35. Job Cancellation During Render

    • Simulator reports cancellation while Unity is rendering.
    • Python sends render.cancel.
  36. Web App Unavailable

    • Simulator can intentionally stop responding or return 503.
    • Python Server retries and dashboard remains usable.
  37. Worker Heartbeat Validation

    • Simulator records worker heartbeats and exposes them via /sim/state.

8A.7 Simulator Dashboard

The local Dashboard should include a simulator panel when simulation mode is enabled.

The simulator panel should allow developers to:

  • View current simulator scenario
  • Reset simulator state
  • Load another scenario
  • View simulated Web App jobs
  • Force a job into a specific state
  • Trigger cancellation for a job
  • Trigger upload failure
  • Trigger Web App unavailable mode
  • View simulated API request history

This panel should only appear when simulator.enabled = true.

8A.8 Simulated Upload Behavior

In simulation mode, uploaded MP4 files should be copied to:

C:\Anuva\Worker\simulator\uploads\{jobId}\

The simulator should create a fake uploaded media response:

{
  "mediaId": "sim_media_job_001",
  "url": "http://127.0.0.1:7090/sim/uploads/job_001/final.mp4",
  "filename": "final.mp4",
  "mimeType": "video/mp4",
  "fileSizeBytes": 184000000
}

This allows the complete render lifecycle to be tested without Payload CMS or S3.

8A.9 Simulator Implementation Requirement

The simulator should be implemented as part of the Python Server project, not as a separate external dependency.

Recommended modules:

anuva_python_server/simulator/
  __init__.py
  app.py
  state.py
  scenarios.py
  fake_client.py
  models.py
  uploads.py

The simulator must be optional and must not run in production unless explicitly enabled.


9. Presentation Config Handling

The Python Server receives a compiled Presentation Config JSON from the Web App or simulator.

It must:

  • Save the original config as presentation_config.original.json.
  • Save a renderer-local version as presentation_config.local.json.
  • Rewrite asset URLs in the local version if Unity needs local file paths or local HTTPS URLs.
  • Validate the basic shape before sending to Unity.
  • Never modify semantic fields such as scene text, camera shot choice, timing intent, or visual assignment logic.

9.1 Public Config Fields Relevant to Unity

Unity expects the compiled config to include:

  • schemaVersion
  • presentation
  • studio
  • scenes[]
  • render

Each scene may include:

  • sceneId
  • index
  • timing
  • voiceover.text
  • voiceover.audio.url
  • voiceover.audio.durationSeconds
  • screen.contentMode
  • screen.caption
  • screen.images[]
  • screen.videos[]
  • directing.camera.shot
  • explainability

The Python Server must preserve these fields exactly.

9.2 Asset URL Rewriting

Depending on Unity implementation, assets may be passed as:

  1. Original signed Web App/S3 URLs
  2. Local file paths
  3. Local HTTPS URLs served by the Python Server

Preferred V1 approach:

  • Download all required assets locally.
  • Generate local HTTPS URLs for Unity and Vuplex where needed.
  • Write a local config for Unity with local URLs.

Example rewrite:

{
  "assetId": "img_123",
  "url": "https://127.0.0.1:7443/jobs/job_001/assets/img_123/product.png",
  "mimeType": "image/png"
}

The original cloud URL should be stored in the local job manifest for debugging.


10. Local Workspace Layout

The Python Server should create a root workspace directory.

Default Windows path:

C:\Anuva\Worker

Recommended layout:

C:\Anuva\Worker
  config\
    worker.yaml
    secrets.env
  jobs\
    {jobId}\
      job_manifest.json
      presentation_config.original.json
      presentation_config.local.json
      assets\
        images\
        videos\
        audio\
        html\
        other\
      output\
        final.mp4
        thumbnail.png
      logs\
        python_job.log
        unity_job.log
        zmq_messages.jsonl
      diagnostics\
        system_snapshot_start.json
        system_snapshot_end.json
        crash_report.json
  logs\
    python_server.log
    python_server.jsonl
  cache\
    assets\
  temp\
  certs\
  simulator\
    scenarios\
    uploads\

10.1 Job Manifest

Each job folder must include a job_manifest.json.

Example:

{
  "jobId": "job_001",
  "workspaceId": "workspace_001",
  "presentationId": "presentation_001",
  "compilationId": "compilation_001",
  "claimedAt": "2026-05-14T10:00:00+05:30",
  "workerId": "unity-worker-01",
  "jobType": "finalRender",
  "status": "inProgress",
  "localConfigPath": "presentation_config.local.json",
  "outputPath": "output/final.mp4",
  "assets": [
    {
      "assetId": "audio_001",
      "remoteUrl": "https://...",
      "localPath": "assets/audio/audio_001.mp3",
      "localUrl": "https://127.0.0.1:7443/jobs/job_001/assets/audio/audio_001.mp3",
      "checksum": "..."
    }
  ]
}

11. Unity Lifecycle Management

11.1 Unity Run Modes

The Python Server should support two Unity modes.

11.1.1 Production EXE Mode

The Python Server launches and monitors a Unity Windows EXE.

Example config:

unity:
  mode: exe
  executable_path: "C:\\Anuva\\Unity\\AnuvaVideoGenerator.exe"
  working_directory: "C:\\Anuva\\Unity"
  launch_args:
    - "-screen-fullscreen"
    - "0"
    - "-screen-width"
    - "1920"
    - "-screen-height"
    - "1080"

11.1.2 Unity Editor Play Mode

The Python Server does not launch Unity. It waits for a running Unity Editor Play Mode instance to connect over ZeroMQ.

Example config:

unity:
  mode: editor
  require_existing_connection: true

This is used for development and integration testing.

11.2 Unity Process Control Requirements

In EXE mode, the Python Server must:

  • Launch Unity if it is not running.
  • Support launching Unity explicitly from the Dashboard before a manual job is claimed and run.
  • Detect if Unity exits unexpectedly.
  • Capture Unity stdout/stderr if available.
  • Track process ID.
  • Track process CPU and memory usage.
  • Attempt graceful shutdown before force-killing.
  • Avoid restart loops by applying retry limits and cooldowns.

11.3 Unity Launch Arguments

Unity should receive sufficient startup context via command-line args or ZeroMQ handshake.

Recommended launch args:

--anuva-worker-id unity-worker-01
--anuva-zmq-host 127.0.0.1
--anuva-zmq-command-port 5560
--anuva-zmq-status-port 5561
--anuva-local-server https://127.0.0.1:7443
--anuva-mode worker

The exact argument names can be adjusted, but they must be documented and stable.

11.4 Unity Readiness

After launch, the Python Server must wait for a Unity readiness message before sending a render job.

Expected Unity message:

{
  "type": "unity.ready",
  "unityInstanceId": "unity-abc123",
  "appVersion": "0.1.0",
  "protocolVersion": "1.0",
  "capabilities": {
    "renderMp4": true,
    "previewRender": true,
    "htmlScreen": true,
    "videoScreen": true
  }
}

If Unity does not become ready within unity_startup_timeout_sec, the Python Server must fail startup or restart Unity based on config.

11.5 Unity Restart Policy

Unity should be restarted when:

  • The process exits unexpectedly.
  • Heartbeat is lost for longer than configured timeout.
  • Unity reports fatal internal error.
  • Unity becomes unresponsive during idle state.
  • A render fails due to Unity crash.

Unity should not be restarted mid-render unless:

  • The render has exceeded timeout.
  • Unity heartbeat is lost.
  • Unity process has exited.
  • Operator explicitly cancels/restarts.

12. ZeroMQ Communication

12.1 Transport

Use ZeroMQ for local communication between Python and Unity C#.

Recommended Python package:

pyzmq

Recommended patterns:

  • Python sends commands to Unity.
  • Unity sends status/events back to Python.

Possible socket arrangement:

Command channel:
  Python PUSH or REQ -> Unity PULL or REP

Status channel:
  Unity PUSH or PUB -> Python PULL or SUB

V1 can use REQ/REP for commands and PUSH/PULL for events.

12.2 Ports

Default local ports:

zmq:
  host: "127.0.0.1"
  command_port: 5560
  status_port: 5561
  heartbeat_port: 5562

All ports must be configurable.

12.3 Message Envelope

Every ZeroMQ message must be JSON UTF-8.

Common envelope:

{
  "id": "msg_001",
  "type": "render.start",
  "jobId": "job_001",
  "timestamp": "2026-05-14T10:00:00+05:30",
  "payload": {}
}

Required envelope fields:

  • id
  • type
  • timestamp
  • payload

Recommended optional fields:

  • jobId
  • workerId
  • unityInstanceId
  • correlationId
  • protocolVersion

12.4 Python to Unity Commands

render.start

Sent when Python wants Unity to start rendering a job.

{
  "id": "msg_100",
  "type": "render.start",
  "jobId": "job_001",
  "timestamp": "2026-05-14T10:00:00+05:30",
  "payload": {
    "configPath": "C:\\Anuva\\Worker\\jobs\\job_001\\presentation_config.local.json",
    "configUrl": "https://127.0.0.1:7443/jobs/job_001/presentation_config.local.json",
    "outputPath": "C:\\Anuva\\Worker\\jobs\\job_001\\output\\final.mp4",
    "jobType": "finalRender",
    "render": {
      "resolution": "1080p",
      "frameRate": 30,
      "format": "mp4"
    }
  }
}

render.cancel

{
  "id": "msg_101",
  "type": "render.cancel",
  "jobId": "job_001",
  "timestamp": "2026-05-14T10:01:00+05:30",
  "payload": {
    "reason": "cancelled_by_webapp"
  }
}

unity.shutdown

{
  "id": "msg_102",
  "type": "unity.shutdown",
  "timestamp": "2026-05-14T10:02:00+05:30",
  "payload": {
    "reason": "service_stopping"
  }
}

unity.ping

{
  "id": "msg_103",
  "type": "unity.ping",
  "timestamp": "2026-05-14T10:03:00+05:30",
  "payload": {}
}

12.5 Unity to Python Events

unity.ready

{
  "id": "evt_001",
  "type": "unity.ready",
  "timestamp": "2026-05-14T10:00:05+05:30",
  "payload": {
    "unityInstanceId": "unity-abc123",
    "appVersion": "0.1.0",
    "protocolVersion": "1.0"
  }
}

render.accepted

{
  "id": "evt_002",
  "type": "render.accepted",
  "jobId": "job_001",
  "timestamp": "2026-05-14T10:00:10+05:30",
  "payload": {
    "unityJobId": "unity-job-001"
  }
}

render.progress

{
  "id": "evt_003",
  "type": "render.progress",
  "jobId": "job_001",
  "timestamp": "2026-05-14T10:01:10+05:30",
  "payload": {
    "progress": 42.5,
    "phase": "capturing",
    "message": "Rendering scene 4 of 10"
  }
}

render.completed

{
  "id": "evt_004",
  "type": "render.completed",
  "jobId": "job_001",
  "timestamp": "2026-05-14T10:05:00+05:30",
  "payload": {
    "outputPath": "C:\\Anuva\\Worker\\jobs\\job_001\\output\\final.mp4",
    "durationSec": 72.4,
    "frameCount": 2172,
    "fileSizeBytes": 184000000
  }
}

render.failed

{
  "id": "evt_005",
  "type": "render.failed",
  "jobId": "job_001",
  "timestamp": "2026-05-14T10:03:00+05:30",
  "payload": {
    "errorCode": "UNITY_RENDER_EXCEPTION",
    "errorMessage": "AVPro capture failed",
    "details": {
      "sceneId": "scene_004"
    }
  }
}

unity.heartbeat

{
  "id": "evt_006",
  "type": "unity.heartbeat",
  "timestamp": "2026-05-14T10:03:10+05:30",
  "payload": {
    "state": "idle | rendering | error",
    "fps": 60,
    "currentJobId": "job_001"
  }
}

12.6 Message Logging

All ZeroMQ messages should be logged to:

jobs/{jobId}/logs/zmq_messages.jsonl

Each line should contain:

{
  "direction": "python_to_unity | unity_to_python",
  "message": {},
  "receivedAt": "ISO timestamp"
}

This is critical for integration debugging.


13. Asset Downloading

13.1 Download Requirements

For each job, the Python Server must download:

  • Presentation Config JSON if supplied as URL
  • Voiceover audio files
  • Images
  • Videos
  • HTML/JS/CSS files for virtual screen display if required
  • Any additional renderer-required files

Downloads must support:

  • HTTPS
  • Redirects
  • Signed URLs
  • Retry with backoff
  • Checksum validation if checksum is provided
  • MIME/type validation where practical
  • File size logging

13.2 Download Failure Handling

If a required asset fails to download:

  1. Mark the job as failed.
  2. Report error code:
  3. ASSET_DOWNLOAD_FAILED
  4. Include:
  5. Asset ID
  6. URL host, not full signed URL in normal logs
  7. HTTP status
  8. Retry count
  9. Exception message
  10. Do not send the job to Unity.

If an optional asset fails to download, behavior should be configurable:

assets:
  fail_on_optional_asset_error: false

13.3 Asset Cache

The Python Server may maintain a content-addressed asset cache.

Cache key priority:

  1. Checksum
  2. Asset ID + updatedAt
  3. URL hash

Example:

cache/assets/{checksum}/{filename}

V1 can implement direct per-job downloads first and add cache later.


14. Local HTTPS File Server

The Python Server must run a local HTTPS server to serve job assets and HTML content to Unity/Vuplex.

14.1 Purpose

The local HTTPS server is required for:

  • Vuplex browser displays inside Unity
  • HTML-based Virtual Screen content
  • Local access to downloaded media via stable URLs
  • Monitoring GUI

14.2 Server Requirements

The server must:

  • Bind to 127.0.0.1 by default.
  • Use HTTPS.
  • Support configurable port.
  • Serve static files from job folders.
  • Prevent directory traversal.
  • Prevent access outside the configured worker root.
  • Emit access logs.
  • Support large video/audio file streaming where needed.
  • Set correct content types.

Default content port:

servers:
  content:
    host: "127.0.0.1"
    port: 7443
    https: true

14.3 URL Structure

Recommended URL structure:

https://127.0.0.1:7443/jobs/{jobId}/presentation_config.local.json
https://127.0.0.1:7443/jobs/{jobId}/assets/images/{file}
https://127.0.0.1:7443/jobs/{jobId}/assets/videos/{file}
https://127.0.0.1:7443/jobs/{jobId}/assets/audio/{file}
https://127.0.0.1:7443/jobs/{jobId}/html/{file}

14.4 TLS Certificate

V1 can use a self-signed local certificate.

Certificate files:

C:\Anuva\Worker\certs\localhost.crt
C:\Anuva\Worker\certs\localhost.key

The system should provide a documented helper command to generate dev certificates.

Example CLI:

anuva-worker cert generate-local

15. Monitoring GUI Server

The Python Server must expose a local monitoring dashboard.

Default port:

servers:
  dashboard:
    host: "127.0.0.1"
    port: 7080
    https: false

15.1 Dashboard Purpose

The dashboard is for operators and developers.

It should show:

  • Worker ID
  • Current state
  • Unity process state
  • Unity connection state
  • Current job
  • Job progress
  • Recent jobs
  • Available Web App render jobs
  • CPU usage
  • RAM usage
  • GPU usage
  • GPU memory
  • Disk free space
  • Last heartbeat time
  • Last error
  • Log tail
  • ZeroMQ connection state
  • Web App connectivity state
  • Simulator state when simulation mode is enabled

15.2 Dashboard Actions

V1 dashboard may support:

  • View status
  • View logs
  • View available render jobs
  • Refresh available render jobs
  • View brief render job summary
  • Launch Unity before manual EXE-mode job claiming/running
  • Manually claim selected render job
  • Restart Unity
  • Stop Unity
  • Retry current job if safe
  • Mark current job failed if stuck
  • Open local job folder
  • Reset simulator state when simulator is enabled
  • Load simulator scenario when simulator is enabled

Actions that mutate state should be protected with a local admin token.

The Dashboard Unity panel must display the configured unity.mode. EXE-only controls such as Launch Unity, Restart, and Stop should be visible only when unity.mode is exe; editor mode should hide those process-control actions.

15.3 Dashboard API Endpoints

Recommended internal endpoints:

GET  /api/status
GET  /api/jobs/current
GET  /api/jobs/recent
GET  /api/webapp/jobs/available
GET  /api/webapp/jobs/{jobId}/summary
POST /api/webapp/jobs/{jobId}/claim
GET  /api/system
GET  /api/logs/tail
POST /api/unity/launch
POST /api/unity/restart
POST /api/unity/stop
POST /api/job/fail-current
GET  /api/simulator/state
POST /api/simulator/reset
POST /api/simulator/load-scenario

16. System and Unity Health Monitoring

16.1 Required Packages

Recommended packages:

psutil
GPUtil
pyzmq
httpx
pydantic
pydantic-settings
fastapi
uvicorn
python-dotenv
tenacity
structlog

Optional:

orjson
watchdog
rich
typer

16.2 Metrics to Capture

The Python Server must capture:

System

  • CPU usage %
  • RAM total/used/free
  • Disk total/used/free for worker root
  • Network connectivity to Web App
  • OS name/version
  • Machine hostname
  • Local time

Unity Process

  • Process ID
  • Running/not running
  • CPU usage %
  • Memory usage
  • Runtime duration
  • Exit code
  • Thread count if available
  • Last stdout/stderr lines if captured

GPU

Using GPUtil where available:

  • GPU name
  • GPU load %
  • GPU memory total
  • GPU memory used
  • GPU temperature
  • Driver visibility if available

If GPU metrics are unavailable, the server should continue running and mark GPU metrics as unavailable.

16.3 Health Snapshot

The server should produce a health snapshot object:

{
  "workerId": "unity-worker-01",
  "timestamp": "2026-05-14T10:00:00+05:30",
  "state": "idle",
  "unity": {
    "mode": "exe",
    "running": true,
    "pid": 1234,
    "connected": true,
    "lastHeartbeatAt": "2026-05-14T10:00:00+05:30"
  },
  "system": {
    "cpuPercent": 32.5,
    "memoryPercent": 64.1,
    "diskFreeGb": 120.4
  },
  "gpu": {
    "available": true,
    "loadPercent": 74.2,
    "memoryUsedMb": 6144,
    "memoryTotalMb": 16384,
    "temperatureC": 72
  },
  "currentJob": {
    "jobId": "job_001",
    "status": "rendering",
    "progress": 42.5
  }
}

16.4 Non-Degradation Requirement

Monitoring must not degrade Unity render frame rate.

Guidelines:

  • Do not poll expensive metrics too frequently.
  • Default health poll interval: 5 seconds.
  • GPU poll interval: 5–10 seconds.
  • Log aggregation should be asynchronous.
  • Avoid heavy file scanning during render.
  • Avoid synchronous HTTP calls on the render status event loop.

17. Error Handling and Failure Modes

17.1 Standard Error Codes

Use stable error codes.

Recommended codes:

WEBAPP_UNAVAILABLE
JOB_CLAIM_FAILED
JOB_CLAIM_CONFLICT
JOB_PACKAGE_INVALID
ASSET_DOWNLOAD_FAILED
CONFIG_INVALID
UNITY_NOT_READY
UNITY_START_TIMEOUT
UNITY_PROCESS_EXITED
UNITY_HEARTBEAT_TIMEOUT
UNITY_RENDER_FAILED
UNITY_RENDER_TIMEOUT
OUTPUT_FILE_MISSING
OUTPUT_FILE_INVALID
UPLOAD_FAILED
JOB_CANCELLED
SIMULATOR_SCENARIO_INVALID
INTERNAL_ERROR

17.2 Failure Report

When failing a job, send a structured payload:

{
  "errorCode": "UNITY_RENDER_FAILED",
  "errorMessage": "Unity reported AVPro capture failure",
  "diagnostics": {
    "workerId": "unity-worker-01",
    "unityPid": 1234,
    "jobId": "job_001",
    "lastUnityEvent": {},
    "systemSnapshot": {},
    "logPaths": [
      "jobs/job_001/logs/python_job.log",
      "jobs/job_001/logs/unity_job.log"
    ]
  }
}

Avoid uploading secrets, signed URLs, or local machine credentials in diagnostics.

17.3 Retry Policy

Polling Web App

  • Retry indefinitely.
  • Use exponential backoff with max interval.
  • Continue local dashboard availability.

Downloading Assets

  • Retry 3 times by default.
  • Use exponential backoff.
  • Fail job if required asset still fails.

Uploading MP4

  • Retry 3–5 times.
  • If upload fails after Unity render succeeded, keep output file and mark job as failed or uploadFailed depending on Web App support.
  • Provide a manual retry option.

Unity Render

  • Do not blindly retry renders in V1 unless configured.
  • If retry is enabled:
  • Restart Unity before retry.
  • Retry at most once.
  • Preserve the first failure logs.

18. Upload Flow

18.1 Output Validation

Before upload, validate:

  • Output file exists.
  • Output file extension is .mp4.
  • File size > minimum configured threshold.
  • Modified time is after render start time.
  • Optional duration check if ffprobe is available.

Recommended config:

output:
  min_file_size_bytes: 100000
  validate_with_ffprobe: false

18.2 Upload Metadata

Upload final MP4 with metadata:

{
  "jobId": "job_001",
  "workspaceId": "workspace_001",
  "presentationId": "presentation_001",
  "compilationId": "compilation_001",
  "workerId": "unity-worker-01",
  "jobType": "finalRender",
  "filename": "presentation_001_final.mp4",
  "mimeType": "video/mp4",
  "fileSizeBytes": 184000000,
  "durationSec": 72.4,
  "renderStartedAt": "2026-05-14T10:00:00+05:30",
  "renderCompletedAt": "2026-05-14T10:05:00+05:30"
}

18.3 Upload Destination

Preferred backend behavior:

  • Python uploads to a Payload CMS endpoint.
  • Payload creates a media_assets record.
  • Payload links the uploaded media to video_generation_jobs.resultMedia.
  • Payload updates the related presentation’s latestPreviewVideo or latestFinalVideo.

Alternative:

  • Web App issues a pre-signed upload URL.
  • Python uploads directly to S3.
  • Python calls a completion endpoint with object metadata.

The Python client should be designed so either strategy can be implemented.


19. Cancellation Handling

The Python Server should periodically check whether the current job has been cancelled in the Web App or simulator.

Cancellation behavior:

  1. If job is queued locally but not sent to Unity:
  2. Stop processing.
  3. Mark local status cancelled.
  4. If Unity is rendering:
  5. Send render.cancel to Unity.
  6. Wait for cancellation acknowledgement.
  7. If Unity does not respond, terminate Unity based on config.
  8. Clean up incomplete outputs.
  9. Notify Web App or simulator.

20. Configuration

20.1 Config File

Default config path:

C:\Anuva\Worker\config\worker.yaml

Example:

worker:
  id: "unity-worker-01"
  display_name: "Unity Worker 01"
  environment: "dev"
  root_dir: "C:\\Anuva\\Worker"
  poll_interval_sec: 10
  max_active_jobs: 1

jobs:
  acquisition_mode: "auto" # auto | manual | hybrid
  list_available_limit: 25
  allow_manual_claim_when_busy: false

webapp:
  mode: "real" # real | simulated
  base_url: "https://anuva.example.com"
  api_token_env: "ANUVA_WORKER_API_TOKEN"
  timeout_sec: 30

simulator:
  enabled: false
  host: "127.0.0.1"
  port: 7090
  data_dir: "C:\\Anuva\\Worker\\simulator"
  scenario: "happy_path_final_render"
  auto_seed_jobs: true
  simulate_latency_ms: 250

unity:
  mode: "exe"
  executable_path: "C:\\Anuva\\Unity\\AnuvaVideoGenerator.exe"
  working_directory: "C:\\Anuva\\Unity"
  startup_timeout_sec: 120
  heartbeat_timeout_sec: 30
  render_timeout_sec: 1800
  graceful_shutdown_timeout_sec: 15
  restart:
    enabled: true
    max_attempts: 3
    cooldown_sec: 20

zmq:
  host: "127.0.0.1"
  command_port: 5560
  status_port: 5561
  heartbeat_port: 5562
  receive_timeout_ms: 1000

servers:
  content:
    enabled: true
    host: "127.0.0.1"
    port: 7443
    https: true
    cert_file: "C:\\Anuva\\Worker\\certs\\localhost.crt"
    key_file: "C:\\Anuva\\Worker\\certs\\localhost.key"
  dashboard:
    enabled: true
    host: "127.0.0.1"
    port: 7080
    https: false
    admin_token_env: "ANUVA_DASHBOARD_TOKEN"

assets:
  download_timeout_sec: 120
  max_retries: 3
  verify_checksum: true
  fail_on_optional_asset_error: false
  use_cache: false

output:
  min_file_size_bytes: 100000
  validate_with_ffprobe: false

logging:
  level: "INFO"
  json_logs: true
  log_dir: "C:\\Anuva\\Worker\\logs"
  retain_days: 14

jobs.acquisition_mode controls how jobs enter the worker:

  • auto: worker polls and claims jobs automatically.
  • manual: worker only processes jobs manually claimed from Dashboard.
  • hybrid: worker polls automatically, but Dashboard can also manually claim jobs while the worker is idle.

If allow_manual_claim_when_busy is false, the Dashboard must block manual claiming while another job is active.

20.2 Environment Variables

Required:

ANUVA_WORKER_API_TOKEN

Optional:

ANUVA_DASHBOARD_TOKEN
ANUVA_CONFIG_PATH
ANUVA_LOG_LEVEL

Secrets must not be stored in source control.


21. Windows Service with NSSM

21.1 Service Installation

The Python Server should provide documentation and helper scripts for NSSM installation.

Example:

nssm install AnuvaUnityWorker "C:\Python311\python.exe" "-m anuva_python_server run --config C:\Anuva\Worker\config\worker.yaml"

Set working directory:

nssm set AnuvaUnityWorker AppDirectory "C:\Anuva\Worker"

Set environment variables:

nssm set AnuvaUnityWorker AppEnvironmentExtra ANUVA_WORKER_API_TOKEN=replace-me

Start service:

nssm start AnuvaUnityWorker

Stop service:

nssm stop AnuvaUnityWorker

21.2 Interactive User Session Requirement

Unity graphics applications may not work correctly from Windows Session 0.

The service must be configured to run in an interactive user session or via an operator login/autostart pattern where Unity can access GPU/display resources.

Recommended operational approaches:

  1. Use NSSM to start the Python Server under a dedicated Windows user account.
  2. Ensure that user can access GPU/display resources.
  3. Use auto-login only in controlled VM environments if required.
  4. Avoid running Unity as a pure Session 0 headless service unless separately validated.
  5. Consider Task Scheduler as an alternative for starting the worker at user login.

21.3 Service Recovery

NSSM or Windows Service Recovery should be configured to restart the Python Server if it crashes.

The Python Server itself should manage Unity restart. NSSM should manage Python restart.


22. Python Project Structure

Recommended repository structure:

anuva-python-server/
  pyproject.toml
  README.md
  docs/
    Anuva_Python_Server_Requirements.md
  src/
    anuva_python_server/
      __init__.py
      __main__.py
      app.py
      config.py
      models.py
      logging_config.py
      cli.py

      webapp/
        __init__.py
        client.py
        models.py

      jobs/
        __init__.py
        poller.py
        lifecycle.py
        downloader.py
        workspace.py
        uploader.py
        manifest.py

      unity/
        __init__.py
        process.py
        zmq_client.py
        protocol.py
        lifecycle.py

      servers/
        __init__.py
        content_server.py
        dashboard_server.py

      simulator/
        __init__.py
        app.py
        state.py
        scenarios.py
        fake_client.py
        models.py
        uploads.py

      monitoring/
        __init__.py
        system_metrics.py
        gpu_metrics.py
        health.py

      utils/
        __init__.py
        paths.py
        checksums.py
        time.py
        retry.py
        security.py

  tests/
    unit/
    integration/

23. CLI Requirements

The package should expose a CLI.

Recommended commands:

anuva-worker run --config C:\Anuva\Worker\config\worker.yaml
anuva-worker validate-config --config C:\Anuva\Worker\config\worker.yaml
anuva-worker poll-once --config C:\Anuva\Worker\config\worker.yaml
anuva-worker list-jobs
anuva-worker claim-job --job-id job_001
anuva-worker download-job --job-id job_001
anuva-worker launch-unity
anuva-worker stop-unity
anuva-worker send-test-render --config-path path\to\presentation_config.local.json
anuva-worker cert generate-local
anuva-worker service print-nssm-install
anuva-worker simulator run --scenario happy_path_final_render
anuva-worker simulator reset
anuva-worker simulator load-scenario happy_path_final_render
anuva-worker simulator list-scenarios
anuva-worker dashboard

The CLI can be implemented using typer or argparse.


24. Logging Requirements

24.1 Log Types

The server should maintain:

  1. Main server log
  2. Per-job Python log
  3. Per-job Unity log if available
  4. ZeroMQ message log
  5. Dashboard access log
  6. Asset download log
  7. Upload log
  8. Simulator API request log when simulator is enabled

24.2 Structured Log Fields

Each structured log event should include:

{
  "timestamp": "2026-05-14T10:00:00+05:30",
  "level": "INFO",
  "event": "job.claimed",
  "workerId": "unity-worker-01",
  "jobId": "job_001",
  "message": "Claimed render job"
}

Recommended fields:

  • timestamp
  • level
  • event
  • workerId
  • jobId
  • presentationId
  • unityPid
  • durationMs
  • errorCode
  • exception

24.3 Sensitive Data Redaction

Logs must redact:

  • API tokens
  • Authorization headers
  • Signed URLs
  • Cookies
  • Secret config values

Signed URLs should be logged as host + path hash, not full query string.


25. Security Requirements

25.1 Network Binding

Default behavior:

  • ZeroMQ binds only to 127.0.0.1.
  • Content server binds only to 127.0.0.1.
  • Dashboard binds only to 127.0.0.1.
  • Simulator binds only to 127.0.0.1.

Do not expose local worker endpoints to public networks by default.

25.2 Dashboard Authentication

If the dashboard allows mutation actions, it must require an admin token.

For V1, read-only dashboard may be unauthenticated if bound to localhost only, but token protection is recommended.

25.3 File Serving Safety

The local content server and simulator asset server must:

  • Normalize paths.
  • Reject .. path traversal.
  • Serve only files under configured worker root or simulator root.
  • Reject unknown job IDs.
  • Avoid directory listing.
  • Set conservative headers.

25.4 Web App Authentication

The Python Server should authenticate using a worker-scoped API token.

The token should be:

  • Scoped to worker operations only.
  • Stored in environment variable.
  • Never logged.
  • Rotatable.

26. Testing Requirements

26.1 Unit Tests

Required unit tests:

  • Config loading and validation
  • Job manifest generation
  • Asset URL rewriting
  • Checksum verification
  • Error code mapping
  • ZeroMQ message encoding/decoding
  • Local path safety
  • Web App client request construction
  • Unity process state transitions
  • Render job summary model validation
  • Manual claim state validation
  • Simulator scenario loading

26.2 Integration Tests

Required integration tests:

  1. Fake Web App returns queued job.
  2. Python claims job.
  3. Python downloads fake assets.
  4. Python writes local config.
  5. Fake Unity receives render.start.
  6. Fake Unity emits progress events.
  7. Fake Unity emits completed event.
  8. Python validates fake MP4.
  9. Python uploads fake MP4.
  10. Python marks job complete.
  11. Local simulator returns multiple available jobs.
  12. Dashboard lists available jobs.
  13. User manually claims a selected job.
  14. Simulator rejects a claim conflict.
  15. Simulator accepts status updates across the full lifecycle.
  16. Simulator stores uploaded MP4 locally.

26.3 Unity Editor Test Mode

Development workflow should support:

  • Start Python Server.
  • Start Unity Editor.
  • Enter Play Mode.
  • Unity sends unity.ready.
  • Python sends test render command.
  • Unity renders or simulates render.
  • Python receives completion.

26.4 Failure Tests

Test these failures:

  • Web App unavailable
  • Job claim conflict
  • Invalid job package
  • Asset download 404
  • Asset checksum mismatch
  • Unity startup timeout
  • Unity heartbeat timeout
  • Unity process crash
  • Render timeout
  • Output MP4 missing
  • Upload failure
  • Job cancellation during render

26.5 Simulator Tests

Required simulator tests:

  1. Load scenario from disk.
  2. List available jobs.
  3. Claim job successfully.
  4. Reject claim for already claimed job.
  5. Serve local simulated assets.
  6. Return job package.
  7. Accept status update.
  8. Record heartbeat.
  9. Simulate cancellation.
  10. Simulate upload success.
  11. Simulate upload failure.
  12. Reset simulator state.
  13. Switch scenario at runtime.
  14. Expose simulator state for dashboard inspection.

27. Acceptance Criteria for V1

The implementation is acceptable when:

  1. The Python Server starts from CLI with a YAML config.
  2. The server can run continuously and poll the Web App.
  3. The server can claim a queued job.
  4. The server can download all job assets into a deterministic local folder.
  5. The server can generate presentation_config.local.json.
  6. The server can launch Unity EXE on Windows.
  7. The server can connect to Unity via ZeroMQ.
  8. The server can send render.start to Unity.
  9. The server can receive progress from Unity.
  10. The server can detect Unity render completion.
  11. The server can validate the MP4 output file.
  12. The server can upload the MP4 to the Web App.
  13. The server can mark the job completed.
  14. The server can fail a job with structured diagnostics.
  15. The server can serve local HTTPS files for Unity/Vuplex.
  16. The server exposes a local monitoring dashboard.
  17. The server can be installed and run through NSSM.
  18. The server can connect to Unity Editor Play Mode for testing.
  19. The Dashboard can list available Web App render jobs with brief summaries.
  20. The Dashboard can manually claim a selected render job while the worker is idle.
  21. Manual claiming uses the same atomic claim semantics as automatic polling.
  22. The Python Server can run in simulated Web App mode.
  23. The simulator can provide local render jobs, job packages, assets, uploads, status updates, and cancellations.
  24. The simulator supports success, failure, cancellation, upload failure, and Web App unavailable scenarios.
  25. The full Python Server + fake/simulated Web App + fake/real Unity flow can be tested locally without the real Anuva Web App.

28. Suggested Implementation Milestones

Milestone 1 — Local Worker Skeleton

Build:

  • Config loader
  • CLI
  • Logging
  • Local workspace manager
  • Dashboard /api/status
  • Health snapshot

No Web App or Unity integration yet.

Milestone 2 — Web App Polling and Job Workspace

Build:

  • Web App client
  • Polling loop
  • Job claim
  • Job package download
  • Asset downloader
  • Job manifest
  • Local config writer

Use fake Web App responses if backend endpoints are not ready.

Milestone 2A — Manual Job Claiming and Dashboard Job Listing

Build:

  • Available job listing client method
  • Render job summary model
  • Dashboard available jobs view
  • Manual claim endpoint
  • Manual claim UI action
  • Busy-state guardrails
  • Claim conflict error handling

Milestone 2B — Local Web App Simulator

Build:

  • Simulator FastAPI app
  • Scenario loader
  • Fake Web App client
  • Simulated job state machine
  • Simulated asset serving
  • Simulated upload handling
  • Simulator Dashboard panel
  • Predefined success/failure scenarios

Milestone 3 — ZeroMQ Unity Protocol

Build:

  • ZeroMQ command sender
  • ZeroMQ event receiver
  • Protocol models
  • Fake Unity simulator
  • Render progress flow

Milestone 4 — Unity EXE Lifecycle

Build:

  • Unity launch
  • Unity readiness wait
  • Unity heartbeat monitor
  • Unity restart
  • Unity shutdown
  • Editor Play Mode connection

Milestone 5 — Render Completion and Upload

Build:

  • Output validation
  • Upload client
  • Complete/fail job flow
  • Retry policies
  • Diagnostics bundle

Milestone 6 — Windows Service and Operations

Build:

  • NSSM docs/scripts
  • Local TLS cert helper
  • Log rotation
  • Operator dashboard actions
  • Production hardening

[project]
name = "anuva-python-server"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
  "fastapi>=0.110",
  "uvicorn[standard]>=0.27",
  "httpx>=0.26",
  "pydantic>=2.6",
  "pydantic-settings>=2.2",
  "pyyaml>=6.0",
  "pyzmq>=25.1",
  "psutil>=5.9",
  "GPUtil>=1.4",
  "tenacity>=8.2",
  "python-dotenv>=1.0",
  "structlog>=24.1",
  "typer>=0.9"
]

30. Example Worker State Machine

STARTING
  -> IDLE
  -> POLLING
  -> LISTING_AVAILABLE_JOBS
  -> MANUAL_CLAIM_WAIT
  -> CLAIMING_JOB
  -> PREPARING_JOB
  -> WAITING_FOR_UNITY
  -> RENDERING
  -> UPLOADING
  -> COMPLETING
  -> IDLE

Any active state:
  -> FAILING
  -> IDLE

Service stop:
  -> STOPPING
  -> STOPPED

31. Example Render Sequence

Python Server starts
Python starts content server
Python starts dashboard server
Python starts simulator if enabled
Operator launches Unity from the Dashboard in manual EXE mode
Unity sends unity.ready
Python polls Web App or waits for manual claim
Python receives queued job or user selects a job in Dashboard
Python claims job
Python downloads config/assets
Python writes local config
Python sends render.start to Unity
Unity sends render.accepted
Unity sends render.progress events
Unity writes final.mp4
Unity sends render.completed
Python validates final.mp4
Python uploads final.mp4
Python marks job completed
Python returns to polling or manual idle state

32. Open Questions for Engineering

These should be resolved during implementation:

  1. Exact Payload CMS REST endpoints for worker operations.
  2. Answer: To be defined at a later stage.
  3. Whether upload is direct-to-Payload or direct-to-S3 with signed URL.
  4. Answer: Direct-to-S3 with Signed URL.
  5. Whether Unity requires local file paths or local HTTPS URLs for all assets.
  6. Answer: Local HTTPS URLs.
  7. Whether Vuplex requires trusted TLS certificates or can use self-signed localhost certs.
  8. Answer: Can use self-signed certs.
  9. Whether Unity Editor Play Mode should connect as client or server in ZeroMQ topology.
  10. Answer: Connect as Client.
  11. Whether the Web App will support uploadFailed as a separate job state.
  12. Answer: Yes.
  13. Whether preview render and final render use the same Unity executable mode.
  14. Answer: Yes.
  15. Whether thumbnail generation is Unity’s responsibility or Python’s responsibility.
  16. Answer: Python.
  17. Whether ffprobe should be bundled for output validation.
  18. Answer: Yes - FFMPEG will be installed on the server.
  19. Whether multiple workers can run on the same VM in the future.
  20. Answer: Yes.
  21. Whether the simulator should exactly mirror future Payload endpoints or remain a worker-facing abstraction.
  22. Answer: Should be an exact mirror.
  23. Whether manual Dashboard claiming should be enabled in production or limited to development/QA environments.
  24. Answer: Yes, should be enabled in production.

33. Local Development Principle

The Python Server must be testable before the real Web App is complete.

A developer should be able to run:

  1. Python Server
  2. Local Web App Simulator
  3. Fake Unity or Unity Editor Play Mode

…and exercise the complete render lifecycle locally.

The simulator is not a mock afterthought. It is a first-class development and QA tool for validating worker behavior, Unity integration, dashboard controls, and failure handling.


34. Final Implementation Principle

The Python Server should be boring, deterministic, observable, and recoverable.

It should not make creative decisions.

It should reliably execute the compiled Presentation Config, supervise Unity, preserve diagnostics, upload the result, and keep the Web App informed.

If a failure occurs, the system should always answer:

  1. Which job failed?
  2. Which worker processed it?
  3. What stage failed?
  4. What did Unity report?
  5. What files were involved?
  6. Can the job be safely retried?

End of Document