Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
dd08de4
docs: add freshclaude restore audit plan
Apr 3, 2026
569a71f
docs: tighten freshclaude restore plan
Apr 3, 2026
9e57a6a
docs: revise freshclaude restore audit plan
Apr 3, 2026
0f1a4d1
docs: tighten freshclaude restore audit plan
Apr 3, 2026
13166aa
docs: tighten freshclaude restore plan
Apr 3, 2026
30e67d4
docs: harden freshclaude restore plan
Apr 3, 2026
7b2870c
docs: add freshclaude restore audit test plan
Apr 3, 2026
1824356
fix: canonicalize freshclaude restore history resolution
Apr 3, 2026
4cc69c8
fix: enrich freshclaude restore snapshots
Apr 3, 2026
3360a75
fix: hydrate freshclaude restore state from canonical snapshots
Apr 3, 2026
eda8032
fix: complete freshclaude visible restore flow
Apr 3, 2026
3805fff
fix: restore freshclaude pane metadata from timeline ids
Apr 3, 2026
e444b87
chore: align ui semantics with verification gates
Apr 3, 2026
de75d30
fix: close freshclaude restore review gaps
Apr 3, 2026
13e8054
fix: tighten restore overlap ambiguity handling
Apr 3, 2026
9d33d81
test: align restore scenarios with final audit plan
Apr 3, 2026
23954f1
fix: tighten restore merge guards
Apr 3, 2026
a6f6989
fix: stabilize freshclaude attach restore order
Apr 3, 2026
43d232c
fix: harden freshclaude restore fallback state
Apr 3, 2026
058e2ee
fix: preserve streaming preview after stop
Apr 3, 2026
e253a16
docs: clarify streaming restore contract
Apr 3, 2026
cfa90ed
fix: harden freshclaude restore history fallback
Apr 3, 2026
f9845a4
Fix FreshClaude durable restore follow-up
Apr 3, 2026
c37c31b
fix: single-source freshclaude restore failures
Apr 3, 2026
6640c86
docs: add robust freshclaude restore redesign proposal
Apr 3, 2026
f51218e
docs: fix robust restore redesign review gaps
Apr 3, 2026
56ac538
docs: tighten robust restore redesign plan
Apr 3, 2026
24a93d8
docs: tighten robust restore redesign plan
Apr 3, 2026
7b1e0b3
docs: tighten robust freshclaude restore plan
Apr 3, 2026
b75907e
docs: harden robust restore redesign plan
Apr 3, 2026
683cf42
docs: tighten restore redesign cross-tab identity plan
Apr 3, 2026
276bb8a
docs: tighten robust restore redesign plan
Apr 3, 2026
eaee894
docs: add robust freshclaude restore test plan
Apr 3, 2026
9897778
fix: harden freshclaude restore flow
Apr 3, 2026
adf18e4
test: lock restore redesign regressions
Apr 4, 2026
90f6888
fix: honor robust restore review findings
Apr 4, 2026
4c34707
fix: close restore review follow-up gaps
Apr 4, 2026
24414f1
Fix restore attach failure handling
Apr 4, 2026
46e3666
Fix restore canonical handoff and live authority
Apr 4, 2026
9a6f47e
Fix restore ledger dedupe and named-resume hydration
Apr 4, 2026
ab3ea88
Fix stale restore retry reset
Apr 4, 2026
8b6775b
Fix cross-tab layout timestamp tracking
Apr 4, 2026
22db1dc
Require snapshot revisions for SDK restore
Apr 4, 2026
14bb7a4
Fail closed when SDK replay gate is unavailable
Apr 4, 2026
8477521
Protect canonical pane session refs in cross-tab sync
Apr 4, 2026
31585ad
Fix sdk attach alias routing
Apr 4, 2026
2f07375
Reset stale restore state before retry
Apr 4, 2026
956fc48
Pin fallback restore body fetch revision
Apr 4, 2026
96092d6
Resolve live attach via durable alias fallback
Apr 4, 2026
6868b3a
Fix restore hydration self-abort race
Apr 4, 2026
9799264
Merge branch 'main' into fix-freshclaude-restore-audit
Apr 4, 2026
c8857ba
docs: add performance fixes implementation plan
Apr 5, 2026
bb01ce8
plan: tighten performance fixes execution
Apr 5, 2026
9f575c6
docs: add performance fixes test plan
Apr 5, 2026
1a25c42
perf: make runtime lan detection async
Apr 5, 2026
2d34cc2
perf: remove dead sync wsl planning wrappers
Apr 5, 2026
f061357
perf: make local-file routing async
Apr 5, 2026
8445d1f
perf: enable incremental typescript caches
Apr 5, 2026
1a9a8c2
perf: lazy-load editor pane
Apr 5, 2026
e20fc2d
perf: memoize large tab and terminal views
Apr 5, 2026
323519d
test: stabilize lazy editor verification
Apr 5, 2026
af7618f
perf: isolate editor lazy bundle
Apr 5, 2026
525caf7
fix: improve MCP agent guidance for split-pane, pane types, and targe…
Apr 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .agents/skills/freshell-orchestration

This file was deleted.

227 changes: 227 additions & 0 deletions .agents/skills/freshell-orchestration/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
---
name: freshell-orchestration
description: "Use when interacting with Freshell panes, panels, or tabs from the CLI for tmux-style automation and multi-pane workflows, outside external-browser automation tasks."
---

# Freshell tmux-style automation

## Start state

Freshell injects `FRESHELL_URL` and `FRESHELL_TOKEN` into every spawned terminal. They are already set in your environment.

## MCP tool (preferred)

If you have the `freshell` MCP tool available, use it directly -- it's faster and doesn't require Bash approval for each command.

Quick start:
- `freshell({action: "help"})` -- see all available commands
- `freshell({action: "list-tabs"})` -- see open tabs
- `freshell({action: "new-tab", params: {name: "Work", mode: "claude"}})` -- create a tab
- `freshell({action: "send-keys", params: {target: "p1", keys: "hello\n"}})` -- send input

The MCP tool accepts the same commands as the CLI below but with structured JSON input instead of positional arguments.

## CLI fallback

If the MCP tool is not available (e.g., running outside Freshell or in a context without MCP support), use the CLI:

```bash
FSH="npx tsx server/cli/index.ts"
$FSH health
```

Use absolute paths for `--cwd` and `--editor`.

## Mental model

- Freshell CLI is an HTTP client over `/api/*`, not a local tmux socket client.
- Tabs and pane trees live in `layoutStore`.
- Terminal lifecycle + scrollback live in `terminalRegistry`.
- Pane kinds: `terminal`, `editor`, `browser`, `agent-chat` (Claude/Codex), `picker` (transient).
- **Picker panes are ephemeral.** A freshly-created tab without `--mode`/`--browser`/`--editor` starts as a `picker` pane while the user chooses what to launch. Once they select, the picker is replaced by the real pane with a **new pane ID**. Never target a `picker` pane for splits or other mutations — wait until it resolves to its final kind, or use `--mode`/`--browser`/`--editor` flags on `new-tab`/`split-pane` to skip the picker entirely.
- Typical loop: `new-tab/split-pane` -> `send-keys` -> `wait-for` -> `capture-pane`/`screenshot-*`.

## Choosing the right action and pane type

- **split-pane vs new-tab:** When the user says "pane", "split", "alongside", "next to", or "side by side", use `split-pane`. Use `new-tab` only when the user explicitly says "tab", "window", or "new [thing]" with no spatial reference. When unsure, `split-pane` is the safer default.
- **Prefer specialized pane types:** Do NOT open a terminal to run `cat`/`vim`/`nano`/`curl`/`wget` when a dedicated pane type fits.
- "open/edit/show a file" -> `split-pane --editor /path/to/file`
- "open/show a URL" or "view a webpage" -> `split-pane --browser URL` or `open-browser URL`
- "run a command" or "use a CLI tool" -> `split-pane --mode shell` or `new-tab --mode shell`
- **Sending text:** Use `send-keys -l` for natural-language prompts or multi-word text. Do NOT append "ENTER" as literal text — send the command with `-l`, then send `ENTER` as a separate call.
- **Default targeting (MCP only):** When no target is specified, the MCP tool resolves to your own pane/tab (set by `FRESHELL_TAB_ID`/`FRESHELL_PANE_ID`), not the user's active viewport. `split-pane` without a target splits your own pane.
- **Default direction:** `split-pane` defaults to vertical (top/bottom). Use `-h` for horizontal (left/right).

## Command reference

Output behavior:
- Most commands print JSON.
- `list-tabs` and `list-panes` print TSV unless `--json`.
- `list-panes --titles` appends a fifth TSV column with the pane title.
- `capture-pane` and `display` print plain text.

Targets:
- Tab target: tab ID or exact tab title.
- Pane target: pane ID, pane index in active tab, or `tabRef.paneIndex`.
- Omitted target on `rename-tab` means the active tab.
- Omitted target on `rename-pane` means the active pane in the active tab.
- Omitted target on `split-pane` (MCP) means your own pane, not the user's active viewport.
- Omitted target falls back to active pane in active tab when command supports it (CLI only).
- If a target or name contains spaces, quote it.
- Use the flagged `-t/-n` form when you want to make the target and name explicit.

Tab commands:
- `new-tab [-n NAME] [--claude|--codex|--mode MODE] [--shell SHELL] [--cwd DIR] [--browser URL] [--editor FILE] [--resume SESSION_ID] [--prompt TEXT]`
- `list-tabs [--json]`
- `select-tab [TARGET]` or `select-tab -t TARGET`
- `kill-tab [TARGET]` or `kill-tab -t TARGET`
- `rename-tab NEW_NAME` - rename the active tab
- `rename-tab TARGET NEW_NAME`
- `rename-tab -t TARGET -n NEW_NAME`
- `has-tab TARGET` or `has-tab -t TARGET`
- `next-tab`
- `prev-tab`

Pane/layout commands:
- `split-pane [-t PANE_TARGET] [-h] [--mode MODE] [--shell SHELL] [--cwd DIR] [--browser URL] [--editor FILE]`
- `list-panes [-t TAB_TARGET] [--json] [--titles]`
- `select-pane PANE_TARGET` or `select-pane -t PANE_TARGET`
- `rename-pane NEW_NAME` - rename the active pane
- `rename-pane TARGET NEW_NAME`
- `rename-pane -t TARGET -n NEW_NAME`
- `kill-pane PANE_TARGET` or `kill-pane -t PANE_TARGET`
- `resize-pane PANE_TARGET [--x X_PCT] [--y Y_PCT]`
- `swap-pane PANE_TARGET --other OTHER_PANE_TARGET`
- `respawn-pane PANE_TARGET [--mode MODE] [--shell SHELL] [--cwd DIR]`
- `attach TERMINAL_ID [PANE_TARGET]` or `attach -t TERMINAL_ID -p PANE_TARGET`

Terminal interaction:
- `send-keys [-t PANE_TARGET] [-l] KEYS...`
- `capture-pane [-t PANE_TARGET] [-S START] [-J] [-e]`
- `wait-for [-t PANE_TARGET] [-p PATTERN] [--stable SECONDS] [--exit] [--prompt] [-T TIMEOUT_SECONDS]`
- `display -p FORMAT [-t PANE_TARGET]` or `display FORMAT [PANE_TARGET]`
- `run [--capture|-c] [--detach|-d] [-T TIMEOUT_SECONDS] [-n NAME] [--cwd DIR] COMMAND...`
- `summarize PANE_TARGET` or `summarize -t PANE_TARGET`
- `list-terminals`

Browser/navigation:
- `open-browser URL [-n NAME]`
- `navigate URL [PANE_TARGET]` or `navigate --url URL -t PANE_TARGET`

Screenshot commands:
- `screenshot --scope pane|tab|view --name NAME [--path DIR_OR_FILE] [--overwrite] [-t TARGET]`
- Aliases:
- `screenshot-pane -t PANE_TARGET --name NAME [--path ...] [--overwrite]`
- `screenshot-tab -t TAB_TARGET --name NAME [--path ...] [--overwrite]`
- `screenshot-view --name NAME [--path ...] [--overwrite]`
- `--name` is required.
- `--path` is optional; default output root is OS temp dir.
- Pane/tab scopes resolve target before capture; view scope captures current app viewport.

Session/service:
- `list-sessions`
- `search-sessions QUERY` or `search-sessions -q QUERY`
- `health`
- `lan-info`

tmux-style aliases:
- `new-window`, `new-session` -> `new-tab`
- `list-windows` -> `list-tabs`
- `select-window` -> `select-tab`
- `kill-window` -> `kill-tab`
- `rename-window` -> `rename-tab`
- `next-window` -> `next-tab`
- `previous-window`, `prev-window` -> `prev-tab`
- `split-window` -> `split-pane`
- `display-message` -> `display`
- `screenshot-pane`, `screenshot-tab`, `screenshot-view` -> `screenshot`

## tmux differences

- Transport/auth: tmux uses local socket; Freshell uses HTTP API + token auth.
- Pane types: tmux terminal-only; Freshell supports terminal/editor/browser.
- Target model: tmux session/window/pane grammar vs Freshell ID/title/index resolution.
- Runtime model: tmux TTY-local; Freshell browser-first and remote-friendly.
- Feature model: Freshell adds session indexing/search and AI summary workflows.

## Playbook: open file in editor pane

New tab:

```bash
FILE="/absolute/path/to/file.ts"
$FSH new-tab -n "Edit $(basename "$FILE")" --editor "$FILE"
```

Split current tab:

```bash
FILE="/absolute/path/to/file.ts"
$FSH split-pane --editor "$FILE"
```

## Playbook: create, split, and rename without UI interaction

```bash
FSH="npx tsx server/cli/index.ts"
CWD="/absolute/path/to/repo"
FILE="/absolute/path/to/repo/README.md"

WS="$($FSH new-tab -n 'Triager' --codex --cwd "$CWD")"
TAB_ID="$(printf '%s' "$WS" | jq -r '.data.tabId')"
P0="$(printf '%s' "$WS" | jq -r '.data.paneId')"
P1="$($FSH split-pane -t "$P0" --editor "$FILE" | jq -r '.data.paneId')"

$FSH rename-tab -t "$TAB_ID" -n "Issue 166 work"
$FSH rename-pane -t "$P0" -n "Codex"
$FSH select-pane -t "$P1"
$FSH rename-pane "Editor"
```

## Playbook: parallel Claude panes

```bash
FSH="npx tsx server/cli/index.ts"
CWD="/absolute/path/to/repo"
PROMPT="Implement <task>. Run tests. Summarize tradeoffs."

SEED_JSON="$($FSH new-tab -n 'Claude x4 Eval' --claude --cwd "$CWD")"
P0="$(printf '%s' "$SEED_JSON" | jq -r '.data.paneId')"
J1="$($FSH split-pane -t "$P0" --mode claude --cwd "$CWD")"
P1="$(printf '%s' "$J1" | jq -r '.data.paneId')"
J2="$($FSH split-pane -t "$P0" -h --mode claude --cwd "$CWD")"
P2="$(printf '%s' "$J2" | jq -r '.data.paneId')"
J3="$($FSH split-pane -t "$P1" -h --mode claude --cwd "$CWD")"
P3="$(printf '%s' "$J3" | jq -r '.data.paneId')"

for p in "$P0" "$P1" "$P2" "$P3"; do
$FSH send-keys -t "$p" -l "$PROMPT"
$FSH send-keys -t "$p" ENTER
$FSH wait-for -t "$p" --stable 8 -T 1800
$FSH capture-pane -t "$p" -S -120 > "/tmp/${p}.txt"
done
```

## Screenshot-specific guidance

- Use a dedicated canary tab when validating screenshot behavior so live project panes are not contaminated.
- Close temporary tabs/panes after verification unless user asked to keep them open.
- Browser panes:
- Same-origin iframe content is captured best-effort.
- If iframe content is not capturable (for example cross-origin/security), screenshots intentionally render a placeholder message with source URL context instead of a silent blank region.
- For assertions, allow either explicit page content or the explicit non-capturable placeholder text depending on origin/security context.

## REST API patterns

- Auth header: `x-auth-token: <TOKEN>` (not Bearer).
- `POST /api/tabs` with `{ name, mode: "shell", shell: "wsl", cwd }` creates a tab with a terminal, bypassing the picker.
- `POST /api/panes/:id/split` with `{ direction: "horizontal"|"vertical", browser?, editor?, mode?, cwd? }` — defaults to vertical; always 50/50.
- `POST /api/panes/:id/resize` with `{ sizes: [left, right] }` (percentages summing to 100) — call immediately after split to fix proportions.
- Editor panes show "Loading..." until visited. When screenshotting multiple tabs, visit each tab once first to trigger editor loading, then loop back for screenshots.
- `DELETE /api/terminals/:id` removes orphaned terminals. Freshell has a 50 PTY limit; orphans from scripted runs accumulate silently.

## Gotchas

- Use `send-keys -l` for natural-language prompts.
- `wait-for --stable` is usually more reliable than prompt heuristics across providers.
- If target resolution fails, run `list-tabs` and `list-panes --json`, then retry with explicit IDs.
Loading
Loading