Skip to main content

View source on GitHub

Stash your own key-value metadata on an OpenHands conversation — for example an external environment_url or environment_conversation_id — and read it back later from your own tooling. Conversations expose a free-form tags map for exactly this. This is the supported replacement for adding a bespoke field (e.g. a custom environment_url column) to the conversation model: use tags instead.

The two-server split

OpenHands has a Cloud app server (manages accounts, sandboxes, and conversations) and, for each sandbox, an agent server (the runtime that owns the conversation). Tags live on the agent-side conversation, and their values surface on the Cloud’s AppConversation.tags field. Auth uses X-Session-API-Key on both servers, but with different keys:
  • Cloud app server → your OH_API_KEY
  • Agent server → the per-conversation session_api_key returned by the Cloud
conversation_url from the Cloud is already the full agent resource URL https://<agent-host>/api/conversations/<id>, so you PATCH it directly. Consistency: the agent server is authoritative and reflects a PATCH immediately (GET {conversation_url} → tags). The Cloud’s AppConversation.tags view is eventually consistent — it typically catches up within a few seconds — so this example confirms the write on the agent server and then polls the Cloud read instead of reading once.
Why not set tags on the Cloud create call? The Cloud POST/PATCH /api/v1/app-conversations payloads do not expose tags today — the agent server is the authoritative place to write them, and the Cloud reflects the result. The agent POST /api/conversations also accepts tags at creation time if you provision the sandbox yourself (see clone-and-attach).

Tag rules

The agent server enforces:
  • keys must be lowercase alphanumeric — no _ or - (use environmenturl, not environment_url; an invalid key is rejected)
  • values are arbitrary strings, ≤ 256 characters
  • PATCH replaces all tags — so this example does a read-modify-write to merge instead of clobbering existing tags
Need to store something structured or longer than 256 chars? Put a JSON string into a single tag value (within the limit), or split across multiple keys.

Run it

Sample output:

Set your own tags

Pass --tag KEY=VALUE (repeatable), and --keep to leave the conversation open so you can inspect the tags in the UI:

API endpoints used