Everything is a URL
Section titled “Everything is a URL”Most platforms treat a URL as an address bolted onto a resource after the fact. Hoody inverts that relationship: the URL is the resource’s identity. A terminal, a desktop, a filesystem, a database, and an AI agent each live at their own address. Deleting the resource kills its URL, sharing the URL shares the resource, and combining resources means combining URLs.
This is the architecture, not a metaphor. Every process on a server you own is an HTTPS endpoint with HTTP/2; the proxy issues and renews the certificates, so there is nothing to configure. You can embed a program in an iframe, drive it from an AI agent, reach it through ssh hoody.com, or open it in a browser on your phone.
Anatomy of a Hoody URL
Section titled “Anatomy of a Hoody URL”Every resource in Hoody lives at a deterministic address:
https://{projectId}-{containerId}-{service}-{instance}.{serverName}.containers.hoody.com| Segment | Example | What it encodes |
|---|---|---|
projectId | 67e89abc123def456789abcd | Which project owns this resource. 24 hex chars. |
containerId | 890abcdef12345678901cdef | Which container runs it. 24 hex chars. Cryptographically unguessable. |
service | terminal | What kind of resource: terminal, display, files, exec, sqlite, browser, agent, code, curl, n, daemon, cron, pipe, watch, notes, run, tunnel, logs. |
instance | 1 | Which instance of that service. Change 1 to 2 and you get a different terminal session or a different desktop. SQLite instances are the exception: they share the container filesystem, and the database itself is chosen with the db query parameter. |
serverName | node-us | The bare metal server hosting it. The name encodes its geography. |
Change one segment and you reach a different resource. Each segment maps to real infrastructure: a project boundary, a container filesystem, a service process, a physical server. The address is the topology of your infrastructure, expressed as text.
Four kinds of URLs
Section titled “Four kinds of URLs”Hoody has four URL families. Each serves a different purpose, but all follow the same principle: the address is the interface.
Container service URLs
Section titled “Container service URLs”Every container gets 18 service URLs the moment it spawns:
https://67e89abc...-890abcdef...-terminal-1.node-us.containers.hoody.comhttps://67e89abc...-890abcdef...-display-1.node-us.containers.hoody.comhttps://67e89abc...-890abcdef...-files-1.node-us.containers.hoody.comhttps://67e89abc...-890abcdef...-exec-1.node-us.containers.hoody.comhttps://67e89abc...-890abcdef...-sqlite-1.node-us.containers.hoody.comhttps://67e89abc...-890abcdef...-browser-1.node-us.containers.hoody.comhttps://67e89abc...-890abcdef...-agent-1.node-us.containers.hoody.comhttps://67e89abc...-890abcdef...-code-1.node-us.containers.hoody.comThe proxy reads the URL, routes to the container, and dispatches to the service; there is no DNS record, port forward, or nginx configuration to set up on your side.
API URLs
Section titled “API URLs”The Hoody API itself is a URL:
https://api.hoody.com/api/v1/containershttps://api.hoody.com/api/v1/projectshttps://api.hoody.com/api/v1/serversYou create, manage, and destroy resources through these endpoints. A request to the API creates a container, and the container’s service URLs exist from that moment.
Proxy alias URLs
Section titled “Proxy alias URLs”When cryptographic URLs are too long for humans, create aliases:
https://my-app.node-us.containers.hoody.comhttps://staging-api.node-eu.containers.hoody.comhttps://client-demo.node-us.containers.hoody.comAn alias goes through the same proxy, with the same routing and security; only the address is shorter. Point a CNAME from your own domain, and your infrastructure lives at api.yourcompany.com.
Realm-scoped URLs
Section titled “Realm-scoped URLs”For multi-tenant isolation, realms namespace the API itself:
https://{realmId}.api.hoody.com/api/v1/containersA realm scopes auth tokens, containers, and projects to its own namespace. A single Hoody account can hold multiple isolated namespaces.
One interface for humans, machines, and AI
Section titled “One interface for humans, machines, and AI”Three audiences interact with computing infrastructure: humans, machines, and AI. The legacy world gives each a different interface: humans get GUIs, machines get wire protocols, AI gets SDKs. Hoody gives all three the same interface: a URL.
Humans
Section titled “Humans”Open a browser and type the URL: you are in a terminal. Change terminal to display in the address bar and you are on a desktop; change display to files and you are browsing the filesystem. Nothing is installed on the device, and no SSH key or VPN is involved.
AI agents
Section titled “AI agents”Give an LLM a container URL. HTTP, JSON, and the GET, POST, PUT, and DELETE verbs are already in its training data, so it needs no SDK, adapter, or extra training to drive the resource.
# List containers; the URL is the queryhoody containers list
# Get a specific container; the URL identifies ithoody containers get 890abcdef12345678901cdefimport { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
// Every resource is a URL behind the scenesconst container = await client.api.containers.get('890abcdef12345678901cdef');
// Construct any service URL from the container dataconst terminalUrl = `https://${container.data.project_id}-${container.data.id}-terminal-1.${container.data.server_name}.containers.hoody.com`;# The URL is the resourcecurl https://api.hoody.com/api/v1/containers/890abcdef12345678901cdef \ -H "Authorization: Bearer $HOODY_TOKEN"
# Execute a command via URLcurl -X POST "https://$PROJECT-$CONTAINER-terminal-1.$SERVER.containers.hoody.com/api/v1/terminal/execute" \ -H "Content-Type: application/json" \ -d '{"command": "ls -la", "wait": true}'One request, one link
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.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
The first link fetches the container record; the second starts ls -la in its terminal and returns a command_id to poll for the output.
# Get the container
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/containers/890abcdef12345678901cdef&method=GET&bearer_token=TOKEN&response=transparent
# Run a command
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT_ID-CONTAINER_ID-terminal-1.SERVER.containers.hoody.com/api/v1/terminal/execute&method=POST&json={"command":"ls%20-la","wait":true}&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.
IoT and embedded devices
Section titled “IoT and embedded devices”Anything that can make an HTTP request can control a full Linux computer: a Raspberry Pi, a smart thermostat, a CI/CD runner.
Composability through URLs
Section titled “Composability through URLs”If everything is a URL, then combining systems is combining URLs. No integration layer, message queue, or adapter pattern sits between two containers; one calls the other’s service URLs directly.
# Chain container operations; each is a URL callhoody snapshots create -c 890abcdef12345678901cdef --alias "before-experiment"
# Clone from that snapshot to a new containerhoody containers copy 890abcdef12345678901cdef \ --target-project-id 67e89abc123def456789abcd \ --source-snapshot "before-experiment"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
// Connect to Container B and read a fileconst containerB = await client.withContainer({ id: CONTAINER_B_ID, project_id: PROJECT_ID, server_name: SERVER_NAME});const config = await containerB.files.get('/home/app/config.json');
// Connect to Container A and write to its SQLiteconst containerA = await client.withContainer({ id: CONTAINER_A_ID, project_id: PROJECT_ID, server_name: SERVER_NAME});await containerA.sqlite.database.executeTransaction( { transaction: [{ statement: `INSERT INTO configs VALUES (?)`, values: [config.data] }] }, { db: 'app', create_db_if_missing: true });# Container A executes a build in Container B's terminalcurl -X POST "https://$PROJECT-$CONTAINER_B-terminal-1.$SERVER.containers.hoody.com/api/v1/terminal/execute" \ -H "Content-Type: application/json" \ -d '{"command": "npm run build", "wait": true}'
# Then reads the artifact via Container B's filescurl "https://$PROJECT-$CONTAINER_B-files-1.$SERVER.containers.hoody.com/api/v1/files/home/app/dist/bundle.js" \ -o bundle.js
# And uploads it to Container Ccurl -X PUT "https://$PROJECT-$CONTAINER_C-files-1.$SERVER.containers.hoody.com/api/v1/files/var/www/html/bundle.js" \ --data-binary @bundle.jsOne request, one link
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.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Runs the build in Container B’s terminal, the first step in the chain. The read that follows saves to local disk and the write reads from it, so neither fits a single link.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT_ID-CONTAINER_B_ID-terminal-1.SERVER.containers.hoody.com/api/v1/terminal/execute&method=POST&json={"command":"npm%20run%20build","wait":true}&response=transparent The chain above runs without an orchestrator, message bus, or service mesh. Each step is a plain HTTP call to a service URL, the same mechanism the rest of the web runs on.
Self-documenting infrastructure
Section titled “Self-documenting infrastructure”Legacy systems need documentation to explain how to reach them: IP addresses, port numbers, protocol versions, and authentication mechanisms live in wikis, READMEs, and tribal knowledge.
A Hoody URL documents itself:
https://67e89abc123def456789abcd-890abcdef12345678901cdef-sqlite-1.node-us.containers.hoody.comRead it left to right: project 67e89abc... owns container 890abcde..., which runs a SQLite database, instance 1, on server node-us. The URL tells you what it is, where it is, and who owns it. Sharing the URL shares the documentation, the access, and the interface in one string.
URLs and AI agents
Section titled “URLs and AI agents”Legacy infrastructure requires an AI to learn bespoke interfaces: SSH key exchange, database wire protocols, custom CLIs. Every tool is a separate skill to acquire.
When everything is a URL, the AI already has the skills it needs. HTTP is the most represented protocol in LLM training data, and JSON is the most represented data format. An AI agent given a Hoody container URL can immediately:
- Execute commands (POST to the terminal URL)
- Read and write files (GET/PUT to the files URL)
- Query databases (POST to the SQLite URL)
- Automate browsers (POST to the browser URL)
- Spawn new containers (POST to the API URL)
- Access desktops (connect to the display URL)
None of this requires an SDK, extra training, or fine-tuning. Models were trained on HTTP, so infrastructure that speaks HTTP needs no translation layer between the model and the machine.
Any AI that can fetch a URL can read @hoody.com and receive a Skill: a machine-readable map of every HTTP endpoint across your containers. ChatGPT, Claude Code, and Codex can all use it; there is no server to host or plugin to install.
The routing contract
Section titled “The routing contract”Every Hoody URL carries the same contract:
- Identity: change a segment and you address a different resource.
- Routing: the proxy reads the URL segments, finds the container, and dispatches to the service.
- Security: the two 24-character IDs (48 hex characters) are cryptographically unguessable. Knowing the URL is the first layer of authorization.
- Composability: anything that can construct a URL can interact with anything in Hoody.
- Portability: the URL works the same pasted into Slack, a CI pipeline, an iframe, or an AI prompt.
URLs in practice
Section titled “URLs in practice”When every resource is a URL, the questions you ask about infrastructure change:
| Old question | New question |
|---|---|
| ”What’s the IP address?" | "What’s the URL?" |
| "What port is it on?” | It is in the URL. |
| ”What protocol does it use?” | HTTPS, always. |
| ”What client do I need?” | A browser, curl, or fetch. |
| ”How do I give someone access?” | Send them the URL. |
| ”How do I revoke access?” | Delete the container; the URL dies with it. |
| ”How do I document this?” | The URL is the documentation. |
One string serves as the API, the interface, and the documentation.
Next: Containers covers what lives at these URLs.