feat(cli): add projects support with --project flag and name resolution#147
feat(cli): add projects support with --project flag and name resolution#147hiroTamada wants to merge 10 commits intomainfrom
Conversation
Add global --project flag (and KERNEL_PROJECT_ID env var) that injects X-Kernel-Project-Id header to scope all API requests to a project. The flag accepts either a project ID or a project name — names are resolved via the projects list endpoint (case-insensitive). Also adds `kernel projects` subcommands: list, create, get, delete, get-limits, set-limits. Upgrades kernel-go-sdk to v0.48.0 for project endpoint support. Made-with: Cursor
|
Firetiger deploy monitoring skipped This PR didn't match the auto-monitor filter configured on your GitHub connection:
Reason: PR modifies CLI functionality (packages/cli) and SDK dependencies, not kernel API endpoints (packages/api/cmd/api/) or Temporal workflows (packages/api/lib/temporal). To monitor this PR anyway, reply with |
Made-with: Cursor
- looksLikeCUID: require first character to be a letter (cuid2 spec) - FakeProxyService.CheckFunc: update type signature and delegation to include body parameter Made-with: Cursor
Reuse cuidRegex from browsers.go in looksLikeCUID and update the regex to require the first character to be a letter (matching the cuid2 spec). Made-with: Cursor
Previously negative values were silently discarded, reporting success without sending the value to the API. Made-with: Cursor
get, delete, get-limits, and set-limits now accept either a project ID or name. Names are resolved via the projects list endpoint, reusing the same resolveProjectByName helper as the --project global flag. Made-with: Cursor
The default page size could miss projects beyond the first page. Request a large limit to cover typical org sizes. Made-with: Cursor
|
|
||
| projectVal, _ := cmd.Flags().GetString("project") | ||
| if projectVal == "" { | ||
| projectVal = os.Getenv("KERNEL_PROJECT_ID") |
There was a problem hiding this comment.
nit: since this now accepts either a project name or ID, should this env var be called KERNEL_PROJECT to match --project and better signal the flexibility?
| // resolveProjectByName lists the caller's projects and returns the ID of the | ||
| // one whose name matches (case-insensitive). Returns an error if no match or | ||
| // multiple matches are found. | ||
| func resolveProjectByName(ctx context.Context, client kernel.Client, name string) (string, error) { |
There was a problem hiding this comment.
curious why we need client-side name resolution here. if the API/SDK already has a get-by-id-or-name path under the hood, might be worth delegating to that instead of listing + matching locally
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| var projectsCmd = &cobra.Command{ |
There was a problem hiding this comment.
question on code organization: browsers uses a cobra-independent struct + typed input pattern (BrowsersCmd, BrowsersListInput, etc.), which seems to make the logic easier to test and keeps flag parsing separate from API behavior/output formatting. since projects is already a multi-command surface, would it be worth following that pattern here too with a ProjectsCmd?
| } | ||
|
|
||
| var projectsLimitsGetCmd = &cobra.Command{ | ||
| Use: "get-limits <id-or-name>", |
There was a problem hiding this comment.
question on command shape: these get-limits / set-limits verbs feel a little inconsistent with the rest of the cli. most resources use list/get/create/update/delete, and when an area grows we seem to introduce a nested noun subtree like browsers fs ... or browsers computer .... if project admin actions are going to expand, would projects limits get / projects limits set be a better fit?
| return nil | ||
| } | ||
|
|
||
| out, _ := json.MarshalIndent(limits, "", " ") |
There was a problem hiding this comment.
looks like these limits commands always print raw json. the rest of the cli seems to reserve machine-readable output for an explicit --output json / -o json flag and otherwise uses human-friendly tables/messages. might be worth making projects follow that same convention for consistency
Adopt the typed handler pattern for projects while preserving Cobra wiring, add nested limits subcommands with backward-compatible aliases, and standardize limits output behavior. Also support KERNEL_PROJECT precedence and paginate project name resolution to avoid missing matches outside the first page. Made-with: Cursor
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
masnwilliams
left a comment
There was a problem hiding this comment.
lgtm — all review comments addressed. typed handler pattern, nested limits subcommands, human-readable output, and KERNEL_PROJECT precedence all look good.
Remove name resolution from the global --project flag. The flag now passes the value directly as the X-Kernel-Project-Id header without attempting to resolve project names. The resolveProjectByName function is retained for explicit project subcommands (e.g. 'projects get <name>') where name lookup is expected.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a20844d. Configure here.
|
|
||
| if projectVal != "" { | ||
| clientOpts = append(clientOpts, option.WithHeader("X-Kernel-Project-Id", projectVal)) | ||
| } |
There was a problem hiding this comment.
Global --project flag skips name-to-ID resolution
High Severity
The --project flag handler in PersistentPreRunE passes the raw projectVal directly into the X-Kernel-Project-Id header without calling resolveProjectArg or resolveProjectByName. When a user supplies a project name instead of an ID, the name string is sent verbatim as the header value rather than being resolved to an actual project ID. The resolveProjectByName function is defined in the same file but never wired into this code path, so the documented name-resolution behavior (CUID2 check, then list-and-match) doesn't occur for the global flag.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit a20844d. Configure here.


Summary
--projectpersistent flag (andKERNEL_PROJECT_IDenv var) that injects theX-Kernel-Project-Idheader to scope all API requests to a specific projectkernel projectssubcommands:list,create,get,delete,get-limits,set-limitskernel-go-sdkto v0.48.0 for project endpoint support (also fixesProxyService.Checksignature change)How it works
When
--projectis provided:GET /projectsto list all projects, finds a case-insensitive name match, and injects the resolved IDTest plan
Tested against staging with a project-scoped API key:
--project "cli-test-project"(by name) — resolves correctly--project "CLI-TEST-PROJECT"(case-insensitive) — resolves correctly--project "g9vcya6unur84k70n0u8s9p9"(by ID) — works directly--project "nonexistent-project"— clear error messageKERNEL_PROJECT_ID="cli-test-project"env var with name — resolves correctly--projectwith scoped API key — auto-scopes via server middlewarekernel projects list/create/get/delete/get-limits/set-limits— all functionalMade with Cursor
Note
Medium Risk
Touches global request-scoping (adds a header to all authenticated API calls) and introduces new project/limits operations, so misconfiguration could unintentionally scope or modify the wrong project; changes are otherwise localized and covered by unit tests.
Overview
Adds project-scoped operation support to the CLI via a new persistent
--projectflag (withKERNEL_PROJECTand legacyKERNEL_PROJECT_IDenv fallback) that injects theX-Kernel-Project-Idheader into all authenticated SDK requests.Introduces a new
kernel projectscommand group to list/create/get/delete projects and to get/set per-project limit overrides, including ID-or-name resolution with pagination and clearer handling of “unlimited” limits and invalid/negative inputs.Upgrades
github.com/kernel/kernel-go-sdktov0.48.0, updates proxy health-check calls to match the newCheck(..., kernel.ProxyCheckParams{})signature, and adjusts/extends tests around project selection/name resolution and limits output.Reviewed by Cursor Bugbot for commit a20844d. Bugbot is set up for automated code reviews on this repo. Configure here.