Synced from pluk. This page is pulled from hivecommons/pluk@main during the docs build. Edit the canonical source in the pluk repository.
Pluk
Pluk classifies, subscribes to, and reacts to JSONL event streams from AI coding agent terminals.
Install
npm install -g @hivecommons/pluk
Quick Start command to create a tmux session, start an AI CLI, attach pluk event capture, and wire up rationguard for real-time excuse detection:
pluk attach my-agent --cli=claude --rationguard --rebuttal=send
This does four things:
- Creates a tmux session named
my-agent - Starts
claudeinside it - Attaches pluk via
tmux pipe-paneto classify all terminal output - Starts
rationguard watchto detect rationalizations and send rebuttals back
To just attach pluk without rationguard:
pluk attach my-agent --cli=claude
To attach to an existing tmux session (e.g., already running goose):
pluk attach my-agent --cli=goose
Note: When attaching to an existing session with
--dangerous, the CLI may not have permission-skip enabled (the flag applies when creating a new session). pluk will print a warning with the command to restart the CLI with the right flag.
A new terminal window is always opened for the tmux session (unless --no-open is set), so you can interact with the agent directly.
See What’s Running
pluk sessions
SESSION CLI STATE TMUX LAST ACTIVITY EVENTS
scanner claude working ● 2s ago 1204
helper claude idle ● 45s ago 892
goose-exp goose idle ○ 3m ago 156
Manual Setup
If you prefer to wire things up yourself:
# 1. Start an AI agent in tmux
tmux new-session -d -s my-agent
tmux send-keys -t my-agent "claude" Enter
# 2. Attach pluk to capture output
export PLUK_RUN_DIR=/tmp/pluk-run
tmux pipe-pane -t my-agent -o "pluk watch my-agent --cli=claude"
# 3. Subscribe to events (another terminal)
pluk subscribe my-agent --filter=state_change,rate_limit,error
# 4. Or start rationguard for real-time detection
rationguard watch my-agent --rebuttal=send
# 5. View the agent
tmux attach -t my-agent
Environment Variables
| Variable | Default | What it does |
|---|---|---|
PLUK_RUN_DIR | /tmp/pluk-run | Directory for session metadata and JSONL event logs |
PLUK_LOG_MAX_BYTES | 10485760 (10 MiB) | Rotate a session’s event log it exceeds this many bytes |
PLUK_LOG_KEEP_LINES | 5000 | Trailing lines kept in the log across rotation |
PLUK_RATIONGUARD_BIN | (unset) | Rationguard command for pluk attach --rationguard when it is not on PATH; same as --rationguard-bin |
CLI Commands
| Command | What it does |
|---|---|
pluk attach <session> | Create tmux + start CLI + wire pluk (+ rationguard) |
pluk sessions | List active pluk-monitored sessions |
pluk subscribe <session> | Tail a pluk JSONL log (like tail -f) |
pluk watch <session> | Classify stdin line-by-line |
pluk send <session> --text="..." --enter | Send text to a tmux session |
pluk patterns --cli=claude | Show loaded patterns for a CLI |
Attach Flags
| Flag | What it does |
|---|---|
--cli=claude | CLI type: claude, copilot, gemini, goose, codex, aider |
--command=<cmd> | Override the CLI command/executable to launch (instead of the default resolved from --cli); combines with --cli-args |
--rationguard | Start rationguard watcher alongside pluk (requires rationguard on PATH — npm install -g @hivecommons/rationguard — or --rationguard-bin; pluk never fetches it from the registry implicitly) |
--rationguard-bin=<cmd> | Explicit rationguard command to run instead of the on PATH, e.g. --rationguard-bin='npx --yes @hivecommons/rationguard@0.11.0' (also PLUK_RATIONGUARD_BIN) |
--rebuttal=send | Auto-send rebuttals when rationguard detects excuses |
--dangerous | Skip CLI permission prompts (--dangerously-skip-permissions for claude, --full-auto for codex, --non-interactive for goose) |
--dir=/path | Working directory for the agent |
--cli-args="..." | Extra arguments to pass to the CLI |
--no-open | Don’t open a terminal window |
--no-raw | Suppress raw_output events from the watcher attach starts (on by default for attach, unlike plain pluk watch, which requires --include-raw to emit them) |
--verbose | Show debug output |
Health diagnostics (watch, subscribe)
pluk watch and pluk subscribe deliberately swallow capture-pane failures,
input errors and malformed log lines so the pipe-pane process never dies. To
tell a healthy quiet session from that is repeatedly failing, add
--diagnostics[=secs] (default every 60 s). It writes JSON line per period,
plus a final on exit, to stderr — stdout stays pure event JSONL:
{"pluk_diagnostics":1,"command":"watch","uptime_s":120,"final":false,"linesSeen":842,"framesPolled":0,"captureFailures":0,"classifyErrors":0,"inputErrors":0,"eventsEmitted":31,"eventsFiltered":4}
``` fixed counter categories are reported — never the session name, raw
terminal output or any other user-provided value — and nothing is sent off-box.
The same counters are available programmatically via `watch(...).stats()` and
`Subscriber#stats()`.
## Programmatic API
```typescript
import { Classifier, getPatterns, subscribe, watch, discoverSessions, attach, send } from '@hivecommons/pluk';
//-command setup: tmux + CLI + pluk + rationguard
attach({
session: 'my-agent',
cli: 'claude',
rationguard: true,
rebuttal: 'send',
dangerouslySkipPermissions: true,
});
// Send text to a tmux session
send({ session: 'my-agent', text: 'check the build', enter: true });
// Discover running sessions
const sessions = discoverSessions('/tmp/pluk-run');
for (const s of sessions) {
console.log(`${s.session}: ${s.cli} (${s.state}, ${s.lastActivityAgo})`);
}
// Classify individual lines
const patterns = getPatterns('claude');
const classifier = new Classifier({ session: 'my-agent', patterns });
const event = classifier.classify('● Read main.go');
// → { type: 'tool_call_started', data: { tool: 'Read', ... } }
// Subscribe to a JSONL log file (tail -f behavior)
const sub = subscribe('my-agent', (event) => {
console.log(event.type, event.data);
}, { filter: ['rate_limit', 'error'] });
// Watch stdin for events
const watcher = watch({
session: 'my-agent',
cli: 'claude',(event) {
if (event.type === 'rate_limit') {
console.warn('Rate limited!', event.data.message);
}
},
});
Event Types
| Type | Meaning |
|---|---|
raw_output | Every non-empty terminal line |
state_change | Agent went idle or started working |
rate_limit | Usage limit / quota exhausted |
login_required | Authentication needed |
trust_dialog | Folder trust prompt |
bypass_permissions | Permission bypass prompt |
tool_call_started | Agent invoked a tool |
tool_call_completed | Tool finished |
error | Error in output |
model_changed | Model was switched |
session_ended | CLI session ended |
command_received | Command sent via pluk-send |
Send Command
Inject text into a running tmux session — used by rationguard to send rebuttals, or by you to send commands:
# Send text and press Enter
pluk send my-agent --text="check the build logs" --enter
# Send literal text (no key interpretation)
pluk send my-agent --text="hello world" --literal
# Also available as a standalone binary
pluk-send --session=my-agent --text="test" --enter
Standalone Binaries
In addition to the pluk <command> subcommand form, three standalone binaries are installed alongside pluk and behave the same as their subcommand equivalents:
| Binary | Equivalent to |
|---|---|
pluk-subscribe | pluk subscribe |
pluk-classify | pluk watch |
pluk-send | pluk send |
Supported CLIs
Built-in event-classification pattern files exist for: Claude Code, GitHub Copilot CLI, Gemini CLI, Goose CLI, OpenAI Codex CLI, Aider.
Custom patterns can be loaded from a directory with --patterns-dir or getPatterns(cli, patternsDir).
Pattern File Format
A pattern file is named <cli>.patterns (e.g. codex.patterns) and placed in
the directory passed to --patterns-dir. Each non-blank, non-comment line is
KEY='regex' — single or double quotes are both accepted, # starts a
comment, and blank lines are ignored. Every value is compiled as a JavaScript
RegExp source string, so use | for alternation (as in the bundled files
below). A key that is omitted, empty, or fails to compile is simply disabled
(treated as null) rather than raising an error.
Recognized keys:
| Key | Meaning |
|---|---|
IDLE_PATTERN | Terminal is at rest / showing a prompt |
WORKING_PATTERNS | Agent is actively working (spinner, status hint) |
RATE_LIMIT_PATTERN | Usage limit / quota exhausted |
LOGIN_PATTERN | Authentication required |
TRUST_DIALOG_PATTERN | Folder trust prompt |
BYPASS_PATTERN | Permission-bypass prompt |
TOOL_START_PATTERN | A tool call started |
TOOL_END_PATTERN | A tool call completed |
ERROR_PATTERN | Error in output |
MODEL_PATTERN | Model was switched |
SESSION_END_PATTERN | CLI session ended |
Minimal example (codex.patterns):
# codex.patterns — minimal custom pattern file
IDLE_PATTERN='^\$ $'
WORKING_PATTERNS='Thinking|Generating'
ERROR_PATTERN='^\s*Error:|^\s*FATAL'
See patterns/*.patterns in this repo for complete, real-world examples.
Works With
- @hivecommons/rationguard — real-time rationalization detection and rebuttal
- @hivecommons/promptargs — template variable substitution for AI prompts
- hivecommons/pluk — the Go binary (this package is the TypeScript port)
License
Apache-2.0