9.7 KiB
Why
Every capability built through Milestone 9 — device-management/driver-registry (apex-agent-mvp, device-agent-runtime-foundation), agent-runtime, workflow-orchestration, multi-agent-collaboration — still assumes one process, one DeviceManager, and a caller who already knows which device_id to target. That is fine for a single developer driving a handful of physical devices from one machine, but it does not scale to "many devices across many hosts, tasks submitted by external systems without knowing which device is free, and new drivers/tools/skills added without editing this repository's core packages." Milestone 10 (Cloud Runtime) is the platform-completion step: it introduces a device pool that aggregates device state across hosts, a scheduler that assigns queued tasks to idle devices instead of requiring callers to pick one, a plugin mechanism so a second driver (or a tool/skill) can register itself without touching driver/, device/, or tools/, and a versioned public SDK/API for external integrators that is distinct from the LLM-facing MCP tool server. None of this replaces the existing single-process, single-goal execution path — it composes it, the same way workflow-orchestration-runtime composed TaskRunner rather than rewriting it.
What Changes
- Add a new
cloud/package, sibling toagents/,workflow/,semantic/,world/,skills_learning/, holding all four new capabilities below. No existing package (driver/,device/,runtime/,tools/,workflow/,agents/,storage/,api/console.py,api/mcp.py) is modified. - Add
cloud/pool.py: aDevicePoolthat aggregates device state across multiple hosts, each still running its own unmodified single-processDeviceManager(device-management). A per-host sync call (DevicePool.sync_host_devices(host_id, snapshot)) pushes that host'sDeviceManager.list_devices()result into the pool on a heartbeat interval; the pool tracksHostRegistration(host id, address, last-seen) andPooledDevice(device id, owning host id, driver_type, status, capability tags) records, and marks a host's devicesunreachable(a new pool-level status, distinct fromdevice-management's ownidle/busy/offline/error) once its heartbeat goes stale — never raises or blocks on a missing host. - Add
cloud/scheduler.py: aTaskSchedulerthat accepts a queued task submission (goal + optional device constraints:driver_type, required capability tags), holds it in a bounded FIFO queue backed bycloud/store.py, and assigns it to the first matchingidlePooledDevicetheDevicePoolreports, via a pluggableAssignmentStrategyregistry (default: FIFO + constraint match; a priority/capability-scoring strategy can be added later without changingTaskScheduler's control flow). - Add
cloud/dispatch.py: aTaskDispatcherthat takes aTaskSchedulerassignment (task +device_id+host_id) and actually runs it by composing the existing, unmodifiedagent-runtimeTaskRunner(single-goal tasks) orworkflow-orchestration'sWorkflowRunner(multi-stepWorkflowDefinitions), strictly through their existing publicrun(task) -> Task/run(definition) -> WorkflowRunentry points — closing the loop from "assigned" to "executed" without a caller ever hand-picking adevice_idagain. - Add
cloud/plugins.py: aPluginManifestschema (name, version,entry_point_kind: driver | tool | skill, module/callable reference) and aPluginRegistrythat discovers manifests via Pythonentry_points(groupdevice_agent_runtime.plugins) and/or a localplugins/*/plugin.jsondirectory scan, validates them, and — fordriver-kind manifests only — registers them intodriver-registry's existingdriver_type -> factoryextension point.tool- andskill-kind manifests are accepted and validated by the same schema but are declared-not-yet-wired in this change (see Non-Goals in design.md), sincetools/and the skill stores (skill-catalog-subscription,skill-learning-runtime) do not yet expose a comparable public registration hook to compose against. - Add
cloud/sdk/(api.py,client.py,models.py): a versioned (/v1/...) public REST API plus a thin Python client, for external integrators to submit tasks/workflows to the pool+scheduler, poll task/device/host status, and list/register plugins — a fleet-facing surface distinct frommcp-tool-server's per-device, LLM-facing tool calls and fromweb-console's operator-facing status/config UI (console-status-api/console-config-api), which both continue to talk to one process's ownDeviceManagerdirectly. - Add
cloud/store.py: a new, independently-owned SQLite file (cloud/cloud.sqlite3) withhost_registrations,pooled_devices,scheduled_tasks, andpluginstables — mirrorsworkflow-orchestration-runtime's precedent of a capability-owned store rather than adding tables tostorage/task_metadata.py. - Add
cloud/config.py: heartbeat interval, host-staleness threshold, queue depth limit, defaultAssignmentStrategyname, SDK API version prefix — all with conservative defaults so this change is inert until a caller actually registers a second host or submits through the new SDK. - BREAKING: none.
driver/,device/,runtime/,tools/,workflow/,agents/,storage/,api/console.py, andapi/mcp.pyare not modified;cloud/is purely additive and composes all of them by import.
Capabilities
New Capabilities
device-pool: A multi-host device registry/discovery layer (DevicePool,HostRegistration,PooledDevice) aggregating the device state each host's existing single-processDeviceManageralready tracks, with heartbeat-based staleness detection so an unreachable host degrades its devices' pool-visible status rather than blocking or crashing the pool.task-scheduler: A queue (TaskScheduler) plus pluggableAssignmentStrategymatching submitted tasks (goal + device constraints) to an idlePooledDevice, and aTaskDispatcherthat executes an assignment by composing the existingagent-runtime/workflow-orchestrationexecution paths as black boxes.plugin-system: A registration mechanism (PluginManifest+PluginRegistry, entry-points or manifest-file discovery) for new drivers/tools/skills to register themselves without editingdriver/,device/,tools/, or the skill stores; concretely wired for driver-kind plugins intodriver-registry's existing extension point, with tool/skill-kind plugins schema-defined for forward compatibility.platform-sdk: A versioned, public-facing REST API and Python client for external integrators to submit tasks/workflows, query device/host/task status, and manage plugins across the device pool — separate frommcp-tool-server(LLM-facing) andconsole-status-api/console-config-api(operator-facing, single-process).
Modified Capabilities
(none — openspec/specs/ is currently empty and none of device-management, driver-registry, agent-runtime, workflow-orchestration, mcp-tool-server, console-status-api, console-config-api have an applied baseline to diff against; this change composes all of them by import/prose dependency only and does not alter their specified behavior.)
Impact
- New package:
cloud/—pool.py(DevicePool,HostRegistration,PooledDevice),scheduler.py(TaskScheduler,AssignmentStrategyregistry,ScheduledTask),dispatch.py(TaskDispatcher),plugins.py(PluginManifest,PluginRegistry),store.py(CloudStore, schema forcloud/cloud.sqlite3),config.py, andcloud/sdk/(api.py,client.py,models.py). - No changes to
core/(ordriver//device/oncedevice-agent-runtime-foundationis applied),runtime/,tools/,storage/,workflow/,agents/,api/console.py,api/mcp.py,api/rest.py— every integration point is by import/composition, matching the precedent set byworkflow-orchestration-runtime(D1, D8) andmulti-agent-runtime(CollaborativeTaskRunnercomposingTaskRunner). - Reads from pending capabilities (composition only, no spec changes to them):
device-management/driver-registryfor the per-hostDeviceManager/driver-type extension pointdevice-poolaggregates andplugin-systemregisters into;agent-runtimeandworkflow-orchestrationfor theTaskRunner/WorkflowRunnerentry pointstask-scheduler'sTaskDispatcherinvokes;mcp-tool-serveras the sibling LLM-facing surfaceplatform-sdksits alongside without replacing;console-status-api/console-config-api(web-console) as the sibling operator-facing surface this change does not extend or duplicate. - Config:
pyproject.tomlgains acloud*entry in[tool.setuptools.packages.find].include; no new third-party dependency is required for the pool/scheduler/plugin data models (plugin discovery uses the standard-libraryimportlib.metadata), thoughcloud/sdk/api.pyreuses the already-declaredfastapi/uvicorndependencies andcloud/sdk/client.pywill need an HTTP client (reusehttpx, already a dev dependency — promote to a runtime dependency intasks.md). - Out of scope: no actual multi-host deployment/infra config (Docker/Kubernetes manifests, service discovery infra) — only the runtime's internal pool/scheduler/plugin/SDK model; no billing, multi-tenant auth, or rate limiting on
platform-sdk(a later change's concern); no cross-host network dispatch mechanism for actually invoking a remote host'sDeviceManagerover the wire (TaskDispatchercomposesTaskRunner/WorkflowRunneronly when the assignment lands on the local host — see design.md's Non-Goals and Open Questions for the remote-dispatch gap); no changes toskill-catalog-subscription,skill-learning-runtime,web-console, ormulti-agent-runtime.