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 8 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
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 e55a6c3. Configure here.
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
cmd/root.go
Outdated
|
|
||
| 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?
cmd/root.go
Outdated
| // 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
cmd/projects.go
Outdated
| "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?
cmd/projects.go
Outdated
| } | ||
|
|
||
| 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?
cmd/projects.go
Outdated
| 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.

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
Adds a global project-scoping mechanism that changes how the Kernel client is constructed (extra header + name resolution) and upgrades the SDK, which could affect all authenticated commands if resolution or header injection is wrong.
Overview
Adds a new top-level
projectscommand with subcommands tolist,create,get, anddeleteprojects, pluslimits get/set(and hiddenget-limits/set-limitscompat commands) including human-readable or--output jsonrendering and validation of negative limit values.Introduces a global persistent
--projectflag (andKERNEL_PROJECT/KERNEL_PROJECT_IDenv selection) that scopes authenticated requests viaX-Kernel-Project-Id, resolving names to IDs by paginatingProjects.Listwith clear errors for no/ambiguous matches.Updates CUID detection to require a leading letter, bumps
kernel-go-sdktov0.48.0, and adjusts proxy health check calls/tests for the SDKChecksignature change.Reviewed by Cursor Bugbot for commit 3093664. Bugbot is set up for automated code reviews on this repo. Configure here.