Execution identity
Published November 10, 2026 · by the AQ team
Every process AQ starts in a work item knows which AQ work item, thread, run and organization it belongs to, and who asked for the work. Code that attributes deploys, leases or recoveries to a workspace and a person can read that from the environment, and prove it with a short-lived token AQ signs.
Environment variables
None of these are secrets. They are set in agent processes (every harness, both AQ models and your own subscriptions), terminals, previews and services.
| Variable | Value | Where |
|---|---|---|
AQ_WORKSPACE_ID | The work item's id (the one in its URL) | Everywhere |
AQ_WORKSPACE_NAME | The work item's title (it can change) | Terminals, previews, services (for agents, read the identity file) |
AQ_SESSION_ID | The AQ thread the agent runs in | Agent processes |
AQ_TENANT_ID, AQ_ORG_SLUG, AQ_ORG_NAME | The organization | Everywhere (AQ_ORG_NAME for agents is in the identity file) |
AQ_REPO_ID | The repository, when the item has one | Everywhere |
AQ_RUN_AS_UID, AQ_RUN_AS_EMAIL | The person whose account, sign-ins and secrets the process uses | Everywhere |
AQ_REQUESTED_BY_UID, AQ_REQUESTED_BY_EMAIL, AQ_REQUESTED_BY_KIND | The person who opened the terminal | Terminals (for agents, read the identity file) |
AQ_IDENTITY_FILE, AQ_IDENTITY_ENV_FILE | The identity file for the current turn (JSON, and the same values as export lines) | Agent processes |
AQ_IDENTITY_VERIFY_URL, AQ_IDENTITY_JWKS_URL | Where to check a token | Everywhere |
The identity file: the current turn
An agent process can live across many turns, so values that change per turn are not taken from its environment. Before every turn AQ rewrites the files named by $AQ_IDENTITY_FILE (JSON) and $AQ_IDENTITY_ENV_FILE (shell), readable only by the person the run acts as. They carry everything above plus:
AQ_RUN_ID(run_id): this turn.AQ_REQUESTED_BY_UID,AQ_REQUESTED_BY_EMAIL,AQ_REQUESTED_BY_NAME,AQ_REQUESTED_BY_KIND(requested_by): who sent the newest message of the turn.kindisperson(typed or spoken in AQ),api(an API key or MCP client),thread(another work item or chat),bot(a bot routine) orsystem; for anything but a person,on_behalf_ofnames the person it acts for, and theAQ_REQUESTED_BY_*lines name that person.AQ_IDENTITY_TOKEN(token): the signed token for this turn, valid 4 hours.
set -a; . "$AQ_IDENTITY_ENV_FILE"; set +a
echo "$AQ_WORKSPACE_ID $AQ_RUN_ID $AQ_REQUESTED_BY_EMAIL"
import json, os
identity = json.load(open(os.environ["AQ_IDENTITY_FILE"]))
print(identity["workspace_id"], identity["run_id"], identity["requested_by"])
The token is a credential for its 4 hours: pass it to your own services, never print it or commit it.
Verify instead of trusting the environment
Anything can set an environment variable. The token cannot be forged: it is an ES256 JWT signed by AQ, with iss https://aq.dev and aud aq-execution-identity. Check it either way:
- Offline with any JWT library against the public keys at
https://aq.dev/v1/identity/jwks.json(cache them for a few minutes, refetch on an unknownkid). Check the signature,aud,issandexp. - Online with
GET https://aq.dev/v1/identity/verifyand the token in theAQ-Identity-Tokenheader (orAuthorization: Bearer). No API key is needed. A valid token answers 200 with its claims; anything else answers 401 with the reason. Never put the token in a URL.
curl -s -H "AQ-Identity-Token: $(python3 -c 'import json,os;print(json.load(open(os.environ["AQ_IDENTITY_FILE"]))["token"])')" \
"$AQ_IDENTITY_VERIFY_URL"
The claims are workspace_id, workspace_name, session_id, run_id, tenant_id, org_slug, repo_id, run_as (user_id, email) and requested_by, plus the standard iat, nbf, exp and jti. Your service should also check that tenant_id is your organization.
Who sent each message
read_item on AQ's MCP server and in agent threads gives every message a sender (the kinds above, the surface it came from, and on whose behalf) beside created_by, the same author the REST API's messages report.
Coming from Conductor
AQ also sets CONDUCTOR_WORKSPACE_PATH, CONDUCTOR_ROOT_PATH, CONDUCTOR_WORKSPACE_NAME and CONDUCTOR_PORT in agent processes, terminals, setup, previews and services, so scripts keep working (migration guide). It never sets CONDUCTOR_IS_LOCAL or anything that claims to be Conductor. For attribution, map:
| Conductor | AQ |
|---|---|
CONDUCTOR_WORKSPACE_ID | AQ_WORKSPACE_ID |
CONDUCTOR_WORKSPACE_NAME (as a label) | AQ_WORKSPACE_NAME (the title); CONDUCTOR_WORKSPACE_NAME stays the branch-derived name |
CONDUCTOR_SESSION_ID | AQ_SESSION_ID, and run_id for the single turn |
| The sender of a message | requested_by in the identity file and token, sender in read_item |