Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
aa34ec7
ai(claude[plugin]): add tmux-parity plugin for feature parity analysis
tony Mar 24, 2026
bce9ce7
ai(claude[plugin]): move agents/commands/skills to project root for a…
tony Mar 26, 2026
7e024fd
ai(claude[plugin]): move commands/agents to .claude/ for slash comman…
tony Mar 26, 2026
c9322b9
Pane(feat[send_keys]): add reset, copy-mode, repeat, hex, format, cli…
tony Mar 26, 2026
4a93ec3
Pane(feat[select]): add direction, last, zoom, mark, and input-toggle…
tony Mar 26, 2026
662fcd1
Pane(feat[display_message]): add format, verbose, delay, notify, list…
tony Mar 26, 2026
bd20cd7
Window(feat[select_layout]): add spread, next, and previous flags
tony Mar 26, 2026
e1db576
Window(feat[move_window]): add after, before, no-select, kill, and re…
tony Mar 26, 2026
2a37167
Server(feat[new_session]): add detach-others, no-size, config flags
tony Mar 26, 2026
88a921d
Session(feat[new_window]): add kill-existing and select-existing flags
tony Mar 26, 2026
91c2217
Pane(feat[split]): add percentage parameter for split-window
tony Mar 26, 2026
e4e7530
Pane(feat[capture_pane]): add alternate-screen, quiet, and escape-mar…
tony Mar 26, 2026
1d2f537
Options,Env(feat): add quiet/values-only to show_options, format/hidd…
tony Mar 26, 2026
bf3291b
Pane(feat[clear_history]): add clear_history() wrapping tmux clear-hi…
tony Mar 26, 2026
29cfa32
Pane,Window(feat[swap]): add swap() wrapping tmux swap-pane and swap-…
tony Mar 26, 2026
4185adf
Pane(feat[break_pane]): add break_pane() wrapping tmux break-pane
tony Mar 26, 2026
7bbb30e
Pane(feat[join]): add join() wrapping tmux join-pane
tony Mar 26, 2026
fb8b452
Pane,Window(feat[respawn]): add respawn() wrapping tmux respawn-pane/…
tony Mar 26, 2026
c108a45
Pane(feat[pipe]): add pipe() wrapping tmux pipe-pane
tony Mar 26, 2026
c3d9066
Server(feat[run_shell]): add run_shell() wrapping tmux run-shell
tony Mar 26, 2026
de0bdd6
Session,Window(feat): add last_window, next_window, previous_window, …
tony Mar 26, 2026
8ccc083
Window,Server(feat): add link, unlink, and wait_for commands
tony Mar 26, 2026
c7d9b62
Server(feat[buffers]): add set_buffer, show_buffer, delete_buffer wra…
tony Mar 26, 2026
7eccaa9
Server(feat[buffers]): add save_buffer, load_buffer, list_buffers for…
tony Mar 26, 2026
72c33c2
Pane(feat[paste_buffer]): add paste_buffer() wrapping tmux paste-buffer
tony Mar 26, 2026
7280e2d
Pane(feat[display_popup]): add display_popup() wrapping tmux display-…
tony Mar 26, 2026
200e88b
Revert "Pane(feat[display_popup]): add display_popup() wrapping tmux …
tony Mar 26, 2026
6bc6c96
Server(feat[list_clients]): add list_clients() wrapping tmux list-cli…
tony Mar 26, 2026
e177bf6
Server(feat[source_file]): add source_file() wrapping tmux source-file
tony Mar 26, 2026
28b7658
Server(feat[if_shell]): add if_shell() wrapping tmux if-shell
tony Mar 26, 2026
0e9599f
test(control_mode): add ControlMode context manager for client-depend…
tony Mar 26, 2026
97fd8bf
Session(feat[detach_client]): add detach_client() wrapping tmux detac…
tony Mar 26, 2026
4d74cc5
Pane(feat[display_popup]): add display_popup() wrapping tmux display-…
tony Mar 26, 2026
9278473
Server,Pane(feat): add show_messages, prompt_history, send_prefix com…
tony Mar 26, 2026
d893a41
Server(feat): add bind_key, unbind_key, list_keys, list_commands
tony Mar 26, 2026
02b3de9
Server,Session(feat): add start_server, lock_session
tony Mar 26, 2026
5b68912
Server(feat): add lock_server, lock_client, refresh_client, suspend_c…
tony Mar 26, 2026
deedcfe
Pane(feat): add copy_mode, clock_mode, choose_buffer/client/tree, cus…
tony Mar 26, 2026
3dc6c3c
docs(parity): update command-mapping reference to reflect current cov…
tony Mar 26, 2026
4fe038d
feat: fill missing flag gaps on recently added commands
tony Mar 26, 2026
fdc006b
Server(feat): add confirm_before, command_prompt wrapping interactive…
tony Mar 26, 2026
9f1dedc
Server(feat[command_prompt]): fill missing flag gaps
tony Mar 27, 2026
61deae8
Pane(feat): fill missing flag gaps on interactive commands
tony Mar 27, 2026
d100fe9
Server(feat[display_menu]): add display_menu() wrapping tmux display-…
tony Mar 27, 2026
13c82e1
docs(parity): update command-mapping to reflect 100% effective coverage
tony Mar 27, 2026
24fb0a2
Window(feat): add next_layout, previous_layout wrapping real tmux com…
tony Mar 27, 2026
156830c
Window(feat[last_pane]): call last-pane directly instead of select-pa…
tony Mar 27, 2026
35e62f9
Pane(feat[move]): add move() wrapping tmux move-pane directly
tony Mar 27, 2026
41ce823
docs(doctests): annotate untestable interactive commands
tony Mar 28, 2026
b208696
Pane(fix[display_popup]): correct border_style flag and add style param
tony Mar 28, 2026
5d38927
Pane(fix[display_popup]): use fused -e flag format for consistency
tony Mar 28, 2026
41c71bb
docs(versionadded): annotate new params on existing methods with 0.45
tony Mar 28, 2026
f1545ee
Pane,Window(fix[respawn]): use fused -c flag format for consistency
tony Mar 28, 2026
c366958
Window(fix[last_pane]): correct flag mapping for -d/-e flags
tony Mar 28, 2026
fe9a91e
Window(fix[split]): forward percentage parameter to Pane.split
tony Mar 28, 2026
1ec656f
Window(fix[select_layout]): use -p flag for previous layout, not -o
tony Mar 28, 2026
59dff2c
Server(fix[new_session]): -f sets client flags, not config file path
tony Mar 28, 2026
f637c10
Server(fix[run_shell]): -C means tmux command, not capture output
tony Mar 28, 2026
639cfb2
Server(fix[command_prompt]): -N means numeric input, not no-execute
tony Mar 28, 2026
ecf35c6
Pane(fix[capture_pane]): -M captures mode screen, not escape markup
tony Mar 28, 2026
23be410
Pane(fix[clear_history]): -H resets hyperlinks, not clears pane content
tony Mar 28, 2026
5bcf727
Pane(fix[copy_mode]): -q cancels modes, -e exits on scroll to bottom
tony Mar 28, 2026
3e1f547
Pane(fix[paste_buffer]): -r changes separator to newline, not no-trai…
tony Mar 28, 2026
27dc88d
Pane(fix[choose_tree]): -s/-w mean collapsed, not only-show
tony Mar 28, 2026
0791357
Window(fix[rotate]): don't always inject -D, respect tmux default
tony Mar 28, 2026
0e104c7
Server(fix[confirm_before,command_prompt]): -b requires tmux 3.3+, no…
tony Mar 28, 2026
1626cf3
Pane(fix[display_popup]): -C closes existing popup, not close-on-success
tony Mar 28, 2026
2bb0c8d
Window(fix[move_window]): -r is standalone renumber, not renumber-aft…
tony Mar 28, 2026
608054e
Session(fix[detach_client]): preserve client targeting semantics
tony Mar 29, 2026
0f6ecd4
Window(fix[move_window]): refresh moved window state
tony Mar 29, 2026
30d0741
ControlMode(fix[client_name]): bind client name to spawned client
tony Mar 29, 2026
ad14227
ControlMode(fix[control_mode]): replace FIFO with os.pipe(), add clea…
tony Mar 29, 2026
b751443
Pane(fix[display_popup]): raise ValueError when close_on_exit + close…
tony Mar 29, 2026
6684b80
Server(fix[confirm_before,command_prompt]): gate -b behind has_gte_ve…
tony Mar 29, 2026
b1ad192
Server,Session(fix[version_guard,detach_scope]): raise on unsupported…
tony Mar 29, 2026
adadb24
Pane(fix[display_popup]): correct ControlMode module path in docstring
tony Mar 29, 2026
a87d646
Server(fix[show_prompt_history,clear_prompt_history]): guard tmux 3.3+
tony Mar 29, 2026
5b66a18
Window(fix[swap]): refresh self and target after swap-window
tony Mar 29, 2026
5708136
Pane(fix[display_message]): no_expand→-l (literal), remove wrong list…
tony Mar 29, 2026
03b1179
Server,Pane(fix[ci-matrix]): align tests/doctests with tmux 3.2a-3.5 …
tony May 2, 2026
767c332
tests(feat[display_menu,display_popup]): broaden parametrized branch …
tony May 2, 2026
ec2d606
Session(fix[detach_client]): scope all_clients=True to this session
tony May 2, 2026
54413a2
Pane(fix[display_message]): -C is update-pane, not no-style
tony May 2, 2026
f621ece
Pane,Server(refactor[imports]): hoist has_gte_version and warnings
tony May 2, 2026
a5724c4
Server(fix[display_menu]): replace stub doctest with monkeypatched ar…
tony May 2, 2026
99346c8
Server(feat[display_menu]): add -H/-M/-O flag coverage
tony May 2, 2026
885ca7a
Pane(feat[display_popup]): add -B/-k/-N flag coverage
tony May 2, 2026
62bb44b
Server(feat[command_prompt]): add -e/-l/-F flag coverage
tony May 2, 2026
55d853e
Pane(feat[copy_mode]): add page_down (-d) and source_pane (-s)
tony May 2, 2026
7c7a6b3
Pane(feat[choose_tree]): expose -F/-f/-O/-r/-Z flags
tony May 2, 2026
80750a1
Pane(feat[capture_pane]): support -b to write into a tmux buffer
tony May 2, 2026
dc41a48
Server(feat[show_messages]): add -T (terminals) and -J (jobs) flags
tony May 2, 2026
bdd2df5
Server(feat[server_access]): add -r and -w flags for read-only/read-w…
tony May 2, 2026
199731a
docs(tmux-parity[skill]): update stale coverage claims
tony May 2, 2026
81bd9ac
docs(tmux-parity[plugin]): use console fences with $ prefix per AGENT…
tony May 2, 2026
b378728
test(session): drop duplicate test_detach_client
tony May 2, 2026
cd1cf68
test(server): fold test_buffer_append into BufferCase parametrisation
tony May 2, 2026
138517d
test(pane): consolidate capture_pane flag-smoke tests
tony May 2, 2026
ebb5672
docs(versionadded): annotate 55 new methods with 0.45
tony May 2, 2026
49f1d76
test(server[show_messages]): gate -T/-J clientless test on tmux 3.6+
tony May 3, 2026
9d9b670
ci(tests): disable matrix fail-fast
tony May 3, 2026
5d479be
test(server[command_prompt]): gate bspace_exit case on tmux 3.3+
tony May 3, 2026
87368a0
Server(fix[command_prompt]): gate bspace_exit on tmux 3.7+
tony May 3, 2026
6a14ffd
ControlMode(fix[__enter__]): close write fd if Popen raises
tony May 3, 2026
d7b9033
test(legacy_api[common]): bump next-version fixture to 3.8
tony May 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "tmux-parity",
"version": "0.1.0",
"description": "Analyze and close feature parity gaps between tmux C source and libtmux Python wrappers",
"author": {
"name": "libtmux contributors"
},
"repository": "https://github.com/tmux-python/libtmux",
"license": "MIT",
"keywords": ["tmux", "parity", "analysis", "code-generation"]
}
47 changes: 47 additions & 0 deletions .claude-plugin/scripts/extract-libtmux-methods.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Extract tmux command invocations from libtmux Python source
# Usage: extract-libtmux-methods.sh [libtmux-src-dir]
# Output: unique tmux command names invoked via .cmd() or as command args
#
# Searches for .cmd("command"), tmux_cmd(..., "command"), and
# args = ["command"] patterns that represent actual tmux command calls.

set -euo pipefail

LIBTMUX_DIR="${1:-$HOME/work/python/libtmux/src/libtmux}"

if [[ ! -d "$LIBTMUX_DIR" ]]; then
echo "Error: libtmux source dir not found at $LIBTMUX_DIR" >&2
exit 1
fi

echo "# Unique tmux commands invoked by libtmux"
{
# Pattern 1: self.cmd("command-name", ...) or .cmd("command-name")
grep -rn '\.cmd(' "$LIBTMUX_DIR"/*.py 2>/dev/null | \
grep -oP '\.cmd\(\s*"([a-z]+-[a-z-]+)"' | \
sed 's/.*"\(.*\)"/\1/'

# Pattern 2: args/cmd = ["command-name", ...] or args/cmd += ["command-name"]
grep -rn '\(args\|cmd\)\s*[+=]\+\s*\["[a-z]\+-' "$LIBTMUX_DIR"/*.py 2>/dev/null | \
grep -oP '\["([a-z]+-[a-z-]+)"' | \
tr -d '["'

# Pattern 3: tmux_args += ("command-name",) or tmux_args = ("command-name",)
grep -rn 'tmux_args\s*[+=]\+.*"[a-z]\+-' "$LIBTMUX_DIR"/*.py 2>/dev/null | \
grep -oP '"([a-z]+-[a-z-]+)"' | \
tr -d '"'

# Pattern 4: string literals in command-building contexts (hooks.py, options.py, common.py)
# Match lines with command strings used in args lists or cmd() calls
grep -rn '^\s*"[a-z]\+-[a-z-]*",' "$LIBTMUX_DIR"/*.py 2>/dev/null | \
grep -oP '"([a-z]+-[a-z-]+)"' | \
tr -d '"' | \
grep -E '^(capture|kill|move|select|set|show|split|clear)-'
} | sort -u

echo ""
echo "# Detailed: command|file:line"
grep -rn '\.cmd(\|args\s*[+=]\+\s*\["\|tmux_args\s*[+=]' "$LIBTMUX_DIR"/*.py 2>/dev/null | \
perl -ne 'if (/^(.+?):(\d+):.*"([a-z]+-[a-z]+-?[a-z]*)"/ && $3 =~ /^(attach|break|capture|choose|clear|clock|command|confirm|copy|customize|delete|detach|display|find|has|if|join|kill|last|link|list|load|lock|move|new|next|paste|pipe|previous|refresh|rename|resize|respawn|rotate|run|save|select|send|server|set|show|source|split|start|suspend|swap|switch|unbind|unlink|wait)-/) { print "$3|$1:$2\n" }' | \
sort
43 changes: 43 additions & 0 deletions .claude-plugin/scripts/extract-tmux-commands.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Extract tmux command entries from cmd-*.c files
# Usage: extract-tmux-commands.sh [tmux-source-dir]
# Output: command_name|alias|getopt_string|target_type
#
# Parses cmd_entry structs to enumerate all tmux commands with their
# flags and target types.

set -euo pipefail

TMUX_DIR="${1:-$HOME/study/c/tmux}"

if [[ ! -d "$TMUX_DIR" ]]; then
echo "Error: tmux source dir not found at $TMUX_DIR" >&2
exit 1
fi

# Process each cmd-*.c file (skip internal files)
for f in "$TMUX_DIR"/cmd-*.c; do
base=$(basename "$f" .c)
case "$base" in
cmd-parse|cmd-queue|cmd-find) continue ;;
esac

# Use perl for reliable multi-field extraction from cmd_entry structs
perl -0777 -ne '
while (/const\s+struct\s+cmd_entry\s+\w+\s*=\s*\{(.*?)\n\};/gs) {
my $block = $1;
my ($name, $alias, $args, $target) = ("", "-", "", "none");

$name = $1 if $block =~ /\.name\s*=\s*"([^"]+)"/;
$alias = $1 if $block =~ /\.alias\s*=\s*"([^"]+)"/;
$args = $1 if $block =~ /\.args\s*=\s*\{\s*"([^"]*)"/;

$target = "pane" if $block =~ /CMD_FIND_PANE/;
$target = "window" if $block =~ /CMD_FIND_WINDOW/;
$target = "session" if $block =~ /CMD_FIND_SESSION/;
$target = "client" if $block =~ /CMD_FIND_CLIENT/;

print "$name|$alias|$args|$target\n" if $name;
}
' "$f"
done | sort
137 changes: 137 additions & 0 deletions .claude/agents/parity-analyzer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
name: parity-analyzer
description: |
Use this agent when the user asks about "tmux parity", "what commands are missing", "coverage report", "what does libtmux wrap", "unwrapped commands", "missing tmux features", "does libtmux support X", "tmux feature coverage", or when the user wants to understand what tmux functionality libtmux does not yet expose.

<example>
Context: User wants to know parity status
user: "What tmux commands does libtmux not wrap yet?"
assistant: "I'll use the parity-analyzer agent to scan tmux source and cross-reference with libtmux."
<commentary>User asking about missing commands, trigger parity analysis.</commentary>
</example>

<example>
Context: User considering what to implement next
user: "Which unwrapped tmux commands would be most useful to add?"
assistant: "I'll use the parity-analyzer agent to analyze coverage and prioritize gaps."
<commentary>User wants prioritized gap analysis, trigger parity-analyzer.</commentary>
</example>

<example>
Context: User asks about specific command
user: "Does libtmux support break-pane?"
assistant: "I'll check with the parity-analyzer agent."
<commentary>Specific command inquiry, use parity-analyzer for accurate answer.</commentary>
</example>

<example>
Context: User working on parity branch
user: "What should I work on next for tmux parity?"
assistant: "I'll use the parity-analyzer agent to identify the highest-priority gaps."
<commentary>Planning parity work, trigger analysis for prioritization.</commentary>
</example>
model: sonnet
color: cyan
tools:
- Read
- Grep
- Glob
- Bash
---

You are a tmux/libtmux feature parity analysis specialist. Analyze the gap between tmux C source and libtmux Python wrappers.

## Source Locations

- **tmux C source (HEAD)**: ~/study/c/tmux/
- **tmux version worktrees**: ~/study/c/tmux-{version}/ (41 versions, 0.8 to 3.6a)
- **libtmux Python source**: src/libtmux/ (in the current project)

## Analysis Process

### Step 1: Extract tmux commands

Run the extraction script for current data:

```console
$ bash .claude-plugin/scripts/extract-tmux-commands.sh ~/study/c/tmux
```

This outputs `command|alias|getopt|target` for every tmux command.

### Step 2: Extract libtmux coverage

Run the libtmux extraction:

```console
$ bash .claude-plugin/scripts/extract-libtmux-methods.sh
```

This outputs the unique tmux command strings that libtmux invokes.

Additionally, check mixin files for commands invoked via `tmux_cmd()`:

```console
$ grep -rn '"set-environment"\|"show-environment"\|"set-hook"\|"set-option"\|"show-option"\|"capture-pane"\|"move-window"\|"select-layout"\|"kill-pane"' src/libtmux/*.py | grep -oP '"([a-z]+-[a-z-]+)"' | sort -u | tr -d '"'
```

### Step 3: Cross-reference

Classify each tmux command:
- **Wrapped**: Command string appears in libtmux source
- **Not Wrapped**: Command string does not appear

For wrapped commands, optionally compare the getopt string from tmux against the Python method parameters to identify missing flags.

### Step 4: Produce report

Output a structured report:

```markdown
## tmux/libtmux Parity Report

### Summary
- Total tmux commands: X
- Wrapped in libtmux: Y (Z%)
- Not wrapped: N

### Wrapped Commands
| Command | libtmux Location |

### Not Wrapped — High Priority
| Command | Alias | Target | Why Useful |
(Include: join-pane, swap-pane, swap-window, respawn-pane, respawn-window, run-shell, break-pane, move-pane, pipe-pane, display-popup, clear-history)

### Not Wrapped — Medium Priority
| Command | Alias | Target | Notes |
(Include: navigation commands, buffer management, wait-for, if-shell, detach-client)

### Not Wrapped — Low Priority
| Command | Alias | Target | Notes |
(Include: interactive UI commands, key bindings, lock commands, config commands)
```

### Priority Guidelines

**High priority** — Commands useful for programmatic tmux control and automation:
- Pane/window manipulation: join-pane, swap-pane, swap-window, break-pane, move-pane
- Process management: respawn-pane, respawn-window, run-shell
- I/O: pipe-pane, clear-history, display-popup

**Medium priority** — Navigation, buffers, and client management:
- Navigation: last-pane, last-window, next-window, previous-window
- Buffer ops: list-buffers, load-buffer, save-buffer, paste-buffer, set-buffer
- Window linking: link-window, unlink-window
- Synchronization: wait-for
- Conditional: if-shell

**Low priority** — Interactive UI and configuration (rarely needed in API):
- Interactive: choose-tree, choose-buffer, copy-mode, command-prompt
- Key binding: bind-key, unbind-key
- Security: lock-server, lock-session, lock-client
- Meta: list-commands, list-keys, show-messages
- Config: source-file, start-server

## Reference Data

The baseline command mapping is at `skills/tmux-parity/references/command-mapping.md`. Use this as a starting point, but always run the extraction scripts for the most current data.
131 changes: 131 additions & 0 deletions .claude/commands/implement-command.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
description: Guide implementing a new tmux command wrapper in libtmux
argument-hint: "<tmux-command-name> — e.g., 'break-pane', 'join-pane', 'swap-window'"
allowed-tools:
- Read
- Write
- Edit
- Grep
- Glob
- Bash
- AskUserQuestion
- Agent
---

# Implement Command

Guide wrapping a tmux command in libtmux, following project coding standards from CLAUDE.md.

Load the `tmux-parity` skill first for reference data and implementation patterns.

If `$ARGUMENTS` is empty, ask the user which tmux command to wrap. Consult `skills/tmux-parity/references/command-mapping.md` for the "Not Wrapped" list to suggest candidates.

## Phase 1: Analyze the tmux Command

1. Read `~/study/c/tmux/cmd-{command}.c` fully
2. Extract from the `cmd_entry` struct:
- **name** and **alias**
- **getopt string** — enumerate all flags, which take values, which are boolean
- **usage string** — human-readable flag descriptions
- **target type** — `CMD_FIND_PANE`, `CMD_FIND_WINDOW`, `CMD_FIND_SESSION`, or none
- **command flags** — `CMD_READONLY`, `CMD_AFTERHOOK`, etc.
3. Read the `exec` function to understand:
- What arguments it processes
- What side effects it has (creates objects, modifies state, produces output)
- What it returns or prints
- Error conditions

4. Present a summary to the user:
```
## tmux command: {name} ({alias})
Target: {pane|window|session|none} → libtmux class: {Pane|Window|Session|Server}
Flags: {table of flags with descriptions}
Behavior: {what the command does}
```

## Phase 2: Determine libtmux Placement

Map the target type to libtmux class:
| Target | Primary Class | File |
|--------|--------------|------|
| `CMD_FIND_PANE` | `Pane` | `src/libtmux/pane.py` |
| `CMD_FIND_WINDOW` | `Window` | `src/libtmux/window.py` |
| `CMD_FIND_SESSION` | `Session` | `src/libtmux/session.py` |
| none | `Server` | `src/libtmux/server.py` |

Some commands may also get convenience methods on parent classes. Ask the user if they want additional convenience methods.

## Phase 3: Find a Similar Implementation

Search libtmux for a wrapped command with similar characteristics:
- Same target type
- Similar flag pattern (boolean flags, value flags, creates objects, etc.)
- Read that method as a template

Consult `skills/tmux-parity/references/libtmux-patterns.md` for the five implementation patterns.

## Phase 4: Design the Method Signature

Present a proposed method signature to the user before implementing. Include:
- Method name (snake_case, derived from tmux command name)
- Parameters mapped from tmux flags (with Python-friendly names and types)
- Return type
- Which flags to include (not all flags need wrapping — ask user about ambiguous ones)

**This is a good point to ask the user to write the method signature and core logic (5-10 lines).** Present the trade-offs:
- Which flags to expose (all vs. commonly used)?
- Return type (Self vs. new object vs. None)?
- Naming conventions for parameters?

## Phase 5: Implement

Follow CLAUDE.md coding standards strictly:

1. **Imports**: `from __future__ import annotations`, `import typing as t`
2. **Method**: Add to the appropriate class file
3. **Docstring**: NumPy format with Parameters, Returns, Examples sections
4. **Doctests**: Working doctests using `doctest_namespace` fixtures (`server`, `session`, `window`, `pane`)
- Use `# doctest: +ELLIPSIS` for variable output
- NEVER use `# doctest: +SKIP`
5. **Logging**: `logger.info("descriptive msg", extra={"tmux_subcommand": "...", ...})`
6. **Error handling**: Check `proc.stderr`, raise `exc.LibTmuxException`

## Phase 6: Create Tests

Add tests in `tests/test_{class}.py` (or a new file if warranted):

1. **Functional tests only** — no test classes
2. **Use fixtures**: `server`, `session`, `window`, `pane` from conftest.py
3. **Test each parameter/flag** combination
4. **Test error cases** if applicable
5. **Use descriptive function names**: `test_{command}_{scenario}`

## Phase 7: Verify

Run the full verification workflow:

```console
$ uv run ruff format .
```

```console
$ uv run ruff check . --fix --show-fixes
```

```console
$ uv run mypy src tests
```

```console
$ uv run pytest tests/test_{class}.py -x -v
```

```console
$ uv run pytest --doctest-modules src/libtmux/{class}.py -v
```

```console
$ uv run pytest
```

All must pass before considering the implementation complete.
Loading
Loading