AppMates 🚀
Catch App Store and Google Play rejections before the stores do.
You upload ten screenshots, wait, and App Store Connect replies
IMAGE_TOOL_FAILURE with no explanation. The actual cause is usually mundane —
a stray alpha channel, a resolution that was valid in 2019, a screenshot two
pixels too tall for Play's aspect ratio rule. AppMates finds those in
milliseconds, tells you exactly which rule you broke, and can repair the files
for you.
$ appmates validate-screenshots ./store/ios/en-US
Auto-detected target store: apple (override with --store)
File Size Device Findings
─────────────────────────────────────────────────────────────────────────────
screen-01.png 1242×2688 iPhone 6.5" ✗ APPLE_ALPHA_CHANNEL
2.9 MB (legacy) Image has an alpha channel (mode RGBA).
→ Flatten onto an opaque background.
! APPLE_LEGACY_SIZE
1242x2688 is absent from Apple's current table.
→ Current equivalent is iPhone 6.5" (1284x2778).
FAIL 10 file(s) checked against apple · 10 error(s) · 10 warning(s)
$ appmates fix-screenshots ./store/ios/en-US --out ./store/ios/en-US-fixed
$ appmates validate-screenshots ./store/ios/en-US-fixed --strict
PASS 10 file(s) checked against apple · 0 error(s) · 0 warning(s)
Why it exists
Three things break releases, and all three are mechanically checkable:
| Problem | What AppMates does |
|---|---|
| Screenshots that violate a store rule | Validates format, alpha channel, colour space, exact resolution, aspect ratio, file weight — and repairs all of them |
| Listing text over a character limit | Checks title/subtitle/description/keywords against both stores' limits, and warns before translation pushes you over |
| Google Play's 12-testers-for-14-days gate | Tracks the streak day by day, including the dips that silently reset your clock |
| A keyword field quietly wasting a third of its budget | Audits the 100 characters Apple never shows anyone, and rebuilds them |
| Building an app into a market that cannot be won | Scores a niche from the public catalogue before you write any code |
| Designing screenshots with no idea what the field does | Summarises competitors' screenshot conventions, and saves theirs for reference |
| No idea whether your listing is indexed at all | Reports your position per keyword and tracks it over time, locally |
| Launching into the one storefront where the term is locked | Scores the same keyword across 14 storefronts and ranks them |
Install
pip install -e ".[dev]"
Or with uv, which is what CI uses:
uv sync --extra dev
Try it without installing anything:
uvx --from . appmates specs
Commands
validate-screenshots
appmates validate-screenshots ./screenshots
appmates validate-screenshots ./screenshots --store google --strict
appmates validate-screenshots ./screenshots --json | jq '.assets[].findings[].code'
appmates validate-screenshots ./screenshots --ignore APPLE_LEGACY_SIZE
--store defaults to auto. App Store and Play screenshots are genuinely
different assets — every current Apple iPhone size violates Play's "long side
≤ 2× short side" rule — so validating one directory against both always
produces noise. AppMates picks whichever store the files actually fit and
tells you which it chose. Use --store both when you want the cross-check anyway.
fix-screenshots
appmates fix-screenshots ./screenshots # dry run: prints the plan
appmates fix-screenshots ./screenshots --out ./fixed # writes repaired copies
appmates fix-screenshots ./screenshots --out ./fixed \
--target apple-iphone-6.9 --background "#0B0B0F"
Flattens alpha onto an opaque background, converts to sRGB, resizes to the nearest valid spec size, and re-encodes anything over the weight limit.
Your originals are never touched. The fixer refuses to write into its own
source directory, and refuses a non-empty output directory without --force.
Resizing letterboxes rather than stretches — a distorted UI screenshot looks
broken to reviewers.
check-testers
appmates check-testers --days-passed 9 --active-testers 12
appmates check-testers --from-file tester-history.json
appmates check-testers -d 20 -t 12 --release-pending
╭─ Google Play · Closed testing ───────────────────────────────╮
│ Status NOT YET ELIGIBLE │
│ Testers 12 / 12 │
│ Continuous days 9 / 14 │
│ Progress ████████████░░░░░░░░ 64.3% │
│ Projected date 2026-07-31 │
╰──────────────────────────────────────────────────────────────╯
The requirement is 12 testers opted in continuously for 14 days. The word
that costs people two weeks is continuously: if your count drops to 11 on day
nine, Google restarts the clock. Pass a day-by-day timeline with --from-file
and AppMates detects the reset:
[
{ "date": "2026-07-01", "opted_in": 12 },
{ "date": "2026-07-02", "opted_in": 11 },
{ "date": "2026-07-03", "opted_in": 13 }
]
The flat --days-passed form cannot see a dip by construction, and the output
says so rather than quietly implying you are fine.
niche
appmates niche "habit tracker" "morning routine" --country fr
appmates niche "sourdough starter log" --leaders
appmates niche "budget app" --json | jq '.keywords[0].verdict'
Keyword score verdict credible competitors
bouldering training log 76.1 OPEN 3
sourdough starter log 66.3 OPEN 1
gratitude journal 39.2 CONTESTED 32
habit tracker 30.8 LOCKED 49
photo editor 16.2 LOCKED 149
Answers the question the established ASO tools structurally cannot: should I build this at all? Rank trackers and keyword optimisers assume a live app — you cannot track the ranking of something that does not exist. This runs before the first line of code, on the public App Store catalogue, with no account and no API key.
There is deliberately no "search volume" number. Apple has never published per-keyword search counts. The Search Ads popularity index that other tools relabel as volume is a relative score with no published methodology, and in September 2025 the number of US keywords scoring above the floor dropped 77% in four days when Apple changed something and told nobody. Every number AppMates prints is something it counted.
Six signals, each shown with its raw observation so you can disagree with the weighting and still trust the facts:
| Signal | What it observes | Why it matters |
|---|---|---|
| Leader entrenchment | median ratings of the top 10 | You can out-design a competitor in a quarter; you cannot out-accumulate ten years of reviews |
| Credible competitors | apps with >1,000 ratings | Not how many apps exist — how many actually hold the position |
| Incumbent neglect | median days since the leaders shipped | A neglected market is an opening; weekly releases mean a funded team defending it |
| User dissatisfaction | median stars of the leaders | 4.9★ incumbents give users no reason to switch; 3.6★ is a product opening |
| Keyword under-targeting | share of leaders with the term in their name | Leaders ranking incidentally means the term is takeable by simply targeting it |
| Publisher concentration | share of slots held by repeat publishers | One studio holding several slots is cross-promotion you cannot outspend |
The weights, curves and thresholds all live in
core/specs/market.yaml with the
reasoning written next to each number. Edit them and re-run.
On the raw result count. An earlier revision scored saturation from the number of apps the store returns. Measured across eight keywords spanning photo editor to sourdough starter log, it returned 162–191 every time — a standard deviation of 9, because the store pads every result page with loosely related apps. Three unrelated markets scored 45, 46 and 47. Counting only apps with real traction separates the same keywords by 1 to 149. The result count is still reported as context, but it is not scored.
markets
appmates markets "habit tracker"
appmates markets "budget app" --countries us,fr,de,jp,br
appmates markets "gratitude journal" --json | jq '.best_country'
habit tracker across 8 storefront(s)
Storefront Score Verdict Credible rivals
France FR 51 ██████░░░░ CONTESTED 12
Italy IT 50 ██████░░░░ CONTESTED 15
Japan JP 48 ██████░░░░ CONTESTED 23
Germany DE 41 █████░░░░░ CONTESTED 36
United States US 31 ████░░░░░░ LOCKED 49
This term is CONTESTED in France and LOCKED in United States.
Which storefront you lead with is a bigger lever here than anything you
can do to the listing itself.
Every ASO tool asks how hard is this keyword? as though there were one answer. There are 175 storefronts and the answer differs in each — difficulty tracks the language a term is searched in more than the size of the country. "habit tracker" faces 49 credible rivals in the US and 12 in France.
That makes it a launch decision — which locale to write first, which language to
localise screenshots into — and almost nobody asks it before shipping. It uses
the same six signals as niche, one storefront at a time.
The summary keys off whether the verdict changes, not the numeric spread. A 19-point gap that moves a term from LOCKED to CONTESTED changes what you should do; a 30-point gap entirely inside CONTESTED does not. An earlier version summarised on the spread alone and reported "about as hard everywhere" for a term that was locked in the US and contested in France.
This is deliberately slow: one request per storefront against a free endpoint that rate-limits, spaced politely apart. A 14-country sweep takes about a minute the first time, then comes from cache. A storefront that fails is recorded and skipped rather than aborting the sweep.
app
appmates app 1438388363
appmates app com.example.myapp --country fr --json
Habit Tracker
Publisher Inner Grow Limited
Version 2.14.18 · shipped 2026-07-10
Rating 4.79★ from 144,369
Size 321.7 MB
Languages 10 — EN, FR, DE, IT, JA, PT, RU, ZH, ES, KO
Listing health
✓ App name within 30 characters 13 of 30 characters used.
? At least three iPhone screenshots The catalogue returned iPad screenshots but not
iPhone ones, which it does for about half of apps.
✓ Recently updated Last shipped 17 days ago.
✗ Downloadable over cellular 321.7 MB.
→ Over 200 MB needs Wi-Fi unless the user has
opted in — friction at the moment they decided
to install.
89/100 — 8 of 9 answerable checks passed, 2 could not be answered
Eleven checks over one published listing: name length, description, screenshot count and aspect ratio, update recency, release notes, localisation, download size, rating volume.
The interesting part is what it refuses to conclude. A check that cannot be answered is marked
?and excluded from the score — an app whose screenshots the catalogue happened to withhold must not rank below one whose it happened to return. That distinction needs the device list: an app that supports iPhone but exposed no iPhone screenshots has almost certainly shipped them, while an iPad-only app genuinely has none. Without it, the first would be reported as a defect and a developer would go "fix" something that was never broken.Two further limits are stated rather than worked around. Screenshot URLs serve a downscaled image that preserves the aspect ratio but not the resolution, so the device family is inferred and the uploaded pixel size is never claimed. Subtitles and the keyword field are not public at all, so neither is checked.
In the web app this is the Overview page, and the app you load there becomes the app the whole session is about — its id prefills the rank check, its name prefills the competitor comparison and the keyword builder.
competitors
appmates competitors "habit tracker" --top 10
appmates competitors "gratitude journal" --screenshots
appmates competitors "gratitude journal" --download ./rivals --width 300
appmates competitors "budget app" --country fr --json
habit tracker · US · 190 results
# App Ratings Stars Updated iPhone iPad
1 Habit Tracker 144,343 4.8 16d 0 10
2 Habit Tracker - HabitKit 2,274 4.9 55d n/a n/a
3 Onrise: Habit Tracker 2,495 4.8 187d 7 0
4 Productive - Habit Tracker 91,098 4.6 129d 7 7
What this field does with screenshots
Median iPhone screenshots 7
Count distribution 3×1 · 7×3
Mostly portrait 4 of 5
Ship iPad screenshots 3 of 5
Using all 10 slots 0
Who you are up against for a term, and how they present. The niche summary is the useful part: knowing the field ships a median of seven portrait screenshots tells you more than any single competitor does.
Dimensions and orientation are read from the screenshot URLs themselves —
the catalogue encodes the served size in the last path segment — so describing
a competitor's whole gallery costs no bandwidth. --download saves them for
offline reference.
Screenshot availability is partial, and the tool says so. Across a 55-app sample the catalogue exposed iPhone screenshots for 47% of apps and some set for 55%. Apps it withheld are marked
n/arather than shown as having none, and they are excluded from the medians instead of counted as zeros — folding them in would halve every figure for a reason that has nothing to do with your competitors. iPhone and iPad counts are separate for the same reason: an app can expose ten iPad screenshots and no iPhone ones.
--terms: what the field agrees on
appmates competitors "gratitude journal" --terms --mine "Kaizen: Gratitude"
Term Consensus In app names In descriptions Yours
habit 92 9/10 10/10 yes
tracker 70 8/10 3/10 yes
goal 30 2/10 7/10 —
routine 18 1/10 5/10 —
Not in your listing: goal, routine, daily, streak
appmates keywords --title '…' -t 'goal' -t 'routine' -t 'daily'
Closes the loop: find the vocabulary your rivals share, then feed what you lack
straight into keywords.
Terms are counted once per app, not per occurrence — otherwise one verbose description outvotes the field. App-name usage weighs four times description usage, because a word inside a 30-character name is a deliberate decision while the same word in paragraph four may be prose. Plural variants are merged, since a field where every app says both "habit" and "habits" would otherwise report each at half strength and neither would rank.
This sees roughly half of what rivals target. The public catalogue exposes app names and descriptions. It does not expose subtitles or keyword fields. Treat the result as a floor on their vocabulary, not the whole of it.
rank
appmates rank 1438388363 "habit tracker" "daily habits"
appmates rank com.example.myapp "budget" --country fr
appmates rank 1438388363 "habit tracker" --history ./ranks.jsonl
Habit Tracker · US · ranked for 3/3 term(s)
Keyword Position Movement Since
habit tracker #1 ▲ 3 2026-07-20
daily habits #1 ▲ 3 2026-07-20
streak counter #4 ▲ 3 2026-07-20
What this measures. The public catalogue returns results in its own relevance order, and this reports your app's place in that order. It is a real, repeatable signal, and it moves when your metadata moves.
What it is not. The App Store app serves search through a different path, with personalisation and paid placements, so the two can disagree. This is a directional measure of how your listing is indexed — not the number a given user would see. Tools that present a figure like this as the App Store ranking are overstating what any public endpoint can tell them.
--history appends each run to a local JSON Lines file and reports movement
against it. There is no server, so that file is the record; appending never
rewrites earlier lines, and one malformed line cannot discard the rest.
keywords
appmates keywords --title "Kaizen: Habit Tracker" --subtitle "Build daily routines" \
--field "habit, habits, habit tracker, daily, app, free, productivity, streak" \
-t "habit tracker" -t "gratitude journal"
appmates keywords listing.toml --json
appmates keywords --title "Kaizen" -t "habit tracker" -t "morning streak" --build
Budget ███████████████████████░░░░░░░ 77/100 · 58 wasted
✗ ASO_KEYWORD_SPACES -9c 9 space(s) in the keyword field.
✗ ASO_DUPLICATE_OF_TITLE -8c 'tracker' is already in the title.
! ASO_CATEGORY_WORD -13c 'productivity' is already indexed from your category.
! ASO_PLURAL_PAIR -7c 'habits' and 'habit' differ only by pluralisation.
Target phrase Reachable Indexed from
habit tracker yes title (habit, tracker)
gratitude journal no missing: gratitude, journal
suggested routine,morning,streak,gratitude,journal,habits
47/100 characters, 30 reclaimed
The 100-character keyword field is the most technical artefact in a listing and the only one never shown to a user — so nothing about it is self-correcting. A listing with a third of its budget wasted looks exactly like a perfect one.
Every rule follows from one documented Apple behaviour: the app name, subtitle and keyword field are indexed as a single pool of words, and matches are formed by combining them. Three consequences do most of the work:
- A phrase is reachable when every one of its words is in the pool. The
phrase itself never has to appear.
habit,trackerranks for "habit tracker". - A word already in your title is already indexed. Repeating it costs characters and buys no reach.
- Every space is overhead, since Apple does the combining.
habit trackerandhabit,trackerindex identically; the second is a character shorter.
--build packs the minimum set of words covering your target phrases into the
budget, dropping anything already in the title, and emits a bare field for
piping. Target order is treated as priority, so the phrases you listed first
survive truncation.
On the waste figure. Costs are deduplicated per word. One word commonly trips several rules at once —
habitcan be both a duplicate within the field and already present in the title — but deleting it reclaims its characters once, not once per rule. Summing the findings would inflate the total by exactly the double-counting this tool exists to call out.
The word lists and severities live in
core/specs/aso.yaml.
validate-metadata
appmates validate-metadata listing.toml
appmates validate-metadata listing.json --store apple --strict
[[locales]]
locale = "en-US"
title = "Kaizen: Habits"
subtitle = "Small steps, big change"
short_description = "Track habits and build streaks."
description = "Kaizen helps you build lasting habits."
keywords = "habit,streak,focus,routine"
Checks Apple (30/30/170/4000/100) and Play (30/80/4000) limits, flags fields
above 90% of their limit because translations run longer than English, and
catches the Apple keyword traps — spaces after commas waste your 100-character
budget, and repeating title words wastes indexing. Takes every locale in the
file at once — check a [[locales]] block per language in one run rather
than one file per language.
submission-check
appmates submission-check --screenshots ./store/ios --metadata listing.toml
appmates submission-check --keywords "habit,streak,focus"
One go/no-go answer, composed from whichever of validate-screenshots,
validate-metadata and keywords you give inputs for — the same three
engines, so nothing here is a new rule. Runs only what you point it at: give
just --keywords to audit a field with no listing file yet. When --metadata
supplies a listing and --keywords doesn't override it, the keyword audit
reads the title, subtitle and keyword field straight out of that locale,
rather than a second copy typed in separately.
pricing
appmates pricing 4.99
appmates pricing 4.99 --model uniform --countries us,gb,in
Suggests a starting price per storefront from one base price — a read-only
sanity check, never a push to any API. ppp_tier (the default) scales the
price down in lower-income storefronts using coarse World Bank income-group
bands; uniform reprints the same price everywhere for comparison. The bands
are deliberately coarse: exact purchasing-power or Big Mac Index data drifts
throughout the year and nothing here is positioned to keep it current, so a
three-band approximation that's honest about being one beats a
precise-looking number that quietly goes stale. Tiers live in
core/specs/pricing.yaml.
asc — App Store Connect, optional
appmates asc status # is a key configured and accepted?
appmates asc pull com.example.app --out listing.json # real listing text + current prices
appmates asc push-metadata com.example.app listing.json # dry run: prints the diff, sends nothing
appmates asc push-metadata com.example.app listing.json --yes # sends it
Everything else in AppMates works with zero account and zero credentials — this is the one command family that doesn't, because reading or writing your real App Store Connect listing needs your real API key. Three things make that safe to opt into:
Your private key never leaves your machine. It is read from disk once, used to sign a short-lived (15-minute) request token, and that's it — never logged, never cached, never sent anywhere but straight to
api.appstoreconnect.apple.com. AppMates' web dashboard and Cloudflare backend are never in this path, ever; there is nothing to trust beyond Apple itself. Seecore/clients/appstore_connect.pyfor exactly what that covers.
- Credentials live in
.env, never a flag. Copy.env.example, fill inLAUNCHPILOT_APP_STORE_KEY_ID/_ISSUER_ID/_PRIVATE_KEY_PATHfrom a key generated at Users and Access → Integrations. A CLI flag would sit in shell history andpsoutput; an env var doesn't. pullis read-only. It writes the exact{"locales": [...]}shapevalidate-metadataandsubmission-checkalready read — paste it straight into the web dashboard's multi-locale checker, no conversion.push-metadatais a dry run by default. It always prints the field-by-field diff first; nothing is sent until you pass--yes. It also runs the same checksvalidate-metadatadoes before sending anything, and refuses to push a listing with an error-level finding unless you also pass--force.- Pricing is pull-only, on purpose.
asc pullshows what's live per territory next to whatappmates pricingsuggests, but does not push a price schedule — that API references specific price-point ids per territory rather than a plain number, and a mistake there is a real, live price in front of real customers. Set it by hand in App Store Connect until this path has been proven against more accounts than the one it was built against.
specs
appmates specs --store apple
appmates specs --json
Prints the bundled specification catalogue with a last_verified date and the
source URL for each store, so you can see how stale the data is.
Use it in CI
Every command exits 0 clean, 1 on findings, 2 on a usage error.
- name: Validate store assets
run: |
appmates validate-screenshots ./store/ios --store apple --strict
appmates validate-metadata ./store/listing.toml
--json emits the same Pydantic models the planned HTTP API will return, so
anything you build against it now keeps working later.
Web checker (no install, no upload)
Every tool above also runs in the browser, with no install, no account and no
server of ours in the path. The offline tools read file headers rather than
pixels; the market tools call Apple's public catalogue directly, which answers
with access-control-allow-origin: *.
python3 -m http.server 8000 --directory web
Each browser engine is conformance-tested against its Python original — finding codes, character costs, coverage, winnability, every signal's observation and rationale, streak and reset detection. CI fails if they disagree or if any generated file is stale. See web/README.md.
python3 -m http.server 8000 --directory web
It is kept honest rather than kept in sync by hand: the specification data is generated from the same YAML the CLI reads, and the JavaScript engine is tested against the Python one on 925 cases plus a set of real images parsed by Pillow. CI fails if any generated file is stale. See web/README.md.
Community marketplace (optional, needs a backend)
Get real closed testers before you ship, and real users for a launch or
update once you have — the "Get testers" / "Be a tester" pages in the web
app (web/views/community.js, web/views/be-tester.js). Two-sided: a
developer posts a listing, real people request to join, and completing a
test earns the tester a High Five they can spend getting their own app
tested. Nothing here ever touches App Store or Play reviews — see
SECURITY.md for why that boundary is load-bearing, not
incidental.
This is the one part of AppMates that needs an account (magic-link email,
no password) and a backend — a separate Cloudflare Worker + D1 database in
its own private repo,
appmates-community, kept
out of this one because its anti-abuse thresholds and rate limits are a
real target for gaming the token economy once this repo is public.
COMMUNITY_API_URL in web/lib/community.js points at it; null disables
the whole feature (the nav items stay hidden and nothing here is ever
called).
What's shipped today: listing creation with an optional auto-expiry date, owner-side deletion, a platform filter on the marketplace, a leaderboard, push notifications (new request, accepted, build link unlocked, feedback ready, declined), and admin moderation (ban a user, remove a listing) off the back of a report queue. A closed-test listing's TestFlight/Play link stays hidden from everyone until the owner accepts a tester and confirms adding them on the actual store console — there's no App Store Connect/Play Developer API integration here to do that step automatically.
Architecture
src/appmates/
├── cli/ # Typer commands: argument parsing and rendering only
└── core/
├── specs/ # ← versioned YAML spec catalogue + registry
├── models/ # Pydantic contracts (Finding, Severity, reports)
└── services/ # the actual logic
web/ # browser checker, generated from and tested against the above
scripts/ # generators for the web artefacts (run with --check in CI)
Three decisions worth knowing about:
Specs are data, not code. core/specs/*.yaml holds every resolution and
constraint, each entry tagged required / accepted / legacy / deprecated
with a source URL and verification date. Store rules drift constantly; updating
them must never require a code change. registry.py is the only access point,
so moving this to a database later touches one module.
Findings carry stable machine codes. APPLE_ALPHA_CHANNEL,
PLAY_MAX_TWICE_MIN, and friends are part of the public contract — CI
annotations, --ignore, and the fixer all key off them.
The CLI holds no logic. Every command calls a core service that returns a
Pydantic model. The CLI renders it; --json serialises it; FastAPI will return
it. One implementation, three surfaces.
Development
uv sync --extra dev
uv run pytest # 174 tests, coverage gate at 85%
uv run ruff check .
uv run ruff format .
uv run mypy # strict
Test images are generated at run time with Pillow rather than committed — binary fixtures cannot be diffed in review, and they hide the very properties (mode, size, alpha) each test is about.
Roadmap
Open source core
- Screenshot validation for App Store and Play
- Automatic repair (alpha, colour space, resolution, weight)
- Listing text validation for both stores
- Closed-testing streak tracking with reset detection
- JSON output and CI exit codes
- Zero-backend web checker with browser-side repair
-
niche— pre-build market assessment from the public catalogue -
keywords— 100-character field audit, coverage map and builder - Every tool in the browser, conformance-tested against the CLI
-
competitors— the field for a term, and what it does with screenshots -
rank— search position per keyword, with local history tracking -
markets— which storefront a term is actually winnable in -
app— one listing's health, and an Overview page that anchors the session -
competitors --terms— the vocabulary a field shares, and what you lack -
appmates init— scaffold aappmates.tomlper project - Play graphic assets (icon, feature graphic) as first-class checks
- Device-frame screenshot generation
- GitHub Action wrapper + SARIF output for inline PR annotations
- Publish to PyPI
SaaS layer
- FastAPI service over the same core models — the
--jsonpayloads are already the API contract - Live store integration: App Store Connect (JWT ES256) and Play Developer API behind the existing
TesterDataSourceprotocol - Hosted spec catalogue so rule changes ship without a release
- Release dashboard: submission status, review times, rejection history across both stores
- Alerting on closed-testing streak breaks — the failure this tool exists to prevent
- Multi-app / team workspaces
The open-source CLI stays fully functional standalone. The SaaS adds hosting, history and live store credentials — never a gate on the local checks.
Contributing
Issues and PRs welcome — see CONTRIBUTING.md for dev setup, checks to run before opening a PR, and the code style expected. This project follows the Contributor Covenant.
License
MIT — see LICENSE.
Sources
Specifications are transcribed from, and dated against, the official docs:
Metadata
Release files for appmates 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| appmates-0.1.0.tar.gz | 602.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| appmates-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 730.4 kB
Release files / appmates-0.1.0.tar.gz
| Download URL | appmates-0.1.0.tar.gz |
|---|---|
| Size | 602.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bda1e14544f09a2a41e1a49ac68da1b2c73d0ac9c2e3f7dedf9242dadc196851
|
|
BLAKE2b-256 checksum How to use checksums |
2643103bdaedfa01031565cc9dd9f180374c90da567008a3f8e2326f1445e5b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.
Transparency logRelease files / appmates-0.1.0-py3-none-any.whl
| Download URL | appmates-0.1.0-py3-none-any.whl |
|---|---|
| Size | 127.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6911e3d2ec66e72e12c741105fe869d9c44755e746d34d3641d3c7ee762845cd
|
|
BLAKE2b-256 checksum How to use checksums |
973b921050ff5fbe11dcb5ed81f7a19443347b27cd33a27c2599cf9c3e9df295
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.
Transparency log