Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions .agents/skills/add-command-spec/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: add-command-spec
description: Guide for adding new command completion specs to warp-command-signatures. Use when creating a new JSON spec for shell command completions, adding generators for dynamic suggestions, or extending existing command specs.
---

# Adding a New Command Spec

## Steps

1. **Create JSON spec**: `command-signatures/json/<command>.json` following the [Fig completion spec schema](https://fig.io/docs/reference)
2. **Create generator** (if needed): Add `command-signatures/src/generators/<command>.rs`, define a `generator()` function returning `CommandSignatureGenerators`, and register it in `generators/mod.rs`

## Style Guideline

Match the formatting conventions used in the command's `--help` output. For example, if the help text uses `UPPER_CASE` for positional argument names, use the same casing in the spec's argument `name` field.

## Validation

Run `cargo test` to verify the spec deserializes correctly and any referenced `generatorName`s exist.

## Reference Examples

- **Simple spec with generator**: `json/kill.json` + `src/generators/kill.rs` — minimal example showing `generatorName` usage for process and signal completions
- **Complex spec with multiple generators**: `json/brew.json` + `src/generators/brew.rs` — shows subcommands, options, and multiple generators (`formulae_generator`, `services`, etc.)
15 changes: 3 additions & 12 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,12 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Run cargo fmt
uses: actions-rs/cargo@v1
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This action is deprecated, unmaintained for like 6 years
https://github.com/actions-rs/cargo

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this at all? The GH runners should have all of the rust toolchain already installed

with:
command: fmt
args: -p warp-command-signatures -p warp-completion-metadata
run: cargo fmt -p warp-command-signatures -p warp-completion-metadata --check
- name: Run cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: -p warp-command-signatures -p warp-completion-metadata --all-targets --all-features -- -D warnings
run: cargo clippy -p warp-command-signatures -p warp-completion-metadata --all-targets --all-features -- -D warnings
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose
run: cargo test --verbose
70 changes: 70 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# AGENTS.md

This file provides guidance to agents when working with code in this repository.

## Overview

This repository provides command completion signatures ("specs") for Warp terminal. It contains two Rust crates:

- **`warp-command-signatures`**: The main library that embeds and exposes command specs. Used as a dependency by `warp-internal`.
- **`warp-completion-metadata`**: Core types for signatures, arguments, options, generators, and the Fig-compatible JSON schema.

## Architecture

### Command Specs (JSON)

Specs are JSON files based on the [Fig completion spec schema](https://fig.io/docs/reference), but **Warp does not use Fig's JavaScript generators**. Instead:

- The `generatorName` field references Rust-based generators (see below)
- Fig's `generateSpec` JavaScript field is present in some imported specs but is **ignored** by Warp
- Static suggestions, templates (`filepaths`, `folders`), and subcommand/option definitions work as documented

| Location | Description |
|----------|-------------|
| `command-signatures/json/*.json` | Hand-written specs |
| `command-signatures/json/autogenerated/powershell/*.json` | Auto-generated PowerShell cmdlet specs |
| `command-signatures/json/overrides/powershell/*.json` | Hand-written overrides for autogenerated specs |

The `assets.rs` module uses `rust-embed` to flatten these directories into a single namespace at compile time, so callers just use `signature_by_name("git")`.

### Generators (Rust)

Generators produce dynamic completions by running shell commands. They are defined in `command-signatures/src/generators/` (one file per command or command family).

A generator consists of:
1. A `GeneratorProcess` (either a static `CommandBuilder` or a function that builds a command from tokens)
2. An `on_complete_callback` that parses the command output into `Suggestion`s

JSON specs reference generators via the `generatorName` field (e.g. `"generatorName": "branches"`). The mapping from name → Rust code is established in `generators/mod.rs` via `dynamic_command_signature_data()`.

Example from `brew.rs`:
```rust
CommandSignatureGenerators::new("brew")
.add_generator(
"formulae_generator", // Referenced in JSON as "generatorName": "formulae_generator"
Generator::script(CommandBuilder::single_command("brew list -1"), |output| {
output.trim().lines()
.map(|line| Suggestion::with_description(line, "Installed formula"))
.collect_unordered_results()
}),
)
```

### Override System

For autogenerated specs (currently PowerShell only), hand-written augmentations live in `json/overrides/`. Overrides are matched by option name or argument index and merged at generation time. Only `template` and `generatorName` fields are currently supported for overrides.

## Key Types

- `Signature`: Defines a command/subcommand (name, options, arguments, subcommands)
- `Argument`: A positional parameter with types (Template, Generator, or literal Suggestion)
- `Opt`: A flag/option with optional arguments
- `Generator`: Produces dynamic suggestions by running shell commands
- `Template`: Built-in generators for files/folders

## Testing Invariants

Tests in `lib.rs` verify:
- All `GeneratorName`s referenced in specs exist in `dynamic_command_signature_data()`
- All JSON specs deserialize without error
- Generator commands contain no unsafe (unquoted) newlines (required for TMUX control mode)
4 changes: 2 additions & 2 deletions completion-metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ pub enum Shell {
/// A shell that can assume POSIX-compliant syntax.
Posix,
Powershell,
CmdExe
CmdExe,
}

impl Shell {
Expand All @@ -262,7 +262,7 @@ impl Shell {
match self {
Shell::Posix => "2>/dev/null",
Shell::Powershell => "2> $null",
Shell::CmdExe => "2> NUL"
Shell::CmdExe => "2> NUL",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cargo fmt fixed this

}
}
}
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[toolchain]
channel = "1.82"
channel = "1.85"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use 1.92 in warp-internal, why 1.85 here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are new clippy lints in 1.92 which causes linting to fail. I updated to 1.85 b/c it's recent enough to fix the CI error but before these new lints. I do agree we should upgrade but I wanted to avoid scope-creeping this PR too much.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm, makes sense

components = ["rustfmt", "clippy"]
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin"]
profile = "minimal"