Hogsend is brand new.Try it
Hogsend
Getting Started

Getting Started

Scaffold a fresh Hogsend app, run it locally against Docker, and watch your first journey fire — from zero to a sending pipeline in a few minutes.

Hogsend is a code-first lifecycle orchestration engine: an event comes in, your code reacts, engagement flows back out. You define journeys in TypeScript, connect them to events (PostHog is the standard source, but any system that can send an HTTP request works), and Hogsend handles the durable execution — email sequences, timing, branching, and exit conditions. Email sends through a swappable provider, Resend by default.

The framework ships as an npm package, @hogsend/engine. You scaffold a fresh app that owns content only — journeys, email templates, webhook sources, custom routes, and your own database migrations — and pins @hogsend/engine. The engine never imports your content; upgrading the framework is pnpm up. See How It Works for the full mental model.

Quick start

  1. Create a new Hogsend app named my-app — local setup runs as part of the scaffold.
  2. cd my-app and start the dev stack.
  3. Visit http://localhost:3002/studio.
pnpm dlx create-hogsend@latest my-app
cd my-app
pnpm hogsend dev   # API + worker + Studio, one terminal

Accept the defaults at every prompt and the scaffolder does the whole first run for you: writes .env with fresh secrets, starts Postgres, Redis, and Hatchet in Docker, runs and verifies migrations, and mints your API keys. When it prints ✓ Ready., the only thing left is pnpm hogsend dev — it prints the URLs when the API is healthy, including Studio at http://localhost:3002/studio. (hogsend is the bundled @hogsend/cli; pnpm add -g @hogsend/cli if you'd rather drop the pnpm prefix.)

Docker must be installed and running before you scaffold — local setup brings the infrastructure up as containers and stops with an error if the daemon is down.

Fire an event and a journey runs:

pnpm hogsend dev --fire test.signup --email you@example.com   # from a second terminal

Then watch it move through Studio. Installation walks the whole loop end to end, including your first journey.

Sends are safe by default. With HOGSEND_TEST_MODE=auto (the default), every email is redirected to your own inbox — subject prefixed [TEST → real@recipient] — until your sending domain verifies. You can exercise real journeys and real sends from minute one without a single message reaching a customer. See Test mode and hogsend domain.

Building with an agent? The scaffold is fully non-interactive — one command takes a machine from nothing to a configured instance:

pnpm dlx create-hogsend@latest my-app --yes \
  --domain mysite.com \
  --admin-email you@example.com --admin-password 'min-8-chars' \
  --posthog

--yes accepts every default, including full local setup. The exit code is honest: 0 means infra up, migrations verified, keys minted. Then start pnpm dev and pnpm worker:dev in the background and poll GET /v1/health. The scaffold ships .claude/skills/ and a tailored CLAUDE.md with a zero-to-running runbook, so an agent working inside the repo already knows the drill.

Requirements

  • Node.js 22.13+ — pinned via the scaffold's .node-version.
  • Docker, installed and running — local setup provisions TimescaleDB, Redis, and Hatchet-Lite as containers.
  • pnpm (recommended) — or npm/yarn/bun via the --pm flag.
  • Optional: a Resend API key (starts with re_) — the app boots and runs journeys without one; add it to .env when you want email to leave the machine. Postmark ships as an opt-in alternative, and any other provider works behind the EmailProvider contract.
  • Optional: a PostHog account — tick PostHog at the "where will events come from?" prompt and setup offers a one-click browser connect at the end. No key needed.

PostHog is the standard event source, but it's not required to boot. You can drive Hogsend entirely through the data plane — POST /v1/events and the @hogsend/client SDK — from your own app code, webhook sources, or any of the built-in integrations. Lifecycle events fan back out to PostHog, Segment, or Slack via outbound destinations.

Step 1 — scaffold

create-hogsend copies a fresh content-only app, pins the current engine version, and — unless you say no — installs dependencies and runs local setup itself:

pnpm dlx create-hogsend@latest my-app --domain mysite.com

--domain wires your sending domain at scaffold time — EMAIL_FROM=hello@mysite.com + EMAIL_DOMAIN=mysite.com land in env.example (and the setup-copied .env inherits them). Skip it and the env keeps a commented placeholder block to fill in later. With --domain and no app name, the name defaults to the first domain label (mysite).

Use . to scaffold into the current folder, and pass --pm npm|yarn|bun to switch package managers (default pnpm). Run it with no flags in a terminal for an interactive setup, or pass --yes to accept every default — scaffold, install, and setup — with no prompts.

The scaffold installs dependencies and initializes a git repo. It also drops a .claude/skills/ tree and a tailored CLAUDE.md so Claude Code can author journeys, emails, and buckets with you (skip with --no-skills).

What setup did

The last prompt — "Set up local infra now?" — runs the same script as pnpm bootstrap. It checks Docker, creates .env with a fresh BETTER_AUTH_SECRET, remaps any busy ports (5434, 6380, 7077, 8888, 3002) back into .env, starts TimescaleDB (Postgres 18), Redis, and Hatchet-Lite via docker compose up -d --wait, auto-mints a HATCHET_CLIENT_TOKEN against your local Hatchet-Lite, runs both migration tracks and verifies the schema actually reached HEAD, and mints two API keys into .env: an ingest-scoped HOGSEND_API_KEY (hsk_… — what the @hogsend/client SDK uses) and a full-admin HOGSEND_ADMIN_KEY (what the hogsend CLI uses). Installation breaks each step down.

When it finishes, your stack is up and the Hatchet dashboard is at http://localhost:8888 (login admin@example.com / Admin123!!). On every day after the first, hogsend dev reuses all of this — it detects the running containers and the minted credentials, and just runs the app.

Locally, the Hatchet token is auto-minted by setup. The bring-your-own-token contract applies only to production — Hatchet Cloud or a self-hosted engine. See Get a Hatchet token for the production path.

Re-running setup

Skipped setup during create, moved machines, or reset Docker? pnpm bootstrap re-runs the entire first-run sequence — it's idempotent, safe to run anytime, and honest about failures (a run with issues exits non-zero and lists them).

Step 2 — create the first Studio admin

Studio is login-only — public sign-up is disabled, and there is no web create-admin form. The first admin is minted from your server, in one of two ways:

  • The setup prompt. After migrations, setup offers an interactive "create your first Studio admin" step (it's skippable, and a no-op in CI / non-TTY or when STUDIO_ADMIN_EMAIL is already set).
  • By hand, any time. Run the scaffold's script, which loads .env and calls the CLI:
pnpm studio:admin   # → hogsend studio admin create

The CLI writes directly to the database (it needs DATABASE_URL + BETTER_AUTH_SECRET from the environment — no HTTP, no running API). Prefer the masked password prompt over --password, which can leak into shell history. On a deploy — or a headless scaffold — set STUDIO_ADMIN_EMAIL (+ optional STUDIO_ADMIN_PASSWORD, or pass --admin-email/--admin-password to create-hogsend) and the API mints the admin on boot into an empty user table. Either way, the password goes only through Better Auth's hasher — never plaintext, never logged. Locked out later? hogsend studio admin reset. See Operating → Studio.

Step 3 — run

One command runs the whole local stack:

pnpm hogsend dev

hogsend dev detects the infra setup brought up (skipping docker compose up when it's already running), checks .env, runs migrations, spawns the API and the worker as prefixed child processes, waits for GET /v1/health, and prints the local URLs — API, Studio, Hatchet dashboard. Ctrl+C stops everything.

The api and worker are two separate processes that share the same codebase: the api serves HTTP and pushes events to Hatchet; the worker executes durable tasks (email sends, journey orchestration, background jobs). Prefer to run them by hand? Each in its own terminal:

pnpm dev          # HTTP API on http://localhost:3002
pnpm worker:dev   # Hatchet worker (second terminal)

In development the api serves interactive docs at http://localhost:3002/docs (Scalar UI) and the OpenAPI spec at /openapi.json. Health is at GET /v1/health. Both are disabled when NODE_ENV=production.

The first journey to edit is src/journeys/welcome.ts. Fire an event at it and watch the worker pick it up — hogsend dev --fire from a second terminal, or the raw curl:

pnpm hogsend dev --fire user.created --email you@example.com
# equivalent:
curl -X POST http://localhost:3002/v1/events \
  -H "Authorization: Bearer $HOGSEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "user.created", "email": "you@example.com" }'

Installation covers this end to end, including authoring the journey itself.

Step 4 — verify your domain

Until your sending domain verifies, test mode redirects every email to your own inbox — so nothing above could reach a real customer. When you're ready to send live, verify the domain from the CLI (it talks to your running instance's admin API; you'll need an admin key — see connecting):

pnpm hogsend domain status              # where am I? (state, records, test-mode banner)
pnpm hogsend domain add mysite.com      # register with the provider, print DNS records
pnpm hogsend domain check               # poll every 15s until verified

add detects where your DNS lives (Cloudflare, Vercel, Route 53, GoDaddy, Namecheap, Porkbun, Google Domains) via NS lookup, prints the records formatted for that host's panel with a deep link — and on Cloudflare or Vercel it offers to apply the records for you when a CLOUDFLARE_API_TOKEN / VERCEL_TOKEN is set. check polls until verified; test mode auto-exits within 60 seconds of DNS verifying, no restart needed. Full reference: hogsend domain.

Next steps