AGENTS.md · git:20261001.9f519c0 · 2026-10-01 · sha256 c2c8ea6d5b439659

AGENTS.md git:20261001.9f519c0A

Immutable. This exact content never changes and is served at /api/v1/blob/c2c8ea6d5b439659.

# AGENTS.md : gplay

Public Go CLI for the Google Play Developer API: one static binary for CI and AI agents, replacing Fastlane `supply`. Distributed via Homebrew (`PollyGlot/homebrew-tap`) and releases; agent skills live in the sibling repo `PollyGlot/google-play-cli-skills`.

## Glossary

Canonical terms live in `CONTEXT.md`; use them verbatim, no synonyms. The core five:

- **Edit**: the API's transactional unit; implicit (per-command) by default, explicit via `gplay edits begin/commit`, pinned in `.gplay/edit-<package>.json`.
- **Account**: a locally registered service-account credential; exactly one active at a time.
- **Project**: repo-local package pin in `.gplay/config.json` (package only, never an Account).
- **Listing**: per-locale store text (title/descriptions/video); release notes and images are separate resources.
- **Track / release**: where a build ships; `production` releases default to `draft` unless `--complete`/`--staged` (ADR-0002).

## Commandes

- The CLI is self-documenting: run `gplay <cmd> --help` to confirm the interface before coding.
- To check an API method's shape, `grep docs/discovery/paths.txt` or `jq` the snapshot; query it, it is too large to read whole.
- Design authority: `docs/DESIGN.md` (auth precedence, exit codes, output, edit lifecycle); **scope authority is the GitHub issue tracker** (`type:prd` / `type:slice` for planned work, `type:parking` for deferred, queried with `gh issue list`), with `docs/COVERAGE.md` as the method-level view (generated by `make coverage-update` from `internal/apiregistry`, never hand-edited); surprising decisions: `docs/adr/`.

## Issues and tickets

Issue tracker, triage labels and domain docs: `docs/agents/`. `to-tickets`,
`triage`, `to-spec`, `wayfinder` and `implement-spec` read their config there.

## Vérifier

- Gate before every PR: `make check`, the required CI checks run locally (`make format` fixes what its format step rejects; `make install-hooks` runs it on pre-push).
- Tests stay offline: use `internal/testkit` (Play transport fake, shared RSA key) injected as `&http.Client{Transport: ...}`; a hand-rolled RoundTripper fails the ratchet (`internal/ratchet`), and a test that reaches the network is wrong.
- New leaf command: classify it. Unlabelled means frozen Public contract (ADR-0010/0042); mark `kernel.Experimental(...)` at registration if its flags may still change. The registry test in `cmd/gplay` fails on unclassified leaves.
- To prove a command **behaves** as advertised, build this worktree and drive the
  offline path: `b=$(mktemp -d)/gplay && go build -o "$b" ./cmd/gplay && "$b" schema --list`
  (then `auth list`, `<cmd> --help`). Two traps: `--version` does not exist (it is
  the `version` subcommand), and a pipe masks the exit code (`gplay tracks list`
  returns 2 alone, 0 when piped into `head`). The local `verify` skill, when
  present, adds evidence capture.

## Les pièges de ce repo

- Never write an API URL by hand: call `apiregistry.Resolve(<method id>)` for the verb and URL template, and add the method to `internal/apiregistry` if it is missing (`archgate_test.go` there fails on any literal API path under `internal/play/` or `commands/`, `internal/play/gcs` excepted).
- Hand-roll every Developer API call in `internal/play/api/` over raw HTTP; the interface stays `google.golang.org/api/androidpublisher`-free (ADR-0007). Auth uses `golang.org/x/oauth2/jwt` fed by the parsed key (depguard bars `oauth2/google`: it links the GCE metadata client).
- `--output json` mirrors the API response verbatim (ADR-0003); stdout carries data, stderr carries logs. Keep it that way in every command.
- release-please bumps the CLI version from the commit **type** alone, blind to paths: reserve `feat`/`fix` for changes to the shipped binary, and type `website/`, `docs/`, `.github/` work as `docs`/`chore`/`ci` (the site deploys on path triggers regardless).
- Solo maintainer, so no approving review can exist: code PRs merge through `scripts/merge-pr.sh <n>` (refuses a head behind `origin/main` or a required check not green, then `gh pr merge --admin --squash`); docs-only PRs (only `*.md` and doc assets, the inverse of the `code` filter in `.github/workflows/ci.yml`, `docs/discovery/**`, the generated `docs/COVERAGE.md` and the pages holding `make docs-update` blocks, `README.md` included, count as code) may skip it once every check is green.
- `internal/` and `commands/` count as code whatever the extension: the binary embeds JSON and CSV via `go:embed`.

## Goût

New surfaces earn their place through an issue first (`type:prd`, or `type:parking` when deferred): surface the scope decision there, then apply the matching `docs/DESIGN.md` section, write the RoundTripper-mocked test, and keep `--help` and docs in `CONTEXT.md` vocabulary.