# Agent identities > Register managed or external agents and review changes to their authority. Section: Synapse and Locus. Web page: https://docs.katara.com/products/agent-identities/ An agent identity binds one [service account](https://docs.katara.com/products/service-accounts.txt) 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 how the agent executes 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](https://docs.katara.com/products/runs.txt) 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](https://docs.katara.com/products/tutorial-external-agent.txt) 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. ## Use the SDK 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: ```typescript 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; ``` ```python 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. ## Review each change 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: ```typescript 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); ``` ```python 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 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 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. ## Recover an uncertain request 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.