# Usage Guide `managed-agents` provides a local control plane for building, running, and debugging managed agents. The usual workflow is: 1. Create or import an agent. 2. Attach skills, tools, MCP servers, files, memory stores, or credentials. 3. Start a session in an environment. 4. Inspect the transcript and debug event stream. 5. Iterate on the agent definition and save new versions. ## Workspace Layout A workspace is a folder that contains runtime configuration, runtime state, and optional seed agent definitions and skill packages. Live metadata is stored in SQLite under the workspace state directory. ```text my-agents/ +-- agents/ # Optional seed agent definitions | +-- assistant.yaml +-- skills/ # Optional seed skill packages | +-- code-review/ | +-- SKILL.md +-- .managed-agents/ +-- config.yaml +-- data.db # SQLite metadata store +-- logs/ | +-- runtime.log +-- files/ # Uploaded file bytes +-- skills/ # Uploaded custom skill package assets +-- snapshots/ # Session workspace snapshots +-- sandbox/ # Local session workspaces ``` The workspace is portable. Commit examples, templates, config, and any seed definitions you intentionally maintain. Keep `.managed-agents/data.db`, `.managed-agents/logs/`, `.managed-agents/files/`, and sandbox state out of source control unless you intentionally want to snapshot local runtime data. ## Agent Definitions Agents can be imported from YAML files in `agents/` or created through the Console/API. Once loaded, the runtime source of truth is SQLite. ```yaml name: assistant description: Helps with development tasks. model: gpt-4o system: | You are a helpful assistant. Answer clearly and use tools when needed. mcp_servers: [] tools: - type: agent_toolset_20260401 default_config: enabled: true permission_policy: type: always_allow skills: - type: custom skill_id: skill_code-review metadata: owner: platform ``` Agent ids are stable object identifiers. YAML seed agents use deterministic ids when they are first imported, while agents created through the API or Console receive server-generated `agent_...` ids. Use the returned id in API calls, sessions, and SDK requests; treat `name` as a human-readable display field. ## Dashboard Workflow Start the runtime: ```bash managed-agents start ``` Open: ```text http://127.0.0.1:3000/dashboard ``` The Dashboard includes: - Workspace and local runtime status - Agent templates and agent versions - Session creation and session debug timelines - Runtime Settings for the single workspace model vendor, loop engine, storage backends, context-memory backend, and default sandbox - Environments - Credential vaults and credentials - Memory stores and memory entries - File upload and file resources - Skill upload and skill details ## Runtime Settings Open `Settings > Models`, `Loop engine`, `Storage`, `Memory`, or `Sandbox` to edit the workspace runtime configuration. Settings V2 stores one versioned JSON document in SQLite under the runtime data directory. Each Console page edits its own section of that document: `Models` edits `model`, `Loop engine` edits `loop_engine`, `Storage` edits `storage`, `Memory` edits `memory`, and `Sandbox` edits `sandbox`. The Form and JSON tabs are two views of that current section, and saving merges the section back into the versioned document. The usual sequence is: 1. Change the relevant field. 2. Click `Save settings`; the Dashboard validates the change before saving. 3. Optionally run `Check configuration` for a local capability check when you need diagnostics before or after saving. 4. Restart the runtime when the page shows `Restart required`. All first-release Settings V2 fields require a runtime restart before they become effective. Until restart, API responses expose both `saved_config` and `effective_config`; sessions continue using the effective revision. The workspace has one active model vendor, one built-in loop engine, SQLite metadata storage, local artifact storage, one context-memory backend, and one default sandbox provider. Named Environments can still override the default sandbox per session. Planned adapters such as S3, mem0, MemU, Harness, Codex, and Claude remain unavailable until their runtime implementations exist; Docker, Kubernetes, and remote sandbox providers appear as available only when the current runtime can reach their transport. Remote sandbox maps to the self-hosted worker queue: configure the worker API URL and key so external workers can claim and complete queued work items; the Settings check calls the remote `/v1/x/health` endpoint. ## Sandbox Backends A sandbox is where an agent's tool commands actually run. One sandbox is bound to one session for that session's lifetime. Each backend declares what it can do, and the runtime reads those capabilities instead of assuming them. Requesting something a backend cannot provide is reported in the runtime log rather than silently dropped. | Backend | Selected as | Isolated from runtime host | Host workspace | Resource limits | Transport | | --- | --- | --- | --- | --- | --- | | Local process | `local` | No | Yes | No | Child process | | Docker | `docker` | Yes | No | Yes | `docker` CLI | | Kubernetes | `kubernetes` | Yes | No | Yes | `kubectl` CLI | | Self-hosted worker | `remote` in Settings, `self_hosted` in an Environment | Runs off-host | No | No | Work-item queue | Consequences worth knowing before choosing one: - **Local is not a security boundary.** File tools are confined to the session workspace and the child process environment is reduced to an allowlist, but a shell command still runs as the same OS user on the same machine as the runtime: it can read outside the workspace and reach the network. Use it for trusted local development, not for running untrusted agent output. - **Workspace snapshots need a host workspace.** Only `local` exposes one, so snapshots are unavailable on the other three. Enabling them anyway logs a warning naming the missing capability. - **Resource limits are honored only by `docker` and `kubernetes`.** Setting `resources` on `local` or `remote` logs a warning instead of appearing to apply. A backend is offered only when the runtime can reach its transport: no Docker daemon means `docker` is not registered, and no reachable cluster means `kubernetes` is not registered. An Environment naming a backend that is not registered fails when the session provisions its sandbox, with an error listing the backends that are registered. It does not fall back to local execution — quietly running unsandboxed after an isolated backend was requested would be a worse outcome than a failed session. Startup logs the registered backends: ```text Sandbox: local, docker, self_hosted ``` ### Kubernetes Sandboxes Requires `kubectl` on `PATH` and a reachable cluster. Each session becomes one Pod running `sleep infinity`; commands run through `kubectl exec` and files move through `kubectl cp`. Configure it under `Settings > Sandbox`, or per Environment: ```json { "sandbox_provider": "kubernetes", "image": "node:22-slim", "kubernetes": { "namespace": "agent-sandboxes", "context": "staging", "service_account": "" } } ``` - The image needs `/bin/sh`, `find`, and `tar` (`tar` is what `kubectl cp` uses). The default `node:22-slim` has all three. - `namespace` must be a lowercase RFC 1123 label and defaults to `default`. - Leaving `service_account` empty creates the Pod with `automountServiceAccountToken: false`, so sandboxed commands cannot call the Kubernetes API. Only set it when an agent genuinely needs cluster access, and scope that account's RBAC accordingly. - Pods are labeled `app.kubernetes.io/managed-by=managed-agents` and `managed-agents/session-id=`, and are deleted when the session reaches a terminal state. See [Deployment Examples](deployment.md) for the RBAC the runtime itself needs to create these Pods. YAML model entries and legacy provider rows are bootstrap/import data for a new workspace. After Settings V2 is seeded, normal Dashboard edits do not rewrite source-controlled YAML files and legacy provider mutation endpoints are read-only compatibility failures. ## Create An Agent Use the Dashboard `Create agent` action, or add a seed YAML file in `agents/` and reload to import it into SQLite: ```bash managed-agents reload ``` Create an agent through the API: ```bash curl -X POST http://127.0.0.1:3000/v1/agents \ -H "Content-Type: application/json" \ -d '{ "name": "assistant", "description": "Helps with development tasks.", "model": "default", "system": "You are a helpful assistant.", "tools": [{ "type": "agent_toolset_20260401" }], "skills": [], "metadata": {} }' ``` ## Start A Session A session is a run of an agent inside an environment. ```bash curl -X POST http://127.0.0.1:3000/v1/sessions \ -H "Content-Type: application/json" \ -d '{ "agent": "agent_assistant", "environment_id": "env_default", "title": "Local smoke test" }' ``` The response contains a `sesn_...` id. Send a user message: ```bash curl -N -X POST http://127.0.0.1:3000/v1/sessions/SESSION_ID/messages \ -H "Content-Type: application/json" \ -d '{"content": "Hello", "stream": true}' ``` List events: ```bash curl http://127.0.0.1:3000/v1/sessions/SESSION_ID/events ``` Resume a live event stream: ```bash curl -N http://127.0.0.1:3000/v1/sessions/SESSION_ID/events/stream \ -H "Last-Event-ID: EVENT_ID" ``` Stop a session: ```bash curl -X POST http://127.0.0.1:3000/v1/sessions/SESSION_ID/stop ``` ## Attach Files To A Session Upload a file: ```bash curl -X POST http://127.0.0.1:3000/v1/files \ -F "file=@notes.txt" ``` Create a session with the file mounted under `/uploads/`: ```bash curl -X POST http://127.0.0.1:3000/v1/sessions \ -H "Content-Type: application/json" \ -d '{ "agent": "agent_assistant", "environment_id": "env_default", "resources": [ { "type": "file", "file_id": "file_abc123", "mount_path": "/uploads/notes.txt" } ] }' ``` ## Attach A Memory Store Create a memory store: ```bash curl -X POST http://127.0.0.1:3000/v1/memory_stores \ -H "Content-Type: application/json" \ -d '{"name": "project-memory", "description": "Long-term project notes"}' ``` Add a memory: ```bash curl -X POST http://127.0.0.1:3000/v1/memory_stores/MEMORY_STORE_ID/memories \ -H "Content-Type: application/json" \ -d '{"path": "/notes/overview", "content": "Use concise release notes."}' ``` Mount the store into a session: ```json { "type": "memory_store", "memory_store_id": "memstore_abc123", "access": "read_write", "instructions": "Use this store for durable project notes." } ``` ## Use Credential Vaults Credential vaults hold credentials that sessions can use without writing secrets into agent YAML files. Create a vault: ```bash curl -X POST http://127.0.0.1:3000/v1/credential-vaults \ -H "Content-Type: application/json" \ -d '{"name": "production-tools"}' ``` Add an environment variable credential: ```bash curl -X POST http://127.0.0.1:3000/v1/credential-vaults/VAULT_ID/credentials \ -H "Content-Type: application/json" \ -d '{ "name": "github-token", "auth_type": "environment_variable", "variable_name": "GITHUB_TOKEN", "value": "ghp_example", "network": { "type": "limited", "allowed_hosts": ["api.github.com"] }, "injection_locations": ["request_headers"] }' ``` Attach one or more vaults when creating a session: ```json { "vault_ids": ["vlt_abc123"] } ``` ## TypeScript SDK ```typescript import { ManagedAgentsClient } from 'managed-agents/sdk'; const client = new ManagedAgentsClient({ baseUrl: 'http://127.0.0.1:3000', }); const session = await client.sessions.create({ agent: 'agent_assistant', environment_id: 'env_default', }); for await (const event of client.sessions.chat(session.id, 'Hello')) { if (event.type === 'agent.message_chunk') { process.stdout.write(event.delta ?? ''); } } ``` ## CLI Commands ```bash managed-agents init managed-agents start --host 127.0.0.1 --port 3000 managed-agents list managed-agents reload managed-agents chat agent_assistant --message "hello" managed-agents template list managed-agents template install managed-agents template create ``` ## Operational Notes - Keep credentials in vaults or environment variables, not in agent YAML files. - Keep uploaded file resources below 10 MB per file. - Keep skill uploads below 8 MB per package. - Use `MANAGED_AGENTS_SECRET_KEY` to provide a stable credential encryption key across runtime moves. - Create a managed API key in the Dashboard or set `MANAGED_AGENTS_API_KEY` before exposing the runtime beyond a trusted local network.