# Artemis Thin Client Design This document describes the remote SDK, not the web console's visual design. The shared runtime and UI boundaries are documented in the repository's [DESIGN.md](../../DESIGN.md). Current behavior below includes the 2.0 exploration adapter; versioned remote endpoints remain a protocol evolution proposal. ## Goals Developer machines install only a small remote SDK, while the host connected to Android devices runs the full Artemis stack. The SDK must: - have no dependency on ADB, device drivers, agents, LLMs, web services, or image libraries; - never attempt to start a local Artemis daemon; - remain compatible with the existing server API; - allow the server to add agent and device capabilities independently; and - provide explicit capability negotiation and errors as the protocol evolves. ## Boundary The client owns request modeling, HTTP communication, status polling, error normalization, and result models. Device discovery, task scheduling, concurrency control, model selection, execution, logs, videos, and artifact generation all belong to the server. The distribution is named `artemis-client`, while the Python import is `artemis_client`. This prevents it from shadowing the full runtime's top-level `artemis` package. The full runtime can depend on this package later and re-export the client from `artemis` for compatibility. ## Phase 1: Compatibility Adapter The first release calls the current `/api/*` administration endpoints directly. The client generates a task ID and maps it to the server's existing `session_id` to make retries idempotent. While a task is queued but not yet visible in the session database, the client reconstructs its state from `queue` and `active_tasks` in `/api/status`. Experimental parameters live in `options`. Older servers ignore unknown fields, while newer servers can consume them without requiring an immediate SDK release. ### Guided exploration in 2.0 `ArtemisClient.exploration()` uses the existing `/api/explorations` API shared with the web workspace and MCP. It supports read-only list/get/case queries, session lifecycle and messages, manual demonstrations, immutable case versions, generation, reruns, and batch-draft creation. It adds no scheduler or local agent. Mutations require a stable `request_id`, except pause/stop. Reusing a request ID must not repeat the business operation. Read operations reject mutation fields; creating a batch draft does not start it. Case generation returns a job whose state is read from the exploration session, rather than blocking the client for the entire model call. Execution status, test verdict, case generation, and rerun results are separate. `TaskResult.succeeded` currently reflects execution status only; it does not prove that the test passed. Consumers must inspect the server's effective test result and evidence, including `runs[].test_result` for exploration, and retain unknown response fields through `raw`. A client polling timeout does not cancel the server task; stopping it is a separate explicit operation. The host owns source metadata, demonstration recording scope, execution budgets, model retries, final acceptance, and artifact persistence. The client passes the requested settings through the shared API and never reconstructs missing PC evidence from Android screenshots or restarts a case after a request failure. ## Phase 2: Proposed stable remote API The following endpoints are an evolution proposal, not the current submission API. Do not replace the working compatibility adapter with these routes until the host implements and advertises them: ```text POST /api/v1/tasks GET /api/v1/tasks/{task_id} DELETE /api/v1/tasks/{task_id} GET /api/v1/tasks/{task_id}/events GET /api/v1/tasks/{task_id}/artifacts GET /api/v1/devices GET /api/v1/capabilities ``` A future remote surface can separate administration access from task access while delegating to the same backend services and scheduler. The proposed error envelope is: ```json { "error": { "code": "DEVICE_OFFLINE", "message": "The selected device is offline", "retryable": false } } ``` ## Compatibility Rules 1. `/api/v1` may add optional request and response fields, but must not change existing field semantics. 2. The client ignores unknown response fields and preserves the original response in each model's `raw` attribute. 3. Every new request field must have a server-side default. 4. `capabilities()` probes `/api/v1/capabilities` and falls back to the known baseline on 404; future feature gating must not pretend that this fallback advertises new host features. 5. Breaking changes ship under `/api/v2`; they are never applied in place. 6. The SDK and server follow semantic versioning independently. ## Security The current daemon exposes administration and credential-related endpoints and must not listen on a public interface without protection. Use an SSH or VPN tunnel in the short term. In production, place a reverse proxy in front of the daemon, expose only the remote API, and enforce HTTPS, bearer-token authentication, request-size limits, rate limits, and audit logging. Tokens are accepted only through arguments or environment variables and are never persisted by the SDK. ## Future Work - SSE event subscriptions with reconnection support; - artifact manifests and streaming downloads; - batch task submission; - server and API version constraints; - retries limited to network failures and idempotent requests; and - OpenAPI contract tests to prevent server and SDK drift.