expo-prebuild-and-config-plugins
Keeps ios/ and android/ generated from app.config.ts and tested config plugins.
Skill by zakariaf
Chalk Labs
Need help deploying expo-prebuild-and-config-plugins?
Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/zakariaf-expo-prebuild-and-config-plugins
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Node.js package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/expo-prebuild-and-config-plugins
What's inside
- Skill name
expo-prebuild-and-config-plugins- Description
- Keeps ios/ and android/ generated from app.config.ts and tested config plugins. Use when adding a plugin, an Info.plist or AndroidManifest entry, or a prebuild step. Not for native code (native-modules-and-new-architecture).
- License
- MIT
- Instructions
- 189 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Files (40)
- SKILL.md
- auto-plugins.json · assets/
- shared.json · assets/
- app-config-plugin-list.ts · examples/
- native-change-report.md · examples/
- with-gradle-jvm-args.ts · examples/
- app-config.md · references/
- cng-and-native-folders.md · references/
- config-plugins.md · references/
- pitfalls-and-rules.md · references/
- testing-and-proof.md · references/
- check-lib.mjs · scripts/
- check-native-generation.mjs · scripts/
- check-native-snapshot.mjs · scripts/
- cng-scan.mjs · scripts/lib/
- source-scan.mjs · scripts/lib/
- selftest.mjs · scripts/
- native-generation.json · templates/contracts/
- with-android-optional-features.test.ts · templates/plugins/
- with-android-optional-features.ts · templates/plugins/
- run-mod.test.ts · templates/test/config-plugins/
- run-mod.ts · templates/test/config-plugins/
- app.config.ts · tests/bases/app/
- ci.yml · tests/bases/app/dot-github/workflows/
- dot-gitignore · tests/bases/app/
- jest.config.js · tests/bases/app/
- package.json · tests/bases/app/
- collect-artifacts.sh · tests/bases/app/scripts/build/
- read-gradle-version.ts · tests/bases/app/scripts/release/
- task-title.ts · tests/bases/app/src/features/tasks/
- app.config.ts · tests/bases/snapshot/
- native-config.json · tests/bases/snapshot/contracts/
- introspect.json · tests/bases/snapshot/
- package.json · tests/bases/snapshot/
- CASES.json · tests/fixtures/check-native-generation/
- SUITE.json · tests/fixtures/check-native-generation/
- EXPECT.txt · tests/fixtures/check-native-generation/good/
- CASES.json · tests/fixtures/check-native-snapshot/
- SUITE.json · tests/fixtures/check-native-snapshot/
- EXPECT.txt · tests/fixtures/check-native-snapshot/good/
SKILL.md (first lines)
# Expo prebuild and config plugins
Continuous Native Generation: `ios/` and `android/` are build output of `app.config.ts`, its config
plugins and the installed native packages. Every native change is a config key or one line in the
plugin list; local plugins are typed, idempotent and tested; the generated folders stay out of git
and out of every script's reach; a committed snapshot of the introspected native config makes each
native change visible in review. Two checkers prove it. Leaving this model is a recorded decision.
## Rules that must hold
1. **`app.config.ts` is the one config, and a pure function.** No `app.json`, `app.config.json` or
second `app.config.*`; it returns the object synchronously, the same environment gives the same
JSON, it holds no `null`, and it applies no plugin in code. Why: Expo reads `.ts` first and ignores
the rest; a Promise is refused; the fingerprint hashes the config; `null` reaches the app as `{}`
(all verified on SDK 57). (`single-config`, `config-evaluates`, `config-deterministic`,
`config-null`, `config-mods`)
2. **`ios/` and `android/` are generated output.** `.gitignore` (and `.easignore`, which replaces it
for EAS) ignores `/ios` and `/android`, anchored; git tracks nothing there; no npm script, `scripts/`
file or CI step writes into them. Why: SDK 57's prebuild deletes them by default, EAS prebuilds
only when they are absent, and an unanchored `ios/` also hides a local module's Swift code.
(`native-ignored`, `native-tracked`, `native-ignore-scope`, `easignore-native`, `native-edit`)
3. **A config key before a plugin.** `ios.infoPlist`, `ios.entitlements`, `locales`,
`android.permissions`/`blockedPermissions`, `ios.deploymentTarget` and expo-build-properties
(SDK versions, `manifestQueries`, cleartext, frameworks) cover most needs; a plugin only for what
none covers. Why: keys are validated, introspectable and maintained by Expo across upgrades.
(`builtin-first`)
4. **Nothing reaches the native projects implicitly.** Every installed package whose plugin prebuild
applies on its own (`assets/auto-plugins.json`) is listed, with the options the app means, in every
variant; no plugin is listed twice; a permission a plugin adds whatever its options (expo-file-system's
storage pair, which every app gets through `expo`) is removed only by `android.blockedPermissions`
(exact case, `WRITE_EXTERNAL_STORAGE`): block it unless the app needs it (shared-storage access).
Why: the defaults add push and Sign in with Apple entitlements, permissions and English purpose
strings (seen in the reference app), and a run-once plugin silently drops a second entry's options
(verified). (`auto-plugin-listed`, `plugin-duplicate`)
5. **Local plugins live in `plugins/with-<capability>.ts`, listed by path.** Default export (a typed
`ConfigPlugin<Options | undefined>`, tagged `@public`), Expo's helpers from `'expo/config-plugins.js'`
on SDK 57 (bare from SDK 58), never `@expo/config-plugins`. Why: `npx expo config` then shows the
file; the bare specifier fails with `ERR_MODULE_NOT_FOUND` once Node imports the file as an ES
module (verified). (`plugin-entry`, `plugin-import`)
6. **Typed mods first; text mods merge; dangerous mods are justified.** A text mod edits through
`CodeGenerator.mergeContents` or behind an `includes` check (inline or in a `plugins/lib/` helper);
`withDangerousMod` carries `// dangerous-mod: <reason>`, writes files only inside it (or helpers
it calls), and writes them whole or guards an append. Why: only typed mods are
introspected; dangerous mods run first and break silently when the SDK template changes.
(`dangerous-mod`, `text-mod-idempotent`)
7. **Every plugin is idempotent and validates its options.** Applying it twice equals once; a bare
entry or a bad option throws a message showing the right entry. Why: `prebuild --no-clean` and
`expo run:*` rerun mods onto existing files (verified: an appending plugin left 1, 2, 3 copies).
8. **Every local plugin has a sibling test that imports it and that Jest runs, through Expo's own mod chain.** `runMod`
(`test/config-plugins/run-mod.ts`), a fresh config per test, a second run, bad options, the other
platform untouched; the Jest config's test roots include `plugins/`. Why: Expo ships no plugin
test harness, the `with*` helpers mutate the config they get, and an unreached test passes silently.
(`plugin-test`)
9. **One owner per native key, and a deliberate order.** Mods run newest first: the plugin listed
first in `plugins` writes last and wins a shared key (verified). Two plugins on one file are tested
together. Why: otherwise a reorder silently changes the app.
10. **Native changes are proven by introspection and reviewed as a snapshot.** `contracts/native-config.json`
is regenerated with `--write` only after a deliberate change and committed with it. Why: the
generated folders never appear in a pull request; the snapshot shows a new permission or entitlement
from any plugin or package. (`native-snapshot`, `native-drift`)
11. **Prebuild is clean in scripts and CI, and before every local build.** Never `--no-clean` in a
script; `npx expo prebuild --clean` before `expo run:*` or a local release build after any config,
plugin, package or variant change. Why: `expo run:*` builds an existing folder as it is (verified);
a layered prebuild depends on earlier runs. (`prebuild-clean`)
12. **Leaving CNG is a recorded decision.** `contracts/native-generation.json` `"mode": "committed"`
with a `reason` and `decidedOn`, both folders committed, no prebuild in any script; native keys
then change by hand. Why: committed folders and prebuild-only keys drift apart (expo-doctor reports
it). (`native-mode`)
## Workflow
1. **Place the change.** Read [references/app-config.md](references/app-config.md) ("Built-in keys
before plugins", "Auto-applied plugins"). A key covers it: edit `app.config.ts` and go to step 6.
A new native package: dependency-management installs it, then list its plugin here (rule 4).
2. **First time in a repo:** read [references/cng-and-native-folders.md](references/cng-and-native-folders.md);
copy `templates/contracts/native-generation.json` to `contracts/`; anchor `/ios` and `/android` in
`.gitignore`; make sure the Jest config's test roots include `'<rootDir>/plugins/**/'`
(unit-and-component-tests owns `jest.config.js`); copy `templates/test/config-plugins/run-mod.ts`
and its test. Then `node ${CLAUDE_SKILL_DIR}/scripts/check-native-snapshot.mjs . --write` and read
every key of `contracts/native-config.json`: it is the audit of what prebuild writes today.
3. **Write the plugin** when no key covers the need: read
[references/config-plugins.md](references/config-plugins.md); copy
`templates/plugins/with-android-optional-features.ts` and its test as the shape (or keep them when
the app needs optional hardware); [examples/with-gradle-jvm-args.ts](examples/with-gradle-jvm-args.ts)
shows a gradle.properties mod. Pure transform, option validation, one typed mod per file.
4. **Test it** per [references/testing-and-proof.md](references/testing-and-proof.md) (levels 1 and 2):
`npx jest --ci --selectProjects unit --runTestsByPath plugins/<file>.test.ts`, and
`npx jest --listTests | grep plugins/` lists it.
5. **List it** in `app.config.ts` by path, with its options and a comment naming the owning skill, the
way [examples/app-config-plugin-list.ts](examples/app-config-plugin-list.ts) does. Variant-dependent
options are computed in the config (app-variants-and-environment owns the variants).
6. **Prove it:** `APP_VARIANT=<v> EXPO_PUBLIC_APP_VARIANT=<v> npx expo config --type introspect --json`
for each variant; `node ${CLAUDE_SKILL_DIR}/scripts/check-native-snapshot.mjs .` and read every
`native-drift` line; when each one is intended, rerun with `--write`. Text or dangerous mods also
get `npx expo prebuild --clean --no-install --platform <p>`, then the same with `--no-clean`, and a
look at the generated file (the change appears once).
7. **Run the app's gates:** `npm run typecheck`, `npx eslint . --max-warnings 0`, `npx jest --ci`.
8. **Check:** `node ${CLAUDE_SKILL_DIR}/scripts/check-native-generation.mjs .` and the snapshot check.
Each `FAIL` names the file, the rule and the fix; [references/pitfalls-and-rules.md](references/pitfalls-and-rules.md)
explains every rule and error text. Fix and rerun until both print `RESULT: PASS`.
9. **Leaving or returning to CNG:** stop and ask the developer first; it changes how every later
native change is made. Then follow "When to leave CNG" or "Coming back to CNG" in
[references/cng-and-native-folders.md](references/cng-and-native-folders.md).
10. **Report** like [examples/native-change-report.md](examples/native-change-report.md): what changed,
the snapshot diff, the proof commands and every `RESULT` line, and what a build still has to show.
## Definition of done
- [ ] `app.config.ts` is the only app config; it evaluates for every variant, twice the same, without `null`.
- [ ] Every native change is a config key or one entry in `plugins`; every installed auto-applied package is listed; no entry twice.
- [ ] Local plugins sit in `plugins/`, listed by path, default-export a typed plugin, import `expo/config-plugins.js` (SDK 57), use typed mods, guard text mods, justify dangerous ones.
- [ ] Each plugin's sibling test passes, applies the plugin twice, covers bad options, and `npx jest --listTests` lists it.
- [ ] Introspection reviewed for each variant; `contracts/native-config.json` regenerated on purpose and committed with the change.
- [ ] Text or dangerous mods: a clean and then a `--no-clean` prebuild show the change once.
- [ ] `.gitignore` ignores `/ios` and `/android` (anchored); git tracks nothing there; no script writes there or runs `--no-clean`; or the committed mode is recorded with its reason.
- [ ] Expected SKIP line only while the app has no Jest config: `SKIP jest.config.js [plugin-test] not yet created (unit-and-component-tests creates it)`. `note:` lines are information, not failures.
- [ ] `node ${CLAUDE_SKILL_DIR}/scripts/check-native-snapshot.mjs .` prints `RESULT: PASS`
- [ ] `node ${CLAUDE_SKILL_DIR}/scripts/check-native-generation.mjs .` prints `RESULT: PASS`From zakariaf/ReactNative-Skills, MIT.
More from zakariaf/ReactNative-Skills
- 0.606score
debug-menu-and-test-hooks
zakariaf
Gates test-only code behind one literal TEST_ONLY switch: debug menu, debug link, simulated clock and offline.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
accessibility-as-code
zakariaf
Enforces a11y labels, 44pt targets, 200% text, VoiceOver, TalkBack.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
adaptive-layout
zakariaf
Lays screens out by window, not device: breakpoints, master-detail panes, readable widths, grids.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
admob-ads-and-consent
zakariaf
Builds AdMob ads behind a port - banners, interstitials, rewarded, UMP consent then ATT, pacing, ADS_MODE test IDs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
analytics-and-consent
zakariaf
Gates analytics on opt-in consent: no SDK before a yes, typed events without personal data, ATT.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
android-release-play
zakariaf
Ships Android App Bundles to Google Play: upload key, Play App Signing, AAB gate, versionCode, tracks, rollout.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
architecture-and-boundaries
zakariaf
Places app code in the src/ layout and checks import boundaries: one-way zones, pure core, ports with fakes, one composition root.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
async-safety
zakariaf
Prevents silent async bugs: effect races, stale results, lost promises, leaked listeners and timers, AbortSignal gaps.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
audio-and-haptics-feedback
zakariaf
Builds SFX and haptics behind ports.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
auth-and-secure-storage
zakariaf
Builds sign-in - tokens in expo-secure-store, shared refresh, protected routes, OAuth PKCE, Apple sign-in.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
background-tasks
zakariaf
Builds expo-background-task jobs: idempotent, budgeted runs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
canvas-gestures-and-hit-testing
zakariaf
Turns canvas taps, swipes, drags and aim into typed intents: one gesture module, hit-testing on the drawn layout.
SkillAFreshness: A★ 11Claude Code +9
Signals
- Stars
- 11
- Forks
- 2
- Open issues
- 0
- Last commit (this folder)
- Oct 17, 2026 (14 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/zakariaf/ReactNative-Skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from zakariaf
- 0.606score
admob-ads-and-consent
zakariaf
Builds AdMob ads behind a port - banners, interstitials, rewarded, UMP consent then ATT, pacing, ADS_MODE test IDs.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
accessibility-as-code
zakariaf
Enforces a11y labels, 44pt targets, 200% text, VoiceOver, TalkBack.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
canvas-gestures-and-hit-testing
zakariaf
Turns canvas taps, swipes, drags and aim into typed intents: one gesture module, hit-testing on the drawn layout.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
adaptive-layout
zakariaf
Lays screens out by window, not device: breakpoints, master-detail panes, readable widths, grids.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
debug-menu-and-test-hooks
zakariaf
Gates test-only code behind one literal TEST_ONLY switch: debug menu, debug link, simulated clock and offline.
SkillAFreshness: A★ 11Claude Code +9 - 0.606score
analytics-and-consent
zakariaf
Gates analytics on opt-in consent: no SDK before a yes, typed events without personal data, ATT.
SkillAFreshness: A★ 11Claude Code +9
Done for you
Rather not set it up yourself?
Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.
See how we build AI agents →Read the case studies
Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.
- launches shipped
- 50+
- launches shipped
- media placements
- 500+
- media placements
- founders on every account
- 2
- founders on every account
Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block
Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.
Get expo-prebuild-and-config-plugins running in your business
Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.
Cite this page
expo-prebuild-and-config-plugins skill. Agent Mart. https://agentmart.dev/skills/zakariaf-expo-prebuild-and-config-plugins (last updated 2026-10-24)