5.7 KiB
Universal Worker Agent — Phase 6: Database & Runtime Registry Extensions
Date: 2026-02
Phase: 6 of 7 (Universal Worker Agent)
Plan: docs/plans/universal-worker-agent.md
Overview
Phase 6 extends the runtime registry so that the universal worker agent (attune-agent) can work with arbitrary runtimes — including languages like Ruby, Go, Java, Perl, and R — without requiring every possible runtime to be pre-registered in the database by an administrator.
Changes Made
6.1 Extended Runtime Detection Metadata
Migration (migrations/20250101000012_agent_runtime_detection.sql):
- Added
auto_detected BOOLEAN NOT NULL DEFAULT FALSEcolumn toruntimetable — distinguishes agent-created runtimes from pack-loaded ones - Added
detection_config JSONB NOT NULL DEFAULT '{}'column — stores detection metadata (detected binary path, version, runtime name) - Added index
idx_runtime_auto_detectedfor efficient filtering
Rust Model (crates/common/src/models.rs):
- Added
auto_detected: boolanddetection_config: JsonDictfields to theRuntimestruct
Repository (crates/common/src/repositories/runtime.rs):
- Added
SELECT_COLUMNSconstant centralising the column list for all runtime queries - Added
auto_detectedanddetection_configtoCreateRuntimeInputandUpdateRuntimeInput - Updated ALL 7 SELECT queries, 2 RETURNING clauses, and the INSERT statement to include the new columns
- Updated the
updatemethod to support settingauto_detectedanddetection_config
External query sites updated:
crates/common/src/runtime_detection.rs—detect_from_database()crates/common/src/pack_environment.rs—get_runtime()crates/worker/src/executor.rs—prepare_execution_context()
All CreateRuntimeInput construction sites updated (7 files):
crates/api/src/routes/runtimes.rscrates/common/src/pack_registry/loader.rscrates/common/tests/helpers.rscrates/common/tests/repository_runtime_tests.rscrates/common/tests/repository_worker_tests.rscrates/executor/tests/fifo_ordering_integration_test.rscrates/executor/tests/policy_enforcer_tests.rs
6.2 Runtime Template Packs
Added 5 new runtime YAML definitions in packs/core/runtimes/:
| File | Ref | Interpreter | Environment | Dependencies |
|---|---|---|---|---|
ruby.yaml |
core.ruby |
ruby (.rb) |
GEM_HOME isolation | Gemfile → bundle install |
go.yaml |
core.go |
go run (.go) |
GOPATH isolation | go.mod → go mod download |
java.yaml |
core.java |
java (.java) |
None (simple) | None |
perl.yaml |
core.perl |
perl (.pl) |
local::lib isolation | cpanfile → cpanm |
r.yaml |
core.r |
Rscript --vanilla (.R) |
renv isolation | renv.lock → renv::restore() |
Each includes verification commands matching the auto-detection module's probe strategy.
6.3 Dynamic Runtime Registration
New module (crates/worker/src/dynamic_runtime.rs):
auto_register_detected_runtimes(pool, detected)— main entry point called fromagent_main.rsBEFOREWorkerService::new()- For each detected runtime:
- Alias-aware lookup in existing DB runtimes (via
normalize_runtime_name) - If not found, looks for a template runtime by ref pattern
core.<name> - If template found, clones it with
auto_detected = trueand substitutes the detected binary path - If no template, creates a minimal runtime with just the interpreter binary and file extension
- Auto-registered runtimes use ref format
auto.<name>(e.g.,auto.ruby)
- Alias-aware lookup in existing DB runtimes (via
- Helper functions:
build_detection_config(),build_execution_config_from_template(),build_minimal_execution_config(),build_minimal_distributions(),capitalize_runtime_name() - 8 unit tests covering all helpers
Agent entrypoint (crates/worker/src/agent_main.rs):
- Added Phase 2b between config loading and
WorkerService::new() - Creates a temporary DB connection and calls
auto_register_detected_runtimes()for all detected runtimes - Non-fatal: registration failures are logged as warnings, agent continues
Runtime name normalization (crates/common/src/runtime_detection.rs):
- Extended
normalize_runtime_name()with 5 new alias groups:ruby/rb→rubygo/golang→gojava/jdk/openjdk→javaperl/perl5→perlr/rscript→r
- Added 5 new unit tests + 6 new assertions in existing filter tests
Architecture Decisions
-
Dynamic registration before WorkerService::new(): The
WorkerServiceconstructor loads runtimes from the DB into an immutableRuntimeRegistrywrapped inArc. Rather than restructuring this, dynamic registration runs beforehand so the normal loading pipeline picks up the new entries. -
Template-based cloning: Auto-detected runtimes clone their execution config from pack templates (e.g.,
core.ruby) when available, inheriting environment management, dependency installation, and env_vars configuration. Only the interpreter binary path is substituted with the actual detected path. -
Minimal fallback: When no template exists, a bare-minimum runtime entry is created with just the interpreter binary. This enables immediate script execution without environment/dependency management.
-
auto.ref prefix: Auto-detected runtimes useauto.<name>refs to avoid collisions with pack-registered templates (which usecore.<name>or<pack>.<name>).
Test Results
- Worker crate: 114 passed, 0 failed, 3 ignored
- Common crate: 321 passed, 0 failed
- API crate: 110 passed, 0 failed, 1 ignored
- Executor crate: 115 passed, 0 failed, 1 ignored
- Workspace check: Zero errors, zero warnings