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
47 changes: 26 additions & 21 deletions .agents/skills/brev-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ brev create my-instance --type g5.xlarge
# List your instances
brev ls

# List external nodes (a separate list from `brev ls`)
# List Brev Connect machines (a separate list from `brev ls`)
brev ls nodes

# SSH into an instance (interactive)
Expand Down Expand Up @@ -171,34 +171,39 @@ brev copy my-instance:/remote/file ./local-path/
# Port forward
brev port-forward my-instance -p 8080:8080

# List Brev-managed HTTP and network ports for an instance or external node
# List Brev-managed ports for an instance or Brev Connect machine
brev ports ls my-instance
brev ports ls my-node --json

# Create a public port (TCP by default)
brev ports create my-instance 8080
brev ports create my-node 53 --protocol udp --allow 203.0.113.10/32
brev ports create my-instance 3000 --protocol http --public
brev ports create my-instance 8888 --protocol http --authorize me@example.com

# Update one mapping interactively or by exact ID
brev ports update my-instance --destination-port 8081
brev ports update my-instance --id nport-abc123 --allow 203.0.113.10/32
brev ports update my-instance --id nport-abc123 --public

# Close one port interactively or by exact ID
brev ports close my-instance
brev ports close my-instance --id nport-abc123 --approve
brev ports ls my-connect-machine --json

# Get all data for one port by exact ID
brev ports get nport-abc123
brev ports get nport-abc123 --json

# Open a port or an inclusive sequential TCP/UDP range (TCP by default)
brev ports open my-instance 8080
brev ports open my-instance 8000-8031
brev ports open my-connect-machine 53 --protocol udp --allow 203.0.113.10/32
brev ports open my-instance 3000 --protocol http --public
brev ports open my-instance 8888 --protocol http --authorize me@example.com

# Update one mapping by its globally unique ID
brev ports update nport-abc123 --destination-port 8081
brev ports update nport-abc123 --allow 203.0.113.10/32
brev ports update nport-abc123 --public

# Remove one port by destination port or exact ID
brev ports remove my-instance 8080
brev ports rm nport-abc123
```

### Listing Instances and Nodes
`brev ls` covers two separate namespaces. External nodes never appear in
`brev ls` covers two separate namespaces. Brev Connect machines never appear in
`brev ls`, so check `brev ls nodes` before concluding a machine doesn't exist.

```bash
brev ls # cloud instances
brev ls instances # same as above, explicit
brev ls nodes # external nodes only (machines registered to the org)
brev ls nodes # Brev Connect machines only
brev ls orgs # organizations
brev ls --json # machine-readable
brev ls nodes --json
Expand Down Expand Up @@ -319,7 +324,7 @@ Do this proactively when:

**"Instance not found":**
- Run `brev ls` to see available instances
- Run `brev ls nodes` — external nodes are a separate list and never show up in `brev ls`
- Run `brev ls nodes` — Brev Connect machines are a separate list and never show up in `brev ls`
- Check if you're in the correct org: `brev org ls`

**"Failed to create instance":**
Expand Down
116 changes: 70 additions & 46 deletions .agents/skills/brev-cli/reference/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ brev ls [subcommand] [flags]
|---|---|
| *(none)* | cloud instances |
| `instances` | cloud instances (explicit form) |
| `nodes` | external nodes only |
| `nodes` | Brev Connect machines only |
| `orgs` | organizations |

**Flags:**
Expand All @@ -229,9 +229,9 @@ brev ls [subcommand] [flags]
| `--all` | | Show all instances in org |
| `--json` | | Output as JSON |

#### Instances vs. external nodes
#### Instances vs. Brev Connect machines

Two separate namespaces — an external node never appears in `brev ls`.
Two separate namespaces — a Brev Connect machine never appears in `brev ls`.

```bash
$ brev ls
Expand Down Expand Up @@ -467,11 +467,10 @@ brev port-forward my-instance -p 3000:3000
```

### brev ports ls
List Brev-managed HTTP applications and raw network port mappings for a
managed instance or registered compute node.
List Brev-managed ports for a managed instance or Brev Connect machine.

```bash
brev ports ls <instance-or-node> [flags]
brev ports ls <instance-or-brev-connect-machine> [flags]
```

**Flags:**
Expand All @@ -480,8 +479,10 @@ brev ports ls <instance-or-node> [flags]
|------|-------------|
| `--json` | Output the port mappings as JSON |

The table output includes endpoint, IP restrictions, public port, destination
port, and protocol. HTTP applications also include their authorization policy.
The compact table output includes ID, endpoint, public port, destination port,
and protocol. Ports are ordered by protocol (`HTTPS`, `HTTP`, `TCP`, `UDP`,
`SSH`), then by ascending destination port. Use `brev ports get` to inspect
authorization, IP restrictions, and the remaining data for one mapping.

For managed instances, this command reads the Brev-managed network
configuration. It does not synthesize the legacy secure-link or firewall rows
Expand All @@ -507,18 +508,41 @@ The JSON output is an array with the following stable fields:
**Examples:**
```bash
brev ports ls my-instance
brev ports ls my-node
brev ports ls my-connect-machine
brev ports ls my-instance --json
```

### Create a port
### Get a port

Create a raw TCP, UDP, or SSH port, or an HTTP application endpoint, on a
managed instance or registered compute node. `open` and `add` are aliases for
`create`.
Get all data for one port mapping by its exact `port_id`.

```bash
brev ports create <instance-or-node> <port> [flags]
brev ports get <port-id> [flags]
```

**Flags:**

| Flag | Description |
|------|-------------|
| `--json` | Output the port mapping as a JSON object |

Human-readable output includes ID, endpoint, public and destination ports,
protocol, allowed sources, authorized emails, public-access state, and type.
The JSON object uses the same stable fields documented for `brev ports ls`.

**Examples:**
```bash
brev ports get nport-abc123
brev ports get nport-abc123 --json
```

### Open a port

Open a TCP, UDP, SSH, HTTP, or HTTPS port on a managed instance or Brev
Connect machine. TCP and UDP also accept inclusive sequential ranges.

```bash
brev ports open <instance-or-brev-connect-machine> <port-or-range> [flags]
```

**Flags:**
Expand All @@ -529,7 +553,7 @@ brev ports create <instance-or-node> <port> [flags]
| `--authorize` | Email authorized for an HTTP endpoint; repeat to add more than one |
| `--hostname` | HTTP endpoint hostname prefix; defaults to the destination port |
| `--public` | Disable authentication for an HTTP endpoint |
| `--json` | Output the created port as JSON |
| `--json` | Output the opened port as JSON |

Omit `--allow` to allow raw-port connections from any source. HTTP endpoints
default to authorizing the current user's email; use `--public` to make one
Expand All @@ -538,28 +562,29 @@ endpoint to a plain-HTTP service, while `https` expects TLS on the destination.

**Examples:**
```bash
brev ports create my-instance 8080
brev ports create my-node 53 --protocol udp
brev ports create my-instance 8080 --allow 203.0.113.10/32
brev ports create my-node 2222 --protocol ssh --json
brev ports create my-instance 3000 --protocol http --public
brev ports create my-instance 8888 --protocol http --authorize me@example.com
brev ports open my-instance 8080
brev ports open my-instance 8000-8031
brev ports open my-connect-machine 53 --protocol udp
brev ports open my-instance 8080 --allow 203.0.113.10/32
brev ports open my-connect-machine 2222 --protocol ssh --json
brev ports open my-instance 3000 --protocol http --public
brev ports open my-instance 8888 --protocol http --authorize me@example.com
```

### Update a port

Update a mapping in place while preserving its `port_id` and public endpoint.
Omit `--id` to select a mapping interactively. `edit` is an alias for `update`.
Update a mapping in place while preserving its globally unique `port_id` and
public endpoint. The CLI resolves the owning environment or Brev Connect
machine automatically. `edit` is an alias for `update`.

```bash
brev ports update <instance-or-node> [flags]
brev ports update <port-id> [flags]
```

**Flags:**

| Flag | Description |
|------|-------------|
| `--id` | Update the exact mapping with this `port_id`; omit to select interactively |
| `--destination-port` | Change the destination port (1-65535) |
| `--allow` | Replace source restrictions with this CIDR; repeat to add more than one |
| `--allow-anywhere` | Clear all source restrictions |
Expand All @@ -576,38 +601,37 @@ separate mutations are not transactional.

**Examples:**
```bash
brev ports update my-instance --destination-port 8081
brev ports update my-instance --id nport-abc123 --allow 203.0.113.10/32
brev ports edit my-node --id nport-abc123 --allow-anywhere
brev ports update my-instance --id nport-abc123 --protocol https
brev ports update my-instance --id nport-abc123 --authorize me@example.com
brev ports update my-instance --id nport-abc123 --public --json
brev ports update nport-abc123 --destination-port 8081
brev ports update nport-abc123 --allow 203.0.113.10/32
brev ports edit nport-abc123 --allow-anywhere
brev ports update nport-abc123 --protocol https
brev ports update nport-abc123 --authorize me@example.com
brev ports update nport-abc123 --public --json
```

### Close ports
### Remove ports

Select and close one port interactively or close an exact mapping by its
`port_id`. `remove` is an alias for `close`.
Remove one port by its globally unique `port_id` without specifying its owner.
To identify a port by destination number instead, also provide the environment
or Brev Connect machine. If multiple mappings use that destination, use an
exact `port_id`. `rm` is an alias for `remove`.

```bash
brev ports close <instance-or-node> [flags]
brev ports remove <port-id>
brev ports remove <instance-or-brev-connect-machine> <destination-port>
```

**Flags:**

| Flag | Description |
|------|-------------|
| `--id` | Close the exact mapping with this `port_id` |
| `--approve` | Skip the confirmation prompt |

Use `brev ports ls <instance-or-node> --json` to obtain stable `port_id` values
Use `brev ports ls <instance-or-brev-connect-machine> --json` to find port IDs
for automation.

On success, the command reports the protocol, destination port, and owning
machine, for example: `Removed TCP port 8080 on my-instance.`

**Examples:**
```bash
brev ports close my-instance
brev ports close my-instance --id nport-abc123 --approve
brev ports remove my-node --id nport-abc123 --approve
brev ports remove my-instance 8080
brev ports rm nport-abc123
brev ports remove nport-abc123
```

## Organization Commands
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ module github.com/brevdev/brev-cli
go 1.25.0

require (
buf.build/gen/go/brevdev/devplane/connectrpc/go v1.20.0-20260911001103-64122a9c386c.1
buf.build/gen/go/brevdev/devplane/protocolbuffers/go v1.36.12-20260911001103-64122a9c386c.1
connectrpc.com/connect v1.20.0
buf.build/gen/go/brevdev/devplane/connectrpc/go v1.21.0-20260915224432-6a5d0c858507.1
buf.build/gen/go/brevdev/devplane/protocolbuffers/go v1.36.12-20260915224432-6a5d0c858507.2
connectrpc.com/connect v1.21.0
github.com/NVIDIA/go-nvml v0.13.0-1
github.com/alessio/shellescape v1.4.1
github.com/brevdev/parse v0.0.11
Expand Down Expand Up @@ -50,7 +50,7 @@ require (
)

require (
buf.build/gen/go/brevdev/protoc-gen-gotag/protocolbuffers/go v1.36.12-20220906235457-8b4922735da5.1 // indirect
buf.build/gen/go/brevdev/protoc-gen-gotag/protocolbuffers/go v1.36.12-20220906235457-8b4922735da5.2 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
buf.build/gen/go/brevdev/devplane/connectrpc/go v1.20.0-20260911001103-64122a9c386c.1 h1:nrPJ9Iw5plC+jbx2szj9CvdDRaYkg+dgGHms7Jsb500=
buf.build/gen/go/brevdev/devplane/connectrpc/go v1.20.0-20260911001103-64122a9c386c.1/go.mod h1:K41bEH5jxz70cfjH6X8P5ykdEpM/+iT2TMr1sYdnPLk=
buf.build/gen/go/brevdev/devplane/protocolbuffers/go v1.36.12-20260911001103-64122a9c386c.1 h1:lpcaoFSjHRkbcehomGsn6JlRGqt+gzFyK+VjlN5zgIE=
buf.build/gen/go/brevdev/devplane/protocolbuffers/go v1.36.12-20260911001103-64122a9c386c.1/go.mod h1:N18pnR0HL6srurI7G19FpSEki71wA1u4e2c5zbfeTV8=
buf.build/gen/go/brevdev/protoc-gen-gotag/protocolbuffers/go v1.36.12-20220906235457-8b4922735da5.1 h1:Qk/4GJyWVWvWsfEFeX4T+k7KouZdRUxxUnIUwJ3hmZg=
buf.build/gen/go/brevdev/protoc-gen-gotag/protocolbuffers/go v1.36.12-20220906235457-8b4922735da5.1/go.mod h1:SacJAYqnICCQAsBA46cSA/hxhqhxYkiYzseucf6/fhQ=
buf.build/gen/go/brevdev/devplane/connectrpc/go v1.21.0-20260915224432-6a5d0c858507.1 h1:CFXTDUzEoMYQzJXAG+hnMO5Cs6h3zVq734k/VnyWuCM=
buf.build/gen/go/brevdev/devplane/connectrpc/go v1.21.0-20260915224432-6a5d0c858507.1/go.mod h1:dS34xJi+QXqWDdKwUHTBfzkcbQFNK3u4UH3F3L6izx0=
buf.build/gen/go/brevdev/devplane/protocolbuffers/go v1.36.12-20260915224432-6a5d0c858507.2 h1:CjGsO8kcUR0YcKzjKy/L5m2jIhnNW6VW6ArYliA2p6o=
buf.build/gen/go/brevdev/devplane/protocolbuffers/go v1.36.12-20260915224432-6a5d0c858507.2/go.mod h1:SBVLUYGc/4vgMlhOJL5SkwIrSh/FL9EEimlpI8zQSXo=
buf.build/gen/go/brevdev/protoc-gen-gotag/protocolbuffers/go v1.36.12-20220906235457-8b4922735da5.2 h1:W5SVs96P8ZgLElYzL93rJu+S+XmkdGQSaVWzPvR5lvg=
buf.build/gen/go/brevdev/protoc-gen-gotag/protocolbuffers/go v1.36.12-20220906235457-8b4922735da5.2/go.mod h1:SacJAYqnICCQAsBA46cSA/hxhqhxYkiYzseucf6/fhQ=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
Expand Down Expand Up @@ -41,8 +41,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
connectrpc.com/connect v1.21.0 h1:LhqSJt7jHf5NJBo9Jq/t/9FjcYAideif0mg+qe2jCUs=
connectrpc.com/connect v1.21.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
Expand Down
28 changes: 28 additions & 0 deletions pkg/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ func NewBrevCommand() *cobra.Command { //nolint:funlen,gocognit,gocyclo // defin
cobra.AddTemplateFunc("providerDependentCommands", providerDependentCommands)
cobra.AddTemplateFunc("hasAccessCommands", hasAccessCommands)
cobra.AddTemplateFunc("accessCommands", accessCommands)
cobra.AddTemplateFunc("hasNetworkingCommands", hasNetworkingCommands)
cobra.AddTemplateFunc("networkingCommands", networkingCommands)
cobra.AddTemplateFunc("hasOrganizationCommands", hasOrganizationCommands)
cobra.AddTemplateFunc("organizationCommands", organizationCommands)
cobra.AddTemplateFunc("hasConfigurationCommands", hasConfigurationCommands)
Expand Down Expand Up @@ -358,6 +360,10 @@ func hasAccessCommands(cmd *cobra.Command) bool {
return len(accessCommands(cmd)) > 0
}

func hasNetworkingCommands(cmd *cobra.Command) bool {
return len(networkingCommands(cmd)) > 0
}

func hasOrganizationCommands(cmd *cobra.Command) bool {
return len(organizationCommands(cmd)) > 0
}
Expand Down Expand Up @@ -398,6 +404,16 @@ func accessCommands(cmd *cobra.Command) []*cobra.Command {
return cmds
}

func networkingCommands(cmd *cobra.Command) []*cobra.Command {
cmds := []*cobra.Command{}
for _, sub := range cmd.Commands() {
if sub.IsAvailableCommand() && isNetworkingCommand(sub) {
cmds = append(cmds, sub)
}
}
return cmds
}

func organizationCommands(cmd *cobra.Command) []*cobra.Command {
cmds := []*cobra.Command{}
for _, sub := range cmd.Commands() {
Expand Down Expand Up @@ -458,6 +474,11 @@ func isAccessCommand(cmd *cobra.Command) bool {
return ok
}

func isNetworkingCommand(cmd *cobra.Command) bool {
_, ok := cmd.Annotations["networking"]
return ok
}

func isOrganizationCommand(cmd *cobra.Command) bool {
_, ok := cmd.Annotations["organization"]
return ok
Expand Down Expand Up @@ -520,6 +541,13 @@ Instance Access:
{{rpad .Name .NamePadding }} {{.Short}}
{{- end}}{{- end}}

{{- if hasNetworkingCommands . }}

Networking:
{{- range networkingCommands . }}
{{rpad .Name .NamePadding }} {{.Short}}
{{- end}}{{- end}}

{{- if hasOrganizationCommands . }}

Organization Management:
Expand Down
Loading
Loading