Skip to content

Installation ​

Install the Hapimatic open-source core on your own Linux machine, check that it is ready, and set up the server.

If an operator has already set up a Hapimatic Cloud VM for you, you do not need this page: start with the Cloud User Quickstart.

Prerequisites ​

  • 64-bit Linux (x86-64 or ARM64) with systemd. macOS is planned. Windows and WSL2 follow later.
  • Command-line tools: git, python3, jq, and curl (or the GitHub CLI, gh).
  • tmux (recommended). The tmux launcher needs it, and the doctor warns when it is missing.
  • At least one supported agent CLI, installed and signed in with your own account. See Supported agent CLIs.

The doctor checks the command-line tools, tmux and the Claude Code CLI, and names anything that is missing. It does not check the operating system, the processor type or systemd, or the other three agent CLIs. Run before the install, it also reports hapi itself as missing and exits with an error; that is expected.

Supported agent CLIs ​

Hapimatic runs Claude Code, Codex, Gemini CLI and OpenCode. Each one is the provider's own, unmodified program, which you install and sign in to yourself. All four are supported at launch:

Agent CLIStatusHow it signs in
Claude CodeCertified on Linux.Your Claude subscription (run claude once and sign in) or a workspace-scoped Anthropic API key that you add under Settings → Keys. See API key billing.
CodexQualification pending.Codex's own sign-in (codex login), or an OpenAI API key.
Gemini CLIQualification pending.A Google AI Studio or Vertex AI API key only — never the Gemini CLI's own Google sign-in.
OpenCodeQualification pending.An API key for the model provider you use with OpenCode.

You sign in to each agent CLI with your own account or API key, and each provider's own terms and usage limits apply to your accounts. For Gemini CLI and OpenCode sessions that you start from the web app, add the key on the API Keys page under Settings → Keys and choose its provider there; for Gemini CLI, GEMINI_API_KEY set in the environment you start the daemon from also works. A session you start from a terminal (hapi gemini, hapi opencode) runs the agent CLI with that terminal's environment.

Restarting the Hapimatic background service (the daemon), with hapi daemon stop and then hapi daemon start, does not end running Claude Code sessions, and neither does restarting hapi server: the sessions keep running and stay connected to the web app. tmux persistence, which is off by default, does not decide whether sessions survive; it decides whether the restarted daemon takes them back. With it off, the restarted daemon leaves the running sessions alone and does not count them in hapi daemon status. With HAPI_TMUX_PERSISTENCE=true set in the environment you start the daemon from, the Claude Code sessions the daemon starts (the ones you start from the web app) run inside tmux, and the restarted daemon takes them back. The daemon then saves the setting in ~/.hapi/settings.json and keeps it on at later starts, even without the variable; to turn it off, delete tmuxPersistenceEnabled from that file and restart the daemon.

One known issue: after a server restart, a Claude Code session that you started from a terminal runs every prompt you already gave it again, one after another, and its terminal switches to remote mode (press space twice to return to local mode). Sessions started from the web app were not affected in our test. Until this is fixed, exit sessions you started from a terminal before you restart the server.

The installer's doctor currently treats the Claude Code CLI (claude) as required: if you use only Codex, Gemini CLI or OpenCode, it reports claude as missing. The install itself still completes.

Machine requirements ​

Hapimatic's session load tests measured these figures:

MinimumRecommended
CPUs24
Memory8 GB16 GB
Disk40 GB50 GB
Open sessions612

Minimum is the smallest machine Hapimatic supports. A machine with 1 CPU and 4 GB of memory is below it: Hapimatic allows it 4 open sessions and suggests 2, and in the test it slowed sharply as soon as a second session ran repository tools beside the first. On a machine below the minimum, the installer's doctor prints a machine spec warning. The warning does not stop the install, and Hapimatic still runs, but fewer sessions run reliably. For this warning, the doctor checks your CPUs, your memory, and the size of the filesystem that holds your home folder. In a container, it uses the container's CPU and memory limits.

Recommended is the machine to choose for regular use: it kept 13 sessions healthy under the same workload, and Hapimatic suggests 12, twice the minimum's 6.

Open sessions are counted per Hapimatic instance (one server and its background service). Each session in the test ran Claude Code with two MCP servers, Playwright and sequential-thinking, and took about 350 MB of memory. The counts in the table are the sessions that stay healthy while a third of them run builds in a loop, with about 20 seconds between builds, and another third run repository tools. That mix is deliberately heavy; sessions that build only now and then leave more headroom. Hapimatic also sets a ceiling on open sessions: 12 on the minimum machine and 19 on the recommended one. An open session keeps its memory whether or not it is working, so the ceiling counts idle sessions too. A language server adds to each session: TypeScript's held about 1.1 GB per session on Hapimatic's own repository. If your sessions use one, expect fewer sessions, and set a lower limit in Preferences.

Disk is a base of about 8.4 GiB, plus about 0.75 GiB for each open session, rounded up to the next 10 GB. The base covers the operating system and Hapimatic, plus one working copy of the test project (Hapimatic's own repository) with its dependencies installed. Each session's share is one more working copy of that project with its dependencies; smaller projects need less. The table's disk figures leave room beyond the session ceilings above. These figures count open sessions only. An archived session keeps its working copy on disk, so each one you keep adds the same 0.75 GiB. In an earlier test, the minimum machine went past 40 GB with 8 sessions open, because 33 archived sessions were still on disk. Deleting an archived session frees its space: Hapimatic keeps a deleted session's working copy for 10 days, then removes it the next time a new session with its own working copy starts in that project.

The figures were measured on 64-bit ARM Linux:

PlatformSupport in version 1Figures
Linux, ARM64, with systemdSupportedMeasured (Ubuntu 24.04)
Linux, x86-64, with systemdSupportedThe same figures, not measured
macOS (Apple silicon)PlannedNone yet (not tested)
Windows (WSL2 or native)Not supported; follows laterNone (not tested)

One suggested setup: a Raspberry Pi 5 with 16 GB of RAM, booting from an NVMe SSD on an M.2 HAT, with the active cooler. It is the setup Hapimatic runs on every day, and it is one choice among many: any 64-bit Linux machine with systemd that meets the minimum above can run Hapimatic.

Install ​

One command installs Hapimatic:

bash
curl -fsSL https://github.com/SolidPD/hapimatic-core/releases/latest/download/install-hapimatic-v1.sh | bash

The installer:

  1. checks your machine with the doctor and lists anything that is missing;
  2. downloads the hapi program for your machine and verifies it against the release's checksums.txt;
  3. installs it as ~/.local/bin/hapi and adds ~/.local/bin to your PATH in your shell's startup files (~/.profile and ~/.bashrc for bash, ~/.zprofile and ~/.zshrc for zsh), between marker lines it can find again;
  4. downloads the toolkit core tier into ~/.hapi/claude-toolkit and links it into ~/.claude/, Claude Code's configuration directory;
  5. records what it installed in ~/.hapi/install-hapimatic.json.

Open a new shell afterwards so that hapi is on your PATH.

To preview the install without changing anything, pass --dry-run:

bash
curl -fsSL https://github.com/SolidPD/hapimatic-core/releases/latest/download/install-hapimatic-v1.sh | bash -s -- --dry-run

The preview lists the hapi install, the toolkit steps and the install record. It does not run the doctor, and it does not yet list the PATH lines from step 3.

The same script also runs the doctor, updates Hapimatic and uninstalls it. To keep a copy for those, download it and run it from the folder you saved it in:

bash
curl -fsSLO https://github.com/SolidPD/hapimatic-core/releases/latest/download/install-hapimatic-v1.sh
bash install-hapimatic-v1.sh

What gets installed ​

  • The open-source core: one program, hapi, which contains the server, the web app, the command line and the background service (the daemon) that starts sessions. It is licensed under AGPL-3.0, and its source is the hapimatic-core repository. On first run it unpacks its bundled tools into ~/.hapi/runtime/.
  • The toolkit core tier: the guidance files, generated settings and hook dispatcher that shape how agent sessions behave. It is licensed under MIT and comes from the hapimatic-toolkit repository; its README explains what it adds to ~/.claude/ and how that works.

The premium plugins are not part of this install.

Check your machine: the doctor ​

With a saved copy of the installer:

bash
bash install-hapimatic-v1.sh doctor

Without one:

bash
curl -fsSL https://github.com/SolidPD/hapimatic-core/releases/latest/download/install-hapimatic-v1.sh | bash -s -- doctor

The doctor prints one line per check, marked [ OK ], [WARN], [MISS] or [info]. It exits with an error only when a required item is missing: the hapi program, git, python3, jq, the Claude Code CLI (claude), or a downloader (curl or gh). The installer runs the same checks first, but only as a report: it lists anything missing and installs anyway. The other lines never make the doctor exit with an error:

  • the toolkit core tier and its version;
  • tmux;
  • how Claude Code is signed in, plus an information line when a Gemini API key is set;
  • the machine spec line, which compares your CPUs, memory and disk with the minimum;
  • the four portable machine conventions, each with its fix;
  • uv and pytest, which only the hook test suite uses;
  • bun and gitleaks, which only building and maintaining Hapimatic from source use (information only).

It reports whether credentials are present, never their values.

Update ​

Run the installer again. It downloads the latest hapi release and replaces the installed copy only if it differs; anything already current is left unchanged, so it is safe to repeat. The toolkit core tier stays at the version the installer pins (v1.0.0); to move it to another release, run the installer with --toolkit-tag <tag>.

Then restart the server and the daemon so that they run the new version: stop hapi server (Ctrl+C in its terminal) and start it again, and run hapi daemon stop, then hapi daemon start. Running Claude Code sessions keep running through the restart, on the version they started with; start a new session to use the new version. Exit any session you started from a terminal before you restart the server (see the known issue under Supported agent CLIs).

Uninstall ​

Before you uninstall, stop the daemon (hapi daemon stop) and the server (Ctrl+C in the terminal running hapi server), especially before --purge, which deletes the database the server has open.

bash
bash install-hapimatic-v1.sh uninstall

Without a saved copy, pipe the installer to bash -s -- uninstall, as for the doctor.

This removes ~/.local/bin/hapi, the marked PATH lines from your shell startup files, ~/.hapi/runtime/ and the install record, and runs the toolkit's own uninstaller, which removes what it linked into ~/.claude/. It keeps your Hapimatic home directory (~/.hapi, or $HAPI_HOME if you set it), which holds your access token and session database. To remove that as well:

bash
bash install-hapimatic-v1.sh uninstall --purge

WARNING

--purge deletes your access token and every recorded session. It cannot be undone.

Server setup ​

The server can be deployed on:

  • Local desktop (default) - Run on your development machine
  • Remote server - Deploy on a VPS, cloud server, or any machine with network access

Start the server:

bash
hapi server

The server listens on http://localhost:3006 by default.

On first run, the server generates a secure access token, prints it, and saves it to ~/.hapi/settings.json. The installer has already created ~/.hapi/.

Config files
~/.hapi/
├── settings.json           # Main configuration, including the access token
├── hapi.db                 # SQLite database (server)
├── daemon.state.json       # Daemon process state
├── logs/                   # Log files
├── claude-toolkit/         # The toolkit core tier (installer)
├── runtime/                # Tools that hapi unpacks on first run
└── install-hapimatic.json  # What the installer installed
Environment variables
VariableDefaultDescription
CLI_API_TOKENAuto-generatedShared secret for authentication
HAPI_SERVER_URLhttp://localhost:3006Server URL for CLI
WEBAPP_PORT3006HTTP server port
HAPI_HOME~/.hapiConfig directory path
DB_PATH~/.hapi/hapi.dbDatabase file path
CORS_ORIGINS-Allowed CORS origins

CLI setup ​

If the server is not on localhost, set these before running hapi:

bash
export HAPI_SERVER_URL="http://your-server:3006"
export CLI_API_TOKEN="your-token-here"

Or use interactive login:

bash
hapi auth login

hapi api, hapi capabilities and hapi federation use the saved token only for a server on this machine (HAPI_SERVER_URL unset or a loopback address). For a remote server, set CLI_API_TOKEN.

Authentication commands:

bash
hapi auth status
hapi auth login
hapi auth logout

Each machine gets a unique ID stored in ~/.hapi/settings.json. This allows:

  • Multiple machines to connect to one server
  • Remote session spawning on specific machines
  • Machine health monitoring

Portable machine conventions ​

Hapimatic's issue workflow and escalation plugins rely on four per-machine conventions. Each is resolved via $HOME — no machine-specific absolute path is ever baked in — so a checkout behaves identically on any machine. None of the four is required to run a session; a fresh machine spawns sessions without them. They gate the issue workflow (committing, escalation, pre-commit gates, GitHub operations), so the open-core installer's readiness doctor reports each as a non-fatal line with a fix rather than a hard install failure:

bash
bash install-hapimatic-v1.sh doctor

Git identity (G1) ​

Every skill that commits needs a git identity. The doctor reads it from git config at any scope (and prints --show-origin so an inherited identity is visible); it never reads it from ~/.config/hapimatic/env — that file is the Anthropic credential store, not an identity source. If user.name or user.email is unset, the doctor reports git identity: unset with the fix:

bash
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

Nothing commits silently as an unknown identity. If git cannot parse one of its config files, or refuses to run in the current repository, the identity and hooks lines name the error instead of reporting a false state.

Secrets file (G4) ​

The escalation and issue-workflow plugins (notify-pm, the inbox poller, …) read their API secrets from ONE per-user location, resolved via $HOME through a single shared helper, resolve_hapimatic_secrets, which tries these candidates in order:

  1. $HAPIMATIC_SECRETS_FILE — explicit override
  2. $HOME/.config/hapimatic/secrets.env — the recommended home, alongside Hapimatic's other per-user config
  3. $HOME/.bashrc.d/99-api-secrets.sh — the operator-provisioning delivery path

When none of the candidates exists, the helper prints a loud but non-fatal message to stderr naming every path it tried, then returns non-zero without exiting the caller — so a consumer such as notify-pm still falls through to any delivery tier that does not need the file, and fails only when no tier delivers. A missing secrets file is never a silent no-op.

The doctor's secrets line is tiered:

  • No consumer installed (the free tier): informational — n/a on the free tier with no file, or the file found.
  • The resolve_hapimatic_secrets helper installed: a missing file is a non-fatal warning that names all three candidate paths, and a present file reports OK. A candidate that exists but is not a readable file (unreadable, a directory, a dangling symlink) ahead of the one being used is also a warning, because consumers skip it.
  • notify-pm or the inbox poller installed without the helper (copies from before the helper existed): those read only $HOME/.bashrc.d/99-api-secrets.sh, so the doctor checks only that file.
  • An explicit $HAPIMATIC_SECRETS_FILE that is not a readable file is always a warning: consumers fall through to the other candidates, so a typo in that path would otherwise go unnoticed.

The resolve_hapimatic_secrets helper and its consumers live in Hapimatic's dotfiles tier, outside this repository; this guide documents the convention they implement.

Git hooks (G6) ​

Hapimatic's global pre-commit dispatcher lives in a $HOME-relative hooks directory. On a machine where the dotfiles tier is deployed, the committed git config points core.hooksPath at ~/.githooks (and excludesfile at ~/.gitignore_global) — tilde-relative, so the dispatcher resolves on every machine regardless of the home-directory path.

There is deliberately no per-repo core.hooksPath step: a repo-local core.hooksPath overrides the global dispatcher (its gates stop firing in that repo) and, where the pointed-at directory is absent, silently disables .git/hooks/ entirely. Repositories that ship their own hooks install them into .git/hooks/, and the global dispatcher chains them.

The doctor checks that the effective core.hooksPath resolves to an existing directory; if it is set but points at a missing directory it reports hooks silently disabled — the exact failure the ~/.githooks relativization prevents. A relative value is resolved against the repository's top level, as git does, and an empty value is a warning, because git then runs no hooks at all. With no core.hooksPath set, the doctor checks that the repository's pre-commit hook exists and is executable, because git skips a hook that is not executable.

GitHub auth (G7) ​

The issue workflow uses the GitHub CLI. Authenticate once:

bash
gh auth login

The free tier runs sessions without gh; only the issue-workflow features need it, so the doctor reports gh: not authenticated — needed for the issue workflow only as a non-fatal line.

Operations ​

Remote access ​

If the server is deployed on a machine with a public IP, you can access it directly via http://your-server-ip:3006. Use HTTPS (via reverse proxy like Nginx or Caddy) for production.

If the server is behind NAT, use one of these options:

Cloudflare Tunnel

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/

bash
export WEBAPP_URL="https://your-tunnel.trycloudflare.com"
Tailscale

https://tailscale.com/download

bash
sudo tailscale up

Access via your Tailscale IP:

http://100.x.x.x:3006

That address is plain HTTP. Tailscale's WireGuard connection encrypts the traffic between your devices, but the address is not HTTPS, and installing the app needs HTTPS.

For HTTPS, share the port with your tailnet through Tailscale Serve:

bash
sudo tailscale serve --bg 3006

The web app is then at https://<machine-name>.<tailnet-name>.ts.net, reachable only from devices on your tailnet. TLS ends on your own machine, so no provider can read the traffic or the access token, and because the address is HTTPS you can install the app from it. Serve needs HTTPS certificates turned on for your tailnet; if they are off, the command prints a link to turn them on. To stop sharing, run sudo tailscale serve reset. On Linux, Tailscale Serve needs root, which is why both commands use sudo; to run them without sudo, run sudo tailscale set --operator=$USER once.

ngrok
bash
ngrok http 3006

A tunnel provider carries the traffic between your browser and your server. Cloudflare Tunnel and ngrok's HTTPS endpoints end TLS at the provider's edge, so the provider can read that traffic, including the access token you sign in with; Tailscale (including Funnel) ends TLS on your own machine.

Telegram setup ​

Enable Telegram notifications and Mini App access:

  1. Message @BotFather and create a bot
  2. Set the bot token and public URL
  3. Start the server and bind your account
bash
export TELEGRAM_BOT_TOKEN="your-bot-token"
export WEBAPP_URL="https://your-public-url"

hapi server

Then message your bot with /start, open the app, and enter your CLI_API_TOKEN.

Daemon setup ​

Run a background service for remote session spawning:

bash
hapi daemon start
hapi daemon status
hapi daemon logs
hapi daemon stop

With the daemon running:

  • Your machine appears in the "Machines" list
  • You can spawn sessions remotely from the web app
  • Sessions persist even when the terminal is closed

Security notes ​

  • Keep tokens secret and rotate if needed
  • Use HTTPS for public access
  • Restrict CORS origins in production
Firewall example (ufw)
bash
ufw allow from 192.168.1.0/24 to any port 3006

The self-hosted core is licensed under AGPL-3.0.