Desired-state compute resources
Record typed desired state, keep a stable resource identity, and inspect reconciliation status through organization-scoped resource reads.
Managed inference desired state is published for approved accounts. Agent Hosts and Batch Jobs additionally require an approved agents orjobs entitlement. Submitting a product-access request does not bypass that gate.
Name identifies desired state within a resource type
Managed inference and Agent Host creation methods are apply operations. The tuple (org_id, resource_type, name) is unique. Reusing it updates the stored spec, returns the same resource ID, resets lifecycle state to pending, and creates an audit entry.
shared response{
"id": "448a...",
"org_id": "9df4...",
"resource_type": "agent",
"name": "research-agent",
"status": "pending",
"namespace": "",
"external_url": "",
"spec": {
"definition": "compose",
"template_id": "openclaw",
"template_version": "2026.2.6-tarka.4",
"tier": "core",
"service_count": 2,
"active_revision": 1,
"secret_variable_names": ["AUTH_PASSWORD", "OPENCLAW_GATEWAY_TOKEN"]
},
"status_detail": {},
"created_at": "2026-08-30T14:00:00Z",
"updated_at": "2026-08-30T14:00:00Z"
}DNS labelLowercase letters, digits, and hyphens; 1–63 characters; start and end with alphanumeric.
stable contractRequired typed fields override conflicting keys supplied in the free-form spec object.
machine-readableControllers may attach provider state or stable failure information without changing desired spec.
Apply an inference service
model_alias must exist in the active model registry. Replica counts must be non-negative, and a non-zero max_replicas must be greater than or equal to min_replicas.
POSTcurl -X POST \
"https://tarka.rest/control/v1/orgs/$TARKA_ORG_ID/inference-services" \
-H "Authorization: Bearer $TARKA_ACCOUNT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name":"himalaya-service",
"model_alias":"himalaya-q8",
"min_replicas":0,
"max_replicas":2,
"spec":{"region":"eu-central"}
}'The canonical organization route is /orgs/{org_id}/inference-services. The compatibility binding /inference-services remains available when org_id is supplied in the request body.
Review the price before applying a host
Send the intended request with dry_run: true to receive spec.compute_quote. Review its billing currency, exact allocated memory, hourly rate and next-lease hold. Submit the same request with dry_run: false and accepted_quote_id within five minutes. The console requires this confirmation. Existing EU API clients may omit the quote; technical core and pro sizes are not subscription offers.
Model calls and any separately accepted data policy are additional. Running hosts renew paid leases. See quotes, reservations and usage policy.
Apply an Agent Host stack
Choose exactly one template_id, inline compose_yaml, or legacy single-container image. OpenClaw, Hermes, and Onyx expose runtime defaults, gateways, and variables through the template catalog. Reusing the same name creates an immutable revision.
GETcurl \
"https://tarka.rest/control/v1/agent-host-templates" \
-H "Authorization: Bearer $TARKA_ACCOUNT_TOKEN"dry_run: true# Upload secrets through the authenticated console handoff first.
# The bundle UUID is safe for the assistant to handle; secret values are not.
jq -n \
--arg bundle "$TARKA_SECRET_BUNDLE_ID" \
'{
name: "research-agent",
template_id: "openclaw",
tier: "core",
dry_run: true,
secrets_bundle_id: $bundle,
runtime: {primary_model_alias: "deepseek-v4.1-flash-eu"}
}' |
curl -X POST \
"https://tarka.rest/control/v1/orgs/$TARKA_ORG_ID/agent-hosts" \
-H "Authorization: Bearer $TARKA_ACCOUNT_TOKEN" \
-H "Content-Type: application/json" \
--data @-compose_yamlMulti-service stacks of prebuilt images with health checks, volumes, tmpfs, resources, and routes. Git builds inside Agent Hosts are disabled; build locally or in your own CI and push to Tarka's registry first.
secret: trueSecret values are encrypted separately and never returned in ProvisionedResource.spec.
primary_model_aliasSelect the host's chat model, supported template gateways, and custom Compose services that receive managed discovery variables.
x-tarka.routesDeclare path/service/port mappings or one public_service andpublic_port override.
GETcurl \
"https://tarka.rest/control/v1/orgs/$TARKA_ORG_ID/agent-hosts/$AGENT_HOST_ID/configuration" \
-H "Authorization: Bearer $TARKA_ACCOUNT_TOKEN"Secret values are empty in this response. A secret with preserve_existing: true can be carried into the next revision without returning its plaintext.
Hermes · ready hostcurl \
"https://tarka.rest/control/v1/orgs/$TARKA_ORG_ID/agent-hosts/$AGENT_HOST_ID/gateways/signal/pairing" \
-H "Authorization: Bearer $TARKA_ACCOUNT_TOKEN"DELETEcurl -X DELETE \
"https://tarka.rest/control/v1/orgs/$TARKA_ORG_ID/agent-hosts/$AGENT_HOST_ID" \
-H "Authorization: Bearer $TARKA_ACCOUNT_TOKEN"Private GitHub images through REST, MCP, and Python
Put image paths such as ghcr.io/my-org/my-agent:v1 in your Compose file. Supply credentials separately in github_registry_credentials. This field is available only with compose_yaml.
Use the token owner's GitHub username and a classic PAT with read:packages, access to every referenced package, and organization SSO authorization when required. The username is not the repository or package owner. Your Tarka account token authenticates the Control API; the GitHub PAT is used only for GHCR pulls.
Named credentials and verified pulls
The console uses POST /control/v1/orgs/{org_id}/agent-host-registry-tests with the host name, a complete credentials array and every GHCR image with its Compose service. Each credential has a label, username, token and assigned services. To preserve a stored token, send its returned id and version and omit the token. Removing an entry removes that credential only after a successful test and apply.
Poll GET /control/v1/orgs/{org_id}/agent-host-registry-tests/{test_id}. When its status is succeeded, include registry_test_id in the complete host apply request. Do not combine it with github_registry_credentials. The proof expires after 30 minutes, binds to the exact service images and current credential version, and is consumed once by a successful apply. Dry runs do not consume it. Cancel queued or running tests with DELETE at the same test URL.
Configuration reads return registry_credentials containing IDs, labels, usernames, versions and service assignments only. Starting a credential test is a human action through the console or direct HTTP and is excluded from MCP. MCP can read test status and submit the verified test ID without receiving a PAT.
Compatible single-credential requests
REST · Python standard libraryimport getpass, json, os, pathlib, urllib.request
payload = {
"name": "private-agent",
"compose_yaml": pathlib.Path("compose.yaml").read_text(),
"github_registry_credentials": {
"username": os.environ["GITHUB_USERNAME"],
"token": getpass.getpass("GitHub classic PAT: "),
},
}
url = "https://tarka.rest/control/v1/orgs/" + os.environ["TARKA_ORG_ID"] + "/agent-hosts"
request = urllib.request.Request(url, method="POST",
data=json.dumps(payload).encode(), headers={
"Authorization": "Bearer " + os.environ["TARKA_ACCOUNT_TOKEN"],
"Content-Type": "application/json",
})
payload["dry_run"] = True
request.data = json.dumps(payload).encode()
with urllib.request.urlopen(request, timeout=60) as response:
preview = json.load(response)
quote = preview["spec"]["compute_quote"]
print(json.dumps(quote, indent=2))
if not quote["admission"]["available"] or input("Accept this price and create? [yes/no] ") != "yes":
raise SystemExit("Not created")
payload.update(dry_run=False, accepted_quote_id=quote["id"])
request.data = json.dumps(payload).encode()
with urllib.request.urlopen(request, timeout=60) as response:
host = json.load(response)
print(host["id"], host["status"])The example reads compose.yaml and prompts for the PAT without echoing it. Do not print the request or put credentials in Compose, spec, source code, logs, or chat transcripts.
Preserve, replace, and remove credentials
Apply the same host name and the complete Compose definition on each update. Tarka checks GHCR access before saving; a failed check leaves credentials and the current revision unchanged.
- Preserve: omit
github_registry_credentials. An empty object is not the preserve operation. - Replace: supply both
usernameand the newtoken. - Remove: send
{remove: true}after switching every GHCR image to anonymous access. Do not combine removal with a username or token.
JSON{
"github_registry_credentials": {
"remove": true
}
}GET /control/v1/orgs/{org_id}/agent-hosts/{agent_host_id}/configuration returns only the saved username and configured status. The token is write-only, encrypted at rest, and never returned or included in revision history. The controller provides it only as an image-pull credential, never a container environment variable.
redacted metadata{
"github_registry_access": {
"username": "octocat",
"configured": true
}
}Deleting a host removes its saved credentials. Removal does not revoke the PAT at GitHub or stop already running containers. Revoke the PAT at GitHub when required.
MCP
Connect your MCP client as described in MCP. Creating a host needs a connection with write access, provisioning:read provisioning:write. Set or change private GHCR credentials yourself through the console or direct HTTP; MCP rejects plaintext registry credentials. Omitted credentials preserve the host's existing pull access. Supply application secrets through a separate handoff, then pass its ID in the complete apply request and review the price before creation.
tools/call parameters{
"name": "tarka_create_agent_host",
"arguments": {
"org_id": "<organization UUID>",
"name": "private-agent",
"dry_run": true,
"compose_yaml": "services:\n agent:\n image: ghcr.io/my-org/my-agent:v1\n",
"secrets_bundle_id": "<uploaded secret handoff UUID>"
}
}Read back with tarka_get_agent_host_configuration and org_id/agent_host_id. Its github_registry_access contains the same redacted metadata. A read-only MCP grant cannot set, replace, or remove credentials.
Secrets from a file or the console
Prepare a handoff with POST /control/v1/orgs/{org_id}/agent-host-secret-bundles and the host's name. Open its console_url yourself to upload a .env file or a JSON object of string values. The local secret-file helper can upload directly from your terminal using your account token in the environment. Do not have the coding agent read the file or paste its contents into chat.
The assistant reads only key names and status, then submits secrets_bundle_id with the host request. The handoff expires after one hour and is consumed only by successful admission for the same organization, name and revision. A concurrent host update requires a new handoff. Direct HTTP clients can continue sending inline secrets.
Python SDK
SDK 0.2.0 adds AgentHostGitHubRegistryCredentials and the matching redacted response type. See the Python credential examples and installable release.
For the console workflow, see Private GitHub images.
Tarka registry images
Push your local build with a Tarka credential and reference registry.tarka.rest/orgs/<organization UUID>/<repository>. Agent Hosts accept tags and pin the resolved digest; jobs require an explicit digest. The resource and image must belong to the same organization. Pull authorization is automatic; omit github_registry_credentials for Tarka images.
Create a queued Batch Job
command is a non-empty argument vector. Jobs execute in US East by default after accepting a current quote. Set TARKA_JOB_IMAGE to a public or same-organization Tarka registry image pinned by digest; the example expects your image to contain Python and the evals.run module. Resources, runtime/network caps, reads and cancellation are explicit. See Batch Job availability.
jobs entitlementimport json, os, urllib.request, uuid
base = "https://tarka.rest/control/v1/orgs/" + os.environ["TARKA_ORG_ID"]
headers = {"Authorization": "Bearer " + os.environ["TARKA_ACCOUNT_TOKEN"],
"Content-Type": "application/json"}
def post(path, body):
request = urllib.request.Request(base + path, method="POST", headers=headers,
data=json.dumps(body).encode())
with urllib.request.urlopen(request, timeout=60) as response:
return json.load(response)
resources = {"cpu_millis": 1000, "memory_mib": 1024, "ephemeral_storage_mib": 1024}
quote = post("/compute-quotes", {"product": "jobs", "location": "us-1",
"resources": resources, "max_runtime_seconds": 60, "max_network_bytes": 1048576})
print(json.dumps(quote, indent=2))
if not quote["available"] or input("Accept this price and create? [yes/no] ") != "yes":
raise SystemExit("Not created")
job = post("/jobs", {"name": "nightly-eval", "location": "us-1",
"image": os.environ["TARKA_JOB_IMAGE"], # Full Linux/amd64 image@sha256:digest.
"command": ["python", "-m", "evals.run"], "resources": resources,
"timeout_seconds": 60, "max_network_bytes": 1048576,
"queue_timeout_seconds": 600, "accepted_quote_id": quote["id"],
"idempotency_key": str(uuid.uuid4())})
print(job["id"], job["status"])List or retrieve shared resource state
Use GET /orgs/{org_id}/resources and optional ?resource_type=inference_service, agent, job, sandbox, bucket, or git_repo. Retrieve one record with GET /orgs/{org_id}/resources/{resource_id}.
| Status | Meaning |
|---|---|
pending | Desired state is accepted and awaits reconciliation. |
provisioning | A controller is applying provider or cluster state. |
ready | The resource is reconciled and usable. |
failed | Reconciliation stopped; inspect status_detail. |
deleting | Product-specific deletion is in progress. |
deleted | The data-plane resource is removed; final control state is retained. |
Object Storage, Hosted Git, Sandboxes, and Agent Hosts have product-specific deletion methods. Managed inference has no generic delete. Batch Jobs have explicit run cancellation; read the final run state to confirm work stopped.