Skip to content

feat: Support the token, workspace, and endpoint in the environment - #602

Merged
razor-x merged 3 commits into
mainfrom
claude/seam-cli-env-vars-q2q06p
Aug 4, 2026
Merged

feat: Support the token, workspace, and endpoint in the environment#602
razor-x merged 3 commits into
mainfrom
claude/seam-cli-env-vars-q2q06p

Conversation

@razor-x

@razor-x razor-x commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

Everything seam login, seam select workspace, and seam select server store may now be given in the environment instead:

Variable Overrides
SEAM_CLI_TOKEN the token stored by seam login
SEAM_CLI_WORKSPACE_ID the workspace stored by seam select workspace
SEAM_CLI_ENDPOINT the server stored by seam select server

Any of them, all of them, or none of them may be set: each is resolved independently and wins over the corresponding stored value, so SEAM_CLI_WORKSPACE_ID alone retargets the workspace while still using the stored token. Nothing needs to be logged in for a token given this way to work, which is what makes the CLI usable from CI.

# One command against another workspace
SEAM_CLI_WORKSPACE_ID=$OTHER_WORKSPACE seam devices list

# No login needed: authenticate from the environment
export SEAM_CLI_TOKEN=$SEAM_API_KEY
seam devices list

# Work against a local Seam Connect instance
SEAM_CLI_ENDPOINT=http://localhost:3020 seam devices list

An API Key is scoped to a single workspace, so it needs no workspace id. A Personal Access Token works across workspaces, so it needs one from either SEAM_CLI_WORKSPACE_ID or seam select workspace.

Commands refuse rather than store an ignored value

Storing a value the environment overrides would leave a command that appears to succeed using something else, so those commands fail instead, name what to unset, and store nothing:

$ SEAM_CLI_TOKEN=$SEAM_API_KEY seam login
Cannot log in while SEAM_CLI_TOKEN is set: it overrides what would be stored. Unset SEAM_CLI_TOKEN to log in.
  • SEAM_CLI_TOKEN blocks seam login (interactive and --token) and seam logout
  • SEAM_CLI_WORKSPACE_ID blocks seam select workspace and seam login --workspace-id
  • SEAM_CLI_ENDPOINT blocks seam select server, seam login --server, and seam config set fake-server

Two placement details: the checks in the login branch all run before any write and before validateToken, so a rejected login neither hits the network nor stores half its arguments; and the select workspace check runs before the non-interactive check, so scripts get the env var error instead of "cannot select in non-interactive mode". The workspace check also lives in interactForWorkspaceId, covering the workspace prompt that interactive seam login triggers for a Personal Access Token.

Errors are reported without a stack trace, like UsageError and NonInteractiveError.

Changes

  • src/lib/env.ts (new): the variable names, readers, EnvVarOverrideError, and assertEnvVarUnset. A value that is empty or only whitespace reads as unset; values are trimmed.
  • src/lib/env.d.ts (new): declares the variables the CLI reads on NodeJS.ProcessEnv, and the readers only accept a name from that declared set.
  • src/lib/get-credentials.ts (new): getToken() and getWorkspaceId() resolve environment before stored config, so every command sees the same credentials.
  • get-server.ts: SEAM_CLI_ENDPOINT wins over the stored server, which flows through every request, validateToken, and the stored-token lookup (tokens are keyed by server).
  • get-seam.ts: resolves through the new modules and reports missing credentials as Not logged in: run "seam login" or set the SEAM_CLI_TOKEN environment variable / No workspace selected: ..., replacing the opaque Missing personalAccessToken or workspaceId from @seamapi/http.
  • bin/cli.ts: the pre-command login gate accepts a token from the environment, and the commands above assert before storing.

Tests

151 pass; lint, typecheck, and prettier are clean.

  • Unit tests for the readers, the assertion, precedence for the token, workspace, and endpoint, and empty-value handling.
  • End-to-end tests assert the real outgoing headers: the environment token wins over the stored one (authorization), a token in the environment authenticates with nothing stored, seam-workspace comes from SEAM_CLI_WORKSPACE_ID, SEAM_CLI_ENDPOINT routes requests to a server the stored config does not point at (with a control run proving the stored server is used without it), both missing-credential errors, and one refusal per command.
  • runCli scrubs SEAM_CLI_* from the inherited environment so a developer's own shell cannot skew results.

Docs

README gains an "Environment variables" section under Usage covering all three variables, the API Key vs Personal Access Token distinction, the refusal behavior, and CI examples.

🤖 Generated with Claude Code

https://claude.ai/code/session_014vMQhRm7UfP3WfSGBX6WUW

claude added 2 commits August 4, 2026 19:31
Credentials may now be given in the environment instead of being stored by
"seam login" and "seam select workspace". Either variable, both, or neither
may be set: whatever is set wins over what is stored.

Resolve the token and workspace id in one place so every command sees the
same credentials, report a clear error when either is missing, and warn when
a command stores a credential the environment currently overrides.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vMQhRm7UfP3WfSGBX6WUW
… command

Move the environment variables into lib/env.ts and add SEAM_CLI_ENDPOINT,
which overrides the server stored by "seam select server" the same way
SEAM_CLI_TOKEN and SEAM_CLI_WORKSPACE_ID override the stored token and
workspace.

Commands that would store an overridden value now fail instead of storing
something the environment ignores: "seam login" and "seam logout" while
SEAM_CLI_TOKEN is set, "seam select workspace" while SEAM_CLI_WORKSPACE_ID
is set, and "seam select server" while SEAM_CLI_ENDPOINT is set. Each
reports what to unset, without a stack trace, and stores nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vMQhRm7UfP3WfSGBX6WUW
@razor-x razor-x changed the title Support credentials via environment variables feat: Support credentials via environment variables Aug 4, 2026
@razor-x razor-x changed the title feat: Support credentials via environment variables feat: Support the token, workspace, and endpoint in the environment Aug 4, 2026
Resolve the cli.ts imports and error reporting so UsageError from main and
EnvVarOverrideError are both reported without a stack trace.

Also declare the environment variables the CLI reads on NodeJS.ProcessEnv in
src/lib/env.d.ts, and read them through that declared set.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vMQhRm7UfP3WfSGBX6WUW
@razor-x
razor-x marked this pull request as ready for review August 4, 2026 20:41
@razor-x
razor-x merged commit d8e9f1e into main Aug 4, 2026
12 checks passed
@razor-x
razor-x deleted the claude/seam-cli-env-vars-q2q06p branch August 5, 2026 05:48
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.

2 participants