Skip to content
 
 

Repository files navigation

Feather

A lightweight, mobile-first viewer and controller for AI coding agents.

Open any Claude Code session on your phone. Read the conversation. Send messages. Watch the terminal. Resume old sessions or spawn new ones — instantly.

Make it yours

The entire app is 6 files. Point Claude (or any AI agent) at this repo and tell it what you want:

  • "Add a cost tracker that shows tokens and dollars per session"
  • "Add push notifications when an agent needs my attention"
  • "Show me a diff view when Claude edits a file"
  • "Add a dark/light theme toggle"
  • "Group consecutive tool calls into a collapsible block"
  • "Add Codex support — here's how their session files work"
  • "Add a search bar that filters across all sessions"
  • "Show a green typing indicator when Claude is responding"
  • "Add keyboard shortcuts — j/k to navigate sessions, Enter to open"

No abstractions to learn. No plugin API to read. One server file, one app shell, one message renderer. You describe it, the agent builds it.

Fork and share

Feather is designed to diverge. Fork it, make it yours, share what you build.

# Fork on GitHub, then:
git clone https://github.com/YOU/feather.git && cd feather
npm install && npm start
# hack away

Pulling from other forks:

# Add someone's fork as a remote
git remote add phil https://github.com/phil/feather.git
git fetch phil

# See what they've been up to
git log phil/main --oneline

# Grab specific commits
git cherry-pick <sha>

# Or merge everything
git merge phil/main

Contributing back:

Open a PR to inceptel/feather from your fork. Or don't — your fork is yours.

Why

You're running Claude Code on a remote machine. You want to check on it from your phone, your iPad, another laptop. You want to send a follow-up message without SSH-ing in. You want to see the conversation rendered beautifully — like a texting app, not a terminal dump.

Feather reads Claude's raw JSONL session files, streams updates via SSE, and connects to tmux sessions via WebSocket terminals. No database. No build pipeline beyond Vite. Just node server.js.

Quick start

npm install inceptel/feather
cd node_modules/feather && npm start

Or from source:

git clone https://github.com/inceptel/feather.git && cd feather
npm install    # installs deps + builds frontend automatically
npm start      # → Feather on http://localhost:4870

Architecture

┌─────────────────────────────────────────┐
│  iPhone / Browser                       │
│  SolidJS SPA                            │
│  ├── MessageView (markdown, bubbles)    │
│  ├── Terminal (xterm.js + WebSocket)    │
│  └── Chat input (auto-grow textarea)   │
└──────────┬──────────────────────────────┘
           │ HTTP + SSE + WS
           ▼
┌──────────────────────────────────────────┐
│  Express server                          │
│  ├── JSONL parser (parseMessage)        │
│  ├── Session discovery (2-phase scan)   │
│  ├── SSE broadcaster (byte-offset IDs)  │
│  ├── fs.watch (inotify, per-directory)  │
│  ├── tmux manager (spawn/resume/send)   │
│  └── WebSocket terminal (node-pty)      │
└──────────┬──────────────────────────────┘
           │ filesystem
           ▼
  ~/.claude/projects/<hash>/<session>.jsonl
  tmux sessions: feather-<8chars>

Files

File Purpose
server.js Entire backend — API, SSE, WebSocket, JSONL parsing, tmux
frontend/src/App.tsx UI shell — sidebar, header, tabs, input bar
frontend/src/api.ts REST + SSE client, types
frontend/src/components/MessageView.tsx Chat bubbles with markdown rendering
frontend/src/components/Terminal.tsx xterm.js + WebSocket terminal
frontend/src/index.tsx SolidJS mount point

Design decisions

  • No database. Read JSONL directly. The filesystem is the source of truth.
  • No polling. fs.watch → SSE push. Client generates session UUID upfront (ClOrdId pattern).
  • tmux as the process manager. Every Claude session runs in a named tmux session. Terminal tab attaches to it. Chat input sends keystrokes via send-keys / paste-buffer.
  • Two-phase session discovery. Stat-only scan + sort by mtime → read first 4KB of top N for titles. 7000+ sessions in 75ms.
  • Byte-offset SSE IDs. Enables resumable streams and gap-free message delivery.
  • Mobile-first. --vh viewport fix, safe-area insets, -webkit-overflow-scrolling: touch, PWA meta tags.

Deploying changes

cd ~/feather
npm run deploy    # stamps version.json, builds frontend, restarts server

Both backend (/api/health) and frontend (tab bar) show the same version timestamp.

Deployment

supervisord

sudo cp infra/feather.supervisor.conf /etc/supervisor/conf.d/feather.conf
supervisorctl reread && supervisorctl update

systemd

sudo cp infra/feather.service /etc/systemd/system/
sudo systemctl enable --now feather

Reverse proxy (Caddy)

handle /feather { redir /feather/ permanent }
handle /feather/api/* {
    uri strip_prefix /feather
    reverse_proxy localhost:4870 {
        flush_interval -1    # required for SSE
    }
}
handle /feather/* {
    uri strip_prefix /feather
    reverse_proxy localhost:4870
}

Dependencies

Backend: express, node-pty, ws Frontend: solid-js, @xterm/xterm, @xterm/addon-fit, marked, dompurify

License

Elastic License 2.0 — free to use, modify, and distribute. Cannot be offered as a hosted service.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages