Skip to content
Development
Skill

/remote-api-footguns

Remote API traps in Kotlin Multiplatform: Ktor clients, defensive parsing, Resource envelopes, OK responses that dropped your data, auth callbacks, retry backoff, downloads, websockets, clock sync. Use when calls succeed but data never lands.

BOOST
From plugin
kotlin-footguns
1.3k10 skills
Install
$ npx -y skills add maxrave-dev/kotlin-footguns --skill remote-api-footguns --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/remote-api-footguns

Context preview

The summary Claude sees to decide when to auto-load this skill.

Remote API traps in Kotlin Multiplatform: Ktor clients, defensive parsing, Resource envelopes, OK responses that dropped your data, auth callbacks, retry backoff, downloads, websockets, clock sync. Use when calls succeed but data never lands.

SKILL.md

remote-api-footguns.SKILL.md
name: remote-api-footguns
description: "Remote API traps in Kotlin Multiplatform: Ktor clients, defensive parsing, Resource envelopes, OK responses that dropped your data, auth callbacks, retry backoff, downloads, websockets, clock sync. Use when calls succeed but data never lands."

Remote API footguns

17 traps mined from a production Kotlin and Compose Multiplatform app, one short file each under `references/`. Every file gives the working pattern, the **Traps** (the specific ways it fails in practice, and why), and a **Verifying it** section with commands to run against the user's own tree.

**How to use this index.** Match the code about to be written, or the symptom being chased, against the entries below: each names its topic and the symptom that should send you to it. Read every file that plausibly applies with the Read tool before proposing code or a fix; each is under 150 lines. Where a Verifying command names the source project's paths, substitute the equivalent paths in the user's tree.

**Cross-references.** A backticked trap name inside a file that is not listed here lives in a sibling area skill: glob `../*/references/<name>.md` to open it.

Clients, parsing and response handling

  • [`ktor-kmp-client-architecture`](references/ktor-kmp-client-architecture.md) — A multiplatform HTTP stack where one expect/actual hands back the engine and each integration builds its own client from it — an instrumented client for API calls next to a deliberately bare one for bulk downloads, content negotiation registered per format, and a settings change that rebuilds the client rather than mutating it. Use when standing up networking in a Kotlin Multiplatform module, when a proxy setting appears to be ignored by some requests but not others, or when downloading a large file crawls and floods the log.
  • [`curl-logger-ktor-plugin`](references/curl-logger-ktor-plugin.md) — A client plugin that logs every outgoing request as one paste-ready curl command — POSIX single-quoting so a body full of quotes, dollars or newlines survives the shell, the whole command in a single log call, a redaction list, and a body read that does not consume a one-shot channel. Use when you want to replay a failing request outside the app, when a logged command will not run when pasted, or when reproducing a bug means rebuilding a request by hand from a log.
  • [`parallel-chunked-download`](references/parallel-chunked-download.md) — Splitting one file into N byte-range requests issued in parallel over a bare HTTP client, each chunk to its own temp file, merged in order, with progress reported through a channel-backed flow — plus when ranges are actually safe, how big a chunk should be, and why a failure retries one chunk rather than the file. Use when a large download is slower than the link allows, when a download restarts from zero after a hiccup, or when a progress bar sticks just short of full.
  • [`structural-defensive-parsing`](references/structural-defensive-parsing.md) — Reading a response whose shape drifts — classify each field by the marker the payload itself declares rather than by its position, treat a filtering map as data loss and count what it drops, refuse to substitute a placeholder for a failed parse, and parse composite strings from their stable end. Use when a parser works in one locale and not another, when a list arrives shorter than the source shows, or when a made-up value turns up somewhere it was never entered.
  • [`response-to-domain-flow`](references/response-to-domain-flow.md) — The five stages a remote response passes through — transport model in a per-integration service module, a pure parser layer, a domain model, a result envelope, then collection — with the rule that each integration is its own module so one source's breakage cannot spread, and the placement rules that keep transport types out of screens. Use when adding a second remote source, when a UI file has started importing response classes, or when a screen shows a spinner forever after a response shape changed.
  • [`api-ok-but-ignored`](references/api-ok-but-ignored.md) — A remote write can answer "ok" and still have discarded what you sent, saying so only in a secondary field riding along with the success. Model accepted-but-discarded as its own outcome, read that field on every write, and log a discard loudly. Reach for it when a submission reports success on every call and the data never appears on the other side.
  • [`unknown-not-a-valid-score`](references/unknown-not-a-valid-score.md) — A parse-failure fallback must be a sentinel outside the legal domain, or expressed in the type — never a value the success path can also produce. Expose "not known" as its own question. Use when a field means two different things depending on where it came from, when a placeholder reaches the screen, or when a consumer cannot tell absent from measured.
  • [`enum-normalize-over-legacy-data`](references/enum-normalize-over-legacy-data.md) — Reading a type marker the remote source declares for itself — normalizing before every comparison because locally stored rows from older app versions hold labels the app invented, treating null as "the source did not say" rather than as a default, exposing an is-known predicate so callers branch on knowledge, and correcting old rows by write-through instead of a migration. Use when a stored type column holds several spellings, when an item is treated as the wrong kind, or before adding a database migration to fix historical values.

Auth, retries and account state

  • [`oauth-callback-not-through-nav`](references/oauth-callback-not-through-nav.md) — Deliver a returning auth callback's token straight to session state and let the login screen close itself by observing the stored session — routing the token through navigation pushes a second login screen and the post-login close peels the wrong one. Use when a browser-based login succeeds but the user is left staring at the login screen.
  • [`retry-
Read more
Ships withkotlin-footguns

By maxrave-dev — creator and maintainer of SimpMusic, the 10.8k-star cross-platform music app every lesson in this repository was mined from.

Get the whole plugin
Stats
1,305
Stars
6
Forks
Active
Maintenance
Python
Language
GPL-3.0
License
20d ago
Last commit
1mo ago
Created
5h ago
Added

Repo: maxrave-dev/kotlin-footguns

Other skills on kotlin-footguns.