Stacks (isolated instances)
Run multiple isolated Happier stacks on one machine (ports + dirs + repo pinning).
Stacks (multiple local Happier instances)
hstack supports running multiple stacks in parallel on the same machine.
A “stack” is just:
- a dedicated server port
- isolated directories for UI build output, CLI home, and logs
- a repo checkout pin (point at a specific worktree/checkout)
- (when using
happier-server) isolated infra (Postgres/Redis/Minio) managed per-stack
Stacks are configured via a plain env file stored under:
~/.happier/stacks/<name>/envCreate a stack
Non-interactive:
hstack stack new exp1 --port=3010 --server=happier-server-lightAuto-pick a port:
hstack stack new exp2Power users: choose a DB provider without extra prompts:
# Light flavor (default): SQLite (no Docker)
hstack stack new exp-light --server=happier-server-light --db-provider=sqlite
# Light flavor (optional): embedded Postgres via PGlite (PG_Light)
hstack stack new exp-pglite --server=happier-server-light --db-provider=pglite
# Full server (default): Postgres (Docker-managed per stack)
hstack stack new exp-full --server=happier-server --db-provider=postgres
# Full server (optional): MySQL (requires an explicit DATABASE_URL; hstack does not provision MySQL)
hstack stack new exp-mysql --server=happier-server --db-provider=mysql --database-url=mysql://user:[email protected]:3306/happierCreate a PR test stack (copy/paste friendly)
If you want maintainers to be able to try your PR quickly, you can give them a single command that:
- creates an isolated stack
- checks out PR(s) into worktrees
- pins those worktrees to the stack
- optionally seeds auth
- optionally starts the stack in dev mode
Example (most common):
hstack stack pr pr123 \
--repo=https://github.com/happier-dev/happier/pull/123 \
--seed-auth --copy-auth-from=dev-auth --link-auth \
--devNotes:
--remote(defaultupstream) controls which Git remote is used to fetchrefs/pull/<n>/head.--seed-authuseshstack stack auth <stack> copy-from <source>under the hood, which also best-effort seeds DB Account rows (avoids FK errors like PrismaP2003).--link-authsymlinks auth files instead of copying them (keeps credentials in sync, but reduces isolation).- For full-server stacks (
happier-server), seeding may require Docker infra to be running. - DB provider flags are forwarded to the underlying
hstack stack newcall:--db-provider=...--database-url=...(full server only)
Auth seeding (recommended: dev-auth)
Create the dev-auth seed stack once, authenticate once, then reuse it when creating new stacks:
hstack auth seedInteractive wizard (TTY only):
hstack stack new --interactiveThe wizard lets you:
- pick the server type (
happier-server-lightorhappier-server) - pick or create a repo worktree for the Happier monorepo
- choose which Git remote to base newly-created worktrees on (defaults to
upstream)
When creating --server=happier-server stacks, hstack will also reserve additional ports and persist
the stack-scoped infra config in the stack env file (so restarts are stable):
HAPPIER_STACK_PG_PORTHAPPIER_STACK_REDIS_PORTHAPPIER_STACK_MINIO_PORTHAPPIER_STACK_MINIO_CONSOLE_PORTDATABASE_URL,REDIS_URL,S3_*
Run a stack
Dev mode (interactive, recommended):
hstack tui stack dev exp1Dev mode (non-interactive / no TUI):
hstack stack dev exp1Dev mode (background):
hstack stack dev exp1 --backgroundProduction-like mode (interactive):
hstack tui stack start exp1Production-like mode (non-interactive / no TUI):
hstack stack start exp1Production-like mode (background):
hstack stack start exp1 --backgroundBuild stack artifacts:
hstack stack build exp1
hstack stack build exp1 --web
hstack stack build exp1 --server
hstack stack build exp1 --daemon
hstack stack build exp1 --allBuild and activate a fresh full runtime snapshot:
hstack stack build exp1 --activate-runtime
hstack stack start exp1 --runtimeActivate only selected components into the active runtime:
hstack stack runtime exp1 activate --web
hstack stack runtime exp1 activate --server
hstack stack runtime exp1 activate --daemon
hstack stack runtime exp1 activate --allNotes:
hstack stack build <name>with no component flags keeps the legacy behavior and builds the web bundle only.--allmeans--web --server --daemon.hstack stack build <name> --activate-runtimestill assembles a complete runtime snapshot (web + server + daemon) under the stack folder.hstack stack runtime <name> activate ...creates a new active runtime snapshot by combining the selected latest artifact(s) with the currently active runtime for unselected components.- Building an artifact alone does not change the active runtime. The running stack keeps serving the currently active snapshot until you activate a new runtime.
--tauriremains the legacy localhstack buildflag. It is not part of named-stack artifact/runtime builds in v1.- Runtime snapshots are currently for named stacks. Repo-local
yarn tui/hstack startremain source-backed flows. hstack stack auth <name> loginfollows the same mode: if a valid runtime snapshot is active, guided login uses the stack-served runtime UI instead of waiting for Expo.
Select how a named stack starts:
# use source code directly (default)
hstack stack start exp1 --source
# require the active runtime snapshot
hstack stack start exp1 --runtime
# persist the default launch mode in the stack env
hstack stack env exp1 set HAPPIER_STACK_RUNTIME_MODE=preferNamed stack runtime flow (recommended for production-like local stacks)
Create a named stack pinned to a checkout/worktree:
hstack stack new dev-built --repo=/absolute/path/to/your/dev-checkoutBuild and activate a stack-local runtime snapshot:
hstack stack build dev-built --activate-runtimePersist runtime preference for future start and service runs:
hstack stack env dev-built set HAPPIER_STACK_RUNTIME_MODE=preferStart it from the activated runtime snapshot:
hstack stack start dev-built --runtimeUpdate flow after code changes:
# rebuild a fresh runtime snapshot from the pinned checkout
hstack stack build dev-built --activate-runtime
# restart the service so it picks up the new active snapshot
hstack stack service dev-built restartComponent-only update flows:
# UI-only change: build the new web artifact, activate only web, then reload the browser
hstack stack build dev-built --web
hstack stack runtime dev-built activate --web# Server-only change: build + activate only server, then restart the stack or service
hstack stack build dev-built --server
hstack stack runtime dev-built activate --server
hstack stack service dev-built restart# CLI/daemon-only change: build + activate only daemon, then restart the daemon or service
hstack stack build dev-built --daemon
hstack stack runtime dev-built activate --daemon
hstack stack service dev-built restartImportant:
- You do not need to reinstall the named-stack service after rebuilding a runtime snapshot.
- The service keeps pointing at the stack env file; it picks the active snapshot on the next start/restart.
- If the stack is in
prefermode, it will use the active runtime snapshot when valid, otherwise fall back to source. - For web-only activation, the runtime-backed server serves from
runtime/current/ui, so a browser reload is enough afterhstack stack runtime <name> activate --web. - For server-only or daemon-only activation, restart the stack process or stack service so it re-resolves the updated runtime.
- Runtime snapshots and component artifacts are pruned automatically after successful activation/builds.
- Default retention is the active build plus the previous one (
2total). - Override with
HAPPIER_STACK_RUNTIME_SNAPSHOT_KEEP_COUNT=<n>andHAPPIER_STACK_RUNTIME_ARTIFACT_KEEP_COUNT=<n>. - Set either value to
1if you want to keep only the current runtime/artifact generation.
- Default retention is the active build plus the previous one (
Doctor:
hstack stack doctor exp1Edit a stack (interactive)
To change server flavor, port, or repo worktree for an existing stack:
hstack stack edit exp1 --interactiveSwitch server flavor for a stack
You can change happier-server-light vs happier-server for an existing stack without re-running the full edit wizard:
hstack stack srv exp1 -- status
hstack stack srv exp1 -- use happier-server-light
hstack stack srv exp1 -- use happier-server
hstack stack srv exp1 -- use --interactiveSwitch repo worktree for a stack (stack wt)
If you want the exact same UX as hstack wt, but scoped to a stack env file:
hstack stack wt exp1 -- status
hstack stack wt exp1 -- use pr/my-ui-pr
hstack stack wt exp1 -- use defaultThis updates the stack env file (~/.happier/stacks/<name>/env), not repo env.local (legacy path still supported).
Run the Happier CLI against a specific stack (stack happier)
If you want to run a happier CLI command against a specific stack (instead of whatever your current shell env points at), use:
hstack stack happier exp1 -- status
hstack stack happier exp1 -- daemon statusStack shorthand also works:
hstack exp1 happier statusStack wrappers you can use
These commands run with the stack env file applied:
hstack stack dev <name>hstack stack start <name>hstack stack build <name>hstack stack runtime <name> activate ...hstack stack doctor <name>hstack stack mobile <name>hstack stack eas <name> [subcommand...]hstack stack happier <name> [-- ...]hstack stack srv <name> -- status|use ...hstack stack wt <name> -- <wt args...>hstack stack tailscale:status|enable|disable|url <name>hstack stack service:* <name>
Tip: hstack stack eas <name> env:sync --environment production syncs the stack’s EXPO_* config values into the Expo project’s EAS Environment Variables.
Global/non-stack commands:
hstack setup-from-source(recommended; installs shims/runtime and bootstraps the monorepo)- Deprecated alias:
hstack setup
- Deprecated alias:
- (advanced)
hstack init(plumbing: shims/runtime/pointer env) - (advanced)
hstack bootstrap(clone/install monorepo + deps)
Services (autostart)
Each stack can have its own autostart service (so multiple stacks can start at login).
hstack stack service exp1 install
hstack stack service exp1 enable
hstack stack service exp1 status
hstack stack service exp1 restart
hstack stack service exp1 logsFirst-time auth (recommended):
hstack stack service exp1 enable --auth-now -- --method=mobile --no-openNotes:
- Services keep the server/UI up even if the daemon is not authenticated yet, and will start the daemon automatically once credentials exist.
- Named-stack services follow the same runtime mode as
hstack stack start <name>.HAPPIER_STACK_RUNTIME_MODE=source: always run from the live checkout.HAPPIER_STACK_RUNTIME_MODE=prefer: use the active runtime snapshot when present, otherwise fall back to source.HAPPIER_STACK_RUNTIME_MODE=require: fail unless a valid active runtime snapshot exists.
--method=mobilerequires a public-reachable URL for your phone (e.g. Tailscale Serve HTTPS, or a reverse proxy). If the stack’s public URL resolves tolocalhost/127.0.0.1, mobile auth won’t work until you configure remote access.
Implementation notes:
- Service name/label is stack-scoped:
main→dev.happier.stackexp1→dev.happier.stack.exp1
- macOS: implemented via launchd LaunchAgents
- Linux: implemented via systemd user services (if available)
- The service persists
HAPPIER_STACK_ENV_FILE, so you can edit the stack env file without reinstalling. - Activating server or daemon runtime changes does not hot-swap a running service process. After
hstack stack build <name> --activate-runtimeorhstack stack runtime <name> activate --server|--daemon|--all, runhstack stack service <name> restartso the service restarts against the new active snapshot. - Web-only activation is the exception: after
hstack stack runtime <name> activate --web, the service keeps serving the updatedruntime/current/uibundle and a browser reload is enough.
Tailscale Serve for a named stack
If you want phone/remote access and secure browser features, expose the named stack over HTTPS:
hstack stack tailscale:enable dev-built
hstack stack tailscale:url dev-builtThen persist the shareable URL in the stack env so auth flows and clients prefer it:
hstack stack env dev-built set HAPPIER_STACK_SERVER_URL=https://your-machine.your-tailnet.ts.netNamed-stack services and runtime-backed auth flows will then use that public URL where appropriate.
Repo/worktree selection per stack
When creating a stack you can point the stack at a repo worktree:
hstack stack new exp3 \\
--repo=local/my-feature \\
--server=happier-serverWorktree specs are interpreted relative to the workspace:
main -> <workspace>/main
dev -> <workspace>/dev
pr/<...> -> <workspace>/pr/<...>
local/<...> -> <workspace>/local/<owner>/<...>
tmp/<...> -> <workspace>/tmp/<owner>/<...>So --repo=pr/foo maps to:
<workspace>/pr/fooYou can also pass an absolute path.
Stack env + repo env precedence
On startup, hstack loads env in this order:
~/.happier-stack/.env(defaults)~/.happier-stack/env.local(optional global overrides; prefer stack env for persistent config)HAPPIER_STACK_ENV_FILE(stack env; highest precedence)
hstack stack ... sets HAPPIER_STACK_ENV_FILE=~/.happier/stacks/<name>/env and clears any already-exported HAPPIER_STACK_* variables so the stack env stays authoritative.
For a full explanation of the different folders/paths (home vs workspace vs runtime vs stack storage) and the exact env precedence rules, see: /docs/hstack/paths-and-env.
Cloned-repo fallback (before you run hstack init):
<repo>/.env(defaults)<repo>/env.local(optional overrides)HAPPIER_STACK_ENV_FILE(stack env)
Manage per-stack environment variables (including API keys)
To add/update environment variables in a stack env file from the CLI:
hstack stack env <stack> set KEY=VALUE [KEY2=VALUE2...]To remove keys:
hstack stack env <stack> unset KEY [KEY2...]To inspect:
hstack stack env <stack> get KEY
hstack stack env <stack> list
hstack stack env <stack> pathNotes:
- This is the recommended place for provider API keys the daemon needs (example:
OPENAI_API_KEY). - Changes apply on the next start of the stack/daemon. Restart to pick them up:
main:hstack start --restart- named stack:
hstack stack start <stack> -- --restart(orhstack stack dev <stack> -- --restart)
Self-host shortcut (defaults to main when not running under a stack wrapper):
hstack env set OPENAI_API_KEY=sk-...Daemon auth + “no machine” on first run
On a fresh machine (or any new stack), the daemon may need to authenticate before it can register a “machine”.
If the UI shows “no machine” (or the daemon shows auth_required), it usually means the stack-specific CLI home
doesn’t have credentials yet:
~/.happier/stacks/<stack>/cli/access.key
To check / authenticate a stack, run:
hstack stack auth <stack> status
hstack stack auth <stack> loginNotes:
- You can run multiple daemons for the same stack on different accounts using
--identity=<name>.default(no flag):~/.happier/stacks/<stack>/cli/...--identity=account-b:~/.happier/stacks/<stack>/cli-identities/account-b/...
- To authenticate an identity without auto-opening a browser, use
--no-open(it prints the URL so you can open it in the browser profile/incognito window you want):
hstack stack auth <stack> login --identity=account-a --no-open
hstack stack auth <stack> login --identity=account-b --no-open- To start/stop an identity’s daemon explicitly:
hstack stack daemon <stack> start --identity=account-a
hstack stack daemon <stack> stop --identity=account-a- For the main stack, use
<stack>=mainand the default<port>=3005(unless you changed it). - If you use Tailscale Serve,
HAPPIER_WEBAPP_URLshould be your HTTPS URL (what you get fromhstack tailscale url). - Logs live under:
- default identity:
~/.happier/stacks/<stack>/cli/logs/ - named identities:
~/.happier/stacks/<stack>/cli-identities/<identity>/logs/
- default identity:
JSON mode
For programmatic usage:
hstack stack list --json
hstack stack new exp3 --json
hstack stack edit exp3 --interactive --json