Summary
There is no command-line path to create a Brev Launchable or to deploy one into a workspace. Today these flows only exist in the web console (brev.dev/launchable/...). For anything scripted — CI publishing a launchable from a repo, agent harnesses spinning up reproducible demo VMs, automated smoke tests — operators have to either drive the Brev API by hand with curl or build a private wrapper. Both are fragile, both require knowing the org-scoped REST routes, and both reinvent error handling.
This issue asks for two new subcommands under a brev launchable group:
brev launchable create — POST to /api/organizations/:id/v2/launchables with a payload built from local files (the same shape the wizard sends).
brev launchable deploy — provision a workspace from an existing launchable id (the same flow https://brev.dev/launchable/deploy/now?launchableID=… triggers when a user clicks it).
Reproduction (today)
$ brev launchable --help
Error: unknown command "launchable" for "brev"
$ brev start "https://brev.dev/launchable/deploy/now?launchableID=env-..."
panic: invalid launchable URL: …
goroutine 1 [running]:
github.com/brevdev/brev-cli/pkg/cmd/start.MakeNewWorkspaceFromURL({0x16b48321b, 0x53})
/go/src/github.com/brevdev/brev-cli/pkg/cmd/start/start.go:561 +0x4cc
github.com/brevdev/brev-cli/pkg/cmd/start.maybeStartFromGitURL(0x14000225c80, …)
/go/src/github.com/brevdev/brev-cli/pkg/cmd/start/start.go:217 +0x7c
…
brev start does have machinery for launchable URLs (the binary's string table contains Deploying launchable: %q, failed to fetch launchable %q: %w, invalid launchable URL: %w, /launchable/deploy/now?launchableID=), but the call path panics on any URL the user supplies in this form.
Working around it currently requires either the web console or hand-crafted API calls. Examples of routes I had to discover by reading strings output on the binary:
POST /api/organizations/:org/v2/launchables (create — works)
POST /api/organizations/:org/v2/launchables/edit (works, with id, drop viewAccess)
POST /api/organizations/:org/workspaces (returns BadRequestError: Legacy workspace version unsupported)
POST /api/users/me/workspaces, /api/launchables/:id/deploy, /api/launchables/:id/launch, /api/v2/workspaces, etc. — all 404
Whatever the web frontend at brev.dev/launchable/deploy/now calls to actually provision a VM is not surfaced anywhere a CLI user can find it.
What we'd like
brev launchable create
Read a payload from a path (or stdin) and POST it to /api/organizations/:org/v2/launchables. On success, print the new launchable's id and shareable URL.
# From a single JSON file containing { name, description, viewAccess,
# createWorkspaceRequest, buildRequest, file? }
brev launchable create --from ./launchable.json
# Or with the lifecycle script broken out (mirrors how the web wizard
# splits them) — the CLI inlines the script into vmBuild.lifeCycleScriptAttr.script.
brev launchable create \
--name "dex-ui" \
--description "Browser control plane for OpenShell" \
--view-access public \
--instance-type n1-standard-2 \
--workspace-group GCP \
--region us-west1 \
--sub-location us-west1-a \
--storage 256 \
--image-id "projects/ubuntu-os-cloud/global/images/family/ubuntu-2404-lts-amd64" \
--port 3000:dex-ui:secure-link \
--setup-script ./launchable-setup.sh
Output:
launchable id: env-3Dvdn5kvH5MJ28hKWdtU2GbkC4W
share url: https://brev.dev/launchable/deploy/now?launchableID=env-3Dvdn5kvH5MJ28hKWdtU2GbkC4W
brev launchable edit and brev launchable list are obvious follow-ups; this issue scopes the MVP to create since that's the entry point.
brev launchable deploy
Provision a new workspace from an existing launchable id. Same flow as clicking the share URL. Should reject any combination that mixes the launchable's create-workspace defaults with conflicting flags rather than silently overriding.
# Default — pull every field from the launchable's createWorkspaceRequest
brev launchable deploy env-3Dvdn5kvH5MJ28hKWdtU2GbkC4W
# With a name + detached so a script can poll separately
brev launchable deploy env-3Dvdn5kvH5MJ28hKWdtU2GbkC4W \
--name dex-ui-smoketest \
--detached
Output (detached):
workspace id: <id>
workspace name: dex-ui-smoketest
state: DEPLOYING
poll with: brev ls dex-ui-smoketest
Output (foreground):
[deploy] provisioning n1-standard-2 in us-west1-a…
[deploy] reached BUILDING after 38s
[deploy] reached RUNNING after 2m41s
[deploy] lifecycle script in progress (poll /var/log/brev/oncreate-lifecycle-script-*.log for details)
[deploy] workspace healthy after 6m12s
secure link: https://3000-…brev-prod.ngc.nvidia.com/
Non-goals for this issue
- Listing org launchables and showing per-launchable launch counts. Trackable separately as
brev launchable list / brev launchable show.
- Authoring launchables with a fully-interactive TUI. The MVP is non-interactive + scriptable.
Why this matters
We just published a Launchable for dex-ui by:
- Hand-crafting the JSON payload from API-shape notes (
api-shapes.md).
- Extracting the operator's Brev access token from
~/.brev/credentials.json and POSTing the create request via curl.
- Iterating with
POST .../v2/launchables/edit to fix storage units, missing imageId, etc.
- Asking the user to click the share URL because we couldn't programmatically launch.
Steps 1–3 should be one command. Step 4 should be the second. Without these, every agent or CI flow that wants to publish + smoke-test a Launchable has to keep reinventing the wheel.
Summary
There is no command-line path to create a Brev Launchable or to deploy one into a workspace. Today these flows only exist in the web console (
brev.dev/launchable/...). For anything scripted — CI publishing a launchable from a repo, agent harnesses spinning up reproducible demo VMs, automated smoke tests — operators have to either drive the Brev API by hand withcurlor build a private wrapper. Both are fragile, both require knowing the org-scoped REST routes, and both reinvent error handling.This issue asks for two new subcommands under a
brev launchablegroup:brev launchable create— POST to/api/organizations/:id/v2/launchableswith a payload built from local files (the same shape the wizard sends).brev launchable deploy— provision a workspace from an existing launchable id (the same flowhttps://brev.dev/launchable/deploy/now?launchableID=…triggers when a user clicks it).Reproduction (today)
brev startdoes have machinery for launchable URLs (the binary's string table containsDeploying launchable: %q,failed to fetch launchable %q: %w,invalid launchable URL: %w,/launchable/deploy/now?launchableID=), but the call path panics on any URL the user supplies in this form.Working around it currently requires either the web console or hand-crafted API calls. Examples of routes I had to discover by reading
stringsoutput on the binary:POST /api/organizations/:org/v2/launchables(create — works)POST /api/organizations/:org/v2/launchables/edit(works, withid, dropviewAccess)POST /api/organizations/:org/workspaces(returnsBadRequestError: Legacy workspace version unsupported)POST /api/users/me/workspaces,/api/launchables/:id/deploy,/api/launchables/:id/launch,/api/v2/workspaces, etc. — all 404Whatever the web frontend at
brev.dev/launchable/deploy/nowcalls to actually provision a VM is not surfaced anywhere a CLI user can find it.What we'd like
brev launchable createRead a payload from a path (or stdin) and POST it to
/api/organizations/:org/v2/launchables. On success, print the new launchable's id and shareable URL.Output:
brev launchable editandbrev launchable listare obvious follow-ups; this issue scopes the MVP tocreatesince that's the entry point.brev launchable deployProvision a new workspace from an existing launchable id. Same flow as clicking the share URL. Should reject any combination that mixes the launchable's create-workspace defaults with conflicting flags rather than silently overriding.
Output (detached):
Output (foreground):
Non-goals for this issue
brev launchable list/brev launchable show.Why this matters
We just published a Launchable for dex-ui by:
api-shapes.md).~/.brev/credentials.jsonand POSTing the create request viacurl.POST .../v2/launchables/editto fix storage units, missingimageId, etc.Steps 1–3 should be one command. Step 4 should be the second. Without these, every agent or CI flow that wants to publish + smoke-test a Launchable has to keep reinventing the wheel.