Skip to content

Commit a380858

Browse files
authored
feat: add brownie skills (#304)
* feat: add brownie skills * refactor: code review
1 parent 3539b90 commit a380858

6 files changed

Lines changed: 490 additions & 0 deletions

File tree

skills/brownie/SKILL.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
name: brownie
3+
description: Provides guidance for shared state in React Native brownfield apps with @callstack/brownie. Define stores in TypeScript, run brownfield codegen, use the generated APIs in React Native and native hosts, and package native artifacts for integration.
4+
license: MIT
5+
metadata:
6+
author: Callstack
7+
tags: react-native, expo, brownfield, state-management, brownie
8+
---
9+
10+
# Overview
11+
12+
Brownie provides cross-platform shared state for React Native brownfield apps. The workflow starts from `*.brownie.ts` store definitions, runs `brownfield codegen` (or packaging commands that include codegen), then uses typed APIs on TypeScript, Android, and iOS sides.
13+
14+
# When to Apply
15+
16+
Reference this skill when:
17+
- Setting up `@callstack/brownie` in an existing brownfield app
18+
- Defining or changing store schemas in `*.brownie.ts`
19+
- Using `useStore`, `subscribe`, `getSnapshot`, or `setState` on the JS side
20+
- Registering and consuming stores in Android or iOS hosts
21+
- Packaging and embedding iOS frameworks that include Brownie
22+
23+
# Quick Reference
24+
25+
- Install Brownie:
26+
```bash
27+
npm install @callstack/brownie
28+
```
29+
- Generate native types:
30+
```bash
31+
npx brownfield codegen
32+
```
33+
- Packaging commands also include Brownie codegen:
34+
```bash
35+
# iOS
36+
npx brownfield package:ios --scheme YourScheme --configuration Release
37+
38+
# Android
39+
npx brownfield package:android --module-name :YourModuleName --variant release
40+
npx brownfield publish:android --module-name :YourModuleName
41+
```
42+
43+
## Routing (concern -> file)
44+
45+
Concern | Read
46+
--------|------
47+
Initial install, prerequisites, setup sequence, first integration pass | [`getting-started.md`](references/getting-started.md)
48+
`*.brownie.ts` schema rules, `BrownieStores` augmentation, type mapping, when to rerun codegen | [`store-definition-and-codegen.md`](references/store-definition-and-codegen.md)
49+
`useStore` selectors, update patterns, low-level APIs (`subscribe`, `getSnapshot`, `setState`) | [`typescript-usage.md`](references/typescript-usage.md)
50+
Android registration lifecycle, serializer options, package settings, build and publish flow | [`android-usage.md`](references/android-usage.md)
51+
Swift store registration and UI usage, plus XCFramework packaging and embedding | [`swift-and-xcframework.md`](references/swift-and-xcframework.md)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Brownie Android Usage
2+
3+
## Discoverability triggers
4+
5+
- "registerStoreIfNeeded brownie"
6+
- "Brownie Android setup package.json kotlin path"
7+
- "Brownie custom serializer kotlin"
8+
- "brownfield package android brownie publish"
9+
10+
## Scope
11+
12+
In scope:
13+
- Android-side store registration lifecycle.
14+
- Brownie Android package configuration and Gson dependency requirements.
15+
- Easy path and advanced serializer options in Kotlin.
16+
- Packaging and publish flow for AAR distribution.
17+
18+
Out of scope:
19+
- Initial installation and first setup checklist. For that, read [`getting-started.md`](getting-started.md) in this folder.
20+
- Store schema authoring and codegen file design. For that, read [`store-definition-and-codegen.md`](store-definition-and-codegen.md) in this folder.
21+
- React Native hook-level patterns. For that, read [`typescript-usage.md`](typescript-usage.md) in this folder.
22+
- iOS Swift and XCFramework guidance. For that, read [`swift-and-xcframework.md`](swift-and-xcframework.md) in this folder.
23+
24+
## Procedure
25+
26+
1. Confirm Android configuration
27+
- `package.json` includes a `brownie` block with:
28+
- `kotlin` output directory
29+
- `kotlinPackageName`
30+
31+
2. Ensure serializer dependency strategy
32+
- Brownie Android default serializer path requires Gson at runtime.
33+
- Hard requirement: do not complete integration unless `com.google.code.gson:gson` is present in the brownfield module or native app dependency graph.
34+
35+
3. Generate/build/publish artifacts
36+
- Build AAR with:
37+
- `npx brownfield package:android --module-name :YourModuleName --variant release`
38+
- Publish to local Maven with:
39+
- `npx brownfield publish:android --module-name :YourModuleName`
40+
- `package:android` also runs Brownie codegen before packaging.
41+
42+
4. Register store at startup
43+
- Use `registerStoreIfNeeded` once during startup to avoid duplicate registration.
44+
- Keep registration before native UI or JS flow assumes store availability.
45+
- `registerStoreIfNeeded` returns `null` if the store key is already registered.
46+
47+
5. Access and update typed store
48+
- Retrieve with `StoreManager.shared.store<T>(STORE_NAME)`.
49+
- Read from `store.state`, update via `store.set { ... }`, observe via `store.subscribe(...)`.
50+
51+
6. Use advanced serializers only when required
52+
- Use `brownieStoreDefinition(..., serializer = ...)` or `encode`/`decode` lambdas.
53+
- Keep decode/encode logic deterministic and version aware for backward compatibility.
54+
55+
## Compact Kotlin example
56+
57+
```kotlin
58+
import com.callstack.brownie.StoreManager
59+
import com.callstack.brownie.registerStoreIfNeeded
60+
import com.callstack.brownie.store
61+
import com.rnapp.brownfieldlib.AppStore
62+
63+
registerStoreIfNeeded(storeName = AppStore.STORE_NAME) {
64+
AppStore(counter = 0.0)
65+
}
66+
67+
val store = StoreManager.shared.store<AppStore>(AppStore.STORE_NAME)
68+
store?.set { state -> state.copy(counter = state.counter + 1) }
69+
```
70+
71+
## Quick reference
72+
73+
- Startup registration: `registerStoreIfNeeded(storeName) { initialState }`
74+
- Store lookup: `StoreManager.shared.store<T>(STORE_NAME)`
75+
- Required runtime dependency: `com.google.code.gson:gson`
76+
- Packaging:
77+
- `npx brownfield package:android --module-name :YourModuleName --variant release`
78+
- `npx brownfield publish:android --module-name :YourModuleName`
79+
- Error cues this guide handles:
80+
- Store not found due to missing registration
81+
- `ClassNotFoundException: com.google.gson.Gson` due to missing Gson dependency
82+
- Decode/encode issues in custom serializer path
83+
- Generated classes not found due to wrong `kotlinPackageName` or output path
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Brownie Getting Started
2+
3+
## Discoverability triggers
4+
5+
- "install @callstack/brownie"
6+
- "set up Brownie in brownfield app"
7+
- "first Brownie store setup"
8+
- "how to start Brownie on iOS or Android"
9+
10+
## Scope
11+
12+
In scope:
13+
- Prerequisites and initial installation.
14+
- First store definition and app entry import.
15+
- Platform handoff sequence for iOS and Android setup.
16+
- First-pass verification that state sync works.
17+
18+
Out of scope:
19+
- Deep schema modeling details and codegen internals. For that, read [`store-definition-and-codegen.md`](store-definition-and-codegen.md) in this folder.
20+
- Advanced JS runtime patterns and low-level TypeScript APIs. For that, read [`typescript-usage.md`](typescript-usage.md) in this folder.
21+
- Platform-specific deep dives. For Android details, read [`android-usage.md`](android-usage.md). For iOS details, read [`swift-and-xcframework.md`](swift-and-xcframework.md) in this folder.
22+
23+
## Procedure
24+
25+
1. Confirm prerequisites
26+
- React Native brownfield setup is already complete.
27+
- `@callstack/react-native-brownfield` is installed.
28+
- Native host app(s) exist for iOS and/or Android.
29+
30+
2. Install Brownie in the React Native app
31+
- Run `npm install @callstack/brownie`.
32+
33+
3. Define the first store
34+
- Create a file ending in `.brownie.ts`.
35+
- Declare an interface extending `BrownieStore`.
36+
- Add module augmentation for `BrownieStores`.
37+
38+
4. Ensure augmentation is loaded
39+
- Import the `.brownie.ts` file from the app entry (`App.tsx` or `index.js`).
40+
41+
5. Add first TypeScript usage
42+
- Use `useStore('StoreName', selector)` in a component.
43+
- Perform one update via object or callback updater.
44+
45+
6. Platform handoff
46+
- iOS path:
47+
1. Run `npx brownfield package:ios --scheme YourScheme --configuration Release`.
48+
2. Confirm package output contains your module XCFramework plus `Brownie.xcframework`, `ReactBrownfield.xcframework`, and Hermes (`hermesvm.xcframework` or `hermes.xcframework`).
49+
3. Embed generated frameworks as `Embed & Sign`.
50+
4. Register the store in app startup.
51+
- Android path:
52+
1. Configure `brownie` settings in `package.json` (`kotlin`, `kotlinPackageName`).
53+
2. Ensure Gson dependency exists in brownfield module or app.
54+
3. Run `npx brownfield package:android --module-name :YourModuleName --variant release`.
55+
4. Run `npx brownfield publish:android --module-name :YourModuleName`.
56+
5. Register store during startup with `registerStoreIfNeeded`.
57+
- Note: both `package:ios` and `package:android` run Brownie codegen as part of packaging.
58+
59+
7. Verify sync
60+
- Update state from React Native and confirm native UI observes updates.
61+
- Update from native and confirm React Native reflects changes.
62+
- If one side is stale after schema edits, rerun packaging/codegen and rebuild host apps.
63+
- Android runtime gate:
64+
- If launch fails with `ClassNotFoundException: com.google.gson.Gson`, add `implementation("com.google.code.gson:gson:<version>")` to brownfield module or host app and rebuild.
65+
66+
## Quick reference
67+
68+
- Install: `npm install @callstack/brownie`
69+
- Store file pattern: `*.brownie.ts`
70+
- Codegen/build entry points:
71+
- `npx brownfield codegen`
72+
- `npx brownfield package:ios --scheme YourScheme --configuration Release`
73+
- `npx brownfield package:android --module-name :YourModuleName --variant release`
74+
- `npx brownfield publish:android --module-name :YourModuleName`
75+
- iOS packaging outputs (CLI docs):
76+
- `ios/.brownfield/package/build/`
77+
- Error cues this guide handles first:
78+
- Store file exists but typed APIs are missing
79+
- Native setup done but store not registered at startup
80+
- First state update does not appear on one side
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Brownie Store Definition and Codegen
2+
3+
## Discoverability triggers
4+
5+
- "where to put .brownie.ts files"
6+
- "BrownieStores module augmentation"
7+
- "brownfield codegen for brownie"
8+
- "generated Swift or Kotlin types are stale"
9+
10+
## Scope
11+
12+
In scope:
13+
- Authoring `*.brownie.ts` stores and augmentation rules.
14+
- Supported schema patterns and type mapping expectations.
15+
- Running `brownfield codegen` and knowing when to rerun.
16+
- Verifying generated artifacts and resolving common drift issues.
17+
18+
Out of scope:
19+
- Initial installation and first integration sequence. For that, read [`getting-started.md`](getting-started.md) in this folder.
20+
- React component usage ergonomics (`useStore`, selectors, updates). For that, read [`typescript-usage.md`](typescript-usage.md) in this folder.
21+
- Platform registration and runtime integration details. For Android, read [`android-usage.md`](android-usage.md). For iOS, read [`swift-and-xcframework.md`](swift-and-xcframework.md) in this folder.
22+
23+
## Procedure
24+
25+
1. Validate store file shape
26+
- File name ends with `.brownie.ts`.
27+
- Store interface extends `BrownieStore`.
28+
- `declare module '@callstack/brownie'` augments `BrownieStores`.
29+
- Store key in `BrownieStores` matches intended public store name.
30+
31+
2. Confirm schema expectations before generation
32+
- Scalars (`number`, `string`, `boolean`) are supported.
33+
- Nested object types are supported and generate native structs/classes.
34+
- Union string literals generate native enum types across platforms; for example, `theme: 'light' | 'dark'` emits Kotlin and Swift enum types (such as `Theme`), with generated enum/type names following codegen naming and casing conventions rather than remaining raw string fields.
35+
36+
3. Ensure augmentation is loaded by TypeScript
37+
- Import each `.brownie.ts` file from app entry point.
38+
39+
4. Run codegen
40+
- Primary command: `npx brownfield codegen`.
41+
- Optional platform scope (if needed by CLI config): `npx brownfield codegen -p swift`.
42+
- Discovery rule: the CLI recursively scans the project for `*.brownie.ts` files (excluding `node_modules`).
43+
44+
5. Verify generated outputs
45+
- Swift output root: `node_modules/@callstack/brownie/ios/Generated/`.
46+
- Confirm store type files exist and include store name bindings/protocol conformance.
47+
- Android generation is driven by brownfield Android packaging flow; confirm generated Kotlin output path aligns with package configuration.
48+
49+
6. Apply rerun and rebuild rule
50+
- Any schema surface change requires rerunning codegen.
51+
- If app behavior still reflects old schema, rebuild native artifacts after codegen.
52+
53+
7. Triage common failures
54+
- Missing generated files: confirm file extension and augmentation block.
55+
- Types not updated: verify app entry imports and rerun codegen from project root.
56+
- Runtime mismatch after schema edits: rerun codegen and rebuild platform artifacts.
57+
58+
## Compact schema example
59+
60+
```ts
61+
import type {BrownieStore} from '@callstack/brownie';
62+
63+
interface AppStore extends BrownieStore {
64+
counter: number;
65+
user: {name: string};
66+
}
67+
68+
declare module '@callstack/brownie' {
69+
interface BrownieStores {
70+
AppStore: AppStore;
71+
}
72+
}
73+
```
74+
75+
## Quick reference
76+
77+
- File contract:
78+
- `*.brownie.ts`
79+
- `interface X extends BrownieStore`
80+
- `declare module '@callstack/brownie' { interface BrownieStores { ... } }`
81+
- Type mapping (most common):
82+
- `number` -> `Double` (Swift)
83+
- `string` -> `String`
84+
- `boolean` -> `Bool`
85+
- nested object -> generated native type
86+
- Commands:
87+
- `npx brownfield codegen`
88+
- `npx brownfield codegen -p swift`
89+
- Regeneration triggers:
90+
- Added/removed store
91+
- Renamed key or changed field types
92+
- Nested model changes

0 commit comments

Comments
 (0)