Skip to content
Agent Orchestration
Skill

/macos-rebuild-dev

Kill the running termio dev app, rebuild it with SwiftPM, and relaunch it as a foreground app. Invoke when the user says 'rebuild', 'rebuild app', 'restart app', 'relaunch', '重新编译', or '重启 app'.

BOOST
From plugin
termio
54428 skills
Install
$ npx -y skills add termio-sh/termio --skill macos-rebuild-dev --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/macos-rebuild-dev

Context preview

The summary Claude sees to decide when to auto-load this skill.

Kill the running termio dev app, rebuild it with SwiftPM, and relaunch it as a foreground app. Invoke when the user says 'rebuild', 'rebuild app', 'restart app', 'relaunch', '重新编译', or '重启 app'.

SKILL.md

macos-rebuild-dev.SKILL.md
name: macos-rebuild-dev
description: "Kill the running termio dev app, rebuild it with SwiftPM, and relaunch it as a foreground app. Invoke when the user says 'rebuild', 'rebuild app', 'restart app', 'relaunch', '重新编译', or '重启 app'."

Rebuild App (local development)

Kill the running **dev** build, rebuild it as the isolated `termio-dev.app` bundle, and relaunch — so every rebuild reflects the current Dock icon and, crucially, does **not** disturb an installed release build you use daily.

The dev channel

termio ships a `TERMIO_CHANNEL=dev` build that is a fully separate app from the release one, so both can run at the same time:

| | release | dev (this skill) | | --- | --- | --- | | Bundle | `termio.app` (usually `/Applications`) | `termio-dev.app` (repo root) | | Bundle id | `sh.termio.app` | `sh.termio.app.dev` | | State + sockets | `~/Library/Application Support/termio` | `…/termio-dev` | | User config | `~/.termio` | `~/.termio-dev` | | Daemon socket | `$TMPDIR/termiod-<uid>` | `…-dev` | | Daemon launchd job | `sh.termio.termiod` | `sh.termio.termiod.dev` | | Companion port | 8787 | 8788 | | CLI on PATH | `termio` | `termio-dev` | | Sparkle auto-update | on | **no update feed** (dev never self-updates) |

All of this falls out of the `.dev` bundle-id suffix via `Sources/termio/Companion/AppChannel.swift` (paths + port) and `scripts/build-app.sh` (id, name, `SUFeedURL` deletion, CLI rebind). Sparkle.framework itself is embedded on both channels — the binary links it either way — so a dev bundle still carries it; it just has nothing to check.

termio is a plain SwiftPM executable (`Package.swift` → `executableTarget` named `termio`); `swift build` alone produces a bare binary with **no Dock icon**. So this skill builds the real bundle via `scripts/build-app.sh`. For a dev build the script auto-picks a real codesigning identity from **your own** keychain (any "Apple Development" / "Developer ID Application" cert — a free Apple ID gives you one) so the dev app can post macOS notifications; `usernoted` rejects an ad-hoc signature outright, so an unsigned dev build can **never** banner. A contributor with **no** signing cert falls back to ad-hoc automatically — the build still succeeds, they just don't get notifications. Set `SIGN_IDENTITY=…` to force a specific one. The app runs unsandboxed with `.exec` PTYs — see `CLAUDE.md`. The icon is `packaging/icon-static.svg`, rasterized to `packaging/AppIcon.png` by `scripts/render-icon.sh` (needs headless Chrome). Note: dev and release currently share the same icon art and differ only by name ("termio dev") — a tinted dev icon is a possible follow-up.

Instructions

When invoked, execute these steps sequentially:

1. **Kill only the running dev app + its tunnel.** Both channels' inner binary is named `termio` (`CFBundleExecutable`), so `pkill -x termio` would kill the release app too. Match the dev bundle **path** instead. SIGKILL skips the app's `willTerminate` cleanup, so also reap the companion tunnel it spawned on the dev port (8788):

   pkill -9 -f "termio-dev.app/Contents/MacOS/termio" || true
   pkill -9 -f "cloudflared tunnel --url http://127.0.0.1:8788" || true
   pkill -9 -f "tunelo port 8788" || true

2. **Build the dev bundle** from the committed `packaging/AppIcon.png` — do *not* re-render the icon (see "Icons" below). Show the tail of the output; if the build fails, show the error and **stop — do NOT relaunch**:

   TERMIO_CHANNEL=dev ./scripts/build-app.sh 2>&1 | tail -12

3. **Re-register the dev bundle with LaunchServices, then refresh the Dock cache.** macOS resolves an app's icon by its bundle id (`sh.termio.app.dev`); `lsregister -f` forces our path to win and `killall Dock` drops the cached icon:

   LSREG="/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister"
   "$LSREG" -f "$PWD/termio-dev.app"
   touch ./termio-dev.app
   killall Dock 2>/dev/null || true

4. **Relaunch via `open`** (NOT `nohup` on the inner binary — that bypasses LaunchServices). `open`'s `--stdout` / `--stderr` still capture logs:

   open ./termio-dev.app --stdout /tmp/termio-dev.log --stderr /tmp/termio-dev.log
   echo "launched ./termio-dev.app (logs: /tmp/termio-dev.log)"

5. **Upgrade the running dev daemon.** `build-app.sh` already rebuilt the daemon into `Resources/termiod`, but a **running** dev daemon keeps its old image: a dev app's launch-time reconcile deliberately refuses to stage (its bundle stamp is a placeholder, and that guard is what keeps a dev build from ever deploying itself over a release daemon). Without this step, a termiod-side change gets "verified" against the previous daemon. The deploy is idempotent — same version reports `current` and does nothing, so it costs nothing on Swift-only rebuilds — and an execve handoff keeps the pid and carries every live session. `TERMIOD_SOCK` must be unset first: a shell inside a termio session carries it pointed at the *release* daemon, and it overrides the channel.

   unset TERMIOD_SOCK
   TERMIO_CHANNEL=dev ./termio-dev.app/Contents/Resources/termiod deploy --json 2>&1 | tail -3

A daemon that isn't running needs nothing: the first pane starts it from the new bundle.

6. **Report** the result: whether the build succeeded, the app relaunched, and the daemon version the deploy reported. If the window doesn't appear, check `/tmp/termio-dev.log`.

Verifying a termiod-side change

Sessions carried across the handoff keep the environment and shell their **old** daemon spawned them with — a change to session spawning (env, injection, PTY setup) is invisible in them by design. Open a **new** session to see it.

Icons

`scripts/render-icon.sh` rasterizes `packaging/icon-static.svg` into `packaging/AppIcon.png` (and the iOS asset) through headless Chro

Read more
Ships withtermio

A terminal-first agentic development environment for agentic coding. Build for CLI/TUI agent. Runtime for Coding Agent, Tmux alternative

Get the whole plugin
Stats
544
Stars
42
Forks
Active
Maintenance
Swift
Language
MIT
License
2d ago
Last commit
4mo ago
Created
4h ago
Added

Repo: termio-sh/termio

Other skills on termio.