copa-cli 0.7.1__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {copa_cli-0.7.1 → copa_cli-0.9.0}/PKG-INFO +273 -158
  2. copa_cli-0.9.0/README.md +819 -0
  3. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/cli.py +2 -1
  4. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/cli_internal.py +52 -5
  5. copa_cli-0.9.0/copa/cli_recipe.py +196 -0
  6. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/config.py +38 -58
  7. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/copa.zsh +160 -54
  8. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/db.py +154 -11
  9. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/fzf.py +39 -1
  10. copa_cli-0.9.0/copa/mcp_server.py +321 -0
  11. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/models.py +72 -1
  12. copa_cli-0.9.0/copa/scoring.py +73 -0
  13. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/sharing.py +23 -1
  14. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa_cli.egg-info/PKG-INFO +273 -158
  15. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa_cli.egg-info/SOURCES.txt +1 -0
  16. {copa_cli-0.7.1 → copa_cli-0.9.0}/pyproject.toml +1 -1
  17. {copa_cli-0.7.1 → copa_cli-0.9.0}/tests/test_modal.py +64 -82
  18. copa_cli-0.7.1/README.md +0 -704
  19. copa_cli-0.7.1/copa/mcp_server.py +0 -159
  20. copa_cli-0.7.1/copa/scoring.py +0 -45
  21. {copa_cli-0.7.1 → copa_cli-0.9.0}/LICENSE +0 -0
  22. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/__init__.py +0 -0
  23. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/__main__.py +0 -0
  24. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/cli_common.py +0 -0
  25. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/cli_llm.py +0 -0
  26. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/cli_share.py +0 -0
  27. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/evolve.py +0 -0
  28. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/history.py +0 -0
  29. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/llm.py +0 -0
  30. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa/scanner.py +0 -0
  31. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa_cli.egg-info/dependency_links.txt +0 -0
  32. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa_cli.egg-info/entry_points.txt +0 -0
  33. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa_cli.egg-info/requires.txt +0 -0
  34. {copa_cli-0.7.1 → copa_cli-0.9.0}/copa_cli.egg-info/top_level.txt +0 -0
  35. {copa_cli-0.7.1 → copa_cli-0.9.0}/setup.cfg +0 -0
  36. {copa_cli-0.7.1 → copa_cli-0.9.0}/tests/test_cli_and_sharing.py +0 -0
  37. {copa_cli-0.7.1 → copa_cli-0.9.0}/tests/test_db.py +0 -0
  38. {copa_cli-0.7.1 → copa_cli-0.9.0}/tests/test_fzf.py +0 -0
  39. {copa_cli-0.7.1 → copa_cli-0.9.0}/tests/test_models.py +0 -0
  40. {copa_cli-0.7.1 → copa_cli-0.9.0}/tests/test_polish.py +0 -0
  41. {copa_cli-0.7.1 → copa_cli-0.9.0}/tests/test_scanner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: copa-cli
3
- Version: 0.7.1
3
+ Version: 0.9.0
4
4
  Summary: Command Palette — smart command tracking, ranking, and sharing for your shell
5
5
  Author: Mark Stanford
6
6
  License-Expression: MIT
@@ -36,12 +36,14 @@ Dynamic: license-file
36
36
 
37
37
  Copa tracks the commands you run, ranks them by frequency and recency, and gives you instant fuzzy search via fzf. Think of it as a smart, searchable, shareable upgrade to shell history.
38
38
 
39
+ ![Copa Demo](demos/00-hero.gif)
40
+
39
41
  ## Features
40
42
 
41
- - **Smart ranking** — commands scored by `2*log(1+freq) + 8*0.5^(age/3d)`, so frequent *and* recent commands float to the top
43
+ - **Smart ranking** — commands scored by `2*log(1+freq) + 8*0.5^(age/3d)`, so frequent _and_ recent commands float to the top
42
44
  - **FTS search** — full-text search across commands and their descriptions
43
- - **fzf integration** — Ctrl+R opens a fuzzy-searchable command palette with preview pane; searches across commands *and* their descriptions
44
- - **Tab completion** — Copa supplements zsh's tab completion for *any* command using your command history database
45
+ - **fzf integration** — Ctrl+R opens a fuzzy-searchable command palette with preview pane; searches across commands _and_ their descriptions
46
+ - **Tab completion** — Copa supplements zsh's tab completion for _any_ command using your command history database
45
47
  - **Auto-evolution** — `copa evolve` finds your most-used commands from zsh history and promotes them
46
48
  - **LLM descriptions** — `copa fix --auto` uses Claude or ollama to generate descriptions for undescribed commands
47
49
  - **Script protocol** — `#@ Description:` / `#@ Usage:` / `#@ Purpose:` / `#@ Flag:` headers in your scripts are auto-detected by `copa scan` across all `$PATH` directories
@@ -49,6 +51,8 @@ Copa tracks the commands you run, ranks them by frequency and recency, and gives
49
51
  - **Inline suggestions** — ghost text appears as you type; Tab accepts or opens a completion menu with the suggestion highlighted
50
52
  - **Groups & Ctrl+G** — organize commands by project, device, or workflow; assign groups inline from the fzf palette with Ctrl+G
51
53
  - **Bulk operations** — Ctrl+B enters select mode for batch group assignment, batch deletion, or batch LLM description
54
+ - **Recipes** — save multi-step command sequences as named recipes; `copa recipe run deploy` executes steps sequentially; share recipes via `.copa` files
55
+ - **Directory-aware suggestions** — commands used in the current directory are boosted in suggestions; automatic, configurable, zero-effort
52
56
  - **Sharing & `copa create`** — export/import command sets as `.copa` JSON files; `copa create` scaffolds a `.copa` file from an existing group
53
57
  - **Set filtering** — scope list, search, and fzf to a specific shared set with `--set`
54
58
  - **MCP server** — expose your commands to Claude Code (or any MCP client)
@@ -96,6 +100,7 @@ copa setup
96
100
  ```
97
101
 
98
102
  This walks you through everything:
103
+
99
104
  1. Checks that **fzf** is installed (tells you how to install if missing)
100
105
  2. Creates the Copa database (`~/.copa/copa.db`)
101
106
  3. Adds shell integration to your `~/.zshrc` (prompts for confirmation)
@@ -134,6 +139,8 @@ copa sync
134
139
 
135
140
  Once shell integration is sourced, pressing **Ctrl+R** opens an fzf-powered command palette instead of the default zsh reverse search. This is Copa's primary interface.
136
141
 
142
+ ![Ctrl+R Palette](demos/04-ctrl-r-palette.gif)
143
+
137
144
  ### What you see
138
145
 
139
146
  Copa pipes every tracked command into fzf with aligned columns:
@@ -152,38 +159,41 @@ This is the key difference from plain zsh Ctrl+R: you're not just searching raw
152
159
 
153
160
  The header shows available modes. Press **Ctrl+R** again while fzf is open to cycle:
154
161
 
155
- | Mode | Sort order | Use case |
156
- |------|-----------|----------|
157
- | `all` | Score (frequency + recency) | Default — best commands float to top |
158
- | `frequent` | Frequency only | Find your most-used commands |
159
- | `recent` | Last used time | Find commands you ran recently |
162
+ | Mode | Sort order | Use case |
163
+ | ---------- | --------------------------- | ------------------------------------ |
164
+ | `all` | Score (frequency + recency) | Default — best commands float to top |
165
+ | `frequent` | Frequency only | Find your most-used commands |
166
+ | `recent` | Last used time | Find commands you ran recently |
167
+ | `recipes` | Run count | Browse and run multi-step recipes |
160
168
 
161
169
  ### Keybindings
162
170
 
163
171
  While the fzf palette is open, these keys are available:
164
172
 
165
- | Key | Action | Effect |
166
- |-----|--------|--------|
167
- | **Ctrl+R** | Cycle mode | all → frequent → recent → all |
168
- | **Ctrl+V** | Append `&` | Run selected command in background |
169
- | **Ctrl+O** | Append `2>&1` | Merge stderr into stdout |
170
- | **Ctrl+X** | Append `\|` | Pipe into next command |
171
- | **Ctrl+T** | Append `>` | Redirect output |
172
- | **Ctrl+A** | Append `&&` | Chain with next command |
173
- | **Ctrl+/** | Append `2>/dev/null` | Suppress stderr |
174
- | **Ctrl+S** | Scope by group | Opens inline group list — Enter filters to that group, ESC returns to all |
175
- | **Ctrl+G** | Assign group | Opens inline group list — Enter assigns the group to the highlighted command |
176
- | **Ctrl+N** | Cycle group | Cycles through groups: (all) → group1 → group2 → ... → (all) |
177
- | **Ctrl+D** | Describe | Generate/edit a description using LLM (with tty-aware input) |
178
- | **Ctrl+F** | Edit flags | Add flag documentation to the highlighted command |
179
- | **Ctrl+B** | Select mode | Enter multi-select for bulk operations (see below) |
180
- | **Ctrl+H** | Toggle header | Show/hide the key hints for more screen space |
181
- | **ESC** | Cancel/back | In scope/group mode: returns to command list. Otherwise: closes fzf |
173
+ | Key | Action | Effect |
174
+ | ---------- | -------------------- | ---------------------------------------------------------------------------- |
175
+ | **Ctrl+R** | Cycle mode | all → frequent → recent → recipes → all |
176
+ | **Ctrl+X** | Compose | Opens a numbered menu to append shell operators (`\|`, `&&`, `>`, `&`, etc.) |
177
+ | **Ctrl+S** | Scope by group | Opens inline group list — Enter filters to that group, ESC returns to all |
178
+ | **Ctrl+G** | Assign group | Opens inline group list — Enter assigns the group to the highlighted command |
179
+
180
+ ![Groups and Scoping](demos/05-groups-and-scoping.gif)
181
+
182
+ | Key | Action | Effect |
183
+ | ---------- | ------------- | ------------------------------------------------------------------- |
184
+ | **Ctrl+N** | Cycle group | Cycles through groups: (all) → group1 → group2 → ... → (all) |
185
+ | **Ctrl+D** | Describe | Generate/edit a description using LLM (with tty-aware input) |
186
+ | **Ctrl+F** | Edit flags | Add flag documentation to the highlighted command |
187
+ | **Ctrl+B** | Select mode | Enter multi-select for bulk operations (see below) |
188
+ | **Ctrl+H** | Toggle header | Show/hide the key hints for more screen space |
189
+ | **ESC** | Cancel/back | In scope/group mode: returns to command list. Otherwise: closes fzf |
182
190
 
183
191
  Keybindings are configurable via `~/.copa/config.toml`. See [Configuration](#configuration).
184
192
 
185
193
  ### Select mode (bulk operations)
186
194
 
195
+ ![Bulk Operations](demos/06-bulk-operations.gif)
196
+
187
197
  Press **Ctrl+B** from the Ctrl+R palette to enter **select mode**. This opens a new fzf view with multi-select enabled:
188
198
 
189
199
  - **Tab** toggles selection on individual commands
@@ -202,11 +212,11 @@ Selected 5 command(s).
202
212
  Action:
203
213
  ```
204
214
 
205
- | Action | What it does |
206
- |--------|-------------|
207
- | **g** | Assign all selected commands to a group (or clear their group) |
208
- | **d** | Delete all selected commands (with confirmation) |
209
- | **a** | Auto-generate descriptions for all selected commands using your configured LLM backend |
215
+ | Action | What it does |
216
+ | ------ | -------------------------------------------------------------------------------------- |
217
+ | **g** | Assign all selected commands to a group (or clear their group) |
218
+ | **d** | Delete all selected commands (with confirmation) |
219
+ | **a** | Auto-generate descriptions for all selected commands using your configured LLM backend |
210
220
 
211
221
  This is useful for organizing large command sets — select 20 undescribed commands and batch-describe them, or move a set of related commands into a group in one step.
212
222
 
@@ -220,18 +230,22 @@ Selecting a command places it directly into your shell prompt (without executing
220
230
 
221
231
  ## Tab Completion
222
232
 
233
+ ![Tab Menu Select](demos/03-tab-menu-select.gif)
234
+
223
235
  Copa supplements zsh's built-in tab completion for **any** command — not just Copa's own CLI. Once `copa.zsh` is sourced, Copa registers as a completer in zsh's completion system.
224
236
 
225
237
  ### Completion modes
226
238
 
239
+ ![Completion Modes](demos/10-completion-modes.gif)
240
+
227
241
  Copa supports four completion modes, configured via `~/.copa/config.toml`:
228
242
 
229
- | Mode | Behavior |
230
- |------|----------|
243
+ | Mode | Behavior |
244
+ | ---------- | ----------------------------------------------------------------------------- |
231
245
  | `fallback` | **(default)** Only show Copa completions when native completers found nothing |
232
- | `hybrid` | Show Copa completions alongside native completions (in a separate group) |
233
- | `always` | Copa completions replace native completions |
234
- | `never` | Disable Copa tab completion entirely |
246
+ | `hybrid` | Show Copa completions alongside native completions (in a separate group) |
247
+ | `always` | Copa completions replace native completions |
248
+ | `never` | Disable Copa tab completion entirely |
235
249
 
236
250
  ```toml
237
251
  # ~/.copa/config.toml
@@ -269,6 +283,10 @@ Copa's own CLI completions (`copa li<TAB>` → `list`) continue to work as befor
269
283
 
270
284
  ## Inline Suggestions (Ghost Text)
271
285
 
286
+ | Tab Mode 1 (direct accept) | Tab Mode 2 (menu select, default) |
287
+ | -------------------------------------------------- | -------------------------------------------------- |
288
+ | ![Tab Mode 1](demos/02a-suggestions-tab-mode1.gif) | ![Tab Mode 2](demos/02b-suggestions-tab-mode2.gif) |
289
+
272
290
  Copa shows grey ghost text after your cursor as you type — the best matching command from your database, ranked by frequency and recency. This works like fish shell's autosuggestions or zsh-autosuggestions, with zero plugin dependencies.
273
291
 
274
292
  ### How it works
@@ -281,43 +299,49 @@ $ git pu█sh origin main ← grey ghost text
281
299
 
282
300
  ### Keybindings
283
301
 
284
- | Key | Suggestion showing | No suggestion |
285
- |-----|-------------------|---------------|
286
- | Type chars | Insert char, re-fetch suggestion | Insert char, fetch suggestion |
287
- | Backspace | Delete char, **latch** (suppress suggestions) | Delete char normally |
288
- | **Tab** | `tab_accept=1`: accept full suggestion. `tab_accept=2` (default): open completion menu with suggestion highlighted at top, native completions below | If latched: unlatch + re-fetch suggestion. Else: normal tab completion |
289
- | **Down** | Open completion menu with suggestion highlighted at top | History navigation |
290
- | **Right arrow** | Accept one word, re-fetch | Move cursor right |
291
- | Enter | Clear suggestion, execute | Execute |
292
- | Esc | Dismiss suggestion | Normal Esc |
293
- | Up | Clear suggestion, navigate history | History navigation |
294
- | Ctrl+R | Clear suggestion, open fzf | Open fzf |
302
+ | Key | Suggestion showing | No suggestion |
303
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
304
+ | Type chars | Insert char, re-fetch suggestion | Insert char, fetch suggestion |
305
+ | Backspace | Delete char, **latch** (suppress suggestions) | Delete char normally |
306
+ | **Tab** | `tab_accept=1`: accept full suggestion. `tab_accept=2` (default): open completion menu with suggestion highlighted at top, native completions below | If latched: unlatch + re-fetch suggestion. Else: normal tab completion |
307
+ | **Down** | Open completion menu with suggestion highlighted at top | History navigation |
308
+ | **Right arrow** | Accept one word, re-fetch | Move cursor right |
309
+ | **Cmd+Right / End** | Accept full suggestion | Move to end of line |
310
+ | Enter | Clear suggestion, execute | Execute |
311
+ | Esc | Dismiss suggestion | Normal Esc |
312
+ | Up | Clear suggestion, navigate history | History navigation |
313
+ | Ctrl+R | Clear suggestion, open fzf | Open fzf |
295
314
 
296
315
  ### Tab accept mode
297
316
 
298
317
  Copa supports two Tab behaviors when a suggestion is showing:
299
318
 
300
319
  **Menu select** (`tab_accept = 2`, default):
320
+
301
321
  1. Press **Tab** — ghost text clears, a completion menu opens with the Copa suggestion highlighted at the top, alongside native completions below
302
- 2. Press **Tab** or **Space** accepts the highlighted item
303
- 3. Press **Escape** — cancels the menu, restores your original text
304
- 4. Use **arrow keys** to navigate if you want a different completion
322
+ 2. Press **Tab** to cycle through options, **Shift+Tab** to cycle backward
323
+ 3. Press **Enter** or **Space** accepts the highlighted item
324
+ 4. Press **Escape** cancels the menu, restores your original text
325
+ 5. Use **arrow keys** to navigate if you want a different completion
305
326
 
306
327
  This gives you a chance to see alternatives before committing. The Copa suggestion is always the first item in the menu.
307
328
 
308
329
  **Inline accept** (`tab_accept = 1`):
330
+
309
331
  - Press **Tab** — the suggestion is accepted directly into your command line. One keystroke, done.
310
332
 
311
333
  ### Completion menu navigation
312
334
 
313
335
  When the completion menu is open (from Tab in `tab_accept = 2` mode or from normal tab completion):
314
336
 
315
- | Key | Action |
316
- |-----|--------|
317
- | **Tab** | Accept the highlighted completion |
318
- | **Space** | Accept the highlighted completion |
319
- | **Escape** | Cancel dismiss menu, restore original text |
320
- | **Arrow keys** | Navigate between completions |
337
+ | Key | Action |
338
+ | -------------- | -------------------------------------------- |
339
+ | **Tab** | Cycle forward through completions |
340
+ | **Shift+Tab** | Cycle backward through completions |
341
+ | **Enter** | Accept the highlighted completion (no trailing space added) |
342
+ | **Space** | Accept the highlighted completion and add a space |
343
+ | **Escape** | Cancel — dismiss menu, restore original text |
344
+ | **Arrow keys** | Navigate between completions |
321
345
 
322
346
  ### Backspace latch
323
347
 
@@ -441,6 +465,8 @@ copa describe 42
441
465
 
442
466
  Generates a description for a specific command by ID. Same accept/edit flow as `fix --auto`.
443
467
 
468
+ ![Flags and Describe](demos/09-flags-and-describe.gif)
469
+
444
470
  ## Script Metadata Protocol
445
471
 
446
472
  Copa recognizes `#@` headers in script files (checked in the first 50 lines):
@@ -470,12 +496,12 @@ Flags:
470
496
 
471
497
  ### Supported headers
472
498
 
473
- | Header | Effect |
474
- |--------|--------|
475
- | `#@ Description: <text>` | Sets the command description (highest priority) |
476
- | `#@ Usage: <text>` | Usage / invocation syntax |
477
- | `#@ Purpose: <text>` | Why the script exists / when to use it |
478
- | `#@ Flag: <flag>: <description>` | Document a flag/option (repeatable) |
499
+ | Header | Effect |
500
+ | -------------------------------- | ----------------------------------------------- |
501
+ | `#@ Description: <text>` | Sets the command description (highest priority) |
502
+ | `#@ Usage: <text>` | Usage / invocation syntax |
503
+ | `#@ Purpose: <text>` | Why the script exists / when to use it |
504
+ | `#@ Flag: <flag>: <description>` | Document a flag/option (repeatable) |
479
505
 
480
506
  Scripts without `#@` headers still work — Copa falls back to legacy patterns (`# Description:`, `# Purpose:`, Python docstrings, generic comments).
481
507
 
@@ -488,6 +514,8 @@ copa scan --dir ~/bin # scan a specific directory
488
514
 
489
515
  ## Sharing
490
516
 
517
+ ![Sharing](demos/07-sharing.gif)
518
+
491
519
  Export a group as a `.copa` file:
492
520
 
493
521
  ```bash
@@ -510,25 +538,25 @@ copa share sync /path/to/team/copa-files/
510
538
 
511
539
  Copa ships with ready-to-use `.copa` files in the [`examples/`](examples/) directory:
512
540
 
513
- | File | Description |
514
- |------|-------------|
515
- | [`git.copa`](examples/git.copa) | Essential Git commands |
516
- | [`docker.copa`](examples/docker.copa) | Docker container management |
517
- | [`python-dev.copa`](examples/python-dev.copa) | Python development workflow |
518
- | [`npm.copa`](examples/npm.copa) | Node.js package management |
519
- | [`network.copa`](examples/network.copa) | Network diagnostics |
520
- | [`curl-http.copa`](examples/curl-http.copa) | HTTP requests and API testing |
521
- | [`ssh-remote.copa`](examples/ssh-remote.copa) | SSH, SCP, and remote server management |
522
- | [`adb.copa`](examples/adb.copa) | Android Debug Bridge |
523
- | [`aws.copa`](examples/aws.copa) | AWS CLI cloud infrastructure |
524
- | [`terraform.copa`](examples/terraform.copa) | Terraform infrastructure-as-code |
525
- | [`k8s.copa`](examples/k8s.copa) | Kubernetes cluster management |
526
- | [`systemd.copa`](examples/systemd.copa) | Linux service management |
527
- | [`sysadmin.copa`](examples/sysadmin.copa) | System administration |
528
- | [`process-monitoring.copa`](examples/process-monitoring.copa) | Process management and debugging |
529
- | [`disk-files.copa`](examples/disk-files.copa) | Disk usage and file management |
530
- | [`tmux.copa`](examples/tmux.copa) | Terminal multiplexer sessions |
531
- | [`homebrew.copa`](examples/homebrew.copa) | Homebrew package manager (macOS) |
541
+ | File | Description |
542
+ | ------------------------------------------------------------- | -------------------------------------- |
543
+ | [`git.copa`](examples/git.copa) | Essential Git commands |
544
+ | [`docker.copa`](examples/docker.copa) | Docker container management |
545
+ | [`python-dev.copa`](examples/python-dev.copa) | Python development workflow |
546
+ | [`npm.copa`](examples/npm.copa) | Node.js package management |
547
+ | [`network.copa`](examples/network.copa) | Network diagnostics |
548
+ | [`curl-http.copa`](examples/curl-http.copa) | HTTP requests and API testing |
549
+ | [`ssh-remote.copa`](examples/ssh-remote.copa) | SSH, SCP, and remote server management |
550
+ | [`adb.copa`](examples/adb.copa) | Android Debug Bridge |
551
+ | [`aws.copa`](examples/aws.copa) | AWS CLI cloud infrastructure |
552
+ | [`terraform.copa`](examples/terraform.copa) | Terraform infrastructure-as-code |
553
+ | [`k8s.copa`](examples/k8s.copa) | Kubernetes cluster management |
554
+ | [`systemd.copa`](examples/systemd.copa) | Linux service management |
555
+ | [`sysadmin.copa`](examples/sysadmin.copa) | System administration |
556
+ | [`process-monitoring.copa`](examples/process-monitoring.copa) | Process management and debugging |
557
+ | [`disk-files.copa`](examples/disk-files.copa) | Disk usage and file management |
558
+ | [`tmux.copa`](examples/tmux.copa) | Terminal multiplexer sessions |
559
+ | [`homebrew.copa`](examples/homebrew.copa) | Homebrew package manager (macOS) |
532
560
 
533
561
  Load any of them:
534
562
 
@@ -569,29 +597,96 @@ alias copa-bt='copa fzf-list --set bluetooth | fzf'
569
597
 
570
598
  ```json
571
599
  {
572
- "copa_version": "1.0",
573
- "name": "bluetooth",
574
- "description": "Bluetooth commands for Android devices",
575
- "author": "markstanford",
576
- "commands": [
577
- {
578
- "command": "adb shell cmd bluetooth_manager enable",
579
- "description": "Enable Bluetooth",
580
- "tags": ["bt", "android"]
581
- },
582
- {
583
- "command": "flash_all",
584
- "description": "Flash AOSP build to device",
585
- "tags": ["aosp"],
586
- "flags": {
587
- "-w, --wipe": "Wipe userdata before flashing",
588
- "--skip <parts>": "Skip specific partitions"
589
- }
590
- }
591
- ]
600
+ "copa_version": "1.0",
601
+ "name": "bluetooth",
602
+ "description": "Bluetooth commands for Android devices",
603
+ "author": "markstanford",
604
+ "commands": [
605
+ {
606
+ "command": "adb shell cmd bluetooth_manager enable",
607
+ "description": "Enable Bluetooth",
608
+ "tags": ["bt", "android"]
609
+ },
610
+ {
611
+ "command": "flash_all",
612
+ "description": "Flash AOSP build to device",
613
+ "tags": ["aosp"],
614
+ "flags": {
615
+ "-w, --wipe": "Wipe userdata before flashing",
616
+ "--skip <parts>": "Skip specific partitions"
617
+ }
618
+ }
619
+ ],
620
+ "recipes": [
621
+ {
622
+ "name": "bt-debug",
623
+ "description": "Enable BT and start logging",
624
+ "steps": [
625
+ {"command": "adb shell cmd bluetooth_manager enable", "description": "Enable BT"},
626
+ {"command": "adb logcat -s bt_btif | tee bt.log", "description": "Start BT logging"}
627
+ ]
628
+ }
629
+ ]
592
630
  }
593
631
  ```
594
632
 
633
+ ## Recipes
634
+
635
+ ![Recipes Demo](demos/12-recipes.gif)
636
+
637
+ Recipes are named, ordered sequences of commands — like a script, but tracked and shareable through Copa.
638
+
639
+ ### Creating recipes
640
+
641
+ ```bash
642
+ # Simple recipe
643
+ copa recipe add deploy \
644
+ -s 'npm run build' \
645
+ -s 'docker build -t app .' \
646
+ -s 'docker push app'
647
+
648
+ # With descriptions (use :: separator)
649
+ copa recipe add deploy \
650
+ -d "Full production deploy" \
651
+ -g devops \
652
+ -s 'npm run build :: Build the project' \
653
+ -s 'npm run test :: Run test suite' \
654
+ -s 'docker push app :: Push to registry'
655
+ ```
656
+
657
+ ### Running recipes
658
+
659
+ ```bash
660
+ # Run all steps sequentially
661
+ copa recipe run deploy
662
+
663
+ # Preview without executing
664
+ copa recipe run deploy --dry-run
665
+
666
+ # Continue past failures
667
+ copa recipe run deploy --no-stop-on-error
668
+ ```
669
+
670
+ ### Managing recipes
671
+
672
+ ```bash
673
+ copa recipe list # List all recipes
674
+ copa recipe list --json # JSON output
675
+ copa recipe show deploy # Show steps
676
+ copa recipe remove deploy # Delete a recipe
677
+ ```
678
+
679
+ ### Sharing recipes
680
+
681
+ Recipes are included in `.copa` files automatically — when you export a group, its recipes come along:
682
+
683
+ ```bash
684
+ copa share export devops -o devops.copa # includes recipes in that group
685
+ copa share load devops.copa # imports commands AND recipes
686
+ ```
687
+
688
+ See `examples/docker.copa` and `examples/deploy.copa` for recipe examples.
689
+
595
690
  ## MCP Server (Claude Code integration)
596
691
 
597
692
  Copa includes an MCP server so Claude Code can search and add commands.
@@ -606,24 +701,37 @@ Add to your Claude Code MCP config (`.mcp.json` in your project or home dir):
606
701
 
607
702
  ```json
608
703
  {
609
- "mcpServers": {
610
- "copa": {
611
- "command": "python3",
612
- "args": ["-m", "copa.mcp_server"]
613
- }
704
+ "mcpServers": {
705
+ "copa": {
706
+ "command": "python3",
707
+ "args": ["-m", "copa.mcp_server"]
614
708
  }
709
+ }
615
710
  }
616
711
  ```
617
712
 
618
713
  Available MCP tools:
714
+
619
715
  - `copa_search` — search commands by keyword
620
716
  - `copa_list_commands` — list commands ranked by score
621
717
  - `copa_list_groups` — list all groups
622
718
  - `copa_get_stats` — usage statistics
623
719
  - `copa_add_command` — add a command
624
720
  - `copa_update_description` — update a description
721
+ - `copa_delete_command` — delete a command by ID
722
+ - `copa_set_group` — set or change a command's group
723
+ - `copa_update_flags` — update flag documentation for a command
724
+ - `copa_pin_command` — pin or unpin a command
625
725
  - `copa_create_group` — create a group with commands
626
726
  - `copa_bulk_add` — bulk add commands
727
+ - `copa_share_load` — load a .copa file as a shared set
728
+ - `copa_share_list` — list all loaded shared sets
729
+ - `copa_share_remove` — remove a shared set
730
+ - `copa_export_group` — export a group as a .copa file
731
+ - `copa_recipe_list` — list all recipes
732
+ - `copa_recipe_show` — show a recipe's steps
733
+ - `copa_recipe_add` — create a recipe from ordered steps
734
+ - `copa_recipe_remove` — remove a recipe
627
735
 
628
736
  ## Configuration
629
737
 
@@ -636,12 +744,7 @@ Copa is configured via `~/.copa/config.toml`. All settings are optional — Copa
636
744
  # Values are fzf key names: ctrl-<letter>, alt-<letter>, ctrl-/
637
745
  # ctrl-r and enter are reserved and cannot be reassigned
638
746
  [keys]
639
- background = "ctrl-v" # append &
640
- merge_output = "ctrl-o" # append 2>&1
641
- pipe = "ctrl-x" # append |
642
- redirect = "ctrl-t" # append >
643
- chain = "ctrl-a" # append &&
644
- suppress = "ctrl-/" # append 2>/dev/null
747
+ compose = "ctrl-x" # open compose submenu (|, &&, >, &, 2>&1, 2>/dev/null)
645
748
  describe = "ctrl-d" # LLM describe
646
749
  group = "ctrl-g" # assign group (inline modal)
647
750
  flags = "ctrl-f" # edit flags
@@ -661,65 +764,75 @@ enabled = true # set to false to disable
661
764
  min_length = 2 # minimum chars before querying
662
765
  tab_accept = 2 # 1 = accept directly, 2 = open menu first
663
766
  color = 242 # ghost text color (256-color palette)
767
+ directory_aware = true # boost suggestions from the current directory
664
768
 
665
- # Composition key behavior (continue vs close)
666
- # "continue" keys re-open fzf so you can chain another command
667
- # All other composition keys close fzf immediately
668
- [composition]
669
- continue = ["pipe", "chain", "redirect"] # default: |, &&, > re-open fzf
769
+ # Fzf layout
770
+ [layout]
771
+ height = "80%" # fzf height (default: 80%)
772
+ preview_size = "40%" # preview pane width (default: 40%)
670
773
  ```
671
774
 
672
- ### Composition key behavior
775
+ ### Compose submenu
673
776
 
674
- When you press a composition key (like Ctrl-A for `&&`), Copa can either **close fzf** (placing the command + operator in your prompt) or **continue** (appending the operator and re-opening fzf so you can select the next command to chain).
777
+ ![Composition](demos/08-composition.gif)
675
778
 
676
- By default, "connector" operators re-open fzf:
677
- - `pipe` (`|`) — continue
678
- - `chain` (`&&`) — continue
679
- - `redirect` (`>`) — continue
779
+ Press **Ctrl+X** while a command is highlighted to open the compose submenu — a numbered menu of shell operators:
680
780
 
681
- And "terminal" operators close fzf:
682
- - `background` (`&`) close
683
- - `merge_output` (`2>&1`) — close
684
- - `suppress` (`2>/dev/null`) — close
781
+ ```
782
+ Compose: 1)| 2)&& 3)> 4)& 5)2>&1 6)2>/dev/null
783
+ Select [1-6]:
784
+ ```
785
+
786
+ | # | Operator | Behavior | What happens |
787
+ |---|---------------|------------|-------------------------------------------------------------|
788
+ | 1 | `\|` | continue | Appends `\|` and re-opens fzf to select the next command |
789
+ | 2 | `&&` | continue | Appends `&&` and re-opens fzf to chain another command |
790
+ | 3 | `>` | continue | Appends `>` and re-opens fzf for the target |
791
+ | 4 | `&` | close | Appends `&` and closes — run in background |
792
+ | 5 | `2>&1` | close | Appends `2>&1` and closes — merge stderr |
793
+ | 6 | `2>/dev/null` | close | Appends `2>/dev/null` and closes — suppress stderr |
794
+
795
+ "Continue" operators re-open fzf so you can build multi-command pipelines. "Close" operators place the final command in your prompt.
685
796
 
686
797
  When chaining, the prompt shows your accumulated command: `copa [git pull && ]>`.
687
798
 
688
- To revert to the old behavior (all keys close immediately), set:
799
+ ## End-to-End Workflow
689
800
 
690
- ```toml
691
- [composition]
692
- continue = []
693
- ```
801
+ ![Workflow](demos/11-workflow.gif)
694
802
 
695
803
  ## CLI Reference
696
804
 
697
- | Command | Purpose |
698
- |---------|---------|
699
- | `copa setup` | Interactive setup wizard |
700
- | `copa add "cmd" -d "desc" -g group -f "flag: desc"` | Save a command (with optional flags) |
701
- | `copa edit ID [-d desc] [-g group] [-f flags] [--pin]` | Edit a command's metadata |
702
- | `copa remove ID` | Remove a command |
703
- | `copa pin ID` | Pin a command to the top |
704
- | `copa unpin ID` | Unpin a command |
705
- | `copa list [-g group] [-s source] [--set name] [--json]` | List by score |
706
- | `copa search "query" [-g group] [--set name] [--json]` | FTS search |
707
- | `copa create -g group [-o file]` | Create a .copa file from a group |
708
- | `copa stats` | Usage statistics |
709
- | `copa doctor` | Check setup and diagnose issues |
710
- | `copa sync` | Import from zsh history |
711
- | `copa scan [--dir path]` | Import script metadata from $PATH |
712
- | `copa evolve [-k 20] [--auto]` | Auto-add frequent commands (with optional LLM descriptions) |
713
- | `copa fix [--auto]` | Add missing descriptions (with optional LLM) |
714
- | `copa describe ID` | Generate description for one command |
715
- | `copa configure` | Set LLM backend (claude/ollama) |
716
- | `copa share export GROUP -o file` | Export group |
717
- | `copa share load SOURCE` | Load shared set |
718
- | `copa share list` | List shared sets |
719
- | `copa share sync DIR` | Sync .copa files from dir |
720
- | `copa import FILE [-g group]` | Import commands from markdown |
721
- | `copa reset` | Wipe database and start fresh (keeps config) |
722
- | `copa uninstall` | Remove Copa data and show cleanup steps |
805
+ | Command | Purpose |
806
+ | -------------------------------------------------------- | ----------------------------------------------------------- |
807
+ | `copa setup` | Interactive setup wizard |
808
+ | `copa add "cmd" -d "desc" -g group -f "flag: desc"` | Save a command (with optional flags) |
809
+ | `copa edit ID [-d desc] [-g group] [-f flags] [--pin]` | Edit a command's metadata |
810
+ | `copa remove ID` | Remove a command |
811
+ | `copa pin ID` | Pin a command to the top |
812
+ | `copa unpin ID` | Unpin a command |
813
+ | `copa list [-g group] [-s source] [--set name] [--json]` | List by score |
814
+ | `copa search "query" [-g group] [--set name] [--json]` | FTS search |
815
+ | `copa create -g group [-o file]` | Create a .copa file from a group |
816
+ | `copa stats` | Usage statistics |
817
+ | `copa doctor` | Check setup and diagnose issues |
818
+ | `copa sync` | Import from zsh history |
819
+ | `copa scan [--dir path]` | Import script metadata from $PATH |
820
+ | `copa evolve [-k 20] [--auto]` | Auto-add frequent commands (with optional LLM descriptions) |
821
+ | `copa fix [--auto]` | Add missing descriptions (with optional LLM) |
822
+ | `copa describe ID` | Generate description for one command |
823
+ | `copa configure` | Set LLM backend (claude/ollama) |
824
+ | `copa share export GROUP -o file` | Export group |
825
+ | `copa share load SOURCE` | Load shared set |
826
+ | `copa share list` | List shared sets |
827
+ | `copa share sync DIR` | Sync .copa files from dir |
828
+ | `copa import FILE [-g group]` | Import commands from markdown |
829
+ | `copa recipe add NAME -s 'cmd' [-s 'cmd' ...]` | Create a multi-step recipe |
830
+ | `copa recipe list [--json]` | List all recipes |
831
+ | `copa recipe show NAME` | Show a recipe's steps |
832
+ | `copa recipe run NAME [--dry-run]` | Run a recipe's steps sequentially |
833
+ | `copa recipe remove NAME` | Remove a recipe |
834
+ | `copa reset` | Wipe database and start fresh (keeps config) |
835
+ | `copa uninstall` | Remove Copa data and show cleanup steps |
723
836
 
724
837
  ## How Scoring Works
725
838
 
@@ -729,6 +842,8 @@ score = 2.0 * log(1 + frequency) + 8.0 * 0.5^(age_seconds / 3_days)
729
842
 
730
843
  Pinned commands get a +1000 bonus. The 3-day half-life means commands used in the last few days are strongly favored — a command used today scores ~8.0 recency, after 3 days ~4.0, after a week ~1.6.
731
844
 
845
+ When `directory_aware = true` (default), commands get a bonus based on where you are: +5.0 for the same directory, +2.0 for a parent or child directory. This means `git push` suggests your project's branch, not another repo's.
846
+
732
847
  ## License
733
848
 
734
849
  MIT