# Containers

**Page:** concepts/containers

[Download Raw Markdown](./concepts/containers.md)

---

# Containers

**Forget everything you know about containers.**

Docker containers are build artifacts. Lightweight, disposable, stateless. You bake an image, ship it, run it, throw it away. They are packaging -- not computing.

Hoody containers are computers. Full Debian 13 Linux machines with systemd, their own filesystem, their own network stack, their own process tree. They boot. They run services. They persist state. They have terminals and desktops and databases and browsers. They are not ephemeral throw-away images. They are machines you live in.

The difference is not incremental. It is categorical. And they run on servers you actually own — bare metal hardware you rent from the marketplace, not a cloud provider's shared infrastructure. Years of privacy and security engineering at Hoody went into making sure your containers are yours.

---

## What You Actually Get

When you create a Hoody container, you get a complete Linux computer:

- **Debian 13** (Trixie) with full package manager (`apt`)
- **systemd** init system (real service management, not hacked entrypoints)
- **Own filesystem** (persistent, writable, full Linux FHS)
- **Own network stack** (own IP, own DNS, own routing table)
- **Own process tree** (PID namespace, proper process isolation)
- **18 built-in HTTP services** (terminal, display, files, exec, sqlite, browser, workspaces, code, curl, notifications, daemons, cron, pipe, notes, watch, run, tunnel, proxy logs)

Every one of those services is a URL. The moment the container spawns, you have 18 live endpoints. No setup, no configuration, no deployment pipeline.


  
    ```bash
    # Create a container -- a full Linux computer
    hoody containers create --project abc123def456789012345678 \
      --server-id node-us-server-id \
      --name "dev-environment" \
      --hoody-kit \
      --dev-kit

    # 30 seconds later: 18 HTTP services, all live
    ```
  
  
    ```typescript
    import { HoodyClient } from '@hoody-ai/hoody-sdk';

    const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: process.env.HOODY_TOKEN });

    // Spawn a full Linux computer
    const container = await client.api.containers.create('abc123def456789012345678', {
      server_id: 'node-us-server-id',
      name: 'dev-environment',
      hoody_kit: true,
      dev_kit: true
    });

    // Immediately available:
    // container.id -> 890abcdef12345678901cdef
    // Terminal, Display, Files, Exec, SQLite, Browser, Workspaces,
    // Code, cURL, Notifications, Daemons, Cron, Pipe, Notes,
    // Watch, Run, Tunnel, Proxy Logs — all at predictable URLs
    ```
  
  
    ```bash
    # One POST, one computer
    curl -X POST "https://api.hoody.icu/api/v1/projects/abc123def456789012345678/containers" \
      -H "Authorization: Bearer $HOODY_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "server_id": "node-us-server-id",
        "name": "dev-environment",
        "hoody_kit": true,
        "dev_kit": true
      }'

    # Response includes container ID
    # Construct any service URL:
    # https://{projectId}-{containerId}-terminal-1.node-us.containers.hoody.icu
    ```
  


---

## Containers vs Docker: Not Even the Same Category

Docker solved packaging. Hoody solves computing. They are not competitors. They are different tools for different problems.

| | Docker Container | Hoody Container |
| :--- | :--- | :--- |
| **What it is** | A process running from a filesystem image | A full Linux computer |
| **Init system** | None (or hacked PID 1) | systemd |
| **Persistence** | Ephemeral by default (volumes are add-ons) | Persistent by default |
| **Network** | Shared bridge / host network | Own network stack with own IP |
| **Services** | One process per container (convention) | 18 built-in HTTP services + anything you install |
| **Access** | `docker exec` from the host | URL from anywhere on Earth |
| **State** | Destroy and rebuild | Snapshot, restore, branch |
| **OS** | Stripped-down layers | Full Debian 13 with apt |
| **Purpose** | Ship software | Run computers |

Docker asks: "How do I package and deploy this app?" Hoody asks: "How do I give someone a computer that is instantly accessible from anywhere?"


You can still run Docker INSIDE a Hoody container. A Hoody container is a full Linux machine -- install Docker, Podman, or anything else. The container is the computer. What you run inside it is up to you.


---

## Containers vs VMs: Same Goal, Different Era

Virtual machines also give you full computers. But VMs were designed for the pre-web era. They assume you will SSH into them, configure them manually, and manage them like pets.

Hoody containers are designed for the HTTP era:

| | Traditional VM | Hoody Container |
| :--- | :--- | :--- |
| **Access** | SSH, VNC, RDP (specialized clients) | HTTPS (browser or curl) |
| **Boot time** | Minutes | Seconds |
| **Overhead** | Full OS + hypervisor | Lightweight (LXC + namespaces) |
| **Density** | 5-20 per server | Hundreds per server |
| **Isolation** | Hardware-level (hypervisor) | Kernel-level (namespaces + seccomp) |
| **Built-in services** | None -- install everything | 18 HTTP services out of the box |
| **Embeddable** | No | Yes -- every service is an iframe-able URL |
| **AI-accessible** | Requires SSH adapter | Native -- AI speaks HTTP |
| **Snapshots** | Slow (full disk image) | Instant (copy-on-write) |

You get VM-grade isolation without VM-grade overhead. You get full computers without the boot time. You get dedicated machines without the density penalty.

---

## The 18 Built-In Services

Every Hoody container comes with the **Hoody Kit** -- 18 services that abstract Linux capabilities into HTTP endpoints. These are not optional add-ons. They are the container's native interface.

| Service | URL Segment | What It Does |
| :--- | :--- | :--- |
| **Terminal** | `terminal-N` | Shell sessions via HTTP + WebSocket |
| **Display** | `display-N` | Full desktop environments (Xfce, etc.) via browser |
| **Files** | `files-N` | Filesystem access (read, write, delete, list) |
| **SQLite** | `sqlite-N` | SQL databases queryable via HTTP |
| **Exec** | `exec-N` | Scripts that become HTTP endpoints automatically |
| **Browser** | `browser-N` | Chrome/Chromium automation via REST |
| **Workspaces** | `workspaces-N` | AI agent orchestration with 100+ tools |
| **Code** | `code-N` | VS Code instances in the browser |
| **cURL** | `curl-N` | Transform any REST call into a GET URL |
| **Notifications** | `n-N` | Push notifications via HTTP |
| **Daemons** | `daemon-N` | Background process management |
| **Cron** | `cron-N` | Scheduled task management |
| **Pipe** | `pipe-N` | Streaming data transfer between devices |
| **Notes** | `notes-N` | Collaborative notebooks with real-time sync |
| **Watch** | `watch-N` | File change notifications via HTTP + WebSocket |
| **Run** | `run-N` | Multi-source app resolver (Nix, pkgx, AppImage, Docker/OCI) |
| **Tunnel** | `tunnel-N` | TCP tunneling over HTTP (expose or pull services) |
| **Proxy Logs** | `logs-N` | Access logs and traffic inspection for Hoody Proxy |

Every service is a URL. Every URL is accessible from anywhere. The container is not just a Linux machine -- it is a Linux machine that speaks HTTP natively.


  
    ```bash
    # Run a command in the container
    hoody terminal sessions exec \
      --command "apt update && apt install -y nodejs" \
      -c 890abcdef12345678901cdef

    # Read a file
    hoody files get /home/user/app.js -c 890abcdef12345678901cdef

    # Query a database
    hoody db exec-transaction \
      --transaction '{"transaction":[{"query":"SELECT * FROM users"}]}' \
      -c 890abcdef12345678901cdef
    ```
  
  
    ```typescript
    import { HoodyClient } from '@hoody-ai/hoody-sdk';

    const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: process.env.HOODY_TOKEN });
    const containerClient = await client.withContainer({
      id: CONTAINER_ID,
      project_id: PROJECT_ID,
      server: SERVER_NAME
    });

    // Terminal: run a command
    const result = await containerClient.terminal.execution.execute({
      command: 'node --version',
      wait: true
    });

    // Files: read application code
    const code = await containerClient.files.get('/home/user/app.js');

    // SQLite: query the database (via direct fetch to the container service URL)
    const base = `https://${PROJECT_ID}-${CONTAINER_ID}`;
    const node = `${SERVER_NAME}.containers.hoody.icu`;
    const data = await fetch(`${base}-sqlite-1.${node}/api/v1/sqlite/db?db=app`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ transaction: [{ query: 'SELECT count(*) FROM users' }] })
    });
    ```
  
  
    ```bash
    # Terminal: install software
    curl -X POST "https://$PROJECT-$CONTAINER-terminal-1.$SERVER.containers.hoody.icu/api/v1/terminal/execute" \
      -H "Content-Type: application/json" \
      -d '{"command": "apt install -y python3", "wait": true}'

    # Files: download a log file
    curl "https://$PROJECT-$CONTAINER-files-1.$SERVER.containers.hoody.icu/api/v1/files/var/log/syslog" \
      -o syslog.txt

    # Display: take a screenshot of the desktop
    curl "https://$PROJECT-$CONTAINER-display-1.$SERVER.containers.hoody.icu/api/v1/display/screenshot" \
      -o desktop.png

    # Browser: navigate to a page
    curl "https://$PROJECT-$CONTAINER-browser-1.$SERVER.containers.hoody.icu/browse?browser_id=0&url=https%3A%2F%2Fexample.com"
    ```
  


---

## Container Isolation

Each container is a security boundary. Not a process boundary. Not a namespace suggestion. A boundary.

**Own filesystem.** Containers cannot see each other's files. No shared volumes by default. Each container has its own root filesystem, its own `/home`, its own `/etc`. You can explicitly share directories between containers if you choose, but isolation is the default.

**Own network.** Each container has its own IP address, its own routing table, its own DNS configuration. Containers do not share a network bridge. They communicate via HTTP URLs through the [proxy](/concepts/proxy/), the same way any two computers on the internet communicate.

**Own processes.** PID namespaces ensure containers cannot see or signal each other's processes. A compromised container cannot `kill -9` its neighbors.

**Kernel-enforced.** This isolation is not application-level. It is enforced by Linux namespaces, seccomp filters, and a hardened kernel. Breaking out of a container requires a kernel exploit, not an application bug.


Containers share the host kernel. This is lighter than a hypervisor but means kernel vulnerabilities could theoretically affect container isolation. Hoody uses a custom hardened Hoody kernel with seccomp filters and restricted syscalls to minimize this surface. For workloads that need full kernel isolation, Hoody can also provision dedicated virtual-machine instances instead of system containers.


---

## Multiple Instances

A container is not limited to one terminal, one desktop, one database. The instance number in the URL (`-1`, `-2`, `-3`) lets you run multiple parallel instances of any service:

```
https://...890abc-terminal-1.node-us.containers.hoody.icu   # Developer's shell
https://...890abc-terminal-2.node-us.containers.hoody.icu   # Build process
https://...890abc-terminal-3.node-us.containers.hoody.icu   # AI agent's session

https://...890abc-display-1.node-us.containers.hoody.icu    # Main desktop
https://...890abc-display-2.node-us.containers.hoody.icu    # Secondary monitor

https://...890abc-sqlite-1.node-us.containers.hoody.icu     # Application database
https://...890abc-sqlite-2.node-us.containers.hoody.icu     # Analytics database
```

Same container. Different sessions. Different users. Different AI agents. All running concurrently, all isolated by instance, all accessible at their own URL.

This is multiplayer by architecture, not by feature flag.

---

## The Economics: Infinite Containers

Traditional VMs consume fixed resources whether you use them or not. A 2-core, 4GB VM costs the same idle as it does under load.

Hoody containers use **KSM** (Kernel Samepage Merging) and **BTRFS deduplication** to share identical memory pages and storage blocks across containers. One hundred containers running the same base Debian image do not consume 100x the memory. They share what is identical and pay only for what differs.

This means:

- **Development containers** cost nearly nothing when idle
- **Test containers** share base OS memory with production containers
- **Staging environments** are not a budget conversation
- **Per-feature containers** become practical, not extravagant
- **AI agents** can each get their own container without resource anxiety

You are not rationing computers. You are spawning them.


  
    ```bash
    # Spawn 10 containers for parallel testing
    for i in $(seq 1 10); do
      hoody containers create --project $PROJECT_ID \
        --server-id $SERVER_ID \
        --name "test-runner-$i" \
        --hoody-kit
    done

    # Each gets 18 HTTP services, each isolated
    # Shared memory pages keep resource usage low
    ```
  
  
    ```typescript
    import { HoodyClient } from '@hoody-ai/hoody-sdk';

    const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: process.env.HOODY_TOKEN });

    // Spin up containers for each team member
    const names = ['alice', 'bob', 'carol', 'dave'];

    const containers = await Promise.all(
      names.map(name =>
        client.api.containers.create(projectId, {
          server_id: serverId,
          name: `dev-${name}`,
          hoody_kit: true,
          dev_kit: true
        })
      )
    );

    // 4 full Linux computers, each with 18 services
    // KSM deduplicates shared memory pages automatically
    ```
  
  
    ```bash
    # Create containers in parallel -- they're cheap
    for name in frontend backend database worker; do
      curl -X POST "https://api.hoody.icu/api/v1/projects/$PROJECT_ID/containers" \
        -H "Authorization: Bearer $HOODY_TOKEN" \
        -H "Content-Type: application/json" \
        -d "{
          \"server_id\": \"$SERVER_ID\",
          \"name\": \"$name\",
          \"hoody_kit\": true,
          \"dev_kit\": true
        }" &
    done
    wait

    # 4 computers created in ~30 seconds
    # Each with terminal, display, files, exec, sqlite...
    ```
  


---

## Container Lifecycle

Containers are not disposable. They have state, history, and continuity.

**Create** -- a POST to the API. The container boots in seconds with all services running.

**Run** -- the container operates as a full Linux machine. Install software, run servers, write code, train models. Everything persists.

**Snapshot** -- capture the entire filesystem state instantly. [Snapshots](/concepts/snapshots/) are copy-on-write, so they cost almost nothing.

**Stop** -- the container halts but preserves its filesystem. Start it again, and everything is where you left it.

**Restore** -- revert to any snapshot. Time travel in seconds.

**Copy** -- duplicate a container to another server or project. Clone your development environment for a new team member in one API call.

**Delete** -- destroy the container. The URL ceases to exist.

At every stage, the container's identity is its URL. Create it, and URLs appear. Delete it, and URLs vanish.

---

## The Atomic Unit of Computing

In legacy infrastructure, the "unit" is ambiguous. Is it a server? A VM? A pod? A process? A function? Teams spend more time debating the abstraction than building on it.

In Hoody, the atomic unit is the container. It is the answer to every question:

- "Where does this service run?" **In a container.**
- "How do I give the AI access?" **Give it the container URL.**
- "How do I isolate this experiment?" **Put it in a container.**
- "How do I roll back?" **Restore the container snapshot.**
- "How do I share this environment?" **Share the container URL.**

One abstraction. One mental model. One URL pattern. Everything else is built on top of containers, not beside them.


When in doubt, create a container. They are cheap, they are fast, they are isolated, and they are HTTP-native. The overhead of a new container is less than the overhead of configuring a shared one.


---

**Next:** [The Hoody Proxy](/concepts/proxy/) -- how URLs reach containers.