# Cloud Control Plane Deployment This guide covers the deployable Cloud API and outbound Device Host Agent. Run commands from the repository root after synchronizing the uv workspace: ```bash uv sync --locked --all-packages ``` ## Local SQLite SQLite is intended for local development and tests with one Cloud API process. Configure public and host credentials even in local mode because anonymous development access cannot authorize a host identity. ```powershell $env:CLOUD_ENVIRONMENT = "local" $env:CLOUD_DATABASE_URL = "sqlite:///cloud/cloud.sqlite3" $env:CLOUD_PUBLIC_CREDENTIALS_JSON = '[{"principal_id":"local-sdk","token":"replace-public-token","scopes":["tasks:submit","tasks:read","pool:read","plugins:read","plugins:admin"]}]' $env:CLOUD_HOST_CREDENTIALS_JSON = '[{"principal_id":"local-host","token":"replace-host-token","scopes":[],"host_id":"host-local"}]' uv run --package device-cloud-api device-cloud-api --host 127.0.0.1 --port 8001 ``` In a second terminal, start the Host Agent with the matching host identity and token: ```powershell $env:HOST_AGENT_CONTROL_PLANE_URL = "http://127.0.0.1:8001" $env:HOST_AGENT_HOST_ID = "host-local" $env:HOST_AGENT_TOKEN = "replace-host-token" uv run --package device-host-agent device-host-agent ``` At startup, the Host Agent loads device registrations from `tasks/device_config.sqlite3`, the same `DeviceConfigStore` used by the local Runtime console API. Register or update devices before starting the Host Agent, then restart it to reload changes. In Compose, `HOST_AGENT_TASKS_PATH` selects the host directory mounted at `/app/tasks`; it defaults to `./tasks`. The Host Agent only initiates outbound HTTP requests. It does not expose an inbound port. ## PostgreSQL Deployment Start from `.env.example`, replace every `change-me-*` value, and keep the resulting `.env` file outside version control. The Compose stack contains PostgreSQL, the Cloud API, and one Host Agent: ```bash docker compose up --build -d docker compose ps ``` The Cloud API container waits for PostgreSQL, runs the committed Alembic migrations, then starts the API on port `8001`. Readiness is available at: ```text GET http://127.0.0.1:8001/health/ready ``` For a deployment that manages processes outside Compose, apply migrations before starting the new Cloud API version: ```powershell $env:CLOUD_DATABASE_URL = "postgresql+psycopg://USER:PASSWORD@HOST:5432/device_cloud" uv run alembic -c packages/cloud-platform/cloud/migrations/alembic.ini upgrade head uv run --package device-cloud-api device-cloud-api --host 0.0.0.0 --port 8001 ``` Production startup requires `CLOUD_ENVIRONMENT=production`, a current schema, and at least one configured bearer credential. ## Credentials And Scopes `CLOUD_PUBLIC_CREDENTIALS_JSON` is a JSON array of public API principals. Grant only the scopes required by each integration: - `tasks:submit`: submit tasks. - `tasks:read`: read task status and failure metadata. - `pool:read`: list hosts and devices. - `plugins:read`: list installed plugin registrations. - `plugins:admin`: register installed plugin entry points. `CLOUD_HOST_CREDENTIALS_JSON` contains Host Agent principals. Every entry must include exactly one `host_id`; its token is valid only for heartbeat, claim, renewal, and result operations for that host. Do not place bearer tokens in command history, image layers, Compose files, or logs. Use environment injection or the deployment platform's secret manager. Rotate a token by deploying the updated Cloud API credential set and Host Agent configuration together. ## Runtime AI Planner The Host Agent reuses the local Runtime planner. AI planning is disabled by default. Configure it in the Host Agent environment when goal assignments must use a model: ```text AI_PLANNER_ENABLED=true AI_PLANNER_PROVIDER=anthropic AI_PLANNER_MODEL=claude-sonnet-5 AI_PLANNER_TIMEOUT_SECONDS=30 ANTHROPIC_API_KEY= ``` For OpenAI, set `AI_PLANNER_PROVIDER=openai`, choose the deployed model through `AI_PLANNER_MODEL`, and provide `OPENAI_API_KEY`. Provider credentials belong only on the Host Agent; the Cloud API does not need them. ## Operational Limitations Run exactly one scheduler-enabled Cloud API process. SQLite supports only the documented single-control-plane development mode. PostgreSQL row locking makes assignment and claim transactions safe if requests overlap, but this release does not implement scheduler leader election or claim active-active scheduler operation. Starting multiple Cloud API replicas would start one scheduler loop per replica and is outside the supported deployment topology. Device execution provides at-least-once side-effect semantics, not exactly-once semantics. A device action can succeed immediately before the Host Agent loses its lease or its result response, after which the control plane may retry the task. Lease renewal and cooperative stop checks prevent later interruptible actions where possible, but they cannot roll back an action already sent to a device or safely terminate an in-progress synchronous driver call. Use bounded attempts, inspect task attempt and failure metadata, and design device workflows to tolerate repeated actions when the target operation allows it. Do not use this release for operations that require a transactional exactly-once guarantee across the cloud database and an external device. ## Shutdown And Rollback For a normal shutdown, stop Host Agents first so they stop polling, interrupt later cooperative actions, finish terminal reporting where the lease remains valid, and attempt a final heartbeat. Stop the Cloud API after Host Agents have exited, then stop PostgreSQL only if the database itself is being maintained: ```bash docker compose stop host-agent docker compose stop cloud-api docker compose stop postgres ``` For rollback: 1. Stop all Host Agents and the Cloud API. 2. Back up PostgreSQL or the SQLite database file. 3. If the previous application version cannot use the current schema, run the tested downgrade while no application process is connected: ```bash uv run alembic -c packages/cloud-platform/cloud/migrations/alembic.ini downgrade -1 ``` 4. Restore the previous application image or checkout and start the Cloud API. 5. Verify `/health/ready`, then restart Host Agents with credentials compatible with the restored Cloud API. Do not remove the PostgreSQL volume during an application rollback. Queued and attempt history are durable database state and should remain available to the restored or forward-deployed control plane.