diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index b403d5f..d611aa6 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,5 +1,5 @@
{
- "name": "biff",
+ "name": "biff-dev",
"description": "UNIX-style team communication for Claude Code: /who, /finger, /plan, /write, /read, /mesg, /tty, /last, /wall, /talk",
"version": "1.10.0",
"author": {
diff --git a/README.md b/README.md
index bbd4341..065192e 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Named after the Berkeley dog whose 1980 mail notification program was part of th
## Quick Start
```bash
-curl -fsSL https://raw.githubusercontent.com/punt-labs/biff/cbca365/install.sh | sh
+curl -fsSL https://raw.githubusercontent.com/punt-labs/biff/677d77a/install.sh | sh
```
Restart Claude Code twice. Type `/who` to see your team.
@@ -37,7 +37,7 @@ biff doctor
Verify before running
```bash
-curl -fsSL https://raw.githubusercontent.com/punt-labs/biff/cbca365/install.sh -o install.sh
+curl -fsSL https://raw.githubusercontent.com/punt-labs/biff/677d77a/install.sh -o install.sh
shasum -a 256 install.sh
cat install.sh
sh install.sh
diff --git a/commands/biff-dev.md b/commands/biff-dev.md
new file mode 100644
index 0000000..f77970e
--- /dev/null
+++ b/commands/biff-dev.md
@@ -0,0 +1,16 @@
+---
+description: Enable or disable biff for this repo
+argument-hint: "y | n"
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__biff"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+Parse the argument as `y` or `n`. Map `y` to `enabled=true`, `n` to `enabled=false`.
+
+## Task
+
+Call `mcp__plugin_biff-dev_tty__biff` with `enabled` set to the parsed value. The result is already formatted by a PostToolUse hook and displayed above. Do not repeat or reformat the data. Do not send any text after the tool call.
diff --git a/commands/finger-dev.md b/commands/finger-dev.md
new file mode 100644
index 0000000..48f19e6
--- /dev/null
+++ b/commands/finger-dev.md
@@ -0,0 +1,16 @@
+---
+description: Check what a teammate is working on and their availability
+argument-hint: "@user"
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__finger"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+Parse the username from arguments, stripping any leading `@` if present.
+
+## Task
+
+Call `mcp__plugin_biff-dev_tty__finger` with `user` set to the parsed username. Emit the tool output exactly as returned — character for character, including the leading ▶ unicode character. Do not reformat, add commentary, wrap in code fences, convert to markdown tables, or add boxes around the output.
diff --git a/commands/last-dev.md b/commands/last-dev.md
new file mode 100644
index 0000000..96346f6
--- /dev/null
+++ b/commands/last-dev.md
@@ -0,0 +1,12 @@
+---
+description: Show session login/logout history
+argument-hint: "[@user] [count]"
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__last"]
+---
+
+
+Call `mcp__plugin_biff-dev_tty__last` with optional `user` (e.g. `@kai`) and `count` (default 25) arguments.
+
+If the result says "No session history.", say "No session history available."
+
+Otherwise, emit the tool output exactly as returned — character for character, including the leading ▶ unicode character. Do not reformat, add commentary, wrap in code fences, convert to markdown tables, or add boxes around the output.
diff --git a/commands/mesg-dev.md b/commands/mesg-dev.md
new file mode 100644
index 0000000..a12aeee
--- /dev/null
+++ b/commands/mesg-dev.md
@@ -0,0 +1,16 @@
+---
+description: Control message reception
+argument-hint: "y | n"
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__mesg"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+Parse the argument as `y` or `n`. Map `y` to `enabled=true`, `n` to `enabled=false`.
+
+## Task
+
+Call `mcp__plugin_biff-dev_tty__mesg` with `enabled` set to the parsed value. The result is already formatted by a PostToolUse hook and displayed above. Do not repeat or reformat the data. Do not send any text after the tool call.
diff --git a/commands/plan-dev.md b/commands/plan-dev.md
new file mode 100644
index 0000000..3d6295d
--- /dev/null
+++ b/commands/plan-dev.md
@@ -0,0 +1,14 @@
+---
+description: Set what you're currently working on (visible to teammates)
+argument-hint: ""
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__plan"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+## Task
+
+Call `mcp__plugin_biff-dev_tty__plan` with `message` set to the full arguments string. The result is already formatted by a PostToolUse hook and displayed above. Do not repeat or reformat the data. Do not send any text after the tool call.
diff --git a/commands/poll-dev.md b/commands/poll-dev.md
new file mode 100644
index 0000000..e1ab7d8
--- /dev/null
+++ b/commands/poll-dev.md
@@ -0,0 +1,30 @@
+---
+description: Set the background polling interval
+argument-hint: "{N}s | {N}m | n"
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__set_poll_interval", "mcp__plugin_biff-dev_tty__get_poll_status", "CronCreate", "CronList", "CronDelete"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+If no argument provided, call `mcp__plugin_biff-dev_tty__get_poll_status` and report the result. Stop.
+
+Otherwise parse the argument as an interval (`{N}s` or `{N}m`, e.g. `2s`, `30s`, `5m`) or `n` (disable). Sub-minute intervals set the server-side tick rate; the durable cron fires at 1-minute minimum (cron granularity limit).
+
+## Task
+
+1. Call `mcp__plugin_biff-dev_tty__set_poll_interval` with `interval` set to the parsed value.
+2. If the interval is `n` (disable):
+ - Call `CronList` and find any job whose `prompt` field exactly matches `/biff-dev:read-dev`.
+ - If found, call `CronDelete` with that job's `id` to remove the polling cron.
+3. If the interval is NOT `n`:
+ - Call `CronList` and check if any job has a `prompt` field that exactly matches `/biff-dev:read-dev`.
+ - If an existing `/biff-dev:read-dev` cron exists, call `CronDelete` on it first.
+ - Call `CronCreate` with:
+ - `cron`: convert the interval to a cron expression (e.g. `2s` -> `*/1 * * * *`, `5s` -> `*/1 * * * *`, `1m` -> `*/1 * * * *`, `2m` -> `*/2 * * * *`, `5m` -> `*/5 * * * *`). For intervals under 1 minute, use `*/1 * * * *` (cron minimum is 1 minute).
+ - `prompt`: `/biff-dev:read-dev`
+ - `recurring`: true
+ - `durable`: true
+4. Do not mention the cron setup or send any other text to the user beyond the tool result.
diff --git a/commands/read-dev.md b/commands/read-dev.md
new file mode 100644
index 0000000..08ee5b2
--- /dev/null
+++ b/commands/read-dev.md
@@ -0,0 +1,11 @@
+---
+description: Check your inbox for new messages
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__read_messages"]
+---
+
+
+Call `mcp__plugin_biff-dev_tty__read_messages` with no arguments.
+
+If the result says "No new messages.", do not emit any text.
+
+Otherwise, emit the tool output exactly as returned — character for character, including the leading ▶ unicode character. Do not reformat, add commentary, wrap in code fences, convert to markdown tables, or add boxes around the output.
diff --git a/commands/talk-dev.md b/commands/talk-dev.md
new file mode 100644
index 0000000..213c7d9
--- /dev/null
+++ b/commands/talk-dev.md
@@ -0,0 +1,28 @@
+---
+description: Start a real-time conversation with a teammate or agent
+argument-hint: "@user [message]"
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__talk", "mcp__plugin_biff-dev_tty__talk_end", "mcp__plugin_biff-dev_tty__write"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+Parse as: first token is the recipient username (strip leading `@` if present), remaining tokens are the opening message (optional).
+
+Examples:
+
+- `@kai` → `to="kai"`
+- `@kai hey, got a minute?` → `to="kai"`, `message="hey, got a minute?"`
+
+## Task
+
+1. Call `mcp__plugin_biff-dev_tty__talk` with the parsed values.
+2. Incoming messages from the partner appear on the status bar automatically (0-2s). No need to poll or call talk_listen.
+3. When the user wants to reply, send with `mcp__plugin_biff-dev_tty__write` to the same user.
+4. When the user says to stop, call `mcp__plugin_biff-dev_tty__talk_end`.
+
+If `$ARGUMENTS` is "end", call `mcp__plugin_biff-dev_tty__talk_end` directly.
+
+Do not repeat or reformat tool output — it is already formatted by hooks.
diff --git a/commands/tty-dev.md b/commands/tty-dev.md
new file mode 100644
index 0000000..f6539a5
--- /dev/null
+++ b/commands/tty-dev.md
@@ -0,0 +1,14 @@
+---
+description: Name the current session (visible in /who and /finger)
+argument-hint: "[name]"
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__tty"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+## Task
+
+Call `mcp__plugin_biff-dev_tty__tty`. If arguments were provided, pass them as `name`. If no arguments, call with no arguments to auto-assign the next ttyN. The result is already formatted by a PostToolUse hook and displayed above. Do not repeat or reformat the data. Do not send any text after the tool call.
diff --git a/commands/wall-dev.md b/commands/wall-dev.md
new file mode 100644
index 0000000..0a8d8a5
--- /dev/null
+++ b/commands/wall-dev.md
@@ -0,0 +1,29 @@
+---
+description: Broadcast a message to all teammates
+argument-hint: '"message" [duration] | clear'
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__wall"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+Parse as one of three modes:
+
+1. **Clear**: if arguments are exactly `clear` → call with `clear=True`
+2. **Post with duration**: if the last token matches a duration pattern (`30m`, `2h`, `1d`, `3d`), it is the duration and everything before it is the message → `message="...", duration="2h"`
+3. **Post with default**: otherwise the entire argument string is the message → `message="..."`
+
+If no arguments are provided, call with no parameters (shows current wall).
+
+Examples:
+
+- `release freeze — do not push to main` → `message="release freeze — do not push to main"`
+- `deploy window open 2h` → `message="deploy window open"`, `duration="2h"`
+- `clear` → `clear=true`
+- (empty) → no parameters
+
+## Task
+
+Call `mcp__plugin_biff-dev_tty__wall` with the parsed values. The result is already formatted by a PostToolUse hook and displayed above. Do not repeat or reformat the data. Do not send any text after the tool call.
diff --git a/commands/who-dev.md b/commands/who-dev.md
new file mode 100644
index 0000000..0f2fa96
--- /dev/null
+++ b/commands/who-dev.md
@@ -0,0 +1,11 @@
+---
+description: List active team members and what they're working on
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__who"]
+---
+
+
+Call `mcp__plugin_biff-dev_tty__who` with no arguments.
+
+If the result says "No sessions.", do not emit any text.
+
+Otherwise, emit the tool output exactly as returned — character for character, including the leading ▶ unicode character. Do not reformat, add commentary, wrap in code fences, convert to markdown tables, or add boxes around the output.
diff --git a/commands/write-dev.md b/commands/write-dev.md
new file mode 100644
index 0000000..1e8d5b7
--- /dev/null
+++ b/commands/write-dev.md
@@ -0,0 +1,30 @@
+---
+description: Send a message to a teammate
+argument-hint: "@user "
+allowed-tools: ["ToolSearch", "mcp__plugin_biff-dev_tty__write", "CronCreate", "CronList"]
+---
+
+
+## Input
+
+Arguments: $ARGUMENTS
+
+Parse as: first token is the recipient username (strip leading `@` if present), remaining tokens are the message body.
+
+Example: `@kai hey, ready for code review?` → `to="kai"`, `message="hey, ready for code review?"`
+
+## Task
+
+Call `mcp__plugin_biff-dev_tty__write` with `to` and `message` set to the parsed values. The result is already formatted by a PostToolUse hook and displayed above. Do not repeat or reformat the data.
+
+## Auto-poll for response
+
+After sending the message, ensure a polling loop exists to catch replies:
+
+1. Call `CronList` and check if any listed job has a `prompt` field that exactly matches `/biff-dev:read-dev`.
+2. If no existing `/biff-dev:read-dev` cron, call `CronCreate` with:
+ - `cron`: `*/5 * * * *`
+ - `prompt`: `/biff-dev:read-dev`
+ - `recurring`: true
+ - `durable`: true
+3. Do not mention the cron setup or send any other text to the user.