Modules declare go 1.27.1 and the build images follow. go fix applied the modernizers, and the ptr helper went once new(expr) could say it; omitzero is not applied, since it changes what the JSON says. Co-authored-by: Hanzo Dev <[email protected]>
phrocs
Insights-branded dev process runner built with Bubble Tea.
Drop-in replacement for mprocs — reads the same YAML config that insightscli dev:generate produces.
Install
If you develop Insights with flox, you already have phrocs: activation builds
it from source (make -C tools/phrocs build) and bin/start runs that build
directly from tools/phrocs/dist/phrocs. The source build is canonical — it
always matches your checkout, so there's nothing to install or keep up to date,
and a stray Homebrew/curl install can't shadow it.
For non-flox setups, install a prebuilt binary:
Homebrew (macOS and Linux):
brew tap insights/tap && brew install phrocs
Install script (macOS and Linux):
curl -fsSL https://raw.githubusercontent.com/Insights/insights/master/tools/phrocs/install.sh | bash
bin/start resolves phrocs in this order: the in-repo dist/phrocs build if
present, otherwise phrocs on PATH.
Build
insightscli phrocs:build
Layout
┌───────────────────────────────────────────┐
│ phrocs ● 3 running │ ← header
├────────────────┬──────────────────────────┤
│ ● backend │ (process output) │
│ ● frontend │ │ ← sidebar + viewport
│ ✗ capture │ │
├────────────────┴──────────────────────────┤
│ j next k prev r restart q quit ? help │ ← footer
└───────────────────────────────────────────┘
Usage
phrocs --config <config.yaml>
phrocs --config <config.yaml> --debug # write debug log to /tmp/phrocs-debug.log
phrocs --version # print version and exit
The config is generated by insightscli dev:generate and lives at .insights/.generated/mprocs.yaml in the repo root.
You typically run phrocs via insightscli start rather than directly.
Keybindings
| Key | Action |
|---|---|
tab |
Swap focus sidebar/output |
↓/j |
Next process (sidebar) / scroll down (output) |
↑/k |
Previous process (sidebar) / scroll up (output) |
pgdn |
Scroll output down |
pgup |
Scroll output up |
home |
Jump to top of output |
end |
Jump to bottom of output |
s |
Start selected process |
x |
Stop selected process |
r |
Restart selected process |
R |
Restart all failed processes |
l |
Clear logs of selected process |
c |
Enter copy mode |
i |
Show process info in pager |
o |
Sort processes by <name/CPU/RAM/status> |
g |
Cycle process grouping (from config groups field) |
a |
Toggle show all registry processes |
t |
Enter setup mode (choose which services to run) |
/ |
Enter search mode (then tab to switch to filter mode) |
esc |
Exit copy, search, and filter modes |
↵ |
Send keystrokes to the process (output pane) |
? |
Toggle full help |
q |
Quit (docker containers keep running; see below) |
Mouse clicks switch focus; mouse wheel scrolls the output pane.
Quitting stops the processes phrocs supervises, but the docker compose containers keep running: docker compose up runs detached (-d), and the compose stack is deliberately shared across worktrees.
To fully tear it down, run insightscli docker:services:down (or insightscli docker:services:remove to also wipe volumes).
Copy mode
Press c to enter copy mode in the output pane.
Navigate with ↑/↓, press c again to mark the selection start, then extend with ↑/↓ and press c to copy to clipboard.
Press esc to exit without copying.
Sending input to a process
Some processes wait for input on stdin, like a (y/n) confirmation, a REPL, an interactive CLI. Focus the output pane (tab), then type to send keystrokes to the process's PTY.
phrocs auto-detects a prompt when the last output didn't end in a newline, and starts forwarding keystrokes right away. That heuristic misses prompts that print a trailing newline, so you can also press ↵ to enter input mode explicitly: every key then goes to the process until you press esc to leave.
Search and filter modes
Press / to enter search mode, type a query, then use ↓/↑ to jump between matches.
Press tab to switch to filter mode, which hides all non-matching lines and shows a count of matches in the footer.
Press tab again in filter mode to return to search mode (the query is preserved).
Press esc to exit and clear the query.
Queries support multiple space-separated tokens — all must match for a line to be included:
| Pattern | Description |
|---|---|
term |
Case-insensitive substring match |
!term |
Negative match — exclude lines containing term |
re:pattern |
Regex match (case-insensitive) |
!re:pattern |
Negative regex — exclude lines matching the pattern |
Info panel
Press i to replace the output pane with detailed info about the selected process:
status, PID, ready state, exit code, timing (started at, uptime, startup duration),
resource usage, config, and buffered line count.
A warning banner appears when memory usage is high.
Docker mode
When a docker-compose process is selected, a third containers pane appears in the sidebar
showing container status. Navigate containers with ↑/↓ when the containers pane is focused.
The first entry shows an overview status table; selecting a container streams its logs.
Press d to open lazydocker with the relevant compose files.
Process viewer
Press p to open a system process viewer filtered to the selected process's PID.
Prefers htop (tree view + PID filter), falls back to btop (unfiltered), then top (PID filter).
Grouping
Press g to cycle through grouping dimensions defined in the config.
Each process can declare a groups map and an optional top-level group_order controls display order.
The top-level default_group names the dimension the sidebar starts grouped by (omit it to start ungrouped).
See bin/mprocs.yaml for the config format.
Processes without a matching group appear under Ungrouped.
The reserved value pinned places a process at the top without a header.
Show all processes
Press a to toggle visibility of all processes from the full registry (bin/mprocs.yaml),
not just those in your current intent config.
Processes not in your intent config appear dimmed with a · status icon. They are config-only placeholders that consume no resources until started. Once started (s), it behaves like any other process (logs, restart, stop, info).
This is useful for getting a big-picture overview of the full dev environment or temporarily starting a process without changing your intent config.
Debug logging
Pass --debug to write a timestamped log of TUI events to /tmp/phrocs-debug.log:
2026/03/06 10:00:00.123456 debug logging started
2026/03/06 10:00:00.145678 resize: 220x54
2026/03/06 10:00:00.200000 status: proc=backend status=running
2026/03/06 10:00:01.300000 key: "j" (type=runes)
2026/03/06 10:00:01.300100 proc selected: 0→1 (frontend)
Tail it in a separate terminal while phrocs is running:
tail -f /tmp/phrocs-debug.log
MCP server
phrocs exposes process data over a Unix domain socket (IPC) so external tools can query status and logs.
A Python MCP server (mcp_server.py) connects to this socket and provides two tools for Claude Code:
get_process_status— query process status (running, stopped, exit code, etc.)get_process_logs— fetch recent log lines, optionally filtered by grep pattern
The socket path is derived from a hash of the workspace directory, so multiple phrocs instances can coexist.
Package structure
phrocs/
├── main.go entry point, arg parsing, program wiring
├── mcp_server.py MCP server for Claude Code integration
└── internal/
├── config/ YAML config loader
├── docker/ docker-compose container inspection + log streaming
├── ipc/ Unix domain socket server (/tmp/phrocs-<hash>.sock)
├── process/ process lifecycle (start, stop, restart, pty I/O)
└── tui/ Bubble Tea model, key map, styles