Skip to content

Agent identities

An agent identity binds one service account to one organization and environment. Its name is a display label; use the returned ID in definitions, grants and requests. Test and Live identities are separate.

Open Locus → Agent Identities to create an identity or inspect its current state. Choose an active service account from the selected organization. Only one identity can use that service account in the same environment.

Choose Managed when Katara will execute the agent’s published definition and admit its runs. Creating an identity alone does not publish a definition, start a worker or grant spending authority. Continue with Runs to approve content, publish the definition and configure the run’s permissions and funding.

Choose External for an agent executed by your own application. Its calls still require current scoped credentials, grants and any applicable action approvals. An external identity does not receive a managed worker or managed execution credentials, and cannot publish a managed agent definition. Tutorial: act from your own runtime sets one up end to end.

The owning service-account ID, execution kind, organization, environment and creator are immutable. To use another service account or execution kind, create a new identity with an eligible service account. Renaming cannot transfer ownership.

Read the selected environment with getEnvironment / get_environment before reviewing a mutation. Use its current authority_epoch and reset_generation in the required expected_environment_epoch and expected_reset_generation fields. Both pins are checked atomically with the write.

With a client authorized for the exact organization and environment:

const scope = { org_id: orgID, environment_id: environmentID };
const request = {
expected_environment_epoch: environment.authority_epoch,
expected_reset_generation: environment.reset_generation,
name: 'Document assistant',
service_account_id: serviceAccountID,
execution_kind: 'managed' as const,
};
const receipt = await client.createAgentIdentity(scope, request, requestKey);
const identityID = receipt.resource_id;
request = {
'expected_environment_epoch': environment['authority_epoch'],
'expected_reset_generation': environment['reset_generation'],
'name': 'Document assistant',
'service_account_id': service_account_id,
'execution_kind': 'managed',
}
receipt = client.create_agent_identity(org_id, environment_id, request, request_key)
identity_id = receipt['resource_id']

Creation accepts names of 1–120 characters after trimming whitespace and returns an operation receipt. Use listAgentIdentities / list_agent_identities to read active, authority_epoch, ownership and execution kind. Pages accept limits 1–100; pass next_cursor as after until absent. The directory requires locus:grants:read; mutations require locus:grants:write and current role authority. Resource restrictions also apply. Use a verified application session for the portal flow; an appropriately scoped API key can use the API where its authority permits.

The change API accepts name, active, the current identity authority_epoch and both reviewed environment pins. Every accepted change advances the epoch, including a rename. Existing grants and managed definitions pinned to the prior epoch no longer match current authority. Disabling stops authorization through the identity; re-enabling does not revive old grants. Review and establish current authority before running again.

After reading the exact identity as identity, an explicit disable request is:

const change = {
expected_environment_epoch: environment.authority_epoch,
expected_reset_generation: environment.reset_generation,
name: identity.name,
active: false,
authority_epoch: identity.authority_epoch,
};
await client.changeAgentIdentity(scope, identity.id, change, requestKey);
client.change_agent_identity(
org_id, environment_id, identity['id'], identity['name'], False,
identity['authority_epoch'], environment['authority_epoch'],
environment['reset_generation'], request_key,
)

A stale epoch returns a conflict. Reload the directory and review its current state before approving a different request. Disabling the identity does not by itself disable its owning service account; manage that account separately when its own access should stop.

Let a managed agent run code and browser steps

Section titled “Let a managed agent run code and browser steps”

A run takes a code or browser step only under a grant that lets its agent execute actions and create runs on itself. enableSandboxAccess / enable_sandbox_access issues that grant for an identity. Name the budget its sandbox steps spend from, the usage class (simulation or test_compute in Test, live in Live), when the grant ends, and the identity’s current authority_epoch as expected_agent_epoch; an identity changed since you read it is refused with a conflict.

An owner or admin makes the request, and the environment must hold Locus for the usage class. Without it the request is refused, rather than issuing a grant no run could use. Keep the exact body and idempotency key after an uncertain response.

Run an external agent on your own executor

Section titled “Run an external agent on your own executor”

An external agent’s work runs on an executor you host. The owner or an admin declares it with declareExternalExecutor / declare_external_executor: the SPIFFE ID the executor’s certificate carries, issued for that agent, and the capabilities it advertises. listExternalExecutors / list_external_executors returns each declaration with its capability_digest. Capabilities cannot be edited; an executor that advertises something else is declared again.

The executor never calls the product API with its certificate. It talks to the executor broker over mutual TLS, and the broker takes the organization, environment and agent from the certificate:

  • POST /v1/runs/{run_id}/claim with declaration_id, capability_digest and ttl_seconds (10 to 120) takes the run and returns a lease token and a fence. A run someone else holds, or whose assignment changed, answers 409; a declaration that is revoked, stale or for another workload answers 403.
  • POST /v1/runs/{run_id}/lease with declaration_id, lease_token and fence says whether the lease is still current. Ask before committing any effect or recording a charge, and stop when it answers false.

A lease is not renewed: once it lapses, claiming again issues a new fence and ends the old one. Changing the agent identity, resetting the environment or revoking the declaration with revokeExternalExecutor / revoke_external_executor stops new claims, and revocation also ends the current lease at once.

Keep the exact reviewed body, organization, environment, identity ID when known, and original idempotency key. If a response is lost, restore the same account and scope, then explicitly repeat that identical request and key. The SDK does not automatically retry it. Do not replace the expected epoch or switch environments under a pending key. A different change requires a new review and key.

After a confirmed receipt, reload the directory. A conflict or denied response is not permission to invent a new epoch. These metadata records contain no execution credentials or customer content; keep API key secrets out of recovery storage.