Skip to content

Getting Started

This guide walks you through deploying your first AI Job on HollowHost, from signing up to triggering your first run.

1. Create a HollowHost account

  1. Go to app.hollowhost.com.
  2. Click Get Started Free and sign up with email + password (or a social provider if enabled in your environment).
  3. Confirm your email via the one-time code HollowHost emails you.

You land on the Dashboard with your free-tier token balance displayed.

2. Prepare your AI Job repository

HollowHost expects a Git repository that can be built into a container image. The minimum requirements:

  • A language runtime declared. Python and TypeScript are both supported out of the box.
  • An entry-point script (e.g. src/main.py, src/index.ts) that HollowHost executes top-to-bottom on every run — like python src/main.py. There is no handler(event, context) callback: your script IS the job.
  • A dependency manifest:
    • Python: requirements.txt (pip) or pyproject.toml (uv).
    • TypeScript: package.json (npm / yarn / pnpm).

Configuration reaches your script through environment variables: the env vars and secrets you define in the dashboard, plus the platform-provided HH_* variables:

Variable Content
HH_EVENT The optional JSON event payload for this run (JSON string; absent when no payload was sent)
HH_RUN_ID The run's unique identifier
HH_SOURCE api (manual/API trigger), scheduler (cron) or flow (a step of a flow)
HH_SCHEDULED_TIME ISO timestamp the schedule fired at (scheduled runs only)

A minimal Python example:

src/main.py
import json
import os

event = json.loads(os.environ.get("HH_EVENT", "null"))
print(f"Hello from my first HollowHost AI Job! event={event}")
requirements.txt
requests==2.32.3

Push this to a GitHub repository — public or private. If private, you will provide a GitHub Personal Access Token with repo read scope when creating the AI Job.

Reusable demo repo

Want to try without writing any code? The team maintains a ready-to-deploy weather AI Job at One-Click-Flare/ia-agent-meteo — use it as-is or fork it.

3. Create your AI Job in HollowHost

  1. From the dashboard, click AI Jobs → New AI Job.
  2. Step 1 — Repository:
    • Repository URL — https://github.com/<org>/<repo>.
    • Branch (optional) — the git branch to deploy. Leave empty to use the repository's default branch (shown as (default branch)).
    • Repository Access — Public repository, or a private one read with the GitHub token saved in Settings → GitHub Token (Use default token) or with a token for this AI Job only (Use custom token, stored encrypted).
  3. Step 2 — Configuration:
    • Language and Package Manager — pip or uv for Python, npm for TypeScript.
    • Sub-path (optional) — for mono-repos, the sub-directory to deploy. Leave empty to deploy the repository root.
    • Entry Point — the file to run (e.g. src/main.py).
    • Project and Swarm (optional) — to file the AI Job.
  4. Click Create AIJob.

The new AI Job shows as its repository's name: give it a name and a description on its Settings tab. The repository, branch, sub-path, language and package manager can't be changed later.

Mono-repo: Entry Point is relative to the sub-path

When you set a Sub-path, that sub-directory becomes the AI Job's root at build time, so the Entry Point stays relative to it. For an AI Job at apps/agent-meteo/src/main.py with Sub-path apps/agent-meteo, set Entry Point to src/main.py — not apps/agent-meteo/src/main.py.

HollowHost validates the repository — and, when set, the branch and sub-path existence (status VALIDATING → VALIDATED).

Mono-repo example

Repo One-Click-Flare/mono-repo, branch dev, AI Job in apps/agent-meteo: set Branch = dev, Sub-path = apps/agent-meteo, Entry Point = src/main.py. The equivalent CLI command is in the CLI reference.

4. Deploy the AI Job

Once the AI Job is VALIDATED:

  1. Open the AI Job detail page.
  2. Click Deploy.

HollowHost now:

  • Builds a container image from your repository.
  • Creates a dedicated, isolated execution environment for this AI Job.
  • Deploys your AI Job and makes it ready to run.

Status flow: DEPLOYING → DEPLOYED (or DEPLOYMENT_ERROR — check the build logs from the AI Job page if so).

5. Configure env vars and secrets (optional)

From the AI Job's Settings tab:

  • Environment variables — non-sensitive config (e.g. LOG_LEVEL, TIMEZONE). Injected into your AI Job at runtime.
  • Secrets — sensitive values (e.g. API keys). Stored encrypted and injected at runtime. Secrets never leave the AI Job's isolation boundary.

Changes take effect on the next run.

6. Trigger your first run

From the AI Job page:

  • Manual run — click Run. To attach a JSON event payload, click Run with event… next to it, paste your JSON and run; the dialog checks the JSON before sending and remembers the last payload you sent for this AI Job (in your browser only). Your code receives it as the HH_EVENT environment variable. The CLI and the API can send one too.
  • Scheduled run — switch to the Schedule tab, enter a cron expression (e.g. 0 9 * * * for every day at 09:00 UTC), and save. HollowHost will trigger the AI Job on the specified cadence.

Once a run completes (or fails), you'll see it in the Runs list with its duration, status, token usage, and a link to the full logs.

Event payload format

An event payload lets you parameterize a single run — same deployed code, different input — without touching the AI Job's configuration (backfill a specific day, process one item, retry a failed batch…).

API contract — POST /agents/{id}/runs with a JSON body:

{"event": <any JSON value>}
  • The event key can hold any JSON value: object, array, string, number, boolean or null. Objects are recommended — they stay extensible.
  • Maximum request body size: 128 KB. Larger payloads, non-JSON bodies, or a body that is not a JSON object envelope are rejected with 400 {"code": "INVALID_EVENT_PAYLOAD"} and no run is created.
  • The event must also fit in 128 KB as HollowHost measures HH_EVENT: with a space after each , and :, and each non-ASCII character escaped as \uXXXX (6 bytes). A dense or non-ASCII-heavy event reaches that limit before the body's: it is rejected the same way, with a message giving its size.
  • The payload is ephemeral: relayed to that single run, never stored in the database. Omitting the body (or the event key) simply runs without a payload.
  • From the web app: Run with event… on the AI Job page (Overview or Runs tab).
  • From the CLI: hollowhost ai-jobs run <id> --event '{...}' or --event-file event.json (the CLI wraps your JSON in the envelope for you).

Runtime delivery — your script reads it from the environment:

Variable Content
HH_EVENT The event value, serialized as a JSON string. Unset when the run was triggered without a payload — always handle the absent case.
HH_RUN_ID Unique identifier of this run
HH_SOURCE api (manual/API/CLI), scheduler (cron) or flow (a step of a flow, whatever started the flow)
HH_SCHEDULED_TIME ISO 8601 timestamp the schedule fired at (scheduled runs only)
import json, os

event = json.loads(os.environ.get("HH_EVENT", "null"))
if event is None:
    event = {}  # no payload — fall back to defaults
day = event.get("day", "today")
const event = JSON.parse(process.env.HH_EVENT ?? "null") ?? {};
const day = event.day ?? "today";

No secrets in events

Event payloads are request data, not a secret store: they can appear in your own calling code, shell history, and client-side tooling. Keep API keys and credentials in the AI Job's Secrets — never in an event.

Pass a result to the next step of a flow

In a swarm's flow, a step can hand data to the steps after it. It writes JSON to the file named by HH_RESULT_PATH; a step with Receive the previous result on (select the step in the flow editor) gets it in HH_EVENT.

Writing a result — every run gets HH_RESULT_PATH; HollowHost keeps what is written there for runs a flow started.

import json, os

picks = ["story-1", "story-2"]
with open(os.environ["HH_RESULT_PATH"], "w") as f:
    json.dump({"picks": picks}, f)
import { writeFileSync } from "node:fs";

const picks = ["story-1", "story-2"];
writeFileSync(process.env.HH_RESULT_PATH!, JSON.stringify({ picks }));
  • Write it any time before your code exits: the file as it is then is the result. A run that fails keeps its result too, so a failing step can say what went wrong.
  • A result is JSON only: at most 32 KB as compact JSON (each non-ASCII character counts 6 bytes, as \uXXXX) and 32 levels deep, without NaN or Infinity. Anything else leaves the step without a result, and resultError says why.
  • Results are kept 30 days. A run's panel shows its result, or why it has none.
  • An AI Job published before step results has no HH_RESULT_PATH: publish it again.

Reading the results of the steps before — HH_EVENT holds one entry per link coming in, a list when there are several, in the order of the links:

{"previous": [
  {"aiJob": "news-pulse", "agentId": "…", "status": "SUCCESS", "runId": "…",
   "result": {"picks": ["story-1", "story-2"]}, "resultError": null},
  {"aiJob": "news-tech", "agentId": "…", "status": "ERROR", "runId": "…",
   "result": null, "resultError": "RESULT_TOO_LARGE"}
]}
import json, os

event = json.loads(os.environ.get("HH_EVENT", "null")) or {}
previous = event.get("previous", [])
if isinstance(previous, dict):
    previous = [previous]  # one step before: a single entry
for step in previous:
    if step["result"] is not None:
        print(step["aiJob"], step["result"])
const event = JSON.parse(process.env.HH_EVENT ?? "null") ?? {};
const previous = [event.previous ?? []].flat(); // one step before: a single entry
for (const step of previous) {
  if (step.result !== null) console.log(step.aiJob, step.result);
}
resultError Why result is null
null The step wrote nothing (or wrote null)
RESULT_NOT_JSON What it wrote isn't JSON, nests deeper than 32 levels, or holds NaN or Infinity
RESULT_TOO_LARGE Over 32 KB
RESULT_UNREADABLE The file couldn't be read
RUNTIME_TOO_OLD Its AI Job was published before step results: publish it again
RESULT_OMITTED Left out to keep HH_EVENT under 120 KB: results are added in the order of the links, and one that no longer fits is left out

A result is input, not instructions

HollowHost passes a result only as JSON data in HH_EVENT, but what it holds comes from another AI Job, and often from what that job read: a web page, an email, an LLM's answer. Treat it like any untrusted input: check its shape, never run it as code or a shell command, and when you give it to an LLM, give it as data to work on, quoted and apart from your instructions, never as instructions to follow.

7. Iterate

Push new commits to your GitHub repo, click Redeploy — HollowHost rebuilds the image and updates the AI Job. Previous versions remain available for rollback.


Next steps

  • Set up token budgets and plan limits from your Account settings to control spend.
  • Read the security model overview to understand the per-AI Job isolation guarantees.

Got stuck? File an issue on the GitHub repo or reach out to the HollowHost team.