feat(cli): read-only 'api get' passthrough with anonymous-by-default reads#17
feat(cli): read-only 'api get' passthrough with anonymous-by-default reads#17mhusbynflow wants to merge 8 commits into
Conversation
The flow-ai skill reads Flow via curl with the token attached through a command substitution ($(< token-file)), which Claude Code cannot auto-approve, so every read prompts for permission. Specify a read-only `flowbio api get <path>` CLI command that resolves credentials itself, giving the skill a single allowlistable command in place of curl. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CLI's api-get passthrough needs to return an API response body verbatim. Add HttpTransport.get_text and Client.get_raw alongside the existing typed getters, returning the undecoded body text. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The api-get passthrough must surface the response body byte-for-byte so the caller can pipe it through jq. Add emit_raw, which writes to stdout unchanged in both human and --json modes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The flow-ai skill reads Flow via curl with the token attached through a command substitution, which Claude Code cannot auto-approve, so every read prompts for permission. Add 'flowbio api get <path> [--param k=v]', a GET-only command that resolves credentials itself and writes the raw response body to stdout, giving the skill a single allowlistable command. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cover the read-only concept, the --param encoding rule, credential precedence, and the exit-code contract with one worked example, per the CLI-docs convention of not duplicating --help output. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Clarify the get_text docstring (it returns text without parsing JSON) and align the api-get RST example with the bash lexer used by the sibling command examples. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The api-get command previously resolved credentials for every invocation, so with no token available and a non-interactive stdin it exited 2 instead of serving public data. Flow serves public resources unauthenticated, so a read should not require a token. Add an AnonymousCredentials strategy (no-op authenticate, no Authorization header) and an allow_anonymous fallback in resolve_credentials: when no token resolves and --login was not passed, api get reads anonymously. A token still wins when present and --login still forces authentication. The fallback is opt-in per command (api get only) via set_defaults, so the upload commands still require credentials. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@claude please review this PR |
|
Claude finished @mhusbynflow's task in 2m 2s —— View job Review —
|
What
Adds a read-only
flowbio api get <path> [--param KEY=VALUE ...]CLI command: an authenticated-or-anonymous GET passthrough that writes the raw API response body to stdout.Motivation. The
flow-aiskill reads Flow viacurlwith the token attached through a command substitution ($(< ~/.config/flow/api-token)). Claude Code cannot auto-approve a Bash command containing command substitution, so every read prompts for permission. Aflowbio api get …command has no substitution and is allowlistable once asBash(flowbio api get:*). It also consolidates token handling in the CLI and keeps the token out of argv and the transcript.How
HttpTransport.get_text+Client.get_raw: raw-body GET primitive (returns the response body as text, unparsed).Output.emit_raw: writes the body to stdout verbatim (no newline, no JSON reshaping) in both human and--jsonmodes.apiresource with a singlegetverb: positionalPATH(relative to the base URL, leading slash optional), repeatable--param KEY=VALUE(URL-encoded), and a?-in-path rejection that points at--param.AnonymousCredentials+ anallow_anonymousfallback inresolve_credentials: with no token available and no--login,api getreads anonymously (public resources only). A token still wins when present;--loginstill forces auth. The fallback is opt-in per command, so the upload commands still require credentials.--json, a{"message", "status_code"}stderr envelope.api getsection insource/cli.rst(concept + one worked example, no--helpduplication).Verification
uv run pytest tests/unit→ 303 passed.uv run ruff checkclean on all changed files.Out of scope
flow-aiskill (separate repo) to call this command instead ofcurl.Note
The branch also carries the design spec and implementation plan under
docs/superpowers/(the artifacts these commits were built from). Happy to drop them from the PR if you'd rather they not land onmaster.🤖 Generated with Claude Code