Skip to content

Commit 335b923

Browse files
authored
feat(search): add cpu subcommand and wide mode to brev search (#289)
* perf(analytics): timeout GPU info collection at 100ms nvidia-smi and system_profiler can be slow. Wrap getGPUInfo in a goroutine with a 100ms deadline so it never blocks CLI responsiveness. * feat(search): add cpu subcommand and wide mode to brev search Restructure `brev search` into gpu/cpu subcommands: - `brev search` / `brev search gpu` - GPU instances (default, backwards compatible) - `brev search gpu --wide` - GPU instances with RAM and ARCH columns - `brev search cpu` - CPU-only instances via ?include_cpu=true API param CPU search has dedicated columns (TYPE, PROVIDER, VCPUs, RAM, ARCH, DISK, $/GB/MO, BOOT, FEATURES, $/HR) and filters (--min-ram, --arch). Shared filters (--provider, --min-vcpu, --min-disk, --max-boot-time, --stoppable, --rebootable, --flex-ports, --sort) work across both modes. Piping into `brev create` works for both GPU and CPU table output. * refactor(search): make --min-ram and --arch shared flags Move --min-ram and --arch from CPU-dedicated flags to shared flags so they are available on all search subcommands (gpu, cpu, and parent). * fix(search): resolve lint issues in gpusearch - Fix gofumpt formatting - Remove unused terminal parameter from displayCPUTable - Reduce cyclomatic complexity of SortInstances using map-based dispatch * feat(ls): add GPU column and concurrent instance type fetching Show GPU name (e.g. A100, H100) in brev ls table output and JSON. Fetch instance types concurrently with workspaces for no added latency. Correctly classify instances as gpu/cpu based on actual GPU support. Remove misleading '(gpu)' suffix from instance type display. * docs(skill): update brev-cli skill docs for CPU search support Add CPU search examples, filters reference, and common patterns. Update trigger keywords and descriptions to include CPU instances.
1 parent 0ff745e commit 335b923

11 files changed

Lines changed: 808 additions & 175 deletions

File tree

.agents/skills/brev-cli/SKILL.md

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: brev-cli
3-
description: Manage GPU cloud instances with the Brev CLI. Use when users want to create GPU instances, search for GPUs, SSH into instances, open editors, copy files, port forward, manage organizations, or work with cloud compute. Trigger keywords - brev, gpu, instance, create instance, ssh, vram, A100, H100, cloud gpu, remote machine.
3+
description: Manage GPU and CPU cloud instances with the Brev CLI. Use when users want to create instances, search for GPUs or CPUs, SSH into instances, open editors, copy files, port forward, manage organizations, or work with cloud compute. Trigger keywords - brev, gpu, cpu, instance, create instance, ssh, vram, vcpu, A100, H100, cloud gpu, cloud cpu, remote machine.
44
allowed-tools: Bash, Read, AskUserQuestion
55
argument-hint: [create|search|shell|exec|open|ls|delete] [instance-name]
66
---
@@ -13,31 +13,35 @@ Token Budget:
1313

1414
# Brev CLI
1515

16-
Manage GPU cloud instances from the command line. Create, search, connect, and manage remote GPU machines.
16+
Manage GPU and CPU cloud instances from the command line. Create, search, connect, and manage remote machines.
1717

1818
## When to Use
1919

2020
Use this skill when users want to:
21-
- Create GPU instances (with smart defaults or specific types)
21+
- Create GPU or CPU instances (with smart defaults or specific types)
2222
- Search for available GPU types (A100, H100, L40S, etc.)
23+
- Search for CPU-only instance types (no GPU)
2324
- SSH into instances or run commands remotely
2425
- Open editors (VS Code, Cursor, Windsurf) on remote instances
2526
- Copy files to/from instances
2627
- Port forward from remote to local
2728
- Manage organizations and instances
2829

29-
**Trigger Keywords:** brev, gpu, instance, create instance, ssh, vram, A100, H100, cloud gpu, remote machine, shell
30+
**Trigger Keywords:** brev, gpu, cpu, instance, create instance, ssh, vram, vcpu, A100, H100, cloud gpu, cloud cpu, remote machine, shell
3031

3132
## Quick Start
3233

3334
```bash
3435
# Search for GPUs (sorted by price)
3536
brev search
3637

38+
# Search for CPU-only instances
39+
brev search cpu
40+
3741
# Create an instance with smart defaults
3842
brev create my-instance
3943

40-
# Create with specific GPU
44+
# Create with specific type
4145
brev create my-instance --type g5.xlarge
4246

4347
# List your instances
@@ -58,8 +62,12 @@ brev open my-instance cursor
5862

5963
### Search GPUs
6064
```bash
61-
# All available GPUs
65+
# All available GPUs (default)
6266
brev search
67+
brev search gpu
68+
69+
# GPU search with wide mode (shows RAM and ARCH columns)
70+
brev search gpu --wide
6371

6472
# Filter by GPU name
6573
brev search --gpu-name A100
@@ -75,6 +83,32 @@ brev search --max-boot-time 5 --sort price
7583
brev search --stoppable --min-total-vram 40 --sort price
7684
```
7785

86+
### Search CPUs
87+
```bash
88+
# All available CPU-only instances
89+
brev search cpu
90+
91+
# Filter by provider
92+
brev search cpu --provider aws
93+
94+
# Filter by minimum RAM
95+
brev search cpu --min-ram 64
96+
97+
# Filter by architecture
98+
brev search cpu --arch arm64
99+
100+
# Filter by vCPUs
101+
brev search cpu --min-vcpu 16
102+
103+
# Sort by price
104+
brev search cpu --sort price
105+
106+
# JSON output
107+
brev search cpu --json
108+
```
109+
110+
CPU search shows: TYPE, PROVIDER, VCPUs, RAM, ARCH, DISK, $/GB/MO, BOOT, FEATURES, $/HR
111+
78112
### Create Instances
79113
```bash
80114
# Smart defaults (cheapest matching GPU)
@@ -234,6 +268,6 @@ brev invite
234268
## References
235269

236270
- **[reference/commands.md](reference/commands.md)** - Full command reference
237-
- **[reference/search-filters.md](reference/search-filters.md)** - GPU search options
271+
- **[reference/search-filters.md](reference/search-filters.md)** - GPU and CPU search options
238272
- **[prompts/](prompts/)** - Workflow guides
239273
- **[examples/](examples/)** - Common patterns

.agents/skills/brev-cli/examples/common-patterns.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,44 @@ git config --global user.name "Your Name"
134134
git config --global user.email "you@example.com"
135135
```
136136

137+
## CPU Instance Patterns
138+
139+
### Find CPU Instances
140+
```bash
141+
# All CPU instances sorted by price
142+
brev search cpu --sort price
143+
144+
# Cheapest ARM CPU instances
145+
brev search cpu --arch arm64 --sort price
146+
147+
# High-memory CPU for data processing
148+
brev search cpu --min-ram 128 --sort price
149+
150+
# Many-core for parallel workloads
151+
brev search cpu --min-vcpu 32 --sort price
152+
```
153+
154+
### Create CPU Instance
155+
```bash
156+
# Create from CPU search
157+
brev search cpu --min-ram 64 | brev create my-cpu-box
158+
159+
# Create CPU instance and run setup
160+
brev search cpu --sort price | brev create data-proc | brev exec @setup.sh
161+
```
162+
163+
### CPU Use Cases
164+
```bash
165+
# Data preprocessing box
166+
brev search cpu --min-ram 64 --min-disk 500 | brev create etl-box
167+
168+
# CI/CD runner
169+
brev search cpu --min-vcpu 8 --max-boot-time 3 | brev create ci-runner
170+
171+
# Web server / API host
172+
brev search cpu --stoppable --sort price | brev create api-server
173+
```
174+
137175
## Quick Start Patterns
138176

139177
### Create and Connect (One-Liner)

.agents/skills/brev-cli/reference/commands.md

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,22 @@ brev create my-instance --dry-run
131131
```
132132

133133
### brev search
134-
Search and filter available GPU instance types.
134+
Search and filter available instance types. Has two subcommands: `gpu` (default) and `cpu`.
135135

136136
```bash
137-
brev search [flags]
137+
brev search [gpu|cpu] [flags]
138138
```
139139

140140
**Aliases:** `gpu-search`, `gpu`, `gpus`, `gpu-list`
141141

142-
**Flags:**
142+
#### GPU Search (default)
143+
```bash
144+
brev search [flags]
145+
brev search gpu [flags]
146+
brev search gpu --wide # shows RAM and ARCH columns
147+
```
148+
149+
**GPU Flags:**
143150
| Flag | Short | Description |
144151
|------|-------|-------------|
145152
| `--gpu-name` | `-g` | Filter by GPU name (partial match) |
@@ -155,16 +162,51 @@ brev search [flags]
155162
| `--sort` | `-s` | Sort by: price, gpu-count, vram, total-vram, vcpu, disk, boot-time |
156163
| `--desc` | `-d` | Sort descending |
157164
| `--json` | | Output as JSON |
165+
| `--wide` | `-w` | Show extra columns (RAM, ARCH) — gpu subcommand only |
158166

159-
**Examples:**
167+
**GPU Examples:**
160168
```bash
161169
brev search
170+
brev search gpu --wide
162171
brev search --gpu-name A100
163172
brev search --min-vram 40 --sort price
164173
brev search --gpu-name H100 --max-boot-time 3
165174
brev search --stoppable --min-total-vram 40 --sort price
166175
```
167176

177+
#### CPU Search
178+
```bash
179+
brev search cpu [flags]
180+
```
181+
182+
Search for CPU-only instance types (no GPU). Uses shared flags only.
183+
184+
**CPU Flags:**
185+
| Flag | Short | Description |
186+
|------|-------|-------------|
187+
| `--provider` | `-p` | Filter by cloud provider |
188+
| `--arch` | | Filter by architecture (x86_64, arm64) |
189+
| `--min-ram` | | Minimum RAM in GB |
190+
| `--min-disk` | | Minimum disk size (GB) |
191+
| `--min-vcpu` | | Minimum number of vCPUs |
192+
| `--max-boot-time` | | Maximum boot time (minutes) |
193+
| `--stoppable` | | Only stoppable instances |
194+
| `--rebootable` | | Only rebootable instances |
195+
| `--flex-ports` | | Only instances with configurable firewall |
196+
| `--sort` | `-s` | Sort by: price, vcpu, type, provider, disk, boot-time |
197+
| `--desc` | `-d` | Sort descending |
198+
| `--json` | | Output as JSON |
199+
200+
**CPU Examples:**
201+
```bash
202+
brev search cpu
203+
brev search cpu --provider aws
204+
brev search cpu --min-ram 64 --sort price
205+
brev search cpu --arch arm64
206+
brev search cpu --min-vcpu 16 --sort price
207+
brev search cpu | brev create my-cpu-box
208+
```
209+
168210
### brev ls
169211
List instances in active org.
170212

.agents/skills/brev-cli/reference/search-filters.md

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
# GPU Search Filters Reference
1+
# Search Filters Reference
22

3-
Detailed guide to filtering and sorting GPU instance types.
3+
Detailed guide to filtering and sorting GPU and CPU instance types.
4+
5+
## Command Structure
6+
7+
`brev search` has two subcommands:
8+
- `brev search` or `brev search gpu` — GPU instances (default, backwards compatible)
9+
- `brev search gpu --wide` — GPU instances with extra RAM and ARCH columns
10+
- `brev search cpu` — CPU-only instances (no GPU)
411

512
## Filter Options
613

@@ -187,3 +194,64 @@ brev search --json | jq '.[] | {type, gpu_name, price}'
187194
| S | Stoppable - can stop/restart without data loss |
188195
| R | Rebootable - can reboot the instance |
189196
| P | Flex Ports - can modify firewall rules |
197+
198+
## CPU Search (`brev search cpu`)
199+
200+
CPU search shows instances without GPUs. It uses shared flags (no GPU-specific flags like `--gpu-name`, `--min-vram`, etc.).
201+
202+
### CPU Filter Options
203+
204+
| Flag | Short | Description |
205+
|------|-------|-------------|
206+
| `--provider` | `-p` | Filter by cloud provider |
207+
| `--arch` | | Filter by architecture (x86_64, arm64) |
208+
| `--min-ram` | | Minimum RAM in GB |
209+
| `--min-disk` | | Minimum disk size in GB |
210+
| `--min-vcpu` | | Minimum number of vCPUs |
211+
| `--max-boot-time` | | Maximum boot time in minutes |
212+
| `--stoppable` | | Only stoppable instances |
213+
| `--rebootable` | | Only rebootable instances |
214+
| `--flex-ports` | | Only instances with configurable firewall |
215+
| `--sort` | `-s` | Sort column (price, vcpu, type, provider, disk, boot-time) |
216+
| `--desc` | `-d` | Sort descending |
217+
| `--json` | | Output as JSON |
218+
219+
### CPU Output Columns
220+
221+
**Interactive (terminal):**
222+
```
223+
TYPE | PROVIDER | VCPUs | RAM | ARCH | DISK | $/GB/MO | BOOT | FEATURES | $/HR
224+
```
225+
226+
**Piped (stdout):**
227+
```
228+
TYPE | TARGET_DISK | PROVIDER | VCPUs | RAM | ARCH | DISK | $/GB/MO | BOOT | FEATURES | $/HR
229+
```
230+
231+
### CPU Filter Examples
232+
233+
```bash
234+
# All CPU instances
235+
brev search cpu
236+
237+
# Cheap ARM instances
238+
brev search cpu --arch arm64 --sort price
239+
240+
# High-memory instances for data processing
241+
brev search cpu --min-ram 128 --sort price
242+
243+
# Many-core instances for parallel workloads
244+
brev search cpu --min-vcpu 32 --sort price
245+
246+
# Fast-booting CPU instances
247+
brev search cpu --max-boot-time 3 --sort price
248+
249+
# Stoppable CPU instances (save costs)
250+
brev search cpu --stoppable --sort price
251+
252+
# AWS CPU instances with large disk
253+
brev search cpu --provider aws --min-disk 500
254+
255+
# Pipe CPU search into create
256+
brev search cpu --min-ram 64 | brev create my-cpu-box
257+
```

pkg/cmd/gpucreate/gpucreate.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ func parseStartupScript(value string) (string, error) {
318318

319319
// searchInstances fetches and filters GPU instances using user-provided filters merged with defaults
320320
func searchInstances(s GPUCreateStore, filters *searchFilterFlags) ([]gpusearch.GPUInstanceInfo, float64, error) {
321-
response, err := s.GetInstanceTypes()
321+
response, err := s.GetInstanceTypes(false)
322322
if err != nil {
323323
return nil, 0, breverrors.WrapAndTrace(err)
324324
}
@@ -340,8 +340,8 @@ func searchInstances(s GPUCreateStore, filters *searchFilterFlags) ([]gpusearch.
340340
}
341341

342342
instances := gpusearch.ProcessInstances(response.Items)
343-
filtered := gpusearch.FilterInstances(instances, filters.gpuName, filters.provider, filters.minVRAM,
344-
minTotalVRAM, minCapability, minDisk, maxBootTime, filters.stoppable, filters.rebootable, filters.flexPorts)
343+
filtered := gpusearch.FilterInstances(instances, filters.gpuName, filters.provider, "", filters.minVRAM,
344+
minTotalVRAM, minCapability, 0, minDisk, 0, maxBootTime, filters.stoppable, filters.rebootable, filters.flexPorts, true)
345345
gpusearch.SortInstances(filtered, sortBy, filters.descending)
346346

347347
return filtered, minDisk, nil
@@ -375,7 +375,7 @@ func runDryRun(t *terminal.Terminal, s GPUCreateStore, filters *searchFilterFlag
375375
}
376376

377377
piped := gpusearch.IsStdoutPiped()
378-
if err := gpusearch.DisplayResults(t, filtered, false, piped); err != nil {
378+
if err := gpusearch.DisplayGPUResults(t, filtered, false, piped, false); err != nil {
379379
return breverrors.WrapAndTrace(err)
380380
}
381381
return nil

pkg/cmd/gpucreate/gpucreate_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (m *MockGPUCreateStore) GetAllInstanceTypesWithWorkspaceGroups(orgID string
9797
return nil, nil
9898
}
9999

100-
func (m *MockGPUCreateStore) GetInstanceTypes() (*gpusearch.InstanceTypesResponse, error) {
100+
func (m *MockGPUCreateStore) GetInstanceTypes(_ bool) (*gpusearch.InstanceTypesResponse, error) {
101101
// Return a default set of instance types for testing
102102
return &gpusearch.InstanceTypesResponse{
103103
Items: []gpusearch.InstanceType{
@@ -355,6 +355,28 @@ func TestParseTableInput(t *testing.T) {
355355
assert.Equal(t, 1000.0, specs[2].DiskGB)
356356
}
357357

358+
func TestParseTableInputCPU(t *testing.T) {
359+
// Simulated plain table output from `brev search cpu`
360+
tableInput := strings.Join([]string{
361+
" TYPE TARGET_DISK PROVIDER VCPUS RAM ARCH DISK $/GB/MO BOOT FEATURES $/HR",
362+
" n2d-highcpu-2 10 gcp 2 2 x86_64 10GB-16TB $0.13 7m SP $0.05",
363+
" n1-standard-1 10 gcp 1 4 x86_64 10GB-16TB $0.14 7m SP $0.06",
364+
" m8i-flex.8xlarge 500 aws 32 128 x86_64 10GB-16TB $0.10 7m SRP $1.93",
365+
"",
366+
"Found 3 CPU instance types",
367+
}, "\n")
368+
369+
specs := parseTableInput(tableInput)
370+
371+
assert.Len(t, specs, 3)
372+
assert.Equal(t, "n2d-highcpu-2", specs[0].Type)
373+
assert.Equal(t, 10.0, specs[0].DiskGB)
374+
assert.Equal(t, "n1-standard-1", specs[1].Type)
375+
assert.Equal(t, 10.0, specs[1].DiskGB)
376+
assert.Equal(t, "m8i-flex.8xlarge", specs[2].Type)
377+
assert.Equal(t, 500.0, specs[2].DiskGB)
378+
}
379+
358380
func TestParseJSONInput(t *testing.T) {
359381
// Simulated JSON output from gpu-search --json
360382
jsonInput := `[

0 commit comments

Comments
 (0)