Skip to content

Commit 8d95410

Browse files
committed
docs(skill): improve remobi-setup with tmux basics, tool detection, security, and button inventory
- New reference: tmux-basics.md — starter guide for users with no tmux config (install, concepts, sessions, keybindings, starter conf, popups, tpm) - New reference: hooks.md — lifecycle hook API docs (6 hooks, contexts, examples) - Phase 2: expanded tmux setup guidance referencing tmux-basics.md, tool detection step (lazygit, yazi, btm, nvim, gh) for popup binding suggestions - Phase 3: new interview questions for detected tools and custom split bindings, improved scroll strategy explanation - Phase 6: security hardening paragraph (CSP, origin checks, buffer limits, etc.) - Phase 7: built-in controls docs (font size, scroll buttons, combo picker, help overlay, landscape+keyboard), PWA config options - Config reference: default button ID tables (29 buttons across row1/row2/drawer), gestures/font/PWA config tables, hooks pointer, popup-heavy example config
1 parent 7235cd3 commit 8d95410

3 files changed

Lines changed: 431 additions & 7 deletions

File tree

.agents/skills/remobi-setup/SKILL.md

Lines changed: 171 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,43 @@ Note down:
6262
- Status bar complexity (affects mobile width recommendations)
6363
- Plugin manager (tpm, etc.)
6464

65-
If the user has no tmux config at all, offer to help set up a basic one before continuing.
65+
If the user has no tmux config at all, read `references/tmux-basics.md` and help them create a starter config:
66+
- Explain what tmux is and its benefits (persistent sessions, windows/panes, popup tools)
67+
- Install tmux if missing
68+
- Create `~/.config/tmux/tmux.conf` with mouse, renumber-windows, true colour, scrollback, vi keys
69+
- Explain sessions/windows/panes and the essential keybindings
70+
- Set up a help popup as the first `display-popup` binding: `bind ? display-popup -E -w 80% -h 80% "tmux list-keys | less"` — immediate payoff, no extra tools, teaches the popup concept
71+
- Suggest `status-position top` (keeps status away from remobi toolbar)
72+
- Optionally set up tpm for plugin management
73+
74+
Only proceed to Phase 3 once the user has a working tmux session.
75+
76+
**Detect installed tools** — check for popular tools that work well as tmux popup bindings:
77+
78+
```bash
79+
which lazygit # Git TUI — great as popup
80+
which yazi # File manager — great as popup
81+
which btm || which htop # System monitor
82+
which nvim || which vim # Editor
83+
which gh # GitHub CLI (gh-dash)
84+
```
85+
86+
Note which tools are installed. In Phase 3, suggest popup bindings for each. In Phase 4, generate matching drawer buttons. If none are installed, suggest lazygit as the most valuable first popup tool.
6687

6788
### Phase 3: Interview the user
6889

6990
Ask questions **one at a time** — don't dump a list. Adapt based on what you learned in phase 2.
7091

7192
1. **What do you primarily use tmux for?** (coding agents, dev workflow, server monitoring, all of the above)
7293
2. **Do you use popup bindings for tools?** Which ones? (lazygit, yazi, neovim, scratch shell, gh-dash, session picker)
73-
3. **Do you want touch scrolling?** What strategy? (`wheel` for mouse-event scrolling, `keys` for PageUp/PageDown paging)
74-
4. **Auto-zoom on mobile?** When you open remobi on your phone, should the current pane zoom to full screen automatically?
75-
5. **Floating zoom button?** A persistent button overlaid on the terminal for one-tap zoom toggle
76-
6. **Custom theme or Catppuccin Mocha?** (Catppuccin Mocha is the default and looks great — only ask if the user's tmux theme is clearly different)
77-
7. **Font preference?** (default: JetBrainsMono NFM)
78-
8. **Any other tmux bindings you want on your phone?** (This catches anything the inspection missed)
94+
3. **Detected tools** — "I detected [lazygit/yazi/btm/etc.] on your system. Would you like popup bindings in tmux and matching drawer buttons in remobi for any of these?" Adapt based on Phase 2 detection. For tools not installed, briefly explain what they are and ask if the user wants to install any.
95+
4. **Custom split bindings?** — Stock tmux uses `%` (vertical) and `"` (horizontal). Some configs remap to `|` and `-`. If custom, the drawer buttons need updated escape codes.
96+
5. **Do you want touch scrolling?**`wheel` (default, recommended) sends mouse-wheel events — works in vim, less, htop, and any mouse-aware app. `keys` sends PageUp/PageDown — simpler, works everywhere including plain tmux copy-mode. Which fits your workflow?
97+
6. **Auto-zoom on mobile?** When you open remobi on your phone, should the current pane zoom to full screen automatically?
98+
7. **Floating zoom button?** A persistent button overlaid on the terminal for one-tap zoom toggle
99+
8. **Custom theme or Catppuccin Mocha?** (Catppuccin Mocha is the default and looks great — only ask if the user's tmux theme is clearly different)
100+
9. **Font preference?** (default: JetBrainsMono NFM)
101+
10. **Any other tmux bindings you want on your phone?** (This catches anything the inspection missed)
79102

80103
Skip questions where you already know the answer from phase 2. Summarise what you've gathered before moving to config generation.
81104

@@ -130,6 +153,18 @@ Common options:
130153
- **Cloudflare Tunnel + Access** — private tunnel with Cloudflare Access policies controlling who can connect (e.g. restrict by email, IdP group, device posture). Do not use unauthenticated quick tunnels.
131154
- **Local network only**`remobi serve` on localhost behind your own VPN or private network.
132155

156+
#### Security hardening
157+
158+
remobi hardens the connection even on private networks. Mention these if the user has security concerns:
159+
160+
- **Binds `127.0.0.1` only** — never exposed to network without explicit `--host` flag
161+
- **Content-Security-Policy** — strict default-src, script-src, connect-src scoped to same host
162+
- **WebSocket origin validation** — rejects cross-origin upgrade requests
163+
- **Relay buffer limit** — 1 MB per connection; drops oversized payloads
164+
- **Crypto-secure internal port** — ttyd listens on a random ephemeral port (crypto PRNG), never exposed
165+
- **X-Frame-Options DENY** — prevents clickjacking via iframes
166+
- **Referrer-Policy: no-referrer** — no URL leaking to external sites
167+
133168
For macOS users, mention `--no-sleep` and point to `references/keep-awake.md` for persistent options.
134169

135170
For users who want manual ttyd control, point to `references/ttyd-flags.md`.
@@ -141,6 +176,16 @@ Tell the user:
141176
2. How to start: `remobi serve`
142177
3. How to access from their phone (URL from deployment choice)
143178
4. PWA install: on mobile, tap "Add to Home Screen" for a standalone app experience
179+
5. Built-in mobile controls (these work out of the box, no config needed):
180+
- **Font size**: `+`/`-` buttons in top-right. Config: `font.mobileSizeDefault` (default 16px), `font.sizeRange` (default [8, 32]), steps by 2
181+
- **Scroll buttons**: Floating arrow buttons on the sides. Long-press for rapid repeat (300ms delay, 100ms interval). Auto-fade after 2s. Strategy follows `gestures.scroll.strategy` (`wheel` sends mouse events, `keys` sends PageUp/PageDown)
182+
- **Combo picker**: Modal for arbitrary key combos — type `C-s`, `M-Enter`, `Alt-x`, `C-[`. Supports Ctrl, Alt, Shift modifiers + named keys (PageUp, Escape, etc.). Opened via drawer "Combo" button
183+
- **Help overlay**: `?` button in top-right. Shows all configured buttons, gestures, and floating buttons in tables. Config-driven, updates when you change buttons
184+
- **Landscape + keyboard**: When on-screen keyboard opens in landscape, row 2 auto-hides and buttons shrink. No config needed
185+
6. PWA: enabled by default. On mobile Safari/Chrome, tap Share then "Add to Home Screen" for standalone app experience. Config options:
186+
- `pwa.enabled` (default `true`) — set `false` to disable manifest + icons
187+
- `pwa.themeColor` (default `'#1e1e2e'`) — status bar colour on mobile
188+
- `pwa.shortName` (optional) — short name for home screen icon (falls back to `name`)
144189

145190
---
146191

@@ -214,6 +259,88 @@ floatingButtons: [
214259

215260
Valid positions: `top-left | top-right | top-centre | bottom-left | bottom-right | bottom-centre | centre-left | centre-right`
216261

262+
### Default button IDs
263+
264+
**Toolbar row 1** (10 buttons):
265+
266+
| `id` | `label` | `action` |
267+
|------|---------|----------|
268+
| `esc` | Esc | `send` `\x1b` |
269+
| `tmux-prefix` | Prefix | `send` `\x02` |
270+
| `tab` | Tab | `send` `\t` |
271+
| `shift-tab` | S-Tab | `send` `\x1b[Z` |
272+
| `left` || `send` `\x1b[D` |
273+
| `up` || `send` `\x1b[A` |
274+
| `down` || `send` `\x1b[B` |
275+
| `right` || `send` `\x1b[C` |
276+
| `ctrl-c` | C-c | `send` `\x03` |
277+
| `enter` || `send` `\r` |
278+
279+
**Toolbar row 2** (7 buttons):
280+
281+
| `id` | `label` | `action` |
282+
|------|---------|----------|
283+
| `q` | q | `send` `q` |
284+
| `alt-enter` | M-↵ | `send` `\x1b\r` |
285+
| `ctrl-d` | C-d | `send` `\x04` |
286+
| `drawer-toggle` | ☰ More | `drawer-toggle` |
287+
| `paste` | Paste | `paste` |
288+
| `backspace` || `send` `\x7f` |
289+
| `space` | Space | `send` `' '` |
290+
291+
**Drawer** (12 buttons):
292+
293+
| `id` | `label` | `action` |
294+
|------|---------|----------|
295+
| `tmux-new-window` | + Win | `send` `\x02c` |
296+
| `tmux-split-vertical` | Split \| | `send` `\x02%` |
297+
| `tmux-split-horizontal` | Split — | `send` `\x02"` |
298+
| `tmux-zoom` | Zoom | `send` `\x02z` |
299+
| `tmux-sessions` | Sessions | `send` `\x02s` |
300+
| `tmux-windows` | Windows | `send` `\x02w` |
301+
| `page-up` | PgUp | `send` `\x1b[5~` |
302+
| `page-down` | PgDn | `send` `\x1b[6~` |
303+
| `tmux-copy` | Copy | `send` `\x02[` |
304+
| `tmux-help` | Help | `send` `\x02?` |
305+
| `tmux-kill-pane` | Kill | `send` `\x02x` |
306+
| `combo-picker` | Combo | `combo-picker` |
307+
308+
### Gestures
309+
310+
| Field | Default | Notes |
311+
|-------|---------|-------|
312+
| `gestures.swipe.enabled` | `true` | |
313+
| `gestures.swipe.left` | `'\x02n'` | Next tmux window |
314+
| `gestures.swipe.right` | `'\x02p'` | Previous tmux window |
315+
| `gestures.swipe.threshold` | `80` | Pixels |
316+
| `gestures.swipe.maxDuration` | `400` | Milliseconds |
317+
| `gestures.pinch.enabled` | `false` | |
318+
| `gestures.scroll.enabled` | `true` | |
319+
| `gestures.scroll.strategy` | `'wheel'` | `'wheel'` (recommended) sends SGR mouse wheel sequences — works in vim, less, htop. `'keys'` sends PageUp/PageDown — simpler, works everywhere |
320+
| `gestures.scroll.sensitivity` | `40` | |
321+
| `gestures.scroll.wheelIntervalMs` | `24` | |
322+
323+
### Font
324+
325+
| Field | Default | Notes |
326+
|-------|---------|-------|
327+
| `font.family` | `'JetBrainsMono NFM, monospace'` | CSS font-family |
328+
| `font.cdnUrl` | jsdelivr nerdfont URL | CSS file for web font |
329+
| `font.mobileSizeDefault` | `16` | px, applied on mobile |
330+
| `font.sizeRange` | `[8, 32]` | Min/max for +/- buttons |
331+
332+
### PWA
333+
334+
| Field | Default | Notes |
335+
|-------|---------|-------|
336+
| `pwa.enabled` | `true` | Set `false` to disable manifest + icons |
337+
| `pwa.themeColor` | `'#1e1e2e'` | Status bar colour on mobile |
338+
| `pwa.shortName` | (none) | Short name for home screen icon, falls back to `name` |
339+
340+
### Hooks (advanced)
341+
342+
Hooks are programmatic, not via `defineConfig()`. See `references/hooks.md` if the user asks about analytics, action filtering, or custom DOM. Do not proactively suggest hooks during setup.
343+
217344
### Escape-code cheat sheet
218345

219346
Use these in `action.data` and gesture `left`/`right` fields:
@@ -329,6 +456,43 @@ export default defineConfig({
329456
})
330457
```
331458

459+
### Popup-heavy workflow — lazygit, yazi, scratch shell
460+
461+
Uses function form to keep default drawer buttons and append popup triggers:
462+
463+
```typescript
464+
import { defineConfig } from 'remobi'
465+
466+
export default defineConfig({
467+
name: 'dev',
468+
drawer: {
469+
buttons: (defaults) => [
470+
...defaults,
471+
{
472+
id: 'lazygit',
473+
label: 'Git',
474+
description: 'Open lazygit popup (prefix + g)',
475+
action: { type: 'send', data: '\x02g' },
476+
},
477+
{
478+
id: 'yazi',
479+
label: 'Files',
480+
description: 'Open yazi file manager popup (prefix + y)',
481+
action: { type: 'send', data: '\x02y' },
482+
},
483+
{
484+
id: 'scratch',
485+
label: 'Scratch',
486+
description: 'Open scratch shell popup (prefix + `)',
487+
action: { type: 'send', data: '\x02`' },
488+
},
489+
],
490+
},
491+
})
492+
```
493+
494+
Requires matching tmux bindings (see `references/tmux-basics.md` popup section).
495+
332496
## Guardrails
333497

334498
- **Never invent root keys.** The validator rejects unknown keys with a path-based error.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Hooks
2+
3+
Lifecycle hooks for remobi. Only reference this if the user asks about analytics, action filtering, custom DOM, or conditional behaviour.
4+
5+
## Overview
6+
7+
Hooks are registered programmatically — they are not part of `defineConfig()`. Import `createHookRegistry` from `'remobi'` and register handlers. Each hook receives typed context and runs asynchronously. Errors are caught and logged without stopping other hooks.
8+
9+
## SendSource type
10+
11+
```typescript
12+
type SendSource = 'toolbar' | 'drawer' | 'floating-buttons' | 'mobile-init'
13+
```
14+
15+
## Hook reference
16+
17+
| Hook | Fires when | Can modify? |
18+
|------|-----------|-------------|
19+
| `beforeSendData` | Before terminal input is sent | Yes — return `{ block: true }` to prevent, or `{ data: '...' }` to rewrite |
20+
| `afterSendData` | After data is sent | No (observation only) |
21+
| `overlayInitStart` | Overlay initialisation begins | No |
22+
| `overlayReady` | Overlay fully initialised and wired | No |
23+
| `toolbarCreated` | Toolbar DOM mounted | No (but can modify DOM) |
24+
| `drawerCreated` | Drawer DOM mounted | No (but can modify DOM) |
25+
26+
## Context interfaces
27+
28+
**BeforeSendDataContext / AfterSendDataContext:**
29+
30+
```typescript
31+
{
32+
term: XTerminal
33+
config: RemobiConfig
34+
source: SendSource
35+
actionType: ButtonAction['type']
36+
kbWasOpen: boolean
37+
data: string
38+
}
39+
```
40+
41+
**OverlayInitContext (overlayInitStart, overlayReady):**
42+
43+
```typescript
44+
{
45+
term: XTerminal
46+
config: RemobiConfig
47+
mobile: boolean
48+
}
49+
```
50+
51+
**ToolbarCreatedContext:**
52+
53+
```typescript
54+
{ term: XTerminal, config: RemobiConfig, toolbar: HTMLDivElement }
55+
```
56+
57+
**DrawerCreatedContext:**
58+
59+
```typescript
60+
{ term: XTerminal, config: RemobiConfig, drawer: HTMLDivElement, backdrop: HTMLDivElement }
61+
```
62+
63+
## Registration API
64+
65+
```typescript
66+
const hooks = createHookRegistry()
67+
const { dispose } = hooks.on('beforeSendData', async (ctx) => {
68+
console.log(`Sending ${ctx.data} from ${ctx.source}`)
69+
return {}
70+
})
71+
```
72+
73+
`dispose()` removes the handler.
74+
75+
## Examples
76+
77+
**Log all sent data:**
78+
79+
```typescript
80+
hooks.on('afterSendData', async (ctx) => {
81+
console.log(`[${ctx.source}] sent: ${JSON.stringify(ctx.data)}`)
82+
})
83+
```
84+
85+
**Block dangerous commands:**
86+
87+
```typescript
88+
hooks.on('beforeSendData', async (ctx) => {
89+
if (ctx.data.includes('rm -rf')) return { block: true }
90+
return {}
91+
})
92+
```
93+
94+
**Add custom DOM to toolbar:**
95+
96+
```typescript
97+
hooks.on('toolbarCreated', async (ctx) => {
98+
const indicator = document.createElement('span')
99+
indicator.textContent = 'LIVE'
100+
indicator.style.color = '#a6e3a1'
101+
ctx.toolbar.prepend(indicator)
102+
})
103+
```

0 commit comments

Comments
 (0)