Unofficial, fast, lightweight, agent-assisted, reviewer-owned CLI for the App Store Connect API. Built in Go with ffcli.
Agent Skills for automating asc workflows including builds, TestFlight, metadata sync, submissions, and signing. https://github.com/rudrankriyam/app-store-connect-cli-skills
- Explicit flags: Use long-form flags in docs/tests/examples (
--app,--output) for clarity - TTY-aware output defaults:
tablein interactive terminals,jsonfor pipes/CI; use--outputfor explicit formats - No interactive prompts: Use
--confirmflags for destructive operations - Pagination:
--paginatefetches all pages automatically
Before implementing or testing any command, run --help to confirm the exact interface. The CLI is self-documenting:
asc --help # List all commands
asc builds --help # List builds subcommands
asc builds list --help # Show all flags for a commandDo not memorize commands. Always check --help for the current interface.
When looking up App Store Connect API docs, prefer the sosumi.ai mirror instead of developer.apple.com.
Replace https://developer.apple.com/documentation/appstoreconnectapi/... with https://sosumi.ai/documentation/appstoreconnectapi/....
For endpoint existence and request/response schemas, use the offline snapshot:
docs/openapi/latest.json and the quick index docs/openapi/paths.txt.
Update instructions live in docs/openapi/README.md.
Notes:
- Validate flags against the request schema for the method you're implementing (create vs update often differ).
- Validate query params against the specific endpoint (top-level vs relationship endpoints may allow different filters).
make build # Build binary
ASC_BYPASS_KEYCHAIN=1 make test # Run tests with keychain bypass (always run before committing)
make lint # Lint code
make format # Format code
make install-hooks # Install local pre-commit hook (.githooks/pre-commit)Canonical test rule: all test runs must use ASC_BYPASS_KEYCHAIN=1 to avoid host keychain prompts and profile bleed-through.
- Before opening or merging a PR, run
make format,make check-command-docs,make lint, andASC_BYPASS_KEYCHAIN=1 make test. - If command/help text changed, run
make generate-command-docsand commitdocs/COMMANDS.mdbefore running checks. - Use
make install-hooksonce per clone to enforce local pre-commit checks. - CI must enforce formatting + lint + tests on both PR and
mainworkflows. - Remove unused shared wrappers/helpers when commands are refactored.
- Use TDD for behavior changes: bugs, refactors that alter behavior, and new features.
- Start with a failing test that captures the expected behavior and edge cases.
- For new features, begin with CLI-level tests (flags, output, errors) and add unit tests for core logic.
- Verify the test fails for the right reason before implementing; keep tests green incrementally.
- Test realistic CLI invocation patterns, not invented happy paths. For example, when testing argument parsing, always consider:
- Flags before subcommands:
asc --flag subcmdvsasc subcmd --flag - Flag values that look like subcommands:
asc --report junit completion - Multiple flags with values:
asc -a val1 -b val2 subcmd
- Flags before subcommands:
- Model tests on actual CLI usage, not assumed patterns. Check
--helpoutput to understand real command structure before writing tests.
- Reproduce first: Before fixing, run the failing test locally to confirm the issue. Don't assume you understand the bug.
- One change at a time: Make one small fix, verify it works, then move to the next. Don't batch multiple changes.
- Re-run after each fix: Re-run the specific failing test after each fix before running the full suite.
- One logical change per commit: Keep commits narrowly scoped and reviewable. Avoid mixing refactor + bug fix + test rewrites in a single commit.
- Never bypass checks: Don't use
--no-verify, don't push directly tomain, don't skip tests to "get around" failures. - Be honest about pre-existing issues: If a test was failing before your changes, say so. Don't claim credit for "fixing" something you didn't break.
- Verify before claiming done: Run the specific failing test again to confirm it's fixed, not just "all tests pass".
- Avoid broad skip logic: Don't skip tests with generic string matches (e.g., "Keychain Error") that can hide regressions. Match specific error codes instead.
- Isolate test auth/env state: Tests that touch auth must set/clear relevant env vars (
ASC_BYPASS_KEYCHAIN,ASC_PROFILE,ASC_KEY_ID,ASC_ISSUER_ID,ASC_PRIVATE_KEY_PATH,ASC_PRIVATE_KEY,ASC_PRIVATE_KEY_B64,ASC_STRICT_AUTH) locally and restore exact original state. - Local test command: When running repository tests manually, use
ASC_BYPASS_KEYCHAIN=1 make testto prevent macOS keychain profile prompts from host environment bleed-through. - Strict skip policy:
t.Skipis allowed only for specific, documented, reproducible conditions (exact error code/condition). Generic skip patterns are not allowed. - Use proper workflow: Branch → change → test → PR. Not: main → change → push.
- Done means checks pass, key exit-code scenarios are validated, and commands run are recorded in handoff.
- For CLI behavior changes (flags, exit codes, output/reporting), follow this sequence:
- Add/adjust failing tests first (RED), then implement (GREEN).
- Do not add placeholder tests; every new test must assert exit code, stderr/stdout, and/or parsed structured output.
- For every new or changed flag, add:
- one valid-path test
- one invalid-value test that asserts stderr and exit code
2
- For argument/subcommand parsing, test edge cases: flags before subcommands, flag values that match subcommand names, mixed flag order.
- Never silently ignore accepted flags; unsupported values must return an error.
- For JSON/XML output tests, parse output (
json.Unmarshal/xml.Unmarshal) instead of relying only on string matching. - For report/artifact file outputs, test both successful write and write-failure behavior.
- Verify CLI exit behavior using a built binary (not only
go run) for black-box checks:go build -o /tmp/asc .- run
/tmp/asc ...and assert exit code + stderr/stdout
- For any new/changed API-facing flag (query params or request attributes), cross-check
docs/openapi/latest.jsonto ensure:- the attribute exists in the correct request schema (create-only vs update-only is common)
- the query parameter is permitted for that endpoint (top-level vs relationship endpoints can differ)
- if the API doesn't support it, don't ship a flag; implement client-side behavior or document the limitation explicitly
- If the change depends on ASC API quirks and you have credentials available locally, run a minimal live smoke test with a built binary (
/tmp/asc).- Prefer read-only commands first; for write operations, use a throwaway app/resource and clean up (create-then-delete).
- Before opening/updating a PR, always run:
make formatmake check-command-docsmake lintASC_BYPASS_KEYCHAIN=1 make test
- In the PR description or handoff, include:
- commands run
- key exit-code scenarios validated
- Default mode is architecture-first, not vibe-first.
- Before implementing any new command/flag, produce a short design note covering:
- command placement in existing taxonomy,
- OpenAPI endpoint/schema validation,
- UX shape (flags/output/exit codes),
- backward-compatibility and deprecation impact,
- RED -> GREEN test plan.
- If command shape is ambiguous, stop and align before coding.
- User-facing commands/flags must follow lifecycle states:
experimental,stable,deprecated,removed. - Do not delete stable commands directly; deprecate first with migration guidance.
- Deprecations must include:
- warning text in help/output,
- tests covering old and new behavior during transition,
- changelog entry with upgrade path.
For each substantial change, include:
- why this approach was chosen,
- one to two alternatives considered and trade-offs,
- expected invocation examples and outputs,
- edge cases and failure modes tested.
A change is not done if the reviewer cannot explain command behavior and trade-offs from the handoff.
- Parallel agents are allowed for independent exploration or test drafting.
- Final implementation integration must be done in a single coherent pass.
- Avoid concurrent edits to the same command group.
- Register new commands in
internal/cli/registry/registry.go. - Always set
UsageFunc: shared.DefaultUsageFuncfor command groups and subcommands. - For outbound HTTP, use
shared.ContextWithTimeout(orshared.ContextWithUploadTimeout) soASC_TIMEOUTapplies. - Validate required flags and assert stderr error messages in tests (not just
flag.ErrHelp). - Add
internal/cli/cmdtestcoverage for new commands; usehttptestfor network payload tests.
API keys are generated at https://appstoreconnect.apple.com/access/integrations/api and stored in the system keychain (with local config fallback). Never commit keys to version control.
| Variable | Purpose |
|---|---|
ASC_KEY_ID, ASC_ISSUER_ID, ASC_PRIVATE_KEY_PATH, ASC_PRIVATE_KEY, ASC_PRIVATE_KEY_B64 |
Auth fallback |
ASC_BYPASS_KEYCHAIN |
Ignore keychain and use config/env auth |
ASC_STRICT_AUTH |
Fail when credentials resolve from multiple sources (true/false, 1/0, yes/no, y/n, on/off) |
ASC_APP_ID |
Default app ID |
ASC_VENDOR_NUMBER |
Sales/finance reports |
ASC_TIMEOUT |
Request timeout (e.g., 90s, 2m) |
ASC_TIMEOUT_SECONDS |
Timeout in seconds (alternative) |
ASC_UPLOAD_TIMEOUT |
Upload timeout (e.g., 60s, 2m) |
ASC_UPLOAD_TIMEOUT_SECONDS |
Upload timeout in seconds (alternative) |
ASC_DEBUG |
Enable debug logging (set to api for HTTP requests/responses) |
ASC_DEFAULT_OUTPUT |
Default output format: json, table, markdown, or md |
When ASC_DEFAULT_OUTPUT is unset, defaults are TTY-aware (table in terminals, json for non-interactive output).
Explicit --output flags always override ASC_DEFAULT_OUTPUT and TTY-aware defaults.
Detailed guidance on specific topics (only read when needed):
- Go coding standards:
docs/GO_STANDARDS.md - Testing patterns:
docs/TESTING.md - Git workflow, CLI structure, adding features:
docs/CONTRIBUTING.md - API quirks (analytics, finance, sandbox):
docs/API_NOTES.md - Development setup, PRs:
CONTRIBUTING.md(root)