Agent: Session leases
Section titled “Agent: Session leases”A session exposes two independent, renewable lease resources, both in-memory and both restart-resilient only insofar as the gateway still recognises them.
The approver lease grants the exclusive right to answer a session’s approval gates. Every decision on an “always” session whose lease was minted (/confirm, a WS confirm frame, or a gated tool-run confirmation) must present the current capability. The capability is returned once, on acquire. A capability minted for another session, a fenced generation, or no capability at all is rejected; an expired capability also fails closed, the requirement persists until someone re-acquires.
The attachment lease keeps a live session, and especially a parked approval gate, alive against the 5-minute idle reaper, so a client that dispatched a turn and disconnected can reconnect and still answer. It is a separate resource with its own expiry, and renewing it does not renew the approver lease.
When a lease expires without renewal the consequence is fail-closed in both cases, but the meaning differs:
- An expired approver lease keeps the requirement active. No holder has the right to answer; the gate stays parked until some caller acquires a new capability. Expiry never lets anyone answer.
- An expired attachment lease no longer suppresses the idle reaper. The session, and any gate parked on it, may be torn down at the next reaper sweep. Re-acquire to resume protection.
Leases are in-memory on the daemon. After a daemon restart GET /sessions/{id}/approval reports held:false, and a client must acquire again. Holder strings are never compared; only capabilities authorise.
All endpoints below live on the agent gateway of the bound container. The base URL takes the form https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com.
Approver lease
Section titled “Approver lease”The approver lease is the only thing that lets you answer a parked gate on an “always” session. Acquire, renew, and release act on the session’s single approver lease.
POST /api/v1/agent/sessions/{id}/approver-lease
Section titled “POST /api/v1/agent/sessions/{id}/approver-lease”Acquire the right to answer this session’s gates.
The response carries the capability exactly once. The daemon verifies the capability at every decision consumption: /confirm, a WS confirm frame, and the confirmed re-issue of a gated tool run. While a gate is parked and a lease change happens, the daemon broadcasts event.decision_requirements { gate_id, generation, lease_required } so peers can re-arm.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Session identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves against. |
X-Hoody-Container | header | string | No | Per-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension. |
X-Hoody-Realm | header | string | No | Per-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes. |
realm | query | string | No | Per-request realm selector (the in-query alias of X-Hoody-Realm, read only when the header is absent). |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
holder | string | Yes | Opaque per-caller id (1 to 64 printable ASCII, no spaces) that identifies this client as the holder (reported as holder on the event.gate_resolved stream event). Never a credential; an empty holder is 400. |
ttl_ms | integer | No | Requested lifetime in milliseconds (the daemon clamps to its bounds). |
replace | boolean | No | Documentation only. A live lease is taken over ONLY by presenting its current capability as proof; replace:true without the proof is still 409 approver_lease_held. After expiry or release an acquire needs no proof. |
lease | string | No | The capability, used as proof an acquire presents to take over a live lease (alternative to the X-Hoody-Approver-Lease header). |
Request example
Section titled “Request example”curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/{id}/approver-lease" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"holder": "ops-console-7a3"}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.claimApproverLease('{id}', { holder: 'ops-console-7a3' });Responses
Section titled “Responses”{ "lease": "alc_01HF3ZP7MX8HQ6VYJK5R2N9C4D", "held": true, "holder": "ops-console-7a3", "generation": 1, "expires_at": "2025-03-19T14:22:08.314Z", "epoch": "ep_01HF3ZP5T7K9M2X8V4N6YQB1RA"}| Field | Type | Description |
|---|---|---|
lease | string | The capability to present as X-Hoody-Approver-Lease on /confirm (acquire only). |
held | boolean | Whether a lease is currently held. |
holder | string | The holder identity (this gateway connection, plus the optional body holder). |
generation | integer | Lease generation; a decision echoes it, and a replacement bumps it (fencing the previous holder). |
expires_at | string | RFC3339 expiry; renew before it. |
epoch | string | The daemon execution epoch the lease is bound to; a restart starts a new one and every lease must be re-acquired. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "approver_lease_held", "message": "another holder owns the approver lease"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
approver_lease_held | Approver lease held | Another unexpired holder owns this session’s approver lease. | Wait for it to expire or be released, or take it over by presenting its current capability as proof (X-Hoody-Approver-Lease / body.lease). replace:true alone never authorises. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). The gateway rejects an oversized body at the edge (http.MaxBytesReader) before the handler reads it. A well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
PATCH /api/v1/agent/sessions/{id}/approver-lease
Section titled “PATCH /api/v1/agent/sessions/{id}/approver-lease”Renew the approver lease.
Extends the presented lease (X-Hoody-Approver-Lease header or body.lease). A capability that does not verify returns 409 approver_lease_invalid; a lease that has already lapsed returns 410 approver_lease_expired (re-acquire).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Session identifier. |
X-Hoody-Approver-Lease | header | string | No | The approver-lease capability returned by POST /sessions/{id}/approver-lease. On renew/release it names the lease to act on. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope. |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override. |
X-Hoody-Container | header | string | No | Per-request bound remote container. |
X-Hoody-Realm | header | string | No | Per-request realm selector. |
realm | query | string | No | Per-request realm selector (in-query alias). |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
ttl_ms | integer | No | Requested lifetime in milliseconds (the daemon clamps to its bounds). |
lease | string | No | The capability (alternative to the X-Hoody-Approver-Lease header). |
Request example
Section titled “Request example”curl -X PATCH "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/{id}/approver-lease" \ -H "Authorization: Bearer <token>" \ -H "X-Hoody-Approver-Lease: alc_01HF3ZP7MX8HQ6VYJK5R2N9C4D" \ -H "Content-Type: application/json" \ -d '{"ttl_ms": 900000}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.renewApproverLease('{id}', { ttl_ms: 900000 }, { XHoodyApproverLease: 'alc_01HF3ZP7MX8HQ6VYJK5R2N9C4D' });Responses
Section titled “Responses”{ "held": true, "holder": "ops-console-7a3", "generation": 1, "expires_at": "2025-03-19T14:37:08.314Z", "epoch": "ep_01HF3ZP5T7K9M2X8V4N6YQB1RA"}| Field | Type | Description |
|---|---|---|
lease | string | The capability. Present ONLY on acquire and never shown again; store it. |
held | boolean | Whether a lease is currently held. |
holder | string | The holder identity. |
generation | integer | Lease generation; a decision echoes it, and a replacement bumps it (fencing the previous holder). |
expires_at | string | RFC3339 expiry; renew before it. |
epoch | string | The daemon execution epoch. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "approver_lease_invalid", "message": "the approver lease does not verify"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
approver_lease_invalid | Approver lease invalid | The presented capability does not verify for this session (wrong session, a fenced generation, or a daemon restart). | Re-acquire the lease (POST /sessions/{id}/approver-lease). |
{ "code": "approver_lease_expired", "message": "the approver lease expired"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
approver_lease_expired | Approver lease expired | The presented lease lapsed; an expired lease never authorises a decision. | Re-acquire the lease (POST /sessions/{id}/approver-lease). |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
DELETE /api/v1/agent/sessions/{id}/approver-lease
Section titled “DELETE /api/v1/agent/sessions/{id}/approver-lease”Release the approver lease.
Releases the presented lease (X-Hoody-Approver-Lease). A capability that does not verify returns 409 approver_lease_invalid; a lease that has already lapsed returns 410 approver_lease_expired.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Session identifier. |
X-Hoody-Approver-Lease | header | string | No | The approver-lease capability. On release it names the lease to act on. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope. |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override. |
X-Hoody-Container | header | string | No | Per-request bound remote container. |
X-Hoody-Realm | header | string | No | Per-request realm selector. |
realm | query | string | No | Per-request realm selector (in-query alias). |
This endpoint accepts no request body.
Request example
Section titled “Request example”curl -X DELETE "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/{id}/approver-lease" \ -H "Authorization: Bearer <token>" \ -H "X-Hoody-Approver-Lease: alc_01HF3ZP7MX8HQ6VYJK5R2N9C4D"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.releaseApproverLease('{id}', { XHoodyApproverLease: 'alc_01HF3ZP7MX8HQ6VYJK5R2N9C4D' });Responses
Section titled “Responses”{ "held": false, "holder": "ops-console-7a3", "generation": 1, "expires_at": "2025-03-19T14:22:08.314Z", "epoch": "ep_01HF3ZP5T7K9M2X8V4N6YQB1RA"}| Field | Type | Description |
|---|---|---|
lease | string | The capability. Present ONLY on acquire and never shown again; store it. |
held | boolean | Whether a lease is currently held. |
holder | string | The holder identity. |
generation | integer | Lease generation. |
expires_at | string | RFC3339 expiry. |
epoch | string | The daemon execution epoch. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "approver_lease_invalid", "message": "the approver lease does not verify"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
approver_lease_invalid | Approver lease invalid | The presented capability does not verify for this session (wrong session, a fenced generation, or a daemon restart). | Re-acquire the lease (POST /sessions/{id}/approver-lease). |
{ "code": "approver_lease_expired", "message": "the approver lease expired"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
approver_lease_expired | Approver lease expired | The presented lease lapsed; an expired lease never authorises a decision. | Re-acquire the lease (POST /sessions/{id}/approver-lease). |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
Attachment lease
Section titled “Attachment lease”The attachment lease keeps a live session, and especially a parked gate, alive across client disconnects. The acquire is decided atomically against the reaper: a session whose close is already committed answers 404. The attachment lease only keeps the session alive; the approver lease is a separate resource with its own expiry, so an expired approver lease still fails closed even while an attachment lease is live.
POST /api/v1/agent/sessions/{id}/attachments
Section titled “POST /api/v1/agent/sessions/{id}/attachments”Hold a live session (and its parked gate) alive.
Returns { lease_id, expires_at }. Renew with PATCH before expiry, release with DELETE. Default lifetime is 15 minutes, capped at 60 minutes.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Session identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope. |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override. |
X-Hoody-Container | header | string | No | Per-request bound remote container. |
X-Hoody-Realm | header | string | No | Per-request realm selector. |
realm | query | string | No | Per-request realm selector (in-query alias). |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
ttl_ms | integer | No | Requested lifetime in milliseconds (default 15m, capped at 60m). |
Request example
Section titled “Request example”curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/{id}/attachments" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"ttl_ms": 900000}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.claimAttachment('{id}', { ttl_ms: 900000 });Responses
Section titled “Responses”{ "lease_id": "atl_01HF3ZQ4MX9JQ7WZK6S3OAE5E2", "expires_at": "2025-03-19T14:37:08.314Z"}| Field | Type | Description |
|---|---|---|
lease_id | string | The lease id (send it on PATCH/DELETE to renew/release). |
expires_at | string | RFC3339 expiry; renew before it or the session may be reaped once idle. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
PATCH /api/v1/agent/sessions/{id}/attachments/{lease_id}
Section titled “PATCH /api/v1/agent/sessions/{id}/attachments/{lease_id}”Renew an attachment lease.
Extends the lease’s expiry, decided atomically against the reaper’s close (404 once closing). A lapsed lease is refused with 410 attachment_expired (acquire a new one). 404 is also returned when the lease is unknown, not this session’s, or not this owner’s. Renewals are re-authorized against the session’s current owner and realm, so a lease never outlives a changed pin or a credential switch.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Session identifier. |
lease_id | path | string | Yes | Attachment lease identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope. |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override. |
X-Hoody-Container | header | string | No | Per-request bound remote container. |
X-Hoody-Realm | header | string | No | Per-request realm selector. |
realm | query | string | No | Per-request realm selector (in-query alias). |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
ttl_ms | integer | No | New lifetime in milliseconds from now (default 15m, capped at 60m). |
Request example
Section titled “Request example”curl -X PATCH "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/{id}/attachments/{lease_id}" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"ttl_ms": 900000}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.renewAttachment('{id}', '{lease_id}', { ttl_ms: 900000 });Responses
Section titled “Responses”{ "lease_id": "atl_01HF3ZQ4MX9JQ7WZK6S3OAE5E2", "expires_at": "2025-03-19T14:52:08.314Z"}| Field | Type | Description |
|---|---|---|
lease_id | string | The lease id. |
expires_at | string | RFC3339 expiry; renew before it or the session may be reaped once idle. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "attachment_expired", "message": "the attachment lease expired; acquire a new one"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
attachment_expired | Attachment lease expired | The attachment lease already lapsed; an expired lease is not revived by renewal. | Acquire a new lease (POST /sessions/{id}/attachments). |
{ "code": "payload_too_large", "message": "request body exceeds the configured size limit"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
payload_too_large | Payload too large | The request body exceeds the configured size cap (MaxBodyBytes). | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
DELETE /api/v1/agent/sessions/{id}/attachments/{lease_id}
Section titled “DELETE /api/v1/agent/sessions/{id}/attachments/{lease_id}”Release an attachment lease.
Drops the lease; the session resumes ordinary idle-reap behaviour. 404 is returned when the lease is unknown, not this session’s, or not this owner’s.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Session identifier. |
lease_id | path | string | Yes | Attachment lease identifier. |
X-Hoody-Cwd | header | string | No | Per-request working-directory scope. |
X-Hoody-Config-Dir | header | string | No | Per-request --config-dir override. |
X-Hoody-Container | header | string | No | Per-request bound remote container. |
X-Hoody-Realm | header | string | No | Per-request realm selector. |
realm | query | string | No | Per-request realm selector (in-query alias). |
This endpoint accepts no request body.
Request example
Section titled “Request example”curl -X DELETE "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/sessions/{id}/attachments/{lease_id}" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.agent.sessions.releaseAttachment('{id}', '{lease_id}');Responses
Section titled “Responses”{ "status": "ok", "released": true}| Field | Type | Description |
|---|---|---|
status | string | "ok" on success. |
released | boolean | Always true on a 200. |
{ "code": "bad_request", "message": "invalid request"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
realm_scope_unsupported | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |
invalid_realm | Invalid realm selector | The realm selector is malformed (not ""/“global”/a 24-hex id). | Pass a valid realm selector. |
{ "code": "forbidden", "message": "request must arrive through the Hoody proxy"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden (Source IP Guard) | The request did not come through the program’s URL. Hoody Kit programs are reached through their URLs only. | Call the agent through its URL, for example with hoody agent …. |
{ "code": "not_found", "message": "resource not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | The requested resource does not exist. | Verify the path and identifier. |
{ "code": "rate_limited", "message": "request rate limit exceeded"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
rate_limited | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the Retry-After header and retry; reduce the request rate. |
{ "code": "internal_error", "message": "internal server error"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
internal_error | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |
{ "code": "service_unavailable", "message": "service unavailable"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
service_unavailable | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor Retry-After and retry. |
See also
Section titled “See also”- Agent: Session approvals for the gates an approver lease lets you answer.