Skip to content

Configuration Reference

Authoritative reference for openma’s configuration shapes. The TypeScript source of truth lives in packages/api-types; the in-repo human-readable schema doc is AGENTS.md.

interface AgentConfig {
id: string; // assigned by the platform
name: string;
model: string; // e.g. "claude-sonnet-4-6"
system: string; // system prompt
tools: ToolDefinition[];
skills?: string[]; // skill ids
environment_id?: string;
mcp_servers?: McpServerConfig[];
memory_store_id?: string;
harness?: string; // defaults to "default"
archived?: boolean;
version: number; // platform-bumped on every update
created_at: string;
updated_at: string;
}

harness: "pi" always enables harness-owned context compaction. These optional metadata keys select and tune the built-in policy:

{
"harness": "pi",
"metadata": {
"compaction_strategy": "cc-style",
"compaction_trigger_fraction": 0.75,
"compaction_max_summary_tokens": 2000,
"compaction_summary_prompt": "Optional replacement summary prompt"
}
}

compaction_strategy accepts cc-style (default), opencode-style, or summarize. Invalid names fall back to cc-style; there is intentionally no none mode. All built-in policies use pi-ai without requesting reasoning.

  • cc-style uses an isolated summary payload: a short summary-only system prompt, no tools, image placeholders instead of image bytes, and a separate compaction session id. This is the robust default and intentionally does not reuse the main agent’s provider prefix cache.
  • opencode-style has the same isolated payload boundary, with a structured Goal / Instructions / Discoveries / Accomplished / Files summary template.
  • summarize is the explicit cache-aware strategy. It replays the main request’s exact system prompt, tool declarations, message history, and session id, then appends the private compaction instruction. It deliberately leaves toolChoice unset because some provider adapters remove tools for toolChoice: "none", which changes the cache prefix. completeSimple does not execute tools; a returned tool call rejects the compaction boundary. Prefix-caching providers can therefore reuse the warm conversation prefix.

Applications can replace the whole PiCompactionPolicy when constructing PiHarness; OpenMA still owns the canonical boundary event, failure fallback, and the single overflow retry. Every strategy replaces old history with a new summary boundary, so the first main-model request after compaction is a new prefix even when the summary call itself reused the old prefix.

type ToolDefinition =
| { type: 'agent_toolset_20260401' } // built-in toolset
| {
type: 'custom';
name: string;
description: string;
input_schema: JsonSchema;
execution:
| { type: 'http'; endpoint: string; method?: string }
| { type: 'sandbox'; command: string };
};
interface McpServerConfig {
name: string; // becomes the prefix: mcp__<name>__<tool>
type: 'url' | 'stdio';
url?: string; // required by host-side OpenMA harnesses
authorization_token?: string; // inline bearer (otherwise: matched vault credential)
stdio?: {
command: string;
args?: string[];
env?: Record<string, string>;
port: number; // 127.0.0.1:port the spawned process binds to
ready_timeout_ms?: number; // default 60_000
};
}

stdio is an adapter-owned declaration. It works only when an external Worker or a harness running inside the sandbox owns the child process and transport. The built-in Node and Cloudflare host-side harnesses require url and reject stdio-only declarations, because sandbox-local 127.0.0.1 is not automatically reachable from the control plane. URL MCP discovery is bounded at 15 s per server; up to 20 servers per agent.

interface EnvironmentConfig {
id: string;
name: string;
base_image: string; // e.g. "openma/sandbox-base:python-3.12"
packages: {
pip?: string[];
npm?: string[];
apt?: string[];
cargo?: string[];
gem?: string[];
go?: string[];
};
network?: {
allowlist?: string[]; // hostnames the sandbox may reach
denylist?: string[];
};
env?: Record<string, string>;
}

A vault is a tenant-scoped credential bundle; credentials inside it are bound to MCP servers or sandbox CLIs.

interface Vault {
id: string;
tenant_id: string;
name: string;
created_at: string;
updated_at: string;
archived_at?: string;
}
// Credentials live in a separate table; each is one of three types
type CredentialAuth =
| { type: 'static_bearer'; token: string; mcp_server_url: string }
| { type: 'mcp_oauth'; access_token: string; refresh_token?: string;
token_endpoint?: string; expires_at?: string; mcp_server_url: string }
| { type: 'cap_cli'; cli_id: string; token: string }; // e.g. cli_id: "gh", "glab", "aws"

Binding to a host happens via the credential, not the vault: a static_bearer / mcp_oauth credential matches by parsing the request hostname against mcp_server_url; a cap_cli credential matches by cli_id lookup in the cap spec registry. Up to 20 credentials per vault. Tokens are AES-GCM-encrypted at rest under PLATFORM_ROOT_SECRET and never returned via the API once written.

Current status: Model Cards currently accept static API-key credentials. Codex/ChatGPT subscription OAuth is a direct-host adapter contract for local debugging; it is not a hosted Model Card or a remote-sandbox credential type.

When that direct-host adapter is enabled, it keeps the provider OAuth credential in the host’s local Pi-compatible credentials store. It must never copy ~/.codex/auth.json, a refresh token, or an access token into a sandbox, workspace checkpoint, output archive, Model Card, or request payload. The sandbox receives no subscription credential and cannot refresh it.

For a remote or managed sandbox, configure an approved API key or provider OAuth credential behind the OMA model gateway instead. The gateway is the credential boundary: it authenticates the request, applies the tenant/model policy, and returns only the model response to the sandbox. This preserves the same harness endpoint shape without turning a subscription login into a portable secret.

These paths are intentionally distinct:

PathCredential locationIntended use
Local direct-hostTrusted host Pi credentials storeLocal debugging only
Remote/managed sandboxOMA model gateway; approved API/OAuth credential stays in the control planeProduction/managed execution

Do not treat the local credential file as a portable session artifact. If it is missing after a runtime replacement, resume the ACP/native session from its declared session state and require the user to authenticate again on the trusted host; do not reconstruct or transmit the subscription token from Session events.

interface SkillMetadata {
type: 'skill';
id: string;
display_title: string;
name: string; // SKILL.md frontmatter `name` — also the mount-folder name
description: string;
source: 'anthropic' | 'custom';
latest_version: string; // numeric epoch string
created_at: string;
updated_at: string;
}
// Per-version detail returned by GET /v1/skills/:id/versions/:version
interface SkillVersion {
version: string;
files: Array<{ filename: string }>; // R2 objects under t/{tenant}/skills/{id}/{version}/<filename>
}

The platform mounts skill files at /home/user/.skills/{name}/ (using the SKILL.md name, not id) and inlines the SKILL.md body directly into the system prompt at session start — no lazy read. The injected wrapping is:

<source name="skill:{id}">
<skill name="{name}">
{full SKILL.md body}
</skill>
</source>

Attach to an agent with the object form (not a bare string array):

{ "skills": [{ "skill_id": "skill_abc123", "type": "custom" }] }

Built-in skills (source: "anthropic"): xlsx, pdf, docx, pptx — four total, no upload needed.

interface MemoryStore {
id: string;
agent_id: string;
embedding_model: string; // defaults to platform setting
vector_index: string; // Vectorize index name
}
interface SessionMeta {
id: string;
agent_id: string;
agent_version: number; // pinned at creation
status: 'pending' | 'running' | 'idle' | 'done' | 'failed';
created_at: string;
updated_at: string;
}
interface SessionEvent {
id: string;
session_id: string;
type: string; // 'agent.message', 'agent.tool_use', 'agent.thinking', etc.
data: unknown;
created_at: string;
}

The full event type catalog is in packages/api-types/src/events.ts.

Required for self-host. Set as Worker secrets via npx wrangler secret put NAME.

VariableWorkerPurpose
PLATFORM_ROOT_SECRETmain, integrationsRoot secret for at-rest encryption (credentials, model card keys, integration tokens) and outbound MCP token signing. Workers refuse to start without it. Back it up — losing it makes every encrypted row unreadable.
BETTER_AUTH_SECRETmainbetter-auth session signing key
API_KEYmainInitial dev API key for the REST API
INTEGRATIONS_INTERNAL_SECRETmain, integrationsShared secret between main and integrations workers
VariableWorkerPurpose
ANTHROPIC_API_KEYmain, agentFallback LLM credential when a tenant has not added a Model Card. In production, prefer per-tenant Model Cards from the Console — they’re encrypted under PLATFORM_ROOT_SECRET and rotatable without redeploy. (Alternates: OPENAI_API_KEY, MINIMAX_API_KEY.)
LINEAR_CLIENT_IDintegrationsLinear OAuth
LINEAR_CLIENT_SECRETintegrationsLinear OAuth
LINEAR_WEBHOOK_SECRETintegrationsVerify inbound Linear webhooks
GITHUB_APP_IDintegrationsGitHub App ID
GITHUB_PRIVATE_KEYintegrationsGitHub App private key (.pem contents)
GITHUB_WEBHOOK_SECRETintegrationsVerify inbound GitHub webhooks
SLACK_CLIENT_IDintegrationsSlack OAuth
SLACK_CLIENT_SECRETintegrationsSlack OAuth
SLACK_SIGNING_SECRETintegrationsVerify inbound Slack events
GOOGLE_CLIENT_IDmainGoogle sign-in for Console
GOOGLE_CLIENT_SECRETmainGoogle sign-in for Console
VariableWorkerPurpose
TAVILY_API_KEYmain, agentWeb search backend for web_search built-in
CLOUDFLARE_API_TOKENmainProgrammatic CF resource management (optional)
CLOUDFLARE_ACCOUNT_IDmainProgrammatic CF resource management (optional)
INTEGRATIONS_PUBLIC_URLmainOverride auto-detected integrations URL
PER_TENANT_DB_ENABLEDmainSet "true" to enable per-tenant D1 isolation
STORE_BACKENDSmainJSON config for storage backends (advanced)
DATABASE_URLmainExternal Postgres URL (advanced)

What each Worker needs in its wrangler.jsonc:

BindingTypeName
MAIN_DBD1openma-auth
CONFIG_KVKV(your namespace)
FILES_BUCKETR2managed-agents-files
AIWorkers AI(built-in)
VECTORIZEVectorizeopenma-memory
SANDBOX_sandbox_defaultService→ agent worker
INTEGRATIONSService→ integrations worker
SEND_EMAILEmail(your sender)
ANALYTICSAnalytics Engineoma_events
BindingTypeName
SESSION_DODurable ObjectSessionDO
SANDBOXDurable ObjectSandbox (Container class)
CONFIG_KVKV(shared with main)
MAIN_DBD1(shared with main)
WORKSPACE_BUCKETR2managed-agents-workspace
FILES_BUCKETR2(shared with main)
AI, VECTORIZE, BROWSER, ANALYTICS(same as main)
BindingTypeName
MAIN_DBD1(shared with main)
MAINService→ main worker