feat(cmd): add subcommand docs to browse docs.stripe.com#1663
Merged
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
RootCommand wraps cobra.Command and exposes WithOptions() for future dependency injection (e.g. HTTP client). Root() provides access to the underlying cobra command for bootstrap and docgen. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
- golangci-lint v2 config with opinionated linter set - goreleaser v2 with ldflags version injection, cosign signing, and grouped changelog - Taskfile with build/run/test/lint/docs/clean tasks - GitHub Actions CI workflow with lint, build, and release jobs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
internal/tools/docgen generates per-command Markdown from the cobra command tree, with optional YAML front matter for static sites. Wired into Taskfile as `task docs`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
feat: bootstrap stripe docs plugin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Introduces internal/docs package with a configurable HTTP client that fetches documentation pages with filesystem caching and TTL-based eviction. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
…nt type Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
- Wrap os errors with fmt.Errorf for wrapcheck compliance - Add doc comments to exported Get and Set methods (revive) - Tighten directory permissions to 0750 and file to 0600 (gosec) - Explicitly discard os.Remove and resp.Body.Close errors (errcheck) - Remove trailing blank line at end of cache.go (gofumpt) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Introduces a new `markdown` package which: - uses goldmark for parsing the Markdown into an AST document - uses glamour for rendering documents with style Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
feat(markdown): add parsing and rendering
Move request construction into callers so do() can be reused by future endpoints (e.g. search) with different methods and accept types. Also switch FetchPage to request text/plain and validate content-type dynamically against the request's Accept header. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Sort query parameters before using the resolved URL as a cache key so that different orderings of the same params produce a cache hit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
feat(docs-client): add HTTP client for fetching docs.stripe.com pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Move default initialization of the docs client and markdown renderer from New() into WithOptions(), creating them only if not explicitly provided. This simplifies main.go to just pass the version. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Strip ANSI codes and disable the pager when invoked by an AI coding agent (Claude Code, Cursor, Codex, Gemini CLI, etc.) to save tokens and avoid broken output in non-interactive contexts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
feat(cmd): wire page fetching into root command
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
- gofmt/goimports: reformat files and fix import group ordering (stripe-cli imports in their own group per goimports local-prefix config) - misspell: cancelled→canceled, behaviour→behavior, initialised→initialized - dogsled: suppress triple-blank-identifier in cache_test (unavoidable, test only cares about the error return) - gocritic/unlambda: replace lambda wrapper with strings.ToLower directly - gocritic/ifElseChain: rewrite two if-else chains in model.View as switch - staticcheck/SA4006: drop two unused model assignments in model_test.go - gocyclo: extract applyPage, handleSelected, and handleKey helpers from Model.Update to bring cyclomatic complexity from 53 down to within limit - remove internal/tools/docgen (plugin-specific; can be added back later) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Windows does not honor Unix-style mode bits for read access, so chmod 000 had no effect and the expected error was never returned. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Same reason as the unreadable-file skip: chmod 0555 has no effect on Windows directory write access, so the expected error was never raised. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
tomer-stripe
left a comment
Collaborator
There was a problem hiding this comment.
couple high level notes but my high level is let's make this conform better to the existing design patterns in the cli. few main things
- let's reuse existing packages where we have them
- we don't have a top-level
internalcommand. let's create adocsspecific one inpkgfor anything there - i think we'll want to make
skillsits own top level command, not namespaced bydocs. let's talk to folks about that one
The reviewer flagged that skills shouldn't be namespaced under `stripe docs` — it belongs as a top-level command. Removing it here keeps the docs subcommand focused and avoids shipping the wrong UX while the correct placement is decided. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The internal/agent package duplicated logic already in pkg/useragent, and the docs client was building its own user-agent string instead of using the one the rest of the CLI sends. Consolidating ensures the docs client is consistent with telemetry elsewhere in the CLI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The flag name --non-interactive better describes the intent (suppress all interactive UI, not just the TUI specifically) and is more consistent with conventions used elsewhere in the CLI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The internal/browser package duplicated browser-launching logic that already existed in pkg/open. Keeping a separate package for a single use-case added unnecessary indirection; consolidating reduces the internal package count and puts the URL safety validation where it can be shared by other callers if needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The rest of the CLI uses logrus for logging; the docs packages were using log/slog with a custom charm.land handler. Consolidating on logrus removes the extra dependency and makes log output consistent with the rest of the CLI's formatting and level configuration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The rest of the CLI uses afero to decouple filesystem operations from OS-specific behavior and to enable in-memory testing without temp directories. Adopting it here removes the Windows-specific test skips and eliminates the need to chmod files to simulate error conditions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
These were pulled in by the slog/charm logger removed in c579963. Running go mod tidy after that change cleans up the now-unused entries. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The previous name read as if the function was acting on the page rather than updating the model with new page data, which was misleading at the call sites. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The reviewer flagged that new packages should live under pkg/ rather than a top-level internal/ directory. Nesting under pkg/docs/ makes the ownership clear and keeps docs-specific packages grouped together. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The palette component was an external dependency on a personal repo (github.com/joelzwarrington/foam). Bringing it in-tree removes that external dependency, making the codebase self-contained and avoiding reliance on an upstream that could change or disappear. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The reviewer flagged that pinning to a specific patch release is unnecessary and should be kept as a separate change from feature work. Keeping it at 1.26.0 avoids mixing version bumps into this PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The files were not run through gofmt before the initial commit, causing golangci-lint to flag them. Keeping formatting consistent avoids noise in future diffs and keeps CI green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The vendored palette package carried British spellings and a View() function with cyclomatic complexity above the project threshold. Fixing these up-front keeps the linter clean and avoids the issues surfacing in future review cycles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
The test was written when the docs command lived as a standalone plugin with its own user-agent prefix. Now that it's part of the CLI, the assertion needs to match the standard CLI user-agent format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
Resolved three conflicts: took the newer go-git and sha1cd versions from master, added the directory plugin hint while omitting docs (now a built-in command), and updated the AI agent help string accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
vcheung-stripe
requested changes
Jun 25, 2026
vcheung-stripe
left a comment
Collaborator
There was a problem hiding this comment.
Only blocking thing I have is to update the help text examples, otherwise lgtm!
- Prefix all help text examples with `stripe docs` instead of bare `docs` - Make --no-pager imply non-interactive mode (skip TUI when --no-pager is set) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Committed-By-Agent: claude
vcheung-stripe
approved these changes
Jun 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces
stripe docsas a built-in subcommand. It was prototyped as a standalone plugin and is bundled into the CLI directly without requiring installation.CleanShot.2026-06-11.at.15.43.08.mp4
Subcommands
stripe docs <path>Opens a docs page by its path. In a terminal it launches an interactive browser; with
--no-tui(or when called from an AI agent) it renders plain Markdown to stdout.CleanShot.2026-06-11.at.15.44.00.mp4
stripe docs search <query>Searches docs.stripe.com.
CleanShot.2026-06-11.at.15.45.09.mp4
stripe docs api <resource>— API reference lookupLooks up API reference pages by resource name (
product), HTTP method + path (GET /v1/products), or event name (product.created). Resolves the canonical reference page and renders it.CleanShot.2026-06-11.at.15.46.12.mp4
stripe docs skills list— agent skillsLists AI agent skills available from docs.stripe.com, with install instructions for connecting them to Claude Code, Cursor, Copilot, etc.
CleanShot.2026-06-11.at.15.47.13.mp4
As the subcommand was developed as a plugin outside of this repository, it contains several new packages at
internal/. To keep this PR as simple as possible and easier to review, minimal changes have been done to migrate the code from https://github.com/stripe/stripe-cli-docs-plugin-go to here.Post merge, I'll be cleaning up some of the duplicated packages. i.e.
internal/agentis very similar topkg/useragent.