# Rapid Internal Tools

**Page:** guides/internal-tools

[Download Raw Markdown](./guides/internal-tools.md)

---

# Rapid Internal Tools

**Every company has the same dirty secret: critical business processes run on spreadsheets, Slack messages, and manual copy-paste between systems.** The admin dashboard that would take two months to build properly never gets built. The webhook processor that should exist gets replaced by someone checking email. The report that should be automated is generated by hand every Friday.

These tools do not get built because the overhead of building them is absurd. Spin up a server. Configure a database. Set up authentication. Write a deployment pipeline. Manage SSL certificates. All for an internal tool that three people use.

On Hoody, an internal tool is a file. You write a function, it becomes an HTTP endpoint. You query the database through HTTP. You share the URL with your team. Done. No infrastructure. No deployment. No maintenance. The file IS the tool.

---

## Why Internal Tools Are Perfect for Hoody

| Traditional Internal Tool | Hoody Internal Tool |
|--------------------------|---------------------|
| Provision a server | Already have one |
| Install a web framework | Write a function in a file |
| Set up a database | hoody-sqlite is already running |
| Configure authentication | Proxy permissions |
| Write deployment scripts | Files are live instantly |
| Manage SSL certificates | Handled by the proxy |
| Monitor uptime | hoody-daemon auto-restarts |
| Schedule tasks | hoody-cron is already running |

The distance between "I need this tool" and "this tool exists" collapses from weeks to minutes.


hoody-exec is the key primitive here. Every script you write in the `scripts/` directory automatically becomes an HTTP endpoint. No routing configuration. No server setup. No framework. Write function, get URL.


---

## Build 1: Admin Dashboard

An admin dashboard that reads user data from SQLite and returns JSON. The frontend can be any HTML page, a React app, or even a curl command.

### Step 1: Create the Data


  
    ```bash
    # Create the users table with sample data (--db is required; --create-db-if-missing creates app.db on first use)
    hoody db exec-transaction --db /hoody/databases/app.db --create-db-if-missing \
      --transaction '[{"statement": "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL, name TEXT NOT NULL, role TEXT DEFAULT '\''user'\'', status TEXT DEFAULT '\''active'\'', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, last_login DATETIME)"}]'

    # Insert sample data
    hoody db exec-transaction --db /hoody/databases/app.db \
      --transaction '[{"statement": "INSERT INTO users (email, name, role, status, last_login) VALUES (\"alice@company.com\", \"Alice Chen\", \"admin\", \"active\", \"2026-03-03\"), (\"bob@company.com\", \"Bob Martinez\", \"user\", \"active\", \"2026-03-04\"), (\"carol@company.com\", \"Carol Kim\", \"user\", \"suspended\", \"2026-02-15\")"}]'
    ```
  
  
    ```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,
    });

    // SDK executeTransaction has a known body-param bug — using fetch for now
    const sqliteUrl = `https://${PROJECT_ID}-${CONTAINER_ID}-sqlite-1.${SERVER}.containers.hoody.icu`;
    const notificationUrl = `https://${PROJECT_ID}-${CONTAINER_ID}-n-1.${SERVER}.containers.hoody.icu`;
    await fetch(`${sqliteUrl}/api/v1/sqlite/db?db=/hoody/databases/app.db&create_db_if_missing=true`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        transaction: [
          { statement: `CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            email TEXT NOT NULL,
            name TEXT NOT NULL,
            role TEXT DEFAULT 'user',
            status TEXT DEFAULT 'active',
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            last_login DATETIME
          )` }
        ],
      })
    });
    ```
  
  
    ```bash
    curl -X POST "https://$PROJECT_ID-$CONTAINER_ID-sqlite-1.$SERVER.containers.hoody.icu/api/v1/sqlite/db?db=/hoody/databases/app.db&create_db_if_missing=true" \
      -H "Content-Type: application/json" \
      -d '{
        "transaction": [{"statement": "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL, name TEXT NOT NULL, role TEXT DEFAULT '\''user'\'', status TEXT DEFAULT '\''active'\'', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, last_login DATETIME)"}]
      }'
    ```
  


### Step 2: Write the Dashboard API

Create a hoody-exec script that serves as the dashboard backend:


  
    ```bash
    hoody exec scripts write \
      --path "admin/dashboard.ts" \
      --content "// @mode serverless\n// @cors reflective\n// @timeout 5000\n\nconst SQLITE = \"https://PROJECT-CONTAINER-sqlite-1.SERVER.containers.hoody.icu\";\n\nconst stats = await fetch(SQLITE + \"/api/v1/sqlite/db?db=/hoody/databases/app.db\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ transaction: [{ query: \"SELECT COUNT(*) as total_users FROM users\" }] })\n}).then(r => r.json());\n\nreturn { statistics: stats, generated_at: new Date().toISOString() };" \
      --create-dirs
    ```
  
  
    ```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,
    });

    await containerClient.exec.scripts.write({
      path: 'admin/dashboard.ts',
      content: `
    // @mode serverless
    // @cors reflective
    // @timeout 5000

    const SQLITE = "${sqliteUrl}";

    const stats = await fetch(SQLITE + "/api/v1/sqlite/db?db=/hoody/databases/app.db", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        transaction: [{
          query: \`SELECT
            COUNT(*) as total_users,
            SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active_users,
            SUM(CASE WHEN status = 'suspended' THEN 1 ELSE 0 END) as suspended_users,
            SUM(CASE WHEN role = 'admin' THEN 1 ELSE 0 END) as admin_count,
            SUM(CASE WHEN last_login > datetime('now', '-7 days') THEN 1 ELSE 0 END) as active_this_week
          FROM users\`
        }]
      })
    }).then(r => r.json());

    const recent = await fetch(SQLITE + "/api/v1/sqlite/db?db=/hoody/databases/app.db", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        transaction: [{ query: "SELECT name, email, role, status, last_login FROM users ORDER BY last_login DESC LIMIT 10" }]
      })
    }).then(r => r.json());

    return {
      statistics: stats.data?.[0] || stats,
      recent_logins: recent.data || recent,
      generated_at: new Date().toISOString()
    };
      `,
      createDirs: true,
    });
    ```
  
  
    ```bash
    curl -X POST "https://$PROJECT_ID-$CONTAINER_ID-exec-1.$SERVER.containers.hoody.icu/api/v1/exec/scripts/write" \
      -H "Content-Type: application/json" \
      -d '{
        "path": "admin/dashboard.ts",
        "content": "// @mode serverless\n// @cors reflective\n// @timeout 5000\n\nconst SQLITE = \"https://PROJECT-CONTAINER-sqlite-1.SERVER.containers.hoody.icu\";\n\nconst stats = await fetch(SQLITE + \"/api/v1/sqlite/db?db=/hoody/databases/app.db\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ transaction: [{ query: \"SELECT COUNT(*) as total_users FROM users\" }] })\n}).then(r => r.json());\n\nreturn { statistics: stats, generated_at: new Date().toISOString() };",
        "createDirs": true
      }'
    ```
  


### Step 3: Use It

Your dashboard API is now live:

```bash
curl "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/admin/dashboard"
```

Response:

```json
{
  "statistics": {
    "total_users": 3,
    "active_users": 2,
    "suspended_users": 1,
    "admin_count": 1,
    "active_this_week": 2
  },
  "recent_logins": [
    { "name": "Bob Martinez", "email": "bob@company.com", "role": "user", "status": "active", "last_login": "2026-03-04" },
    { "name": "Alice Chen", "email": "alice@company.com", "role": "admin", "status": "active", "last_login": "2026-03-03" }
  ],
  "generated_at": "2026-03-04T12:00:00.000Z"
}
```

**From nothing to a working admin dashboard API: one file, one URL, zero infrastructure.**

---

## Build 2: Webhook Processor

Receive webhooks from external services, store them in SQLite, and send notifications.

### The Script


  
    ```bash
    hoody exec scripts write \
      --path "webhooks/stripe.ts" \
      --content "// @mode serverless\n// @cors *\n// @timeout 10000\n// @concurrent false\n\nconst SQLITE = \"https://PROJECT-CONTAINER-sqlite-1.SERVER.containers.hoody.icu\";\nconst NOTIFY = \"https://PROJECT-CONTAINER-n-1.SERVER.containers.hoody.icu\";\n\nawait fetch(SQLITE + \"/api/v1/sqlite/db?db=/hoody/databases/app.db\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({\n    transaction: [{\n      query: \"INSERT INTO webhook_events (source, event_type, payload, received_at) VALUES (?, ?, ?, ?)\",\n      values: [\"stripe\", req.body.type, JSON.stringify(req.body), new Date().toISOString()]\n    }]\n  })\n});\n\nreturn { received: true, event: req.body.type };" \
      --create-dirs
    ```
  
  
    ```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,
    });

    const sqliteUrl       = `https://${PROJECT_ID}-${CONTAINER_ID}-sqlite-1.${SERVER}.containers.hoody.icu`;
    const notificationUrl = `https://${PROJECT_ID}-${CONTAINER_ID}-n-1.${SERVER}.containers.hoody.icu`;

    await containerClient.exec.scripts.write({
      path: 'webhooks/stripe.ts',
      content: `
    // @mode serverless
    // @cors *
    // @timeout 10000
    // @concurrent false

    const SQLITE = "${sqliteUrl}";
    const NOTIFY = "${notificationUrl}";

    await fetch(SQLITE + "/api/v1/sqlite/db?db=/hoody/databases/app.db", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        transaction: [{
          query: "INSERT INTO webhook_events (source, event_type, payload, received_at) VALUES (?, ?, ?, ?)",
          values: ["stripe", req.body.type, JSON.stringify(req.body), new Date().toISOString()]
        }]
      })
    });

    if (req.body.type === "payment_intent.succeeded") {
      const amount = req.body.data.object.amount / 100;
      await fetch(NOTIFY + "/api/v1/notifications/notify", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          summary: "Payment Received",
          body: amount + " " + req.body.data.object.currency.toUpperCase() + " payment successful",
          display: "0",
          urgency: "normal"
        })
      });
    }

    return { received: true, event: req.body.type };
      `,
      createDirs: true,
    });
    ```
  
  
    ```bash
    curl -X POST "https://$PROJECT_ID-$CONTAINER_ID-exec-1.$SERVER.containers.hoody.icu/api/v1/exec/scripts/write" \
      -H "Content-Type: application/json" \
      -d '{
        "path": "webhooks/stripe.ts",
        "content": "// @mode serverless\n// @cors *\n// @timeout 10000\n// @concurrent false\n\nconst SQLITE = \"https://PROJECT-CONTAINER-sqlite-1.SERVER.containers.hoody.icu\";\n\nawait fetch(SQLITE + \"/api/v1/sqlite/db?db=/hoody/databases/app.db\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({\n    transaction: [{\n      query: \"INSERT INTO webhook_events (source, event_type, payload, received_at) VALUES (?, ?, ?, ?)\",\n      values: [\"stripe\", req.body.type, JSON.stringify(req.body), new Date().toISOString()]\n    }]\n  })\n});\n\nreturn { received: true, event: req.body.type };",
        "createDirs": true
      }'
    ```
  


Point Stripe's webhook URL at:

```
https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/webhooks/stripe
```

Every webhook is stored in SQLite. Payment successes and failures trigger push notifications to your phone. The `@concurrent false` magic comment ensures webhooks are processed one at a time -- no race conditions, no duplicate processing.


Notice the `@concurrent false` magic comment. For webhooks, serial processing prevents race conditions. For high-throughput endpoints, increase it: `@concurrent 10` allows 10 parallel executions.


---

## Build 3: Report Generator

Generate CSV reports from database queries and serve them via hoody-files.

### The Script


  
    ```bash
    SQLITE="https://$PROJECT_ID-$CONTAINER_ID-sqlite-1.$SERVER.containers.hoody.icu"
    FILES="https://$PROJECT_ID-$CONTAINER_ID-files-1.$SERVER.containers.hoody.icu"

    hoody exec scripts write \
      --path "reports/weekly-users.ts" \
      --content "// @mode serverless\n// @cors reflective\n// @timeout 30000\n\nconst SQLITE = \"$SQLITE\";\nconst FILES = \"$FILES\";\n\nconst result = await fetch(SQLITE + \"/api/v1/sqlite/db?db=/hoody/databases/app.db\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ transaction: [{ query: \"SELECT name, email, role, status FROM users\" }] })\n}).then(r => r.json());\n\nconst rows = result.data || result;\nconst csv = \"Name,Email,Role,Status\\n\" + rows.map(r => [r.name, r.email, r.role, r.status].join(\",\")).join(\"\\n\");\n\nres.setHeader(\"Content-Type\", \"text/csv\");\nreturn csv;" \
      --create-dirs
    ```
  
  
    ```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,
    });

    const sqliteUrl = `https://${PROJECT_ID}-${CONTAINER_ID}-sqlite-1.${SERVER}.containers.hoody.icu`;
    const filesUrl  = `https://${PROJECT_ID}-${CONTAINER_ID}-files-1.${SERVER}.containers.hoody.icu`;

    await containerClient.exec.scripts.write({
      path: 'reports/weekly-users.ts',
      content: `
    // @mode serverless
    // @cors reflective
    // @timeout 30000

    const SQLITE = "${sqliteUrl}";
    const FILES = "${filesUrl}";

    const result = await fetch(SQLITE + "/api/v1/sqlite/db?db=/hoody/databases/app.db", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        transaction: [{ query: "SELECT name, email, role, status, created_at, last_login FROM users ORDER BY last_login DESC" }]
      })
    }).then(r => r.json());

    const rows = result.data || result;
    const headers = "Name,Email,Role,Status,Created,Last Login";
    const csvRows = rows.map(r =>
      [r.name, r.email, r.role, r.status, r.created_at, r.last_login].join(",")
    );
    const csv = headers + "\\n" + csvRows.join("\\n");

    // Upload is PUT /api/v1/files/{path} with the raw file content as the body.
    const filename = "weekly-report-" + new Date().toISOString().split("T")[0] + ".csv";
    await fetch(FILES + "/api/v1/files/hoody/storage/reports/" + filename, {
      method: "PUT",
      headers: { "Content-Type": "text/csv" },
      body: csv
    });

    res.setHeader("Content-Type", "text/csv");
    res.setHeader("Content-Disposition", "attachment; filename=" + filename);
    return csv;
      `,
      createDirs: true,
    });
    ```
  
  
    ```bash
    curl -X POST "https://$PROJECT_ID-$CONTAINER_ID-exec-1.$SERVER.containers.hoody.icu/api/v1/exec/scripts/write" \
      -H "Content-Type: application/json" \
      -d '{
        "path": "reports/weekly-users.ts",
        "content": "// @mode serverless\n// @cors reflective\n// @timeout 30000\n\nconst SQLITE = \"https://PROJECT-CONTAINER-sqlite-1.SERVER.containers.hoody.icu\";\n\nconst result = await fetch(SQLITE + \"/api/v1/sqlite/db?db=/hoody/databases/app.db\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ transaction: [{ query: \"SELECT name, email, role, status FROM users\" }] })\n}).then(r => r.json());\n\nconst rows = result.data || result;\nconst csv = \"Name,Email,Role,Status\\n\" + rows.map(r => [r.name, r.email, r.role, r.status].join(\",\")).join(\"\\n\");\n\nres.setHeader(\"Content-Type\", \"text/csv\");\nreturn csv;",
        "createDirs": true
      }'
    ```
  


Hit the URL and download the report:

```bash
curl -o report.csv "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/reports/weekly-users"
```

The report is also saved to the filesystem via hoody-files, creating an archive of historical reports.

### Automate with hoody-cron

Run the report automatically every Friday:


  
    ```bash
    hoody cron entries create root \
      --schedule "0 9 * * 5" \
      --command "curl -s https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/reports/weekly-users > /dev/null" \
      --comment "Weekly user report generation"
    ```
  
  
    ```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,
    });

    const execUrl = `https://${PROJECT_ID}-${CONTAINER_ID}-exec-1.${SERVER}.containers.hoody.icu`;

    await containerClient.cron.entries.create('root', {
      schedule: '0 9 * * 5',  // Every Friday at 9 AM
      command: `curl -s ${execUrl}/reports/weekly-users > /dev/null`,
      comment: 'Weekly user report generation',
    });
    ```
  
  
    ```bash
    curl -X POST "https://$PROJECT_ID-$CONTAINER_ID-cron-1.$SERVER.containers.hoody.icu/users/root/entries" \
      -H "Content-Type: application/json" \
      -d '{
        "schedule": "0 9 * * 5",
        "command": "curl -s https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/reports/weekly-users > /dev/null",
        "comment": "Weekly user report generation"
      }'
    ```
  


Every Friday at 9 AM, the report generates and saves to the filesystem. No crontab editing. No server maintenance. An HTTP call configured the schedule.

---

## Access Control with Proxy Permissions

Internal tools should not be public. Lock them down:


  
    ```bash
    # Password protect the container
    # Writes are optimistic-concurrency guarded: pass the current file_version via --if-match
    hoody containers proxy permissions replace -c $CONTAINER_ID \
      --project $PROJECT_ID \
      --if-match "$(hoody containers proxy permissions get --container $CONTAINER_ID --field file_version)" \
      --groups '{"team": {"type": "password", "password": "internal-tools-2026"}}' \
      --permissions '{}'

    # Or restrict to office IP
    hoody containers proxy permissions replace -c $CONTAINER_ID \
      --project $PROJECT_ID \
      --if-match "$(hoody containers proxy permissions get --container $CONTAINER_ID --field file_version)" \
      --groups '{"office": {"type": "ip", "range": "203.0.113.0/24"}}' \
      --permissions '{}'
    ```
  
  
    ```typescript
    import { HoodyClient } from '@hoody-ai/hoody-sdk';

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

    // Writes need an If-Match precondition (the current file_version is returned
    // as a header by GET). Pass it via the `ifMatch` option, e.g. { ifMatch: 'file:v1' }.
    await client.api.proxyPermissionsContainer.replace(CONTAINER_ID, {
      project: PROJECT_ID,
      container: CONTAINER_ID,
      groups: { team: { type: 'password', password: 'internal-tools-2026' } },
      permissions: { team: { terminal: true, files: true, display: true, exec: true, sqlite: true, http: true } },
      default: 'deny'
    }, { ifMatch: 'file:v1' });
    ```
  
  
    ```bash
    # Writes require an If-Match precondition (read the current file_version via GET first)
    curl -X PATCH "https://api.hoody.icu/api/v1/containers/$CONTAINER_ID/proxy/permissions" \
      -H "Authorization: Bearer $HOODY_TOKEN" \
      -H "Content-Type: application/json" \
      -H "If-Match: file:v1" \
      -d '{"project":"'$PROJECT_ID'","container":"'$CONTAINER_ID'","groups":{"team":{"type":"password","password":"internal-tools-2026"}},"permissions":{"team":{"terminal":true,"files":true,"display":true,"exec":true,"sqlite":true,"http":true}},"default":"deny"}'
    ```
  


Now all services -- exec endpoints, SQLite UI, terminal access -- require the password. One setting protects everything.

---

## Share with Your Team

Share the URL. That is the entire distribution process.

```
Admin Dashboard:    https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/admin/dashboard
Webhook Processor:  https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/webhooks/stripe
Weekly Report:      https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/reports/weekly-users
SQLite Web UI:      https://PROJECT-CONTAINER-sqlite-1.SERVER.containers.hoody.icu
File Browser:       https://PROJECT-CONTAINER-files-1.SERVER.containers.hoody.icu
```

Or create clean aliases:

```bash
hoody proxy create --container-id $CONTAINER_ID --program exec --index 1 --alias "admin"
# Now accessible at: admin.hoody.icu/admin/dashboard
```

Your team opens the URL. The tool is there. No deployment, no installation, no training on how to access it. If they can open a browser, they can use the tool.

---

## The Pattern

Every internal tool on Hoody follows the same pattern:

1. **Write a hoody-exec script** -- The logic lives in a file that becomes a URL
2. **Use hoody-sqlite for data** -- Queries and storage through HTTP
3. **Use hoody-notifications for alerts** -- Push notifications when events occur
4. **Use hoody-files for output** -- Reports, exports, archives
5. **Use hoody-cron for scheduling** -- Automated execution on a schedule
6. **Use proxy permissions for access** -- Password or IP restriction
7. **Share the URL** -- Distribution complete

No servers to manage. No frameworks to learn. No deployment pipelines to configure. No SSL certificates to renew. No Docker images to build. No Kubernetes manifests to write.

Just functions that become URLs, talking to databases that are URLs, saving files that are URLs, on a schedule that is configured via URL.


Your first internal tool takes 10 minutes. Your second takes 5 because the container is already set up. By your tenth tool, you have an entire internal platform -- dashboard, webhooks, reports, automations -- all in one container, all accessible via URLs, all managed through HTTP.


---

## What's Next

- **[Building a Full-Stack Application](/guides/full-stack-app/)** -- Scale from internal tool to customer-facing product
- **[Deploying Autonomous AI Agents](/guides/ai-agents/)** -- Let AI build your next internal tool
- **[Hoody Exec Deep Dive](/kit/exec/)** -- Master the script-to-API primitive
- **[SQLite via HTTP](/kit/sqlite/)** -- Advanced database operations