happy-stacks
v0.4.0
Published
Run [**Happy**](https://happy.engineering/) locally and access it remotely and securely (using Tailscale).
Readme
Happy Stacks
Run Happy locally and access it remotely and securely (using Tailscale).
What is Happy?
Happy is an UI/CLI stack (server + web UI + CLI + daemon) who let you monitor and interact with Claude Code, Codex and Gemini sessions from your mobile, a web UI and/or a desktop app.
What is Happy Stacks?
happy-stacks is a guided installer + local orchestration CLI for Happy.
If you only want to self-host Happy, start with the Self-host section below. If you want to develop Happy (worktrees, multiple stacks, upstream PR workflows), see the Development section further down.
Self-host Happy (install + run)
Step 1: Setup
Recommended:
npx happy-stacks setup --profile=selfhostsetup can optionally start Happy and guide you through authentication.
Step 2: Start Happy
Starts the local server, CLI daemon, and serves the pre-built UI.
happys startStep 3 (first run only): authenticate
On a fresh machine (or any new stack), the daemon needs to authenticate once before it can register a “machine”.
happys auth loginIf you want a quick diagnosis:
happys auth statusStep 4: Enable Tailscale Serve (recommended for mobile/remote)
happys tailscale enable
happys tailscale urlStep 5: Mobile access
Make sure Tailscale is [installed and running] (https://tailscale.com/kb/1347/installation) on your phone, then either:
- Open the URL from
happys tailscale urlon your phone and “Add to Home Screen”, or - [Download the Happy mobile app] (https://happy.engineering/) and configure it to use your local server.
Details (secure context, phone instructions, automation knobs): [docs/remote-access.md](docs/remote-access.md).
Development (worktrees, stacks, contributor workflows)
Setup (guided)
npx happy-stacks setup --profile=devDeveloping from a cloned repo
git clone https://github.com/leeroybrun/happy-stacks.git
cd happy-stacks
node ./bin/happys.mjs setup --profile=devNotes:
In a cloned repo,
pnpm <script>still works, buthappys <command>is the recommended UX (same underlying scripts).To make the installed
~/.happy-stacks/bin/happysshim (LaunchAgents / SwiftBar) run your local checkout without publishing to npm, set:echo 'HAPPY_STACKS_CLI_ROOT_DIR=/path/to/your/happy-stacks-checkout' >> ~/.happy-stacks/.envOr (recommended) persist it via init:
happys init --cli-root-dir=/path/to/your/happy-stacks-checkout
Why this exists
- Automated setup:
happys setup+happys startgets the whole stack up and running. - No hosted dependency: run the full stack on your own computer.
- Lower latency: localhost/LAN is typically much faster than remote hosted servers.
- Custom forks: easily use forks of the Happy UI + CLI (e.g.
leeroybrun/*) while still contributing upstream toslopus/*. - Worktrees: clean upstream PR branches without mixing fork-only patches.
- Stacks: run multiple isolated instances in parallel (ports + dirs + component overrides).
- Remote access:
happys tailscale ...helps you get an HTTPS URL for mobile/remote devices.
How Happy Stacks wires “local” URLs
There are two “URLs” to understand:
- Internal URL: used by local processes on this machine (server/daemon/CLI)
- typically
http://127.0.0.1:<port>
- typically
- Public URL: used by other devices (phone/laptop) and embedded links/QR codes
- recommended:
https://<machine>.<tailnet>.ts.netvia Tailscale Serve
- recommended:
Diagram:
other device (phone/laptop)
|
| HTTPS (secure context)
v
https://<machine>.<tailnet>.ts.net
|
| (tailscale serve)
v
local machine (this repo)
+--------------------------------+
| happy-server-light OR |
| happy-server (via UI gateway) |
| - listens on :PORT |
| - serves UI at / |
+--------------------------------+
^
| internal loopback
|
http://127.0.0.1:<port>
(daemon / CLI)More details + automation: [docs/remote-access.md](docs/remote-access.md).
How it’s organized
- Scripts:
scripts/*.mjs(bootstrap/dev/start/build/stacks/worktrees/service/tailscale/mobile) - Components:
components/*(each is its own Git repo) - Worktrees:
components/.worktrees/<component>/<owner>/<branch...> - CWD-scoped commands: if you run
happys test/typecheck/lintfrom inside a component checkout/worktree and omit components, it runs just that component;happys build/dev/startalso prefer the checkout you’re currently inside.
Components:
happy(UI)happy-cli(CLI + daemon)happy-server-light(light server, can serve built UI)happy-server(full server)
Quickstarts (feature-focused)
Remote access (Tailscale Serve)
happys tailscale enable
happys tailscale urlDetails: [docs/remote-access.md](docs/remote-access.md).
Worktrees + forks (clean upstream PRs)
Create a clean upstream PR worktree:
happys wt new happy pr/my-feature --from=upstream --use
happys wt push happy active --remote=upstreamTest an upstream PR locally:
happys wt pr happy https://github.com/slopus/happy/pull/123 --use
happys wt pr happy 123 --update --stashDeveloper quickstart: create a PR stack (isolated ports/dirs; idempotent updates)
This creates (or reuses) a named stack, checks out PR worktrees for the selected components, optionally seeds auth, and starts the stack.
Re-run with --reuse to update the existing worktrees when the PR changes.
happys stack pr pr123 \
--happy=https://github.com/slopus/happy/pull/123 \
--happy-cli=https://github.com/slopus/happy-cli/pull/456 \
--seed-auth --copy-auth-from=dev-auth --link-auth \
--devOptional: enable Expo dev-client for mobile reviewers (reuses the same Expo dev server; no second Metro process):
happys stack pr pr123 --happy=123 --happy-cli=456 --dev --mobileOptional: run it in a self-contained sandbox folder (delete it to uninstall completely):
SANDBOX="$(mktemp -d /tmp/happy-stacks-sandbox.XXXXXX)"
happys --sandbox-dir "$SANDBOX" stack pr pr123 --happy=123 --happy-cli=456 --dev
rm -rf "$SANDBOX"Update when the PR changes:
- Re-run with
--reuseto fast-forward worktrees when possible. - If the PR was force-pushed, add
--force.
happys stack pr pr123 --happy=123 --happy-cli=456 --reuse
happys stack pr pr123 --happy=123 --happy-cli=456 --reuse --forceMaintainer quickstart: one-shot “install + run PR stack” (idempotent)
This is the maintainer-friendly entrypoint. It is safe to re-run and will keep the PR stack wiring intact.
npx happy-stacks setup-pr \
--happy=https://github.com/slopus/happy/pull/123 \
--happy-cli=https://github.com/slopus/happy-cli/pull/456Optional: enable Expo dev-client for mobile reviewers (works with both default --dev and --start):
npx happy-stacks setup-pr --happy=123 --happy-cli=456 --mobileOptional: run it in a self-contained sandbox folder (auto-cleaned):
npx happy-stacks review-pr --happy=123 --happy-cli=456Short form (PR numbers):
npx happy-stacks setup-pr --happy=123 --happy-cli=456Override stack name (optional):
npx happy-stacks setup-pr --name=pr123 --happy=123 --happy-cli=456Update when the PR changes:
- Re-run the same command to fast-forward the PR worktrees.
- If the PR was force-pushed, add
--force.
npx happy-stacks setup-pr --happy=123 --happy-cli=456
npx happy-stacks setup-pr --happy=123 --happy-cli=456 --forceDetails: [docs/worktrees-and-forks.md](docs/worktrees-and-forks.md).
Server flavor (server-light vs full server)
- Use
happy-server-lightfor a light local stack (no Redis, no Postgres, no Docker), and UI serving via server-light. - Use
happy-serverwhen you need a more production-like server (Postgres + Redis + S3-compatible storage) or want to develop server changes for upstream.- Happy Stacks can manage the required infra automatically per stack (via Docker Compose) and runs a UI gateway so you still get a single
https://...ts.netURL that serves the UI + proxies API/websockets/files.
- Happy Stacks can manage the required infra automatically per stack (via Docker Compose) and runs a UI gateway so you still get a single
Switch globally:
happys srv status
happys srv use --interactiveSwitch per-stack:
happys stack srv exp1 -- use --interactiveDetails: [docs/server-flavors.md](docs/server-flavors.md).
Stacks (multiple isolated instances)
happys stack new exp1 --interactive
happys stack dev exp1Point a stack at a PR worktree:
happys wt pr happy 123 --use
happys stack wt exp1 -- use happy slopus/pr/123-fix-thing
happys stack dev exp1Details: [docs/stacks.md](docs/stacks.md).
Dev stacks: browser origin isolation (IMPORTANT)
Non-main stacks use a stack-specific localhost hostname (no /etc/hosts changes required):
http://happy-<stack>.localhost:<uiPort>
This avoids browser auth/session collisions between stacks (separate origin per stack).
Menu bar (SwiftBar)
happys menubar install
happys menubar openDetails: [docs/menubar.md](docs/menubar.md).
Mobile iOS dev (optional)
# Install the shared "Happy Stacks Dev" dev-client app on your iPhone:
happys mobile-dev-client --install
# Install an isolated per-stack app (Release config, unique bundle id + scheme):
happys stack mobile:install <stack> --name="Happy (<stack>)"Details: [docs/mobile-ios.md](docs/mobile-ios.md).
Reviewing PRs in an isolated sandbox
- Unique hostname per run (default):
happys review-prgenerates a unique stack name by default, which results in a uniquehappy-<stack>.localhosthostname. This prevents browser storage collisions when the sandbox is deleted between runs. - Reuse an existing sandbox: if a previous run preserved a sandbox (e.g.
--keep-sandboxor a failure in verbose mode), re-runninghappys review-proffers an interactive choice to reuse it (keeping the same hostname + on-disk auth), or create a fresh sandbox.
Tauri desktop app (optional)
happys build --tauriDetails: [docs/tauri.md](docs/tauri.md).
Commands (high-signal)
- Setup:
happys setup(guided; selfhost or dev)- (advanced)
happys init(plumbing: shims/runtime/pointer env) - (advanced)
happys bootstrap --interactive(component installer wizard)
- Run:
happys start(production-like; serves built UI via server-light)happys dev(dev; Expo dev server for UI, optional dev-client via--mobile)
- Server flavor:
happys srv statushappys srv use --interactive
- Worktrees:
happys wt use --interactivehappys wt pr <component> <pr-url|number> --use [--update] [--stash] [--force]happys wt sync-allhappys wt update-all --dry-run/happys wt update-all --stash
- Stacks:
happys stack new --interactivehappys stack dev <name>/happys stack start <name>happys stack edit <name> --interactivehappys stack wt <name> -- use --interactivehappys stack review <name> [component...] [--reviewers=coderabbit,codex] [--base-ref=<ref>]happys stack migrate
- Reviews (local diff review):
happys review [component...] [--reviewers=coderabbit,codex] [--base-remote=<remote>] [--base-branch=<branch>] [--base-ref=<ref>]
- Menu bar (SwiftBar):
happys menubar install
Docs (deep dives)
- Remote access (Tailscale + phone):
[docs/remote-access.md](docs/remote-access.md) - Server flavors (server-light vs server):
[docs/server-flavors.md](docs/server-flavors.md) - Worktrees + forks workflow:
[docs/worktrees-and-forks.md](docs/worktrees-and-forks.md) - Stacks (multiple instances):
[docs/stacks.md](docs/stacks.md) - Paths + env precedence (home/workspace/runtime/stacks):
[docs/paths-and-env.md](docs/paths-and-env.md) - Menu bar (SwiftBar):
[docs/menubar.md](docs/menubar.md) - Mobile iOS dev:
[docs/mobile-ios.md](docs/mobile-ios.md) - Tauri desktop app:
[docs/tauri.md](docs/tauri.md)
Configuration
Where config lives by default:
~/.happy-stacks/.env: stable “pointer” file (home/workspace/runtime)~/.happy-stacks/env.local: optional global overrides~/.happy/stacks/main/env: main stack config (port, server flavor, component overrides)
Notes:
- Canonical env prefix is
HAPPY_STACKS_*(legacyHAPPY_LOCAL_*still works). - Canonical stack storage is
~/.happy/stacks(legacy~/.happy/localis still supported). - Repo env templates:
- Use
.env.exampleas the canonical template (copy it to.envif you’re running this repo directly). - If an LLM tool refuses to read/edit
.env.exampledue to safety restrictions, do not create anenv.exampleworkaround—instead, ask the user to apply the change manually.
- Use
Sandbox / test installs (fully isolated)
If you want to test the full setup flow (including PR stacks) without impacting your “real” install, run everything with --sandbox-dir.
To fully uninstall the test run, stop the sandbox stacks and delete the sandbox folder.
SANDBOX="$(mktemp -d /tmp/happy-stacks-sandbox.XXXXXX)"
# Run a PR stack (fully isolated install)
npx happy-stacks --sandbox-dir "$SANDBOX" setup-pr --happy=123 --happy-cli=456
# Tear down + uninstall
npx happy-stacks --sandbox-dir "$SANDBOX" stop --yes --no-service
rm -rf "$SANDBOX"Notes:
- Sandbox mode disables global OS side effects (PATH edits, SwiftBar plugin install, LaunchAgents/systemd services, Tailscale Serve enable/disable) by default.
- To explicitly allow those for testing, set
HAPPY_STACKS_SANDBOX_ALLOW_GLOBAL=1(still recommended to clean up after).
For contributor/LLM workflow expectations: [AGENTS.md](AGENTS.md).
