Agent skill

Fdroid Reproducible Foss

by r0adkll in r0adkll/Campfire

Rules and reliable local tests for keeping Campfire's foss flavor F-Droid-compatible — a clean source scan (using scandelete, never scanignore) and a byte-for-byte reproducible build.

GPL-3.0Auto-check passedMobile

Install Fdroid Reproducible Foss

skills CLI
$ npx skills add r0adkll/Campfire --skill fdroid-reproducible-foss -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install r0adkll/Campfire fdroid-reproducible-foss --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/r0adkll/Campfire.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/fdroid-reproducible-foss .claude/skills/fdroid-reproducible-foss && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
fdroid-reproducible-foss
GitHub stars
141
Token cost
~2.7k tokens
SKILL.md length
1,062 words
Files
2
Skills in repo
9
Repo updated
First seen
Licence
GPL-3.0

At a glance

Rules and reliable local tests for keeping Campfire's foss flavor F-Droid-compatible — a clean source scan (using scandelete, never scanignore) and a byte-for-byte reproducible build.

  • Works in 3 steps: Run the real F-Droid scanner → Confirm the foss build still configures… → Verify reproducibility of a published…
  • Editing the fdroiddata metadata
  • SKILL.md covers What F-Droid requires of the…, Invariants you must not break, How the scanner actually works… and Pattern: isolating a…, plus 4 more sections
  • Runs Shell scripts from its folder; calls git, apt-get and docker; reaches gitlab.com

What it does

Fdroid Reproducible Foss is an agent skill from r0adkll/Campfire. Rules and reliable local tests for keeping Campfire's foss flavor F-Droid-compatible — a clean source scan (using scandelete, never scanignore) and a byte-for-byte reproducible build. Trigger when editing the fdroiddata metadata; adding, removing, or moving a proprietary dependency / Gradle plugin / custom Maven repository; changing anything the foss flavor builds (app/android, gradle/build-logic, settings.gradle.kts, baseline profiles, R8/ProGuard); cutting a release F-Droid mirrors; or when asked to "check the…

Its SKILL.md is about 2.7k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `scan-source.sh`).

It sits in Mobile, covering Reproducible research. It works with Gradle and Android. The repository describes itself as: A KMP Compose app for Audiobookshelf. The licence is GPL-3.0.

When your agent uses it

  • Editing the fdroiddata metadata
  • Moving a proprietary dependency / Gradle plugin / custom Maven repository
  • Changing anything the foss flavor builds (app/android
  • Gradle/build-logic

Example prompts

  • “check the F-Droid scan”
  • “verify reproducibility”
  • “why did F-Droid flag X”
  • “/fdroid-reproducible-foss”

Requirements

  • Python 3
  • A Bash shell
  • Docker

Workflow steps

3 steps, taken from the step headings in SKILL.md.

  1. Run the real F-Droid scanner
  2. Confirm the foss build still configures with those files deleted (the F-Droid scenario)
  3. Verify reproducibility of a published foss APK

What it can do on your machine

Read from SKILL.md and the folder at commit 8348ab0. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships script files (Shell), which the agent can run.

    Shell commands in SKILL.md call:

    • git
    • apt-get
    • docker
    • curl

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • gitlab.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Fdroid Reproducible Foss loads about 2.7k tokens when it runs. Until then it costs about 154 tokens; SKILL.md has 1,062 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~154
When it runs · the whole SKILL.md, loaded when a task matches
~2.7k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from r0adkll/Campfire at commit 8348ab0, republished under its GPL-3.0 licence (© r0adkll). 1,062 words, ~2,673 tokens.

Download SKILL.mdSave it as .claude/skills/fdroid-reproducible-foss/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
fdroid-reproducible-foss
description
Rules and reliable local tests for keeping Campfire's `foss` flavor F-Droid-compatible — a clean source scan (using scandelete, never scanignore) and a byte-for-byte reproducible build. Trigger when editing the fdroiddata metadata; adding, removing, or moving a proprietary dependency / Gradle plugin / custom Maven repository; changing anything the foss flavor builds (app/android, gradle/build-logic, settings.gradle.kts, baseline profiles, R8/ProGuard); cutting a release F-Droid mirrors; or when asked to "check the F-Droid scan", "verify reproducibility", or "why did F-Droid flag X".

What F-Droid requires of the foss flavor

Two independent hard requirements. Both must hold or the fdroiddata pipeline goes red:

  1. A clean source scan — the checked-out source must contain no "unknown maven repos" and no proprietary "usual suspects" once scandelete has run. Maintainers disallow scanignore (F-Droid docs: it is only "where there is a very good reason"); the sanctioned mechanism is scandelete, which deletes files not needed by the build before scanning.
  2. A byte-for-byte reproducible build — F-Droid rebuilds assembleFossRelease from the release tag and it must match our published campfire-foss-release.apk exactly, so F-Droid ships our-signed APK (AllowedAPKSigningKeys).

The MR: https://gitlab.com/fdroid/fdroiddata/-/merge_requests/46619 (metadata metadata/app.campfire.android.yml).

Invariants you must not break

  • The foss flavor never depends on a proprietary module. Firebase, Cast, Block Store, ML Kit, Mixpanel, Play in-app-updates, App Distribution are wired to standard* / alpha* / beta* configurations only — never foss* (see app/android/build.gradle.kts). If you add a proprietary integration, follow the same pattern, and put its build files where F-Droid can scandelete them (see below).
  • No custom Maven repository literal in any scanned .gradle/.gradle.kts. The scanner flags any maven(...) / maven { url … } call whose URL isn't on F-Droid's allow-list — and it captures whatever is inside the parens, so even maven(someVariable) is flagged as unknown maven repo 'someVariable)'. Reading the URL from a property does not help. Custom repos must live in a scandelete-able standalone script (see the emulator.wtf pattern).
  • Reproducibility hooks stay in place:
    • Project.normalizeFossReleasePgMapId() (in gradle/build-logic/convention/.../Reproducible.kt), called from app/android/build.gradle.kts — zeroes R8's pg-map-id in the foss DEX (the one thing that varied per build environment).
    • baselineProfile { variants { create("foss") { dexLayoutOptimization = false } } } in app/android/build.gradle.kts — keeps the baseline profile but drops the non-deterministic startup DEX layout for foss only.
  • campfire.version / campfire.versionCode stay in lockstep (MMmmppRR, asserted by verifyVersionCode + scripts/release). F-Droid's UpdateCheckData reads campfire.versionCode from gradle.properties on the tag.

How the scanner actually works (so you can reason about it)

Source: fdroidserver/scanner.py, scan_source(). F-Droid CI runs fdroidserver master (installed from the tarball on debian:trixie-slim, not pip), so test against master.

  • Only these file types get content-scanned: .java (DexClassLoader only), .gradle / .gradle.kts (usual-suspects + maven-URL), and binaries (.apk/.jar/.aar/.class/.dex/.so/.zip/.gz/.wasm, extensionless/.bin/.out/.exe, executables). gradle.properties, .kt, .py, and shell scripts are NOT scanned for repos or suspects — confirmed by reading the dispatch and by A/B test.
  • Usual suspects resolve libs.* version-catalog accessors through libs.versions.toml, so libs.firebase.crashlytics.gradlePlugin in a .gradle.kts is flagged even though the coordinate is in the TOML. // comments are ignored; only real implementation(...)-style lines match.
  • scandelete deletes listed paths before the scan runs, so a flagged file that the foss build doesn't need is removed and never scanned. This is why the isolated files below can each carry the flagged content.

Pattern: isolating a proprietary Gradle plugin so it can be scandelete'd

Firebase's plugins can't sit in build.gradle.kts (root) or gradle/build-logic/convention/build.gradle.kts — those are scanned and can't be deleted. So:

  • The proprietary plugin deps + the convention plugin live in a separate build-logic module gradle/build-logic/firebase/ (its build.gradle.kts carries libs.firebase.*.gradlePlugin).
  • gradle/build-logic/settings.gradle.kts includes it only if (file("firebase/build.gradle.kts").exists()).
  • convention/build.gradle.kts does runtimeOnly(project(":firebase")) under the same if (file(...).exists()) guard.
  • The plugin is applied from a convention plugin (AndroidApplicationConventionPlugin) via pluginManager.apply("app.campfire.firebase"), guarded by rootProject.file("gradle/build-logic/firebase/build.gradle.kts").exists() — the same presence check, so it is never requested once scandeleted. Don't guard it on google-services.json: the plugin also adds the alpha/beta App Distribution SDK that src/preRelease compiles against, and it already skips the Firebase Gradle plugins itself when that file is missing (fork PRs, local builds).
  • fdroiddata scandeletes gradle/build-logic/firebase/build.gradle.kts → module not included, plugin never applied, build-logic still compiles.

Gotcha: legacy apply(plugin = "id") does NOT resolve an included-build plugin — it must be applied from inside a convention plugin (on the build-logic classpath) or via the plugins {} block.

Pattern: a custom Maven repo needed only for tooling (emulator.wtf)

The emulator.wtf Gradle plugin resolves from mavenCentral; only its ew-cli runner is exclusive to maven.emulator.wtf, and only when actually running on emulator.wtf (CI baseline generation) — never a foss/normal build. So:

  • The repo is declared in a standalone gradle/emulatorwtf-repo.gradle.kts (a settings script adding it via dependencyResolutionManagement).
  • settings.gradle.kts applies it only if (file("gradle/emulatorwtf-repo.gradle.kts").exists()) — the apply line has no maven call, so it isn't flagged.
  • app/baselineprofile/build.gradle.kts sets emulatorwtf { repositoryCheckEnabled.set(rootProject.file("gradle/emulatorwtf-repo.gradle.kts").exists()) } (extension name is lowercase emulatorwtf).
  • fdroiddata scandeletes gradle/emulatorwtf-repo.gradle.kts → deleted before scan (0 errors), apply skipped, repo check off. Any real emulator.wtf use just needs the file present — no extra flags.

Use this same shape for any future third-party repo that only serves build/test tooling.

Show full SKILL.md (392 more words)Show less

Testing — do this before pushing metadata or a release

Commit your changes first (the scanner test archives a git ref). Then:

1. Run the real F-Droid scanner
bash
.claude/skills/fdroid-reproducible-foss/scan-source.sh            # scans HEAD
.claude/skills/fdroid-reproducible-foss/scan-source.sh <git-ref>  # scans a ref

It exports the ref, applies the same scandelete list the metadata declares, runs fdroidserver master scan_source() in Docker, and prints SCAN COUNT + each error. Must be 0. Keep the script's SCANDELETE list identical to the metadata's scandelete: block.

2. Confirm the foss build still configures with those files deleted (the F-Droid scenario)
bash
git worktree add --detach /tmp/fdsim <git-ref>
cd /tmp/fdsim && rm <the scandelete files>          # + ensure no app/android/google-services.json
./gradlew :app:android:assembleFossRelease --dry-run --console=plain   # expect BUILD SUCCESSFUL
cd - && git worktree remove --force /tmp/fdsim

(Use a worktree, not git archive | tar — the latter drops the gradlew exec bit and munges permissions.)

3. Verify reproducibility of a published foss APK

The pg-map-id in the published campfire-foss-release.apk must be all-zeros:

bash
unzip -p campfire-foss-release.apk classes.dex | grep -a -o '"pg-map-id":"[0-9a-f]*"' | head
# expect "pg-map-id":"0000…0000"

After F-Droid's pipeline runs, the fdroid build job log should say "compared built binary to supplied reference binary successfully". If it differs, pull the job log and diffoscope our APK against F-Droid's …_<versionCode>.binary.apk artifact to find the delta.

Updating the fdroiddata metadata

  • Keep the scandelete: list in sync with scan-source.sh (currently 6 files; see scandelete-metadata-companion.yml in the session scratchpad for the canonical block).
  • Bump versionName / versionCode / commit to the release tag; AllowedAPKSigningKeys stays 4a3be90f…; keep Binaries, AutoUpdateMode: Version, UpdateCheckMode: Tags, UpdateCheckData.
  • Canonicalize with the CI-exact fdroidserver (debian:trixie-slim + master tarball) before pushing, or rewritemeta/lint will reformat differently than your local pip install:
    bash
    docker run --rm -v "$PWD":/repo -w /repo debian:trixie-slim bash -c '
      apt-get update -qq && apt-get install -qy --no-install-recommends fdroidserver curl ca-certificates git python3-yaml
      mkdir /fds && curl -s https://gitlab.com/fdroid/fdroidserver/-/archive/master/fdroidserver-master.tar.gz | tar -xz -C /fds --strip-components=1
      export PATH=/fds:$PATH PYTHONPATH=/fds:/fds/examples
      fdroid rewritemeta app.campfire.android && fdroid lint app.campfire.android'
  • Commit as the user only — no Co-Authored-By trailer on fdroiddata commits (they must appear to come from the user's account alone). Commit signing uses 1Password SSH; if it errors with failed to fill whole buffer, ask the user to unlock 1Password and retry.

Gotchas learned the hard way

  • handleproblem in the scanner is silent when common.get_options() is None (no log, no JSON) but still increments the count. To surface which file/message counts, pass json_per_build=scanner.MessageStore() and set common.options (see scan-source.sh).
  • The two central.sonatype.com snapshot repos in settings.gradle.kts are gated behind campfire.config.enableSnapshots and are on F-Droid's allow-list, so they don't count.
  • Comments that mention a coordinate or hostname are fine — the scanner ignores // lines and only matches real dependency/maven(...) calls.
  • Baseline profiles matter to end users; never "fix" reproducibility by dropping the profile. Drop only dexLayoutOptimization for foss.

© r0adkll, GPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in .claude/skills/fdroid-reproducible-foss of r0adkll/Campfire.

  • SKILL.md
  • scan-source.sh

Open the folder on GitHubat commit 8348ab0

Compare with similar skills

Fdroid Reproducible Foss next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Fdroid Reproducible Foss compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Fdroid Reproducible Foss this skillr0adkll/Campfire141—~2.7kAutomated safety check: PassGPL-3.0
Android API Diffgkd-kit/gkd43k—~796Automated safety check: PassGPL-3.0
Android Developmentdpconde/claude-android-skill336—~1.7kAutomated safety check: PassMIT
Run Jetpack Android Appwordpress-mobile/WordPress-Android3.2k—~886Automated safety check: PassGPL-2.0
Orca Android Emulator Controlstablyai/orca89k—~558Automated safety check: PassApache-2.0
Claude Android NinjaDrjacky/claude-android-ninja124—~5.2kAutomated safety check: PassApache-2.0

Similar skills

  • Android API Diff

    gkd-kit/gkd

    Looks up Android framework Java and AIDL APIs across versions with the android-api-diff CLI: signatures, availability, source files and hidden-API access code.

    43k GitHub stars~796 tokensUpdated today
    MobileAuto-check passed
  • Android Development

    dpconde/claude-android-skill

    Create production-quality Android applications following Google's official architecture guidance and NowInAndroid best practices.

    336 GitHub stars~1.7k tokensUpdated 10 mo ago
    MobileAuto-check passed
  • Run Jetpack Android App

    wordpress-mobile/WordPress-Android

    Builds the Jetpack debug app with Gradle and installs it on a connected Android device or an emulator started from an available AVD.

    3.2k GitHub stars~886 tokensUpdated yesterday
    MobileAuto-check passed
  • Android device and emulator control from inside Orca over adb, with the live device view in Orca's emulator pane. Use when driving an adb-connected emulator…

    89k GitHub stars~558 tokensUpdated today
    MobileAuto-check passed
  • Claude Android Ninja

    Drjacky/claude-android-ninja

    Build and migrate Android apps with Kotlin, Jetpack Compose, MVVM, Hilt, Room 3 (KSP, SQLiteDriver, Flow/suspend DAOs), Navigation3, and multi-module Gradle.

    124 GitHub stars~5.2k tokensUpdated 11 days ago
    MobileAuto-check passed
  • Expo Brownfield Integration

    mweinbach/agent-coworker

    Helps add Expo and React Native to an existing native iOS or Android app, and choose between a prebuilt AAR or XCFramework and a fully integrated build.

    156 GitHub starsUsed in 2 repos~900 tokens
    MobileAuto-check: notes

More from r0adkll/Campfire

All 9 skills in this repo
  • PR Stack

    r0adkll/Campfire

    Open, describe, and maintain pull requests in Campfire, especially stacks of dependent PRs (each branch built on the one before).

    141 GitHub stars~1.7k tokensUpdated today
    Auto-check passed
  • Compose Modifier

    r0adkll/Campfire

    Enforce the Compose guideline that every @Composable function must declare modifier: Modifier = Modifier as its first optional parameter and apply it to the root layout.

    141 GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • I18n Compose

    r0adkll/Campfire

    Extract hardcoded user-facing string literals from a Jetpack Compose / Compose Multiplatform file into the owning module's composeResources/values/<modulestrings.xml, then replace each call site…

    141 GitHub stars~3.2k tokensUpdated today
    Auto-check passed
  • Iconbutton A11y

    r0adkll/Campfire

    Enforce the Campfire IconButton accessibility convention — every IconButton (and its derivatives) must be wrapped with IconButtonTooltip and given a localized action label.

    141 GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Socket Event Listener

    r0adkll/Campfire

    Enforce the Campfire pattern for feature modules to react to Audiobookshelf socket events.

    141 GitHub stars~2.5k tokensUpdated today
    Auto-check passed
  • Compose UI

    r0adkll/Campfire

    Campfire Compose UI conventions. An agent skill from r0adkll/Campfire.

    141 GitHub stars~886 tokensUpdated today
    Auto-check passed

Works with

Questions about Fdroid Reproducible Foss

What does Fdroid Reproducible Foss do?

Rules and reliable local tests for keeping Campfire's foss flavor F-Droid-compatible — a clean source scan (using scandelete, never scanignore) and a byte-for-byte reproducible build. Fdroid Reproducible Foss is an agent skill from r0adkll/Campfire. Rules and reliable local tests for keeping Campfire's foss flavor F-Droid-compatible — a clean source scan (using scandelete, never scanignore) and a byte-for-byte reproducible build.

When should I use Fdroid Reproducible Foss?

Fdroid Reproducible Foss fits situations like: editing the fdroiddata metadata; moving a proprietary dependency / Gradle plugin / custom Maven repository; changing anything the foss flavor builds (app/android; gradle/build-logic.

How do I install Fdroid Reproducible Foss in Claude Code?

Run `npx skills add r0adkll/Campfire --skill fdroid-reproducible-foss -a claude-code`. Or copy the skill folder (.claude/skills/fdroid-reproducible-foss in r0adkll/Campfire) into .claude/skills/fdroid-reproducible-foss in your project. Claude Code loads it when a task matches its description.

How do I install Fdroid Reproducible Foss in Codex?

Run `npx skills add r0adkll/Campfire --skill fdroid-reproducible-foss -a codex`. Or copy the skill folder (.claude/skills/fdroid-reproducible-foss in r0adkll/Campfire) into .agents/skills/fdroid-reproducible-foss in your project. Codex loads it when a task matches its description.

Can I use Fdroid Reproducible Foss in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add r0adkll/Campfire --skill fdroid-reproducible-foss -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/fdroid-reproducible-foss, .gemini/skills/fdroid-reproducible-foss, .github/skills/fdroid-reproducible-foss and .opencode/skills/fdroid-reproducible-foss in your project.

What does Fdroid Reproducible Foss need to run?

Going by SKILL.md and its folder, Fdroid Reproducible Foss needs a shell for the scripts in its folder and the command-line tools its instructions call (git, apt-get, docker and curl). Our summary lists: Python 3; A Bash shell; Docker.

Does Fdroid Reproducible Foss access the network?

SKILL.md names 1 domain. In commands or code: gitlab.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Fdroid Reproducible Foss safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Fdroid Reproducible Foss use?

Fdroid Reproducible Foss is published under the GPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Fdroid Reproducible Foss use?

About 2.7k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Fdroid Reproducible Foss?

Skills that share tags, products or a category with Fdroid Reproducible Foss: Android API Diff (gkd-kit/gkd, 43k stars), Android Development (dpconde/claude-android-skill, 336 stars), Run Jetpack Android App (wordpress-mobile/WordPress-Android, 3.2k stars) and Orca Android Emulator Control (stablyai/orca, 89k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Fdroid Reproducible Foss?

r0adkll (a GitHub user) maintains it in r0adkll/Campfire, which has 141 GitHub stars. The repository holds 9 skills in this directory. The repository was last updated on October 11, 2026.

Source: r0adkll/Campfire on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.