cli-bridge

Manage short-code bundles that authorize the local starchild CLI to talk to this agent, including the agent-shell local-exec channel and the local MCP proxy (stdio MCP servers on the user's machine). Use when connecting or disconnecting the starchild CLI (e.g. mint a CLI bridge code, list my CLI bun

By starchild-ai-agent · 1,783 installs

npx skills add starchild-ai-agent/official-skills --skill cli-bridge

Source repository · Upstream listing

cli bridge — issue CLI bundles for the user's own starchild binary This skill mints a fresh AKM key ( scope=chat:bridge:cli ) on the local clawd, then registers it with sc chatroom in exchange for a short opaque code ( sc xxxxxxxx ). The bundle handed to the user contains only that short code — never the AKM secret, never the Fly machine id. Why a short code instead of the raw AKM? Earlier versions baked the AKM secret + Fly machine id into the bundle directly. That worked but had two downsides — the bundle leaked routing metadata when decoded, and any party that ever held the bundle held a permanent AKM secret. The short code form fixes both: Bundle base64 decodes to {d, c:"", k:"sc …", s, exp, l} — no secret, no Fly machine id. cli revoke <sc … kills just the short code; the underlying AKM stays alive (use cli revoke akm <prefix to nuke that too). sc chatroom now holds the AKM secret in its DB. That's a deliberate trust shift — the AKM stays inside Fly's internal network instead of riding around on user laptops. Scope boundary — read this first cli bridge covers exactly one path : the user's local CLI talking 1:1 to that user's own clawd. It is not a chatroom membership credential. Use case Right credential Wrong Personal CLI ↔ own clawd (this skill) chat:bridge:cli AKM, fronted by sc … code — Join an sc chatroom room chat:thread:chatroom {room id} AKM via chatroom join chat:bridge:cli AKM Browse a public room as a guest no credential needed any AKM Install the CLI The rest of this skill assumes starchild is on the user's $PATH — install it first if it isn't. One liner (auto detects OS + arch) Picks the right binary for darwin/linux × arm64/amd64, drops it on $PATH (Apple Silicon lands in /opt/homebrew/bin ; Linux falls back to ~/.local/bin ; sudo only when the dir isn't user writable), patches the user's shell rc if the install dir wasn't already on $PATH , and runs starchild version as a self check. SHA256 etag means re running is a cheap "already current" no op (HTTP 304, no download). Source for review: [tools/install cli.sh](https://workroom.iamstarchild.com/install/cli) ( SERVER URL is rewritten at request time). Homebrew The starchild formula ships binaries for macOS (arm64 / amd64) and Linux (arm64 / amd64) — brew install picks the right one for the host. The formula has no bottle block, so install runs a tiny Ruby script that downloads the prebuilt binary from the server ( workroom.iamstarchild.com ) and drops it on $PATH — there's no local compile step. To upgrade later: brew update && brew upgrade starchild . Linux caveat: Homebrew itself works on Linux, but expects a Ruby + build toolchain (one time apt install build essential ruby / distro equivalent). For a Linux host, the oneliner above skips that and is functionally identical, so prefer it unless the user is already a brew user. starchild app (the desktop workspace) is macOS only — that formula builds from source (rust + node) and only the macOS build is meaningful. Verify If you just ran the one liner and your shell still says command not found , open a new terminal — the PATH update is in your rc, not the current session. Prerequisites Same as chatroom : AKM is installed in this clawd ( POST /api/keys works on loopback) AKM accepts scope="chat:bridge:cli" and the /chat/stream middleware allows arbitrary thread id for that scope (already shipped in clawd branch aladdin/feat/akm chatroom ) sc chatroom is on a build that includes POST /cli keys (migration 007+) FLY MACHINE ID (or CONTAINER ID ) env is set CHATROOM PUBLIC URL env points at the sc chatroom gateway (defaults to https://workroom.iamstarchild.com ) CHATROOM SERVER URL env points at the Fly internal sc chatroom (defaults to http://sc chatroom.internal:8080 ) Commands cli login — mint a new bundle Default TTL is 90 days; max is 365 days. Output is a one liner the user copies into starchild login . The bundle is opaque — sc chatroom resolves it on each call. cli list — show active bundles Lists every CLI short code minted by this user on sc chatroom. Columns: code, issued, expires, uses, label. cli revoke — kill a bundle Default: kills the short code in sc chatroom; underlying AKM stays alive. With akm : also revokes the AKM on local clawd, taking out every bundle backed by it. Local shell via agent shell (CLI ≥ v0.2.0) A cli login bundle minted with enable shell also authorizes the agent to run shell commands on the user's own machine — for "is nginx running on my laptop", "organize ~/Downloads", and the like. A plain bundle is a chat bridge only and grants no shell access (see "Shell is off by default" below). The user starts a small daemon: agent shell refuses to start if the logged in bundle wasn't granted shell — it tells the user to get a enable shell bundle rather than connecting a channel clawd would reject. The daemon is single instance (pidfile + flock) and macOS/Linux only. It self updates at startup and periodically; downloaded binaries are verified against an embedded Ed25519 release key before swapping, so a hostile or MITM'd update server can't push arbitrary code to the user's machine. How it works: the daemon dials wss://<chatroom /ws/cli shell with the bundle's sc … code. sc chatroom resolves the code and reverse proxies the WebSocket to the user's clawd machine — it accepts the laptop's upgrade, opens its own upstream WS to clawd pinned with fly force instance id , and pumps bytes between the two (this is not fly replay : chatroom and clawd are different Fly apps, and cross app replay is rejected with 403). The AKM is injected server side on the upstream hop — it never reaches the laptop. clawd holds the connection in its ShellHubService ; the local shell tool is then exposed to the LLM only while a shell capable laptop is connected , and pushes commands down the socket. Shell is off by default (capability gate) cli login does not grant shell unless enable shell is passed. The AKM is the authoritative capability source: clawd reads it on the /ws/cli shell handshake and refuses every exec for a connection that doesn't carry shell ( 264). So a leaked plain bundle is a chat credential, never local RCE. Grant shell: cli login.py label … enable shell → AKM capabilities: ["shell"] , bundle carries x: ["shell"] . Upgrade an existing no shell bundle: you can't flip it in place — mint a new enable shell bundle, starchild login it, and cli revoke the old one. Privilege escalation always goes through a fresh issuance. What the agent knows up front (capability manifest) On connect, the daemon sends a hello frame advertising: Platform — os (darwin/linux), arch (arm64/amd64), and the active shell . So the agent knows whether it's talking to BSD or GNU userland, which package manager to assume, etc. — no more guessing ps flags or hitting ps: illegal option . Policy summary — mode ( default deny when no allow rules exist, else allowlist ), the user's allowed rules, explicit denied extra rules, and the always on builtin denied list. File transfer policy — the transfer dir (always allowed workspace), yolo flag, and the read allow / write allow globs from ~/.config/starchild/file policy.toml . Present only when the bundle carries the files capability. See "File path policy" below for the full rules; this bullet is just so the agent knows the laptop advertised file transfer at all. clawd renders this into the agent's system prompt (only while connected), so the agent picks a permitted command — or tells the user plainly that the local policy forbids it — instead of probing blindly. Session behavior Connection level cwd. Each command's resulting working directory is echoed back (via a trailing pwd sentinel stripped from stdout) and persisted for the next command, so cd has real meaning across calls within a session — without the cost/fragility of a full PTY. An explicit per call cwd overrides it. Output truncation. stdout/stderr are each capped at 200 lines (plus a byte cap) so a find / or log dump can't flood the LLM context. The full pre truncation line count is reported ( stdout lines / stderr lines ), and truncated: true is set — the agent can say "showing first 200 of N lines" rather than truncating silently. Heartbeat. The daemon pings every 45s to keep the idle WebSocket alive (Fly's edge cuts idle sockets at ~2.5min). Exec runs in a goroutine so a long command doesn't block heartbeats. Local execution policy (the only auto run guard) The daemon runs headless (no TTY to prompt on), so every command is gated by ~/.config/starchild/exec policy.toml (parsed as a tiny YAML allow: / deny: line format — no TOML dependency, despite the name). Rules are substring matches by default; wrap a rule in / / for a regex: Decision order: built in deny (always wins) → file deny → file allow → default deny. Two hard rules apply regardless of the file: A built in deny list of interactive/TTY blocking and destructive commands is always refused: vim / vi / nano / emacs , less / more / man , top / htop / btop , ssh / telnet , sudo / su / doas , tmux / screen , reboot / shutdown / halt , plus the shapes rm rf , mkfs , dd if= , … sh , … bash , /dev/sd . Default deny: anything not matched by an allow rule is denied. So with no policy file the policy mode is default deny and nothing runs until the user opts commands in. Limitations Unattended policy only. There is no interactive approval prompt; the policy file is the sole guard. A future version adds a web approval popup. Synchronous commands only. No background jobs / progress polling yet. macOS/Linux only. The daemon refuses to run on Windows. Revocation: cli revoke <sc … kills the short code; the daemon's next reconnect then fails auth and the channel closes. File transfer via agent shell (CLI ≥ v0.3.0) When the bundle is minted with enable files , the same agent shell daemon also serves file transfer between the user's machine and the agent's workspace. Content streams disk→disk and never passes through the chat, so large/binary files (10MB+ PDFs, images, archives) work . Three agent facing tools + one user command: request upload(laptop path) — agent pulls a file FROM the laptop into workspace/uploads/ ("take my ~/big.pdf and summarize it"). write local file(src, dst) — agent sends a workspace file TO the laptop ("save workspace/output/report.pdf to my ~/Downloads"). src is a workspace path, not inline content. read local file(path) — read a small text file for the agent to see (config/log snippet). Large/binary files go through request upload . starchild push <file — user proactively uploads a local file into the agent's workspace/uploads/ ; it's announced to the agent in its prompt. files is an independent capability from shell — a bundle can have either, both, or neither. Like shell, it's off by default and authoritative on the AKM (clawd refuses transfer frames for a connection without it). File path policy (laptop side, layered) Transfers are gated on the laptop by a path policy, strictest first: 1. Built in protected paths are ALWAYS refused (even under yolo ): ~/.ssh , ~/.aws , shell rc ( .zshrc / .bashrc /…), .config/starchild , launchd/systemd/cron, .git/hooks , browser cookie stores, .env , ssh keys. Writing those would be persistent RCE; reading them leaks creds. 2. Dedicated transfer dir ( ~/starchild transfer , auto created) — always allowed for read + write. The safe default workspace; prefer it. 3. Outside that