Development workflow
The “one-stop” guide to develop Happier locally with hstack (worktrees + stacks + dev-auth).
This document is intended to be sufficient for humans and LLMs to work safely and repeatably in the Happier monorepo.
If you’re brand new, read these first:
- Worktrees + forks:
/docs/hstack/worktrees-and-forks - Stacks:
/docs/hstack/stacks - Paths/env precedence:
/docs/hstack/paths-and-env - Quickstarts (copy/paste flows):
/docs/hstack/quickstarts - Running (dev vs start):
/docs/hstack/running - Validation (typecheck/lint/test):
/docs/hstack/validation - CLI reference:
/docs/hstack/cli-reference - Debugging:
/docs/hstack/debugging - Troubleshooting:
/docs/hstack/troubleshooting
Core concepts (the mental model)
Monorepo
hstack is monorepo-first: UI/CLI/server all live in the same Happier git repo.
Current layout:
apps/ui(UI)apps/cli(CLI + daemon)apps/server(server; light + full flavors)apps/stack(this tool)
Workspace checkouts (where code lives)
Your workspace contains:
main/— stable checkout (treat as read-only)dev/— the canonical development checkout (dev branch)- categorized worktrees:
pr/<...>— PR checkouts (hstack wt pr ...)local/<owner>/<...>— feature worktreestmp/<owner>/<...>— throwaway worktrees
Worktrees (where you implement)
Never develop directly in main/. Treat it as “launcher defaults”.
All implementation work should happen in:
dev/, or- a worktree under
local/,tmp/, orpr/.
Stacks (how you test safely)
A stack is an isolated runtime environment (ports + dirs + DB + CLI home), stored under:
~/.happier/stacks/<stack>/...Each stack is configured by:
~/.happier/stacks/<stack>/envStacks are how you test changes without mutating your “main” environment.
Server flavor (which backend you’re running)
Each stack runs exactly one server flavor:
happier-server-light(recommended) — simplest local install (SQLite by default; optional embedded Postgres via PGlite)happier-server(full) — Docker-managed Postgres/Redis/Minio
See: /docs/hstack/server-flavors.
Non‑negotiables (discipline that keeps stacks safe)
- Use
hstackas the entrypoint- Don’t run raw
yarn dev,expo,docker compose, etc. when you intend stack-scoped behavior. - hstack needs stack-scoped env + runtime bookkeeping to keep things isolated.
- Don’t run raw
- Develop in worktrees
- Use
dev/orhstack wt ...worktrees; don’t editmain/.
- Use
- Test in non-
mainstacks- Prefer
hstack stack <stack> dev|start|test|typecheck|lintso you don’t mutate the default stack.
- Prefer
- Don’t kill global daemons
- Multiple stack daemons are expected (one per stack).
- Stop stacks explicitly:
hstack stoporhstack stack stop <name>.
Quickstarts (common development flows)
1) Typical feature work (UI + CLI + server changes in one worktree)
Create a worktree based on upstream (recommended for clean PR history):
hstack wt new local/my-feature --from=upstream --useCreate an isolated stack and point it at the active worktree:
hstack stack new exp1
hstack stack wt exp1 -- use activeRun dev mode:
hstack tui stack dev exp1If you can’t use the TUI (non-interactive terminals / CI), run:
hstack stack dev exp1Validate:
hstack stack typecheck exp1
hstack stack lint exp1
hstack stack test exp12) Use the canonical dev/ checkout instead of a feature worktree
Create a dev stack and pin it to dev/:
hstack stack new dev
hstack stack wt dev -- use dev
hstack tui stack dev dev
# (optional) mobile dev-client + QR:
hstack tui stack dev dev --mobile3) Testing an upstream PR locally (recommended)
Create a PR worktree:
hstack wt pr 123 --useCreate an isolated PR stack (idempotent updates supported):
hstack stack pr pr123 --repo=123 --devIf you already have a dev-auth seed stack, add:
hstack stack pr pr123 --repo=123 --dev --seed-auth --copy-auth-from=dev-auth --link-authPR workflow (dev branch targeting)
Happier uses:
mainas the stable branchdevas the contribution branch (PR base)
Recommended flow:
- Base your worktree on
upstream/dev - Push to your fork (
origin) - Open a PR into
upstream/dev
hstack helps keep this clean by defaulting new worktrees to upstream-based histories and by encouraging origin pushes.
See: /docs/hstack/worktrees-and-forks.
If you prefer a guided workflow for “extract feature branch from dev”, use:
hstack contrib ensure-dev
hstack contrib extract my-feature --pushstart vs dev
hstack start/hstack stack start <name>: “production-like” behavior (built UI, fewer watch processes)hstack dev/hstack stack dev <name>: development (watchers, dev servers, faster iteration)
If you’re unsure, use hstack tui stack dev <stack> (or hstack stack dev <stack> in non-interactive environments).
Developer-only: set up dev-auth once (recommended)
Create the seed stack and do the guided login:
hstack auth seedThen new stacks can reuse the same auth:
hstack stack auth <stack> copy-from dev-authSee: /docs/hstack/auth.
Process isolation (why stops/restarts are safe)
Stacks track runtime ownership in a per-stack runtime state file:
~/.happier/stacks/<stack>/stack.runtime.jsonhstack uses this to:
- stop only stack-owned processes
- reuse ephemeral ports on restart when appropriate
- avoid killing by port globally
“Upstream-first” worktree workflow (recommended)
The goal is:
- keep your fork’s long-lived branches clean and stable
- create upstream-targeting PR branches quickly
- avoid mixing “fork-only” changes into upstream PRs
Suggested pattern:
- Create a worktree based on
upstream/dev:
hstack wt new local/my-feature --from=upstream --base=upstream/dev --use- Develop and validate inside an isolated stack:
hstack stack new exp1
hstack stack wt exp1 -- use active
hstack stack dev exp1- Push the branch to your fork and open a PR into
upstream/dev:
hstack wt push active --remote=originIf you need to keep a fork-only “distribution patch” (rare), keep it on a separate branch and do not merge it into your upstream PR worktrees.
Watch mode + hot-reload-ish iteration
hstack’s dev mode is the default for development because it:
- starts the server in a dev-friendly mode
- starts the UI dev server (Expo/Next, depending on the app)
- restarts processes safely using stack-owned runtime state
When switching flags (e.g. enabling mobile), it’s usually better to restart the stack using hstack rather than restarting individual processes.
Validation commands (typecheck / lint / test)
Prefer stack-scoped validation so the environment matches what you’re actually running:
hstack stack typecheck exp1
hstack stack lint exp1
hstack stack test exp1For the active checkout (non-stack), you can also run:
hstack typecheck
hstack lint
hstack testCLI reference (high-signal)
Core:
- Setup:
hstack setup --profile=dev|selfhost - Run:
hstack start/hstack dev - Stop:
hstack stop - Diagnostics:
hstack where,hstack doctor
Stacks:
- Create/list/info:
hstack stack new,hstack stack list,hstack stack info - Run:
hstack stack dev <name>,hstack stack start <name> - Switch repo:
hstack stack wt <name> -- use <spec> - Switch server:
hstack stack srv <name> -- use happier-server-light|happier-server - Auth:
hstack stack auth <name> status|login|copy-from - PR stacks:
hstack stack pr <name> --repo=<pr>
Worktrees:
- Create/use:
hstack wt new <slug> --use - PR checkout:
hstack wt pr <pr> --use - List/status/update:
hstack wt list,hstack wt status,hstack wt update,hstack wt update-all - Push:
hstack wt push active --remote=origin
Auth seeding:
- Seed stack:
hstack auth seed - Bulk seed:
hstack auth copy-from dev-auth --all --except=main,dev-auth - Dev key:
hstack auth dev-key
Useful environment knobs (high-signal)
Paths:
HAPPIER_STACK_WORKSPACE_DIR(workspace root)HAPPIER_STACK_REPO_DIR(active checkout; usually managed byhstack wt use)HAPPIER_STACK_CLI_ROOT_DIR(run hstack from a local checkout)
Auth:
HAPPIER_STACK_AUTH_SEED_FROM(default auth source for new stacks; commonlydev-auth)HAPPIER_STACK_AUTH_MODE(copyvslink)
Server selection:
HAPPIER_STACK_SERVER_COMPONENT(happier-server-lightvshappier-server)
Troubleshooting (high-signal)
“What is hstack actually using?”
hstack where
hstack stack info <name>“Why is this stack using the wrong checkout?”
Check the pinned repo:
hstack stack info <name>
cat ~/.happier/stacks/<name>/env | rg HAPPIER_STACK_REPO_DIRFix by repointing:
hstack stack wt <name> -- use dev
# or:
hstack stack wt <name> -- use pr/123-fix-thing