Skip to main content

Why this bridge exists now

OpenAgents intentionally keeps the web application and user account surface in Laravel while the long-running agent runtime lives in Elixir. The current implementation treats Laravel as the authenticated control plane and the Elixir service as the deterministic execution plane. This gives us a stable user-facing API while still letting the runtime own evented execution, replay-safe state transitions, and tool orchestration. The bridge that now exists is concrete and reusable. Laravel receives authenticated Sanctum requests, validates user input at the edge, injects trusted principal context, signs the internal payload, and forwards to /internal/v1/* endpoints on openagents-runtime. The runtime validates the signature and principal headers, executes the operation, and returns a structured response that Laravel relays back to the caller. This pattern is now in production shape for runtime tools, skill registry operations, and Codex worker lifecycle operations.

Current request flow and trust boundary

The user-facing endpoints are under /api/runtime/* in Laravel. These controllers call typed runtime clients that add retry behavior, timeout budgets, a body hash, and an internal signature header. Runtime-side routes are all under /internal/v1/* and require the signed internal auth plug. Laravel sends X-OA-USER-ID for authenticated users and forwards trace headers when present so end-to-end request tracing survives proxying. The critical boundary rule is that runtime ownership and authorization decisions are not delegated to untrusted payload fields. Laravel injects authenticated context, and runtime validates ownership from its own records. This prevents user-to-user cross-run or cross-worker confusion even if callers send misleading IDs.

Runtime configuration surface in Laravel

The bridge is driven by apps/openagents.com/config/runtime.php in the main openagents repository. The active controls include the runtime base URL, per-endpoint path templates, bounded retries, connect and request timeouts, and internal signing key metadata. The same config also exposes routing controls for runtime driver selection and rollback switches, which keeps migration from legacy runtime flows operationally safe. Because this is now used by multiple controllers, runtime requests are not one-off HTTP calls scattered across the app. They are centralized in dedicated clients (RuntimeToolsClient, RuntimeSkillRegistryClient, and RuntimeCodexClient) that all follow the same signature, retry, timeout, and response normalization behavior.

Reusable tool invocation through the API

Tool execution is now exposed through one reusable endpoint:
POST /api/runtime/tools/execute
Authorization: Bearer <sanctum_token>
Content-Type: application/json
The payload includes tool_pack, mode, manifest or manifest_ref, request, and optional policy context. Laravel enforces that the user_id in payload cannot disagree with the authenticated principal, injects authenticated user_id into the request envelope, then forwards to runtime internal tools execution. Runtime then applies policy checks, manifest validation, and tool-pack dispatch. This endpoint is the canonical way to execute runtime tools through the web API. It avoids adding one Laravel route per tool operation and gives us a single integration seam for policy, receipts, and future settlement enforcement.

Operator test path via Artisan

The implementation also includes a direct smoke command in Laravel console routes:
php artisan runtime:tools:invoke-api \
  --api-base=http://127.0.0.1:8000 \
  --token=<SANCTUM_TOKEN> \
  --mode=replay \
  --operation=get_issue \
  --repository=OpenAgentsInc/openagents \
  --issue-number=1747
This command posts to /api/runtime/tools/execute with a full coding payload and prints the status plus JSON response. It was added as an operational verification path so we can test the full control-plane bridge without requiring frontend integration first.

What this enables next

With this bridge in place, OpenAgents can continue shipping runtime capabilities without rewriting the web app and without exposing internal runtime auth details to clients. New runtime primitives can be exposed as additional /api/runtime/* routes that reuse the same signing and principal model, and they can be adopted incrementally by existing product surfaces. This keeps migration velocity high while preserving operational control over correctness-critical runtime behavior.