This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
make build # build ./bin/quartr, version baked in via -ldflags
make test # go test ./...
make install # go install ./cmd/quartr; if QUARTR_API_KEY is in env,
# also runs `quartr auth login` to persist the key
# to ~/.config/quartr/config.json (mode 0600)
make dist # cross-compile release archives + checksums into ./dist
make clean # remove ./bin and ./dist
go test ./internal/cli -run TestBuildConfigPrecedence # run a single test
pre-commit run --all-files # lint+test against the whole tree
~/go/bin/golangci-lint run # lint without pre-commit (needs v2.12+)pre-commit install was already run in this clone — every commit runs golangci-lint (with --fix) and go test ./.... The lint hook shells out to the golangci-lint on PATH instead of the upstream pre-commit repo, which builds the linter from source with whatever Go it finds; a linter built with Go < 1.27 refuses to load this config, and one built with an older patch release than the go on PATH panics while type-checking the standard library (file requires newer Go version). Whenever the toolchain moves, rebuild the linter with it:
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.13.2CI pins the same version through golangci/golangci-lint-action@v7.
Three internal packages, no external deps (Go stdlib only):
internal/quartr— HTTP client and config persistence.Client.GetBytesretries 429/5xx with backoff (honorsRetry-After).LoadConfig/SaveConfighandle the JSON file at~/.config/quartr/config.json.internal/cli— command dispatch and request shaping. The whole CLI surface is driven by a singleresourcesmap inresources.gokeyed by command name; each entry describes the API path templates, allowed query params (paramSet), and download/stream URL fields.handlers.godispatches the operations (list/get/summary/pages/text/chapters/segments/download/stream) against any resource by reading from that map. Adding a new resource = one map entry, no per-command handler code.internal/output— formats results astable/json/csv/raw.--fieldssupports dotted paths (event.title) viagetPathrecursive traversal.
cmd/quartr/main.go is a 3-line entry point that calls cli.Run.
- Auth precedence is
flag > env > file > defaults— implemented ininternal/cli/config.gobuildConfig. Tests mustt.Setenvto clearQUARTR_*env vars before asserting defaults; otherwise the user's shell env leaks in. - Companies API uses
ids, notcompanyIds— handled bylistFlags.toParamstaking acompanyEndpointflag. Don't generalize this away; Quartr's API is genuinely asymmetric. --allauto-bumps--limitto 500 unless the user passed--limitexplicitly. Detection lives inflagWasPassed(string-scan over the raw args, since theflagpackage can't distinguish "default" from "explicitly default").parseInterspersedinflags.golets users writecmd <id> --flag value. The stdlibflagpackage stops at the first positional, so we shuffle flags before positionals before delegating.- Downloads do NOT send
x-api-keyby default — the QuartrfileUrlis publicly fetchable.--with-api-keyis the opt-in. textstreams to stdout by default;downloadwrites a file by default. Both sharesaveURL. The asymmetry is deliberate: parsed Markdown is meant to be piped or redirected, while PDFs and audio are not. Don't unify them./textreturns a link, not text.DocumentTextDtois{documentId, textUrl, updatedAt, createdAt}; the Markdown lives attextUrlon the CDN.--metadataexposes the envelope.
- golangci-lint v2 syntax (config has
version: "2"at top). v1 is built with Go 1.24 and rejects this repo's Go 1.27 target — never downgrade. gomodguardis referenced asgomodguard_v2after the v2.12 deprecation rename.gocritic.hugeParamis intentionally disabled — passingresource(200B) by value is the design, not a perf bug.gosec G304/G602excluded globally — file paths from CLI args and bounds-checked slice indexes are inherent to the tool.gosec G117is suppressed via//nolint:gosecon the single line where it fires (json.MarshalIndent(cfg, ...)ininternal/quartr/config.go) — that file IS the credential storage, by design.varnamelen/goconst/tagliatelle/canonicalheaderare disabled because they fire heavily on idiomatic short-scope vars, output-format string literals, Quartr's camelCase JSON tags, and Quartr's lowercase headers (x-api-key).
- Remote:
git@github.com:TJC-LP/quartr-cli.git(public). - Module path is
github.com/TJC-LP/quartr-cli, which must keep matching the repo URL — that is what makesgo install github.com/TJC-LP/quartr-cli/cmd/quartr@latestresolve. Renaming the repo means renaming the module. mainis protected — push to a feature branch and open a PR withgh pr create. Direct pushes tomainare rejected..env,bin/, anddist/are gitignored; the.env.exampleexception is preserved.
Cutting a release is one push:
git tag -a v0.2.0 -m "v0.2.0"
git push origin v0.2.0.github/workflows/release.yml fires on v* tags, runs the tests, calls
make dist VERSION=${tag#v}, and publishes the archives with gh release create --generate-notes. A tag containing a hyphen (v0.2.0-rc1) publishes as
a prerelease.
- Tags carry the
v; the reported version does not.v0.1.0producesquartr 0.1.0. The workflow asserts this before publishing, so a mismatch fails the release rather than shipping a mislabeled binary. make distis the single build recipe — CI calls it rather than reimplementing the matrix, and thedistjob inci.ymlruns it on every PR so a broken cross-compile surfaces before a tag exists.- Version resolution lives in
internal/quartr/version.go, not incli, so--versionand theUser-Agentheader cannot drift. Order:-ldflags -X ...quartr.buildVersion, thendebug.ReadBuildInfo(module version forgo install pkg@version, VCS revision for a checkout build), thendev. If you move or renamebuildVersion, updateVERSION_LDFLAGSin the Makefile. - Release archives bundle
README.mdandLICENSEalongside the binary and ship with aSHA256SUMSfile.
The .claude/skills/quartr/ skill (loaded automatically by the harness when working in this repo) documents how to drive the quartr binary at runtime — commands, flags, recipes, and the type-id lookup tables for events and document forms (10-K = 11, etc.). Reference it instead of re-deriving CLI usage from the source.