Skip to content

feat(cli): add projects support with --project flag and name resolution#147

Open
hiroTamada wants to merge 8 commits intomainfrom
hiro/cli-project-support
Open

feat(cli): add projects support with --project flag and name resolution#147
hiroTamada wants to merge 8 commits intomainfrom
hiro/cli-project-support

Conversation

@hiroTamada
Copy link
Copy Markdown
Contributor

@hiroTamada hiroTamada commented Apr 10, 2026

Summary

  • Adds a global --project persistent flag (and KERNEL_PROJECT_ID env var) that injects the X-Kernel-Project-Id header to scope all API requests to a specific project
  • The flag accepts either a project ID or a project name — names are resolved via the projects list endpoint with case-insensitive matching
  • Adds kernel projects subcommands: list, create, get, delete, get-limits, set-limits
  • Upgrades kernel-go-sdk to v0.48.0 for project endpoint support (also fixes ProxyService.Check signature change)

How it works

When --project is provided:

  1. If the value looks like a cuid2 ID (24 lowercase alphanumeric chars), it's used directly as the project ID header
  2. Otherwise, the CLI authenticates first, calls GET /projects to list all projects, finds a case-insensitive name match, and injects the resolved ID
  3. Clear errors for: no match found, multiple matches (ambiguous name)

Test 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 message
  • KERNEL_PROJECT_ID="cli-test-project" env var with name — resolves correctly
  • No --project with scoped API key — auto-scopes via server middleware
  • kernel projects list/create/get/delete/get-limits/set-limits — all functional

Made 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 projects command with subcommands to list, create, get, and delete projects, plus limits get/set (and hidden get-limits/set-limits compat commands) including human-readable or --output json rendering and validation of negative limit values.

Introduces a global persistent --project flag (and KERNEL_PROJECT/KERNEL_PROJECT_ID env selection) that scopes authenticated requests via X-Kernel-Project-Id, resolving names to IDs by paginating Projects.List with clear errors for no/ambiguous matches.

Updates CUID detection to require a leading letter, bumps kernel-go-sdk to v0.48.0, and adjusts proxy health check calls/tests for the SDK Check signature change.

Reviewed by Cursor Bugbot for commit 3093664. Bugbot is set up for automated code reviews on this repo. Configure here.

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-agent
Copy link
Copy Markdown

Firetiger deploy monitoring skipped

This PR didn't match the auto-monitor filter configured on your GitHub connection:

Any PR that changes the kernel API. Monitor changes to API endpoints (packages/api/cmd/api/) and Temporal workflows (packages/api/lib/temporal) in the kernel repo

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 @firetiger monitor this.

- 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
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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, "", " ")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
@socket-security
Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedgolang/​github.com/​kernel/​kernel-go-sdk@​v0.44.1-0.20260323174449-5e56fc5d99a6 ⏵ v0.48.072 +1100100100100

View full report

@hiroTamada hiroTamada requested a review from rgarcia April 13, 2026 16:52
Copy link
Copy Markdown
Contributor

@masnwilliams masnwilliams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm — all review comments addressed. typed handler pattern, nested limits subcommands, human-readable output, and KERNEL_PROJECT precedence all look good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants