Monitor and control your coding agents from your phone. Touch controls for tmux over the web. Published on npm as remobi.
Pure TypeScript + DOM API β no framework. Transpiles to JS via tsdown for npm distribution. Bundles a browser client via esbuild and serves it from Node.
- Node 22+ β runtime
- pnpm β package manager
- esbuild β browser client bundle
- tsdown β transpile TS β JS for npm publish
- vitest β test runner
- TypeScript (strict) β no
any, discriminated unions for actions - Biome β lint + format
- happy-dom β DOM testing
- Hono β HTTP + WebSocket server (
remobi serve) - node-pty β PTY bridge for
remobi serve - xterm.js β browser terminal rendering
git config core.hooksPath .hk-hooks # Run once after clone
pnpm test # Run all tests
pnpm run test:pw # Playwright e2e tests (chromium + webkit)
pnpm run check # Biome lint + format check
pnpm run check:fix # Auto-fix lint + format
pnpm run build # Deprecated legacy command
pnpm run build:dist # Transpile for publishing (tsdown)From source (bundles overlay on the fly, no build step):
tsx cli.ts serve # localhost:7681, default tmux session
tsx cli.ts serve --port 8080 -- bash --norc # custom port, bash instead of tmuxFrom a local build:
pnpm run build:dist && node dist/cli.mjs serveCommits must follow Conventional Commits format, enforced by hk commit-msg hook.
- Format:
type(scope): description - Types:
feat,fix,chore,docs,refactor,test,ci,perf,style,build,revert - Breaking changes: include a
BREAKING CHANGE:footer.!after type/scope is optional shorthand only and must be paired with the footer because semantic-release major detection relies on the footer.
Choosing the right type matters β it controls whether semantic-release publishes to npm:
| Type | Release | When to use |
|---|---|---|
fix |
patch | Bug fix visible to package consumers (runtime behaviour, CLI output, published types) |
feat |
minor | New feature visible to consumers |
BREAKING CHANGE: footer |
major | Breaking change to public API; ! is optional shorthand but not sufficient on its own in this repo |
ci |
none | CI/CD workflow changes (GitHub Actions, release config) |
chore |
none | Tooling, deps, repo hygiene β anything not shipped to consumers |
docs |
none | Documentation only |
refactor |
none | Code restructuring with no behaviour change |
test |
none | Adding or updating tests |
NEVER use fix for non-consumer-facing changes. fix triggers an npm release β it means a bug fix visible to package consumers (runtime behaviour, CLI output, published types). If the change only affects CI, dev tooling, tests, or repo internals, use ci, chore, or test instead β even if it "fixes" something. When in doubt, ask: "would a consumer notice if this change didn't exist?" If no, it's not fix.
src/index.tsβ entry: waitForTerm then init overlaysrc/config.tsβ defaults, defineConfig, deepMergesrc/types.tsβ all shared typessrc/toolbar/β toolbar DOM + button definitionssrc/drawer/drawer.tsβ command drawer with flat gridsrc/drawer/commands.tsβ re-exports defaultDrawerButtons from configsrc/gestures/β swipe, pinch, scroll detection + gesture locksrc/controls/β font size, help overlay, combo picker, floating buttons, scroll buttonssrc/theme/β catppuccin-mocha + applysrc/viewport/β height management, landscape detectionsrc/util/dom.tsβ element creation helperssrc/util/terminal.tsβ sendData, resizeTerm, waitForTermsrc/util/haptic.tsβ vibration feedbacksrc/util/keyboard.tsβ isKeyboardOpen, conditionalFocussrc/util/tap.tsβ onTap: touch + click handler for iOS Safari compatibilitysrc/util/node-compat.tsβ sleep, readStdin, spawnProcess, collectStreamsrc/actions/registry.tsβ action dispatch + clipboardsrc/hooks/registry.tsβ lifecycle hook systemsrc/config-schema.tsβ Valibot validation schemassrc/config-resolve.tsβ button array resolutionsrc/config-validate.tsβ config assertionssrc/cli/args.tsβ CLI argument parsingsrc/pwa/β PWA manifest, meta-tags, iconssrc/reconnect.tsβ connection loss overlaysrc/overlay-entry.tsβ IIFE entry point for browser bundlestyles/base.cssβ all CSScli.tsβ CLI: serve, init, deprecated build/inject, --versionbuild.tsβ browser client bundling + HTML rendering
- Transpiles to JS via tsdown:
binβdist/cli.mjs,exportsβdist/*.mjs+dist/*.d.mts filesarray controls what's published:dist/,styles/,src/pwa/icons/,README.md,CHANGELOG.md,LICENSE- CI:
.github/workflows/ci.ymlβ pnpm test + biome check - Release:
releasejob in.github/workflows/ci.ymlβ semantic-release on push tomainanddev, gated oncheckjob- Versioning, changelog, npm publish, and GitHub Release are all automated
npx semantic-release --dry-runfor local verification- Stable channel:
mainβ npmlatest - Prerelease channel:
devβ npmdev+ GitHub prereleases - Promote experimental releases by merging
devintomain - Release triggers:
feat:β minor,fix:β patch,BREAKING CHANGEβ major - No release:
chore:,docs:,refactor:,test:,ci:
- See Local Development above for running from source
- Button actions use discriminated unions (
type: 'send' | 'ctrl-modifier' | 'paste' | 'combo-picker' | 'drawer-toggle') - Unified control schema: use
ControlButtonfor both toolbar and drawer items - Config shape:
drawer.buttons(notdrawer.commands) - Config via
defineConfig()β typed, with sensible defaults - Config resolution:
--configflag β cwd β~/.config/remobi/(XDG fallback) - Drawer takes a flat
readonly ControlButton[]β rendered as a single grid - Help overlay is config-driven and must be fail-safe (never break core controls if help fails)
- Mobile viewport handling: lock document scroll and compute height from visual viewport (keyboard-aware)
- Changelog and versioning are fully automated by semantic-release β do not manually edit
CHANGELOG.md. Use conventional commit types to control releases:feat:β minor,fix:β patch,BREAKING CHANGEβ major. Non-release types:chore:,docs:,refactor:,test:,ci: - All DOM creation in
util/dom.tshelpers - Keyboard state preserved: capture
isKeyboardOpen()before action, useconditionalFocus()after - Tests use happy-dom for DOM environment (e2e/CLI tests use node environment)
- Agent skill:
.agents/skills/remobi-setup/SKILL.mdprovides AI agents with onboarding and config guidance. When config shape, CLI commands, action types, or validation rules change, update the skill to stay in sync. - Agent onboarding: when helping a user set up remobi (not develop it), read
.agents/skills/remobi-setup/SKILL.mdand follow its workflow. Critical:set -g mouse onmust be enabled in the user's tmux config for touch scroll to work β the skill covers this but agents skipping it is the most common setup failure.