Integrating an AI provider the usual way puts a real API key inside the container, where it lands in environment variables, config files, and logs. Anyone with container access can read it, including freelancers and AI-generated code.
Containers using Hoody AI hold no provider API key. They authenticate by container identity instead, and the real key stays on the host.
constauth='container-dev-env';// Only proves "I am this container"
// Or: 'container-1', 'container-2' for numbered containers
// This auth token:
// - Doesn't work outside your infrastructure
// - Dies when container is deleted
// - Can't be used by freelancers elsewhere
// - Is useless if exfiltrated
container-X is not an API key, and the gateway never parses the X. Any bearer token starting with container- asks the gateway to authenticate by container identity: a call made from inside a container is recognised as that container. Numbered identities like container-1 and descriptive ones like container-dev-alice are treated identically, so the suffix is a label for your own readability.
The gateway attributes usage to the resolved container and its owning account regardless of the token suffix. Per-container accounting ships: the gateway keeps one usage ledger per container, keyed by the resolved container id rather than by the token string, and a container reads its own records back over three routes.
Method
Path
Purpose
GET
/usage
This container’s records, newest first. Takes since_ms, until_ms, limit (max 500) and cursor; a page ends at 500 rows or 2 MiB, whichever comes first
GET
/usage/summary
Totals for a window, including how many records the provider did not report
DELETE
/usage?before_ms=...
Bounded delete of this container’s own records. Rows for in-flight requests are never deleted
They sit at the gateway root (https://ai.hoody.com/usage), not under /api/v1, and they authenticate the way inference does: by which container the request came from, and nothing else. Two consequences follow. Any process inside the container can read that container’s usage, privileged or not, because the identity is the container rather than a user within it. And since a container can delete its own history, this ledger is a convenience copy for the tenant rather than authoritative billing evidence. Use it to see AI consumption per workload and to attribute cost to a client or project; take the account’s own billing records as the authority.
Prompts travel from the container to the gateway on your server, and from there to the AI provider:
Container → Hoody AI (your server) → AI Provider → Response
The Hoody platform knows:
You created a container
The container has AI enabled
Aggregate spend and request counts, for billing
It does not know:
Your AI prompts
AI responses
What you’re building
The AI gateway runs on your own server. When shadow logging is configured it records request metadata (a method and endpoint class, never the raw path; source address; status; duration) but never prompt or response bodies, and never your keys. Hoody provisions the upstream provider key for your account, so aggregate spend and request counts are visible for billing. On paid models the upstream provider receives your prompts and responses; free-tier requests reach the same upstream providers through Hoody-operated accounts.
AI access is a per-container flag. You can toggle it on a single container, revoke access immediately by deleting the container, and list containers to audit which ones have AI enabled.
cURL runs inside your container and can wrap any HTTP
request into a single GET URL. The call stops being something you need a client
for and becomes something you can paste into a browser, send in a chat, bookmark,
schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever
credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
Toggles AI on one container and off another, deletes a third to revoke access instantly, and lists the first 100 containers so you can audit which have AI enabled (repeat through data.pagination.totalPages for the rest).
# Enable AI
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/PROD_ID&method=PATCH&bearer_token=TOKEN&json={"ai":true}&response=transparent
# Disable AI
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/UNTRUSTED_ID&method=PATCH&bearer_token=TOKEN&json={"ai":false}&response=transparent
# Delete container
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/FREELANCER_ID&method=DELETE&bearer_token=TOKEN&response=transparent
# Audit containers (page 1)
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/?page=1%26limit=100&method=GET&bearer_token=TOKEN&response=transparent
The link carries a credential and executes with it, so it is as sensitive as
the credential itself — and it passes through the cURL service's request log
on the way, not just the target's. Share it only where you would share the
secret, and prefer a delegated token with minimal permissions and an expiry:
see API tokens.
There is no container token to rotate: deleting the container ends its identity. The host-side upstream provider key is separate and follows a normal rotation process.
Beyond container-level access control, the Hoody Kit agent service (hoody-agent) ships hooks that let you enforce policy at the prompt level. A SessionStart hook’s output is injected into the system prompt for the life of the session, for example “Never execute destructive commands without asking first”. A UserPromptSubmit hook can append context to a prompt before it is sent, or block the prompt outright. Treat this as a strong default, not a hard boundary: a system prompt steers a model; it does not constrain it the way a firewall constrains a packet.
You can also monitor what an AI agent reads and writes as it works. A PostToolUse hook matching Read runs your own logging command every time that agent reads a file. A hook’s reach is the scope you write it to, not the session you write it from: the example below uses the project scope, so every session working in that project runs it, including sessions started later. It is not a server-wide monitor, and writing one is a fail-closed two-step: mint a single-use nonce, then spend it.
--name'Log agent reads'--description'Log every Read tool call'
Each hook is a lifecycle event, a matcher, and a shell command you supply, defined in plain JSON. There is no JavaScript to write and no proxy or URL change involved.
Give each container a name that records its purpose and intended access level:
Terminal window
container-prod-api# Production workload
container-dev-alice# Developer-specific
container-client-acme# Client-specific
container-untrusted-test# Limited permissions
Names are for your own readability. The gateway does not parse the suffix, so treat naming as documentation rather than an access-control or audit mechanism.
cURL runs inside your container and can wrap any HTTP
request into a single GET URL. The call stops being something you need a client
for and becomes something you can paste into a browser, send in a chat, bookmark,
schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever
credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
Turns AI off for a container that is already running untrusted or third-party code. Route it through a trusted container’s curl-1 — the link carries your Hoody API token, and the untrusted container should never see it.
The link carries a credential and executes with it, so it is as sensitive as
the credential itself — and it passes through the cURL service's request log
on the way, not just the target's. Share it only where you would share the
secret, and prefer a delegated token with minimal permissions and an expiry:
see API tokens.
cURL runs inside your container and can wrap any HTTP
request into a single GET URL. The call stops being something you need a client
for and becomes something you can paste into a browser, send in a chat, bookmark,
schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever
credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
Creates a snapshot before letting AI touch the container, then restores it by name if the result is bad. Route them through a different container’s curl-1 — a restore reboots CONTAINER_ID from the captured disk, so it can’t serve its own restore. Swap the snapshot name in the restore link for the one your create call actually returns.
The link carries a credential and executes with it, so it is as sensitive as
the credential itself — and it passes through the cURL service's request log
on the way, not just the target's. Share it only where you would share the
secret, and prefer a delegated token with minimal permissions and an expiry:
see API tokens.
cURL runs inside your container and can wrap any HTTP
request into a single GET URL. The call stops being something you need a client
for and becomes something you can paste into a browser, send in a chat, bookmark,
schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever
credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
The link carries a credential and executes with it, so it is as sensitive as
the credential itself — and it passes through the cURL service's request log
on the way, not just the target's. Share it only where you would share the
secret, and prefer a delegated token with minimal permissions and an expiry:
see API tokens.
You own the infrastructure, so you can configure your own AI providers directly on the host instead of using Hoody AI credits. You would then manage those API keys yourself, which brings back the exposure this page describes.
If an attacker gains root access to your server, they can read the Hoody AI configuration. Threat model:
Host root can list containers, read their storage and change their isolation, so treat a compromised host as a compromise of everything on it: rebuild on a trusted host and rotate every provider key that was present. Container isolation assumes a trusted host and does not survive this: host tooling can read a container’s storage and execute inside it
Deleting a container does not revoke provider keys that were already copied: rotate them
Your provider/gateway API keys are stored on the host (in host-side config, plaintext by default); root on the host can read them, just as with any self-hosted AI gateway
This is still better than scattering the same keys across every container that needs AI access, but treat the host filesystem as part of the key’s trust boundary. The host’s LUKS full-disk encryption is already on and covers the machine being stolen; it does nothing for root on a running host, which is the threat here. Rotate on suspicion rather than relying on the disk layer.
No. Container-level rate limiting is not implemented. AI access is controlled at the container level by the ai boolean flag, which is enabled or disabled and nothing more.