frontier-os-app-builder 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/agents/fos-executor.md +22 -65
  4. package/agents/fos-plan-checker.md +13 -12
  5. package/agents/fos-planner.md +20 -67
  6. package/agents/fos-researcher.md +14 -10
  7. package/agents/fos-verifier.md +11 -5
  8. package/bin/fos-tools.cjs +48 -11
  9. package/bin/install.js +8 -5
  10. package/commands/fos/add-feature.md +1 -2
  11. package/commands/fos/discuss.md +0 -1
  12. package/commands/fos/new-app.md +1 -3
  13. package/commands/fos/new-milestone.md +1 -1
  14. package/commands/fos/plan.md +0 -2
  15. package/package.json +7 -1
  16. package/references/app-patterns.md +46 -28
  17. package/references/deployment.md +40 -74
  18. package/references/module-index.md +32 -0
  19. package/references/sdk/chain.md +92 -0
  20. package/references/sdk/communities.md +159 -0
  21. package/references/sdk/events.md +212 -0
  22. package/references/sdk/init.md +126 -0
  23. package/references/sdk/navigation.md +49 -0
  24. package/references/sdk/offices.md +76 -0
  25. package/references/sdk/partnerships.md +111 -0
  26. package/references/sdk/storage.md +44 -0
  27. package/references/sdk/thirdparty.md +240 -0
  28. package/references/sdk/token-amount.md +99 -0
  29. package/references/sdk/types.md +27 -0
  30. package/references/sdk/ui-utils.md +39 -0
  31. package/references/sdk/user.md +208 -0
  32. package/references/sdk/wallet.md +334 -0
  33. package/references/verification-rules.md +18 -18
  34. package/templates/app/frontier-services.tsx +75 -18
  35. package/templates/app/layout.tsx +19 -9
  36. package/templates/app/package.json +2 -1
  37. package/templates/app/public/favicon.svg +3 -0
  38. package/templates/app/sdk-context.tsx +7 -9
  39. package/templates/app/sdk-services.tsx +92 -117
  40. package/templates/app/vercel.json +8 -47
  41. package/templates/state/plan.md +32 -14
  42. package/templates/state/roadmap.md +2 -2
  43. package/templates/state/summary.md +26 -29
  44. package/workflows/add-feature.md +6 -1
  45. package/workflows/discuss.md +9 -3
  46. package/workflows/execute-plan.md +3 -3
  47. package/workflows/execute.md +17 -6
  48. package/workflows/new-app.md +54 -18
  49. package/workflows/new-milestone.md +9 -2
  50. package/workflows/plan.md +14 -5
  51. package/workflows/ship.md +26 -10
  52. package/workflows/status.md +0 -1
  53. package/references/module-inference.md +0 -348
  54. package/references/sdk-surface.md +0 -1600
  55. package/templates/app/main-simple-standalone.tsx +0 -19
  56. package/templates/app/main-simple.tsx +0 -19
  57. package/templates/state/manifest.json +0 -12
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BerlinhouseLabs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -17,6 +17,8 @@ npx frontier-os-app-builder
17
17
 
18
18
  That's it. This installs `/fos:*` commands into your Claude Code environment.
19
19
 
20
+ > Running `npx frontier-os-app-builder` executes the installer automatically. If you install globally instead (`npm i -g frontier-os-app-builder`), run `frontier-os-app-builder` once afterward to populate `~/.claude`.
21
+
20
22
  To uninstall:
21
23
 
22
24
  ```bash
@@ -72,6 +74,12 @@ npx frontier-os-app-builder --uninstall
72
74
  | `/fos:next` | Auto-route to the next step in the workflow |
73
75
  | `/fos:status` | Show current project state |
74
76
 
77
+ ## Configuration
78
+
79
+ | Environment variable | Used by | Effect |
80
+ |---|---|---|
81
+ | `FOS_GITHUB_ORG` | `/fos:ship` | Creates the deployed app's GitHub repo under this organization. When unset (the default), the repo is created under your authenticated `gh` user account. |
82
+
75
83
  ## How it works
76
84
 
77
85
  The framework is a multi-layered meta-prompting system:
@@ -92,6 +100,23 @@ Each command reads state from `.frontier-app/` on disk, does its work, writes up
92
100
  - **Frontier-specific verification** — checks CORS origins, iframe detection, standalone fallback, SDK permissions, dark theme
93
101
  - **Milestones** — iterative development with `/fos:new-milestone` for v2, v3, and beyond
94
102
 
103
+ ## Frontier Studio
104
+
105
+ Frontier Studio is a live companion dashboard that runs alongside Claude Code. It watches your `.frontier-app/` state files and shows a visual dashboard with a live app preview in your browser.
106
+
107
+ ```bash
108
+ cd your-app-directory
109
+ npx frontier-studio
110
+ ```
111
+
112
+ Opens `http://localhost:4983` with:
113
+
114
+ - **Project dashboard** — phases, status, SDK modules, progress, next action
115
+ - **Live preview** — your app rendered via Vite HMR in an iframe (desktop/tablet/mobile)
116
+ - **Activity stream** — file changes, git commits, phase transitions in real time
117
+
118
+ See [studio/README.md](./studio/README.md) for development details.
119
+
95
120
  ## SDK Coverage
96
121
 
97
122
  The framework has built-in knowledge of all 10 Frontier SDK modules:
@@ -128,11 +128,12 @@ node $HOME/.claude/frontier-os-app-builder/bin/fos-tools.cjs scaffold <template>
128
128
  | `vite.config.ts` | `./vite.config.ts` |
129
129
  | `frontier-services.tsx` | `./src/lib/frontier-services.tsx` |
130
130
  | `layout-standalone.tsx` | `./src/views/Layout.tsx` |
131
- | `main-router.tsx` or `main-simple-standalone.tsx` | `./src/main.tsx` |
131
+ | `main-router.tsx` | `./src/main.tsx` |
132
132
  | `router.tsx` | `./src/router.tsx` |
133
133
  | `index.css` | `./src/styles/index.css` |
134
134
  | `test-setup.ts` | `./src/test/setup.ts` |
135
135
  | `gitignore` | `./.gitignore` |
136
+ | `public/` | `./public/` |
136
137
 
137
138
  **Critical scaffold requirements:**
138
139
  - `src/lib/frontier-services.tsx` — Exports `useServices()` with mock backend. Modified only during SDK Integration phase.
@@ -183,19 +184,23 @@ const wallet = services.wallet;
183
184
  **Create hooks with loading/error states:**
184
185
  ```typescript
185
186
  import { useState, useEffect } from 'react';
186
- import { useServices } from '../lib/frontier-services';
187
- import type { ReturnType } from '@frontiertower/frontier-sdk';
187
+ import { useServices, type FrontierServices } from '../lib/frontier-services';
188
+
189
+ // Derive feature data types from the FrontierServices seam — NEVER import the
190
+ // SDK in feature code (it isn't installed in scaffold/feature phases and fails
191
+ // verification rule M-03). `ReturnType` here is the TypeScript built-in.
192
+ type Balance = Awaited<ReturnType<FrontierServices['wallet']['getBalance']>>;
188
193
 
189
- export function useFeature() {
194
+ export function useBalance() {
190
195
  const services = useServices();
191
- const [data, setData] = useState<ReturnType | null>(null);
196
+ const [data, setData] = useState<Balance | null>(null);
192
197
  const [loading, setLoading] = useState(true);
193
198
  const [error, setError] = useState<string | null>(null);
194
199
 
195
200
  useEffect(() => {
196
201
  const fetchData = async () => {
197
202
  try {
198
- const result = await services.module.method();
203
+ const result = await services.wallet.getBalance();
199
204
  setData(result);
200
205
  } catch (err) {
201
206
  setError(err instanceof Error ? err.message : 'Failed to load data');
@@ -241,39 +246,18 @@ export default function FeatureView() {
241
246
 
242
247
  ### Tailwind Dark Theme Classes
243
248
 
244
- Always use these semantic classes (defined in index.css @theme block):
245
- - **Backgrounds:** `bg-background`, `bg-card`, `bg-muted-background`
246
- - **Text:** `text-foreground`, `text-card-foreground`, `text-muted-foreground`
247
- - **Borders:** `border-border`
248
- - **Interactive:** `bg-primary text-primary-foreground`, `bg-accent text-accent-foreground`
249
- - **Status:** `text-success`, `text-danger`, `text-alert`
250
- - **Inputs:** `bg-input`, `ring-ring`, `outline-outline`
251
-
252
- **NEVER use hardcoded colors** (no `bg-white`, `text-black`, `bg-gray-900`). Always use the semantic CSS variable classes.
249
+ Use semantic Tailwind classes from the app's index.css @theme block (bg-background, text-foreground, etc.). See app-patterns.md "Dark Theme CSS Variables" section for the full token list. **NEVER use hardcoded colors** (no `bg-white`, `text-black`, `bg-gray-900`).
253
250
 
254
251
  ### Type Safety
255
252
 
256
253
  - Always use the SDK types from `@frontiertower/frontier-sdk`
257
- - Never invent types — use `WalletBalance`, `WalletBalanceFormatted`, `UserOperationReceipt`, `SmartAccount`, etc.
254
+ - Never invent types — use `WalletBalance`, `UserOperationReceipt`, `SmartAccount`, etc.
258
255
  - If a type is not exported by the SDK, define a local interface that matches the SDK's return shape
259
256
  - Always use `strict: true` TypeScript
260
257
 
261
- ### Module Access Reference
258
+ ### Module Access
262
259
 
263
- When accessing modules via `useServices()`, use these property names:
264
-
265
- | Service Property | Description |
266
- |-----------------|-------------|
267
- | `services.wallet` | Wallet operations (balance, transactions, send) |
268
- | `services.storage` | Storage operations (get, set, delete) |
269
- | `services.chain` | Chain/blockchain operations |
270
- | `services.user` | User profile and authentication |
271
- | `services.partnerships` | Partnerships module |
272
- | `services.thirdParty` | Third-party integrations |
273
- | `services.communities` | Communities module |
274
- | `services.events` | Events module |
275
- | `services.offices` | Offices module |
276
- | `services.navigation` | Navigation module |
260
+ Access modules via `services.<module>` from `useServices()`. Property names match SDK module names in lowercase (`services.wallet`, `services.events`, etc.).
277
261
 
278
262
  </feature_execution>
279
263
 
@@ -293,9 +277,9 @@ When accessing modules via `useServices()`, use these property names:
293
277
  **TIER 2 — SDK INTEGRATION PHASE ONLY:**
294
278
  7. **SDK access:** `useSdk()` hook from `src/lib/sdk-context.tsx`, used only inside `sdk-services.tsx` and `Layout.tsx`.
295
279
  8. **Iframe detection:** `isInFrontierApp()` check in Layout.tsx. Standalone mode shows fallback banner.
296
- 9. **SdkProvider wrapping:** App wrapped in SdkProvider when inside iframe. SDK initialized once via useRef, destroyed on unmount.
280
+ 9. **Provider wrapping:** In-frame, Layout wraps the app in `SdkProvider` AND bridges the SDK into `FrontierServicesProvider` (so `useServices()` resolves). SDK created once in an effect and exposed via `useState`, destroyed on unmount.
297
281
  10. **Permissions:** Every SDK method used must have permission declared in manifest.json.
298
- 11. **CORS:** vercel.json must include all 3 Frontier OS origins (os.frontiertower.io, sandbox.os.frontiertower.io, localhost:5173).
282
+ 11. **CORS:** vercel.json sets CORS for the production origin plus a CSP `frame-ancestors` listing the 3 Frontier OS origins (os.frontiertower.io, sandbox.os.frontiertower.io, localhost:5173) and security headers. Copy templates/app/vercel.json verbatim.
299
283
  12. **SDK imports:** Use `@frontiertower/frontier-sdk` for SDK classes. Exact import paths, not barrel imports.
300
284
  </frontier_os_rules>
301
285
 
@@ -303,35 +287,7 @@ When accessing modules via `useServices()`, use these property names:
303
287
 
304
288
  ### SDK Integration Phase Execution
305
289
 
306
- For the SDK Integration phase (always the final phase), perform these mechanical operations:
307
-
308
- **Step 1: Add SDK dependency**
309
- ```bash
310
- npm install @frontiertower/frontier-sdk
311
- ```
312
-
313
- **Step 2: Create sdk-context.tsx**
314
- Render from `templates/app/sdk-context.tsx` to `src/lib/sdk-context.tsx`.
315
- This file is IDENTICAL across all apps — never customize it.
316
-
317
- **Step 3: Create sdk-services.tsx**
318
- Render from `templates/app/sdk-services.tsx` to `src/lib/sdk-services.tsx`.
319
- This adapter maps each `FrontierServices` method to the corresponding `sdk.getModule().method()` call.
320
-
321
- **Step 4: Upgrade frontier-services.tsx**
322
- Modify `src/lib/frontier-services.tsx` to add environment detection:
323
- - Import `isInFrontierApp` from `@frontiertower/frontier-sdk/ui-utils`
324
- - If in iframe: import and use `createSdkServices` from `./sdk-services`
325
- - If standalone: use existing `createMockServices()` (no change to mock code)
326
-
327
- **Step 5: Upgrade Layout.tsx**
328
- Follow standard Layout pattern from `templates/app/layout.tsx`:
329
- - Add `isInFrontierApp()` detection
330
- - Add `createStandaloneHTML()` fallback for standalone mode
331
- - Wrap children in `SdkProvider` when in iframe
332
-
333
- **Step 6: Add CORS origins to vercel.json**
334
- Replace vercel.json with full version from `templates/app/vercel.json` (has all 3 CORS origin blocks plus SPA rewrite).
290
+ Follow the SDK Integration pattern from app-patterns.md "SDK Integration Pattern" section. The steps are: add SDK dependency; create sdk-context.tsx; create sdk-services.tsx (wire the modules your app uses); swap in templates/app/layout.tsx (it bridges the SDK into FrontierServicesProvider so useServices() works in-frame); swap in the full vercel.json. Leave frontier-services.tsx unchanged — it stays the SDK-free mock seam; do NOT add SDK imports or detection to it. Use templates from templates/app/ for each file.
335
291
 
336
292
  </sdk_integration_execution>
337
293
 
@@ -497,7 +453,7 @@ tasks_completed: N/N
497
453
 
498
454
  # Phase [X] Plan [Y]: [Name] Summary
499
455
 
500
- [One-liner must be substantive: "Balance display with useBalance hook calling getBalanceFormatted(), card-based UI with loading/error states" NOT "Balance feature implemented"]
456
+ [One-liner must be substantive: "Balance display with useBalance hook calling getBalance() and formatting via formatAmount(), card-based UI with loading/error states" NOT "Balance feature implemented"]
501
457
 
502
458
  ## Tasks Completed
503
459
 
@@ -513,7 +469,7 @@ tasks_completed: N/N
513
469
 
514
470
  | Method | Module | Permission | Files |
515
471
  |--------|--------|------------|-------|
516
- | wallet.getBalanceFormatted() | Wallet | wallet:getBalanceFormatted | src/hooks/useBalance.ts |
472
+ | wallet.getBalance() | Wallet | wallet:getBalance | src/hooks/useBalance.ts |
517
473
 
518
474
  ## Deviations from Plan
519
475
 
@@ -561,7 +517,8 @@ Do NOT skip. Do NOT proceed to state updates if self-check fails.
561
517
  </self_check>
562
518
 
563
519
  <sdk_reference>
564
- @frontier-os-app-builder/references/sdk-surface.md
520
+ Focused SDK reference is provided via <files_to_read> in the spawn prompt.
521
+ Contains only modules relevant to this app (from references/sdk/*.md).
565
522
  </sdk_reference>
566
523
 
567
524
  <app_patterns_reference>
@@ -48,7 +48,7 @@ Before verifying, load project context:
48
48
  <core_principle>
49
49
  **Plan completeness =/= Goal achievement**
50
50
 
51
- A task "create balance display" can be in the plan while the SDK method `getBalanceFormatted()` is called with wrong arguments. The task exists but the goal "show user's balance" won't be achieved.
51
+ A task "create balance display" can be in the plan while the SDK method `getBalance()` is called with wrong arguments. The task exists but the goal "show user's balance" won't be achieved.
52
52
 
53
53
  Goal-backward verification works backwards from outcome:
54
54
 
@@ -74,10 +74,10 @@ Then verify each level against the actual plan files.
74
74
  3. Check method signatures match (parameter types, return types)
75
75
  4. Verify the correct module accessor is used (e.g., `getWallet()` not `wallet()`)
76
76
 
77
- Feature phases access methods via `services.module.method()` (not `sdk.getModule().method()`). The method NAMES are the same — validate against sdk-surface.md for correctness. The import path should be `../lib/frontier-services`, not `../lib/sdk-context`.
77
+ Feature phases access methods via `services.module.method()` (not `sdk.getModule().method()`). The method NAMES are the same — validate against the per-module SDK reference files (references/sdk/*.md) for correctness. The import path should be `../lib/frontier-services`, not `../lib/sdk-context`.
78
78
 
79
79
  **Validation rules:**
80
- - Method must exist in @frontier-os-app-builder/references/sdk-surface.md
80
+ - Method must exist in the focused SDK reference (provided via <files_to_read>)
81
81
  - Module accessor must use the correct getter: `sdk.getWallet()`, `sdk.getStorage()`, etc.
82
82
  - Parameter types must match SDK definitions (e.g., `bigint` for amounts, `string` for addresses)
83
83
  - Return types referenced in task must match SDK definitions
@@ -86,17 +86,17 @@ Feature phases access methods via `services.module.method()` (not `sdk.getModule
86
86
  - Method name doesn't exist in SDK (e.g., `getTokenBalance()` instead of `getBalance()`)
87
87
  - Wrong module (e.g., `sdk.getUser().getBalance()` instead of `sdk.getWallet().getBalance()`)
88
88
  - Wrong parameter types (e.g., `number` instead of `bigint` for token amounts)
89
- - Invented types not in SDK (e.g., `BalanceInfo` instead of `WalletBalanceFormatted`)
89
+ - Invented types not in SDK (e.g., `BalanceInfo` instead of `WalletBalance`)
90
90
 
91
91
  **Example issue:**
92
92
  ```yaml
93
93
  issue:
94
94
  dimension: sdk_method_correctness
95
95
  severity: blocker
96
- description: "Task 2 references sdk.getWallet().getTokenBalance() — method does not exist. Use getBalance() or getBalanceFormatted()"
96
+ description: "Task 2 references sdk.getWallet().getTokenBalance() — method does not exist. Use getBalance()"
97
97
  plan: "02-01"
98
98
  task: 2
99
- fix_hint: "Replace getTokenBalance() with getBalanceFormatted() — returns WalletBalanceFormatted with .total, .fnd, .internalFnd string fields"
99
+ fix_hint: "Replace getTokenBalance() with getBalance() — returns WalletBalance with .total, .fnd, .internalFnd bigint fields; format each with formatAmount() from '@frontiertower/frontier-sdk'"
100
100
  ```
101
101
 
102
102
  ## Dimension 2: Permission Alignment
@@ -128,10 +128,10 @@ For feature phases: permission mismatches are severity **warning** (permissions
128
128
  issue:
129
129
  dimension: permission_alignment
130
130
  severity: blocker
131
- description: "Task 1 calls sdk.getWallet().getBalanceFormatted() but manifest.json does not declare wallet:getBalanceFormatted permission"
131
+ description: "Task 1 calls sdk.getWallet().getBalance() but manifest.json does not declare wallet:getBalance permission"
132
132
  plan: "02-01"
133
133
  task: 1
134
- fix_hint: "Add 'wallet:getBalanceFormatted' to permissions array in manifest.json, or add a task to update manifest"
134
+ fix_hint: "Add 'wallet:getBalance' to permissions array in manifest.json, or add a task to update manifest"
135
135
  ```
136
136
 
137
137
  ## Dimension 3: File Structure Compliance
@@ -205,7 +205,7 @@ issue:
205
205
  - ❌ `layout.tsx` template (without `-standalone`) — use `layout-standalone.tsx`
206
206
  - ❌ `package.json` template (without `-standalone`) — use `package-standalone.json`
207
207
  - ❌ `vercel.json` template (without `-standalone`) — use `vercel-standalone.json`
208
- - ❌ `main-simple.tsx` template (without `-standalone`) use `main-simple-standalone.tsx`
208
+ - ❌ single-component entries — use `main-router.tsx` instead (all apps use the router)
209
209
 
210
210
  If the researcher recommended SDK patterns from production apps, the planner should NOT have included them in Phase 1. Flag as blocker with fix hint: "Phase 1 is standalone-first. Remove SDK artifacts and use standalone templates."
211
211
 
@@ -357,8 +357,8 @@ issue:
357
357
  1. Plan includes task to add `@frontiertower/frontier-sdk` dependency (`npm install`)
358
358
  2. Plan includes task to create `src/lib/sdk-context.tsx` from template
359
359
  3. Plan includes task to create `src/lib/sdk-services.tsx` adapter
360
- 4. Plan includes task to upgrade `src/lib/frontier-services.tsx` with environment detection
361
- 5. Plan includes task to upgrade `src/views/Layout.tsx` with iframe detection + SdkProvider
360
+ 4. Plan keeps `src/lib/frontier-services.tsx` as the SDK-free mock seam (NO task to add SDK imports/detection there)
361
+ 5. Plan includes task to swap in `src/views/Layout.tsx` from the template (iframe detection + `SdkProvider` + `FrontierServicesProvider` bridge so `useServices()` resolves)
362
362
  6. Plan includes task to add CORS origins to `vercel.json`
363
363
  7. Plan includes verification task (build, typecheck, full validation)
364
364
 
@@ -414,7 +414,8 @@ Return structured PASS/FAIL with issues list:
414
414
  </output_format>
415
415
 
416
416
  <sdk_reference>
417
- @frontier-os-app-builder/references/sdk-surface.md
417
+ Focused SDK reference is provided via <files_to_read> in the spawn prompt.
418
+ Contains only modules relevant to this app (from references/sdk/*.md).
418
419
  </sdk_reference>
419
420
 
420
421
  <verification_rules_reference>
@@ -121,14 +121,14 @@ Phase 1 ALWAYS produces a single plan that scaffolds the entire app. This plan u
121
121
  - `vite.config.ts` — Vite + Vitest config (parameterized: APP_NAME)
122
122
  - `frontier-services.tsx` — Service layer with mock implementations (parameterized: modules used)
123
123
  - `layout-standalone.tsx` — Shell layout for standalone mode (parameterized: APP_NAME)
124
- - `main-router.tsx` or `main-simple-standalone.tsx` — React root (choose based on routing needs)
124
+ - `main-router.tsx` — React root (router entry; all apps use the router)
125
125
  - `router.tsx` — Route definitions (parameterized: routes)
126
126
  - `index.css` — Tailwind + dark theme variables (parameterized: app colors)
127
127
  - `test-setup.ts` — Vitest setup (identical across apps)
128
128
  - `gitignore` — Git ignore patterns
129
129
 
130
130
  **Scaffold plan specifics:**
131
- - ALL files listed in the template directory must be created
131
+ - All standalone template files listed above must be created (excluding SDK-only and non-standalone variants from the BLOCKLIST below)
132
132
  - `frontier-services.tsx` goes to `src/lib/frontier-services.tsx`
133
133
  - `layout-standalone.tsx` goes to `src/views/Layout.tsx`
134
134
  - `index.css` goes to `src/styles/index.css`
@@ -142,7 +142,7 @@ Phase 1 ALWAYS produces a single plan that scaffolds the entire app. This plan u
142
142
  **Phase 1 BLOCKLIST — NEVER include these in a scaffold plan:**
143
143
  - ❌ `sdk-context.tsx` — this file is created during SDK Integration phase, NOT Phase 1
144
144
  - ❌ `layout.tsx` template — use `layout-standalone.tsx` instead (no iframe detection, no SdkProvider)
145
- - ❌ `main-simple.tsx` template — use `main-simple-standalone.tsx` instead
145
+ - ❌ single-component entries — use `main-router.tsx` instead (all apps use the router; no single-component entry)
146
146
  - ❌ `package.json` template — use `package-standalone.json` instead (no SDK dependency)
147
147
  - ❌ `vercel.json` template — use `vercel-standalone.json` instead (no CORS headers)
148
148
  - ❌ `@frontiertower/frontier-sdk` in dependencies — SDK is added during SDK Integration phase
@@ -161,8 +161,8 @@ Feature phases create plans with tasks for:
161
161
  - **Tests** — Vitest tests for hooks and components
162
162
 
163
163
  **Task specificity requirements:**
164
- - Name exact service methods: `services.wallet.getBalanceFormatted()` not "get balance"
165
- - Name exact types: `WalletBalanceFormatted` not "balance type"
164
+ - Name exact service methods: `services.wallet.getBalance()` not "get balance"
165
+ - Name exact types: `WalletBalance` not "balance type"
166
166
  - Name exact file paths: `src/hooks/useBalance.ts` not "a balance hook"
167
167
  - Name exact Tailwind classes: `bg-card text-card-foreground rounded-lg p-4` not "styled card"
168
168
  - Name exact imports: `import { useServices } from '../lib/frontier-services'` not "import services"
@@ -177,17 +177,17 @@ The SDK Integration phase is ALWAYS the last phase. It is mechanical — no feat
177
177
  1. **Add SDK dependency** — `npm install @frontiertower/frontier-sdk@{{SDK_VERSION}}`. Add to package.json dependencies.
178
178
  2. **Create sdk-context.tsx** — Render from `templates/app/sdk-context.tsx` to `src/lib/sdk-context.tsx`. Standard SdkProvider + useSdk() hook, identical across all apps. NEVER modify after creation.
179
179
  3. **Create sdk-services.tsx** — Render from `templates/app/sdk-services.tsx` to `src/lib/sdk-services.tsx`. Adapter mapping FrontierServices interface to real SDK calls via useSdk().
180
- 4. **Upgrade frontier-services.tsx** — Modify `src/lib/frontier-services.tsx` to detect environment: `window.self !== window.top`. If in iframe import and use sdk-services adapter. If standalone use existing mock services. Import `isInFrontierApp` from `@frontiertower/frontier-sdk/ui-utils`.
181
- 5. **Upgrade Layout.tsx** — Follow standard Layout pattern from `templates/app/layout.tsx`: add `isInFrontierApp()` detection, `createStandaloneHTML()` fallback, `SdkProvider` wrapping of `<Outlet />`.
182
- 6. **Add CORS origins to vercel.json** — Replace with full `templates/app/vercel.json` content (adds all 3 Frontier OS origin blocks).
180
+ 4. **Leave frontier-services.tsx unchanged** — it stays the SDK-free mock seam. The iframe/standalone switch lives in Layout (step 5); do NOT add SDK imports or detection to `src/lib/frontier-services.tsx`.
181
+ 5. **Swap in Layout.tsx** — Copy `templates/app/layout.tsx`: `isInFrontierApp()` detection, `createStandaloneHTML()` fallback, and in-frame wrap `<Outlet />` in `SdkProvider` + bridge the SDK into `FrontierServicesProvider` (`createSdkServices(sdk)`) so `useServices()` resolves.
182
+ 6. **Swap in the full vercel.json** — Replace with `templates/app/vercel.json` (CORS + CSP `frame-ancestors` for the 3 origins + security headers).
183
183
  7. **Verify** — Build passes (`npm run build`), typecheck passes (`npx tsc --noEmit`), all verification rules pass including Tier 2.
184
184
 
185
185
  **Success criteria (fixed, not user-determined):**
186
186
  1. `src/lib/sdk-context.tsx` exists and exports `useSdk` + `SdkProvider`
187
187
  2. `src/lib/sdk-services.tsx` exists and maps all used service methods to real SDK calls
188
- 3. `src/lib/frontier-services.tsx` detects iframe and routes to SDK adapter
189
- 4. `src/views/Layout.tsx` has `isInFrontierApp()` detection and `SdkProvider` wrapping
190
- 5. `vercel.json` has all 3 CORS origin blocks
188
+ 3. `src/views/Layout.tsx` bridges the SDK into `FrontierServicesProvider` (via `createSdkServices`) so `useServices()` resolves in-frame
189
+ 4. `src/views/Layout.tsx` has `isInFrontierApp()` detection, `SdkProvider`, AND `FrontierServicesProvider`
190
+ 5. `vercel.json` has CORS + CSP `frame-ancestors` (3 origins) + security headers
191
191
  6. `npm run build` succeeds
192
192
  7. `npx tsc --noEmit` passes
193
193
 
@@ -209,22 +209,22 @@ Every task has six required fields:
209
209
  - Rule: At minimum, include the files this task's code will import from or integrate with.
210
210
 
211
211
  **<action>:** Specific implementation instructions with CONCRETE SDK values.
212
- - Good: "Create `useBalance` hook that calls `services.wallet.getBalanceFormatted()` returning `WalletBalanceFormatted`. Handle loading/error states with useState. The hook returns `{ balance: WalletBalanceFormatted | null, loading: boolean, error: string | null }`. Import `useServices` from `../lib/frontier-services`. Wrap the service call in try/catch. Call in a useEffect with `[services]` dependency."
212
+ - Good: "Create `useBalance` hook that calls `services.wallet.getBalance()` returning `WalletBalance` (bigint fields `total`/`fnd`/`internalFnd`), formatting for display via `formatAmount` imported from `@frontiertower/frontier-sdk`. Handle loading/error states with useState. The hook returns `{ balance: WalletBalance | null, loading: boolean, error: string | null }`. Import `useServices` from `../lib/frontier-services`. Wrap the service call in try/catch. Call in a useEffect with `[services]` dependency."
213
213
  - Bad: "Create a hook that fetches the balance"
214
214
 
215
215
  **<verify>:** How to prove the task is complete.
216
- - Good: `grep -q "getBalanceFormatted" src/hooks/useBalance.ts && npx tsc --noEmit`
216
+ - Good: `grep -q "getBalance" src/hooks/useBalance.ts && npx tsc --noEmit`
217
217
  - Bad: "It works"
218
218
 
219
219
  **<acceptance_criteria>:** Grep-verifiable conditions the executor checks programmatically. Every task MUST include this field.
220
220
  - Good:
221
- - `grep -q "getBalanceFormatted" src/hooks/useBalance.ts`
221
+ - `grep -q "getBalance" src/hooks/useBalance.ts`
222
222
  - `grep -q "loading" src/hooks/useBalance.ts`
223
223
  - `npx tsc --noEmit` exits 0
224
224
  - Bad: "It compiles", or omitting acceptance_criteria entirely
225
225
 
226
226
  **<done>:** Acceptance criteria — measurable state of completion.
227
- - Good: "`useBalance.ts` exports a hook that returns `{ balance, loading, error }`. TypeScript compiles without errors. The hook calls `getBalanceFormatted()` with proper error handling."
227
+ - Good: "`useBalance.ts` exports a hook that returns `{ balance, loading, error }`. TypeScript compiles without errors. The hook calls `getBalance()` and formats with `formatAmount()`, with proper error handling."
228
228
  - Bad: "Balance hook is complete"
229
229
 
230
230
  ## Task Types
@@ -299,7 +299,7 @@ SDK Modules: [Which SDK modules are used, if any]
299
299
  @.frontier-app/STATE.md
300
300
 
301
301
  # SDK reference for modules used:
302
- @frontier-os-app-builder/references/sdk-surface.md
302
+ # Provided via <files_to_read> in spawn prompt (focused per-module refs from references/sdk/)
303
303
 
304
304
  # Prior plan summaries if needed:
305
305
  @.frontier-app/phases/XX-name/NN-NN-SUMMARY.md
@@ -376,57 +376,9 @@ Plans should complete within ~50% context. Each plan: 2-3 tasks maximum.
376
376
 
377
377
  <frontier_os_specifics>
378
378
 
379
- ## Service Method Reference for Plans
379
+ ## Service Method Reference
380
380
 
381
- When referencing service methods in task actions, use the EXACT patterns:
382
-
383
- **Initialization (always via useServices):**
384
- ```typescript
385
- import { useServices } from '../lib/frontier-services';
386
- const services = useServices();
387
- ```
388
-
389
- **Module access:**
390
- ```typescript
391
- const wallet = services.wallet;
392
- const storage = services.storage;
393
- const chain = services.chain;
394
- const user = services.user;
395
- const partnerships = services.partnerships;
396
- const thirdParty = services.thirdParty;
397
- const communities = services.communities;
398
- const events = services.events;
399
- const offices = services.offices;
400
- const navigation = services.navigation;
401
- ```
402
-
403
- **Standard hook pattern:**
404
- ```typescript
405
- export function useFeature() {
406
- const services = useServices();
407
- const [data, setData] = useState<FeatureType | null>(null);
408
- const [loading, setLoading] = useState(true);
409
- const [error, setError] = useState<string | null>(null);
410
-
411
- useEffect(() => {
412
- const fetch = async () => {
413
- try {
414
- const result = await services.module.method();
415
- setData(result);
416
- } catch (err) {
417
- setError(err instanceof Error ? err.message : 'Unknown error');
418
- } finally {
419
- setLoading(false);
420
- }
421
- };
422
- fetch();
423
- }, [services]);
424
-
425
- return { data, loading, error };
426
- }
427
- ```
428
-
429
- **Permission mapping:** `services.module.method()` requires permission `module:method` in manifest.json.
381
+ Access modules via `services.<module>` from `useServices()` (imported from `../lib/frontier-services`). Property names match SDK module names in lowercase. Method signatures and types are in the focused SDK reference provided via `<files_to_read>`. Permission mapping: `services.module.method()` requires permission `module:method` in manifest.json.
430
382
 
431
383
  ## Required Patterns for All Plans
432
384
 
@@ -463,7 +415,8 @@ When spawned in revision mode with checker issues:
463
415
  </revision_mode>
464
416
 
465
417
  <sdk_reference>
466
- @frontier-os-app-builder/references/sdk-surface.md
418
+ Focused SDK reference is provided via <files_to_read> in the spawn prompt.
419
+ Contains only modules relevant to this app (from references/sdk/*.md).
467
420
  </sdk_reference>
468
421
 
469
422
  <app_patterns_reference>
@@ -48,16 +48,17 @@ If CONTEXT.md exists, it constrains your research scope. Don't explore alternati
48
48
  All production apps live at `~/frontieros/frontier-os-app-*`. Use this mapping to identify which apps to study based on the current phase's feature needs.
49
49
 
50
50
  ### Wallet / Payments / Transactions
51
- **Apps:** `frontier-os-app-pos`, `frontier-os-app-pos-payment`, `frontier-os-app-subscriptions`
51
+ **Preferred apps (v0.23+ bigint amounts — study these first):** `frontier-os-app-fiat-rails` (bigint `transferFrontierDollar`/transfers + on/off-ramp), `frontier-os-app-ifnd-converter` (gold v0.24 migration — `getBalance()` + `formatAmount()`/`parseAmount()` patterns)
52
+ **Legacy apps (PRE-bigint — useful for UI/flow patterns only, NOT for amount handling):** `frontier-os-app-pos`, `frontier-os-app-pos-payment`, `frontier-os-app-subscriptions`. WARNING: these predate v0.23, use `amount: string`, and `pos`/`pos-payment` still call the REMOVED `getBalanceFormatted()`. Do NOT copy their amount/balance code — use the preferred apps for that.
52
53
  **What to study:**
53
- - `transferFrontierDollar()` and `transferOverallFrontierDollar()` call patterns
54
+ - `transferFrontierDollar()` and `transferOverallFrontierDollar()` call patterns — amounts are `bigint` base units (v0.23+); build with `parseAmount('10.5')` from `@frontiertower/frontier-sdk`
54
55
  - Payment confirmation flows and receipt UI
55
- - Balance display with `getBalanceFormatted()`
56
+ - Balance display: `getBalance()` returns `WalletBalance { total, fnd, internalFnd }` (all `bigint`); format each field with `formatAmount()` from `@frontiertower/frontier-sdk`
56
57
  - Transaction error handling and retry patterns
57
58
  - Loading states during biometric auth prompts
58
59
 
59
60
  ### Events / Bookings / Reservations
60
- **Apps:** `frontier-os-app-superhero-hotel`
61
+ **Apps:** `frontier-os-app-superhero-hotel` (PRE-bigint, v0.15.x — good for event/booking UI + flow patterns; if the phase touches FND amounts or the new event security-deposit methods, take amount/balance patterns from the v0.23+ Wallet apps above instead)
61
62
  **What to study:**
62
63
  - Event listing and detail views
63
64
  - Booking flow (date selection, confirmation, payment)
@@ -79,7 +80,7 @@ All production apps live at `~/frontieros/frontier-os-app-*`. Use this mapping t
79
80
  - Reward tracking with wallet integration
80
81
 
81
82
  ### Maintenance / AI / Tools
82
- **Apps:** `frontier-os-app-maintenance`
83
+ **Apps:** `frontier-os-app-maintenance` (PRE-bigint, v0.15.x — good for ThirdParty/AI integration + tool-layout patterns; do not copy any FND amount/balance handling from it)
83
84
  **What to study:**
84
85
  - ThirdParty module usage
85
86
  - AI/ML integration patterns
@@ -201,20 +202,21 @@ For every SDK module relevant to the phase, document:
201
202
  ```typescript
202
203
  // Import
203
204
  import { useSdk } from '../lib/sdk-context';
205
+ import { formatAmount } from '@frontiertower/frontier-sdk'; // bigint -> display string (package root, NOT /ui-utils)
204
206
 
205
207
  // In component
206
208
  const sdk = useSdk();
207
209
  const wallet = sdk.getWallet();
208
210
 
209
- // Call pattern
210
- const [balance, setBalance] = useState<WalletBalanceFormatted | null>(null);
211
+ // Call pattern — getBalance() returns WalletBalance { total, fnd, internalFnd } (all bigint base units)
212
+ const [balance, setBalance] = useState<WalletBalance | null>(null);
211
213
  const [loading, setLoading] = useState(true);
212
214
  const [error, setError] = useState<string | null>(null);
213
215
 
214
216
  useEffect(() => {
215
217
  const fetchBalance = async () => {
216
218
  try {
217
- const result = await wallet.getBalanceFormatted();
219
+ const result = await wallet.getBalance(); // display via formatAmount(result.fnd) — getBalanceFormatted() was REMOVED in v0.23
218
220
  setBalance(result);
219
221
  } catch (err) {
220
222
  setError(err instanceof Error ? err.message : 'Failed to load balance');
@@ -225,7 +227,8 @@ useEffect(() => {
225
227
  fetchBalance();
226
228
  }, [wallet]);
227
229
 
228
- // Permission: wallet:getBalanceFormatted
230
+ // Display: formatAmount(balance.total) — symbol-free decimal string; prepend '$' yourself if wanted
231
+ // Permission: wallet:getBalance (import { formatAmount } from '@frontiertower/frontier-sdk')
229
232
  ```
230
233
 
231
234
  ### 2. Component Structure
@@ -357,7 +360,8 @@ Do NOT continue reading indefinitely. Research without output is a stuck signal.
357
360
  </analysis_paralysis_guard>
358
361
 
359
362
  <sdk_reference>
360
- @frontier-os-app-builder/references/sdk-surface.md
363
+ Focused SDK reference is provided via <files_to_read> in the spawn prompt.
364
+ Contains only modules relevant to this app (from references/sdk/*.md).
361
365
  </sdk_reference>
362
366
 
363
367
  <app_patterns_reference>
@@ -146,13 +146,14 @@ grep -q "createStandaloneHTML" src/views/Layout.tsx && echo "PASS: I-02" || echo
146
146
 
147
147
  Verify the pattern: when `isInFrontierApp()` returns false, `createStandaloneHTML()` is called and rendered via `dangerouslySetInnerHTML`.
148
148
 
149
- ### I-03: SdkProvider wrapping children
149
+ ### I-03: SdkProvider + FrontierServicesProvider wrapping children
150
150
 
151
151
  ```bash
152
- grep -q "SdkProvider" src/views/Layout.tsx && echo "PASS: I-03" || echo "FAIL: I-03"
152
+ grep -q "SdkProvider" src/views/Layout.tsx && echo "PASS: I-03 SdkProvider" || echo "FAIL: I-03 SdkProvider"
153
+ grep -q "FrontierServicesProvider" src/views/Layout.tsx && echo "PASS: I-03 FrontierServicesProvider" || echo "FAIL: I-03 FrontierServicesProvider (useServices() will crash at runtime)"
153
154
  ```
154
155
 
155
- Verify `<SdkProvider>` wraps `<Outlet />` or the app's child component in the "in Frontier" code path.
156
+ Verify the "in Frontier" path wraps children in `<SdkProvider>` AND bridges the SDK into `<FrontierServicesProvider>` (feature code uses `useServices()`, not `useSdk()`).
156
157
 
157
158
  ### I-04: useSdk() hook available and used
158
159
 
@@ -174,11 +175,15 @@ If any file outside `sdk-context.tsx` instantiates `new FrontierSDK()` directly,
174
175
  > **Tier 2 — SDK Integration phase only.** CORS origins are added during SDK Integration.
175
176
 
176
177
  ```bash
177
- # Check all 3 origins present
178
+ # Check all 3 origins present (in the CSP frame-ancestors directive)
178
179
  for origin in "os.frontiertower.io" "sandbox.os.frontiertower.io" "localhost:5173"; do
179
180
  grep -q "$origin" vercel.json && echo "PASS: $origin" || echo "FAIL: $origin missing from vercel.json"
180
181
  done
181
182
 
183
+ # Check CSP frame-ancestors + security headers
184
+ grep -q "frame-ancestors" vercel.json && echo "PASS: CSP frame-ancestors" || echo "FAIL: CSP frame-ancestors missing"
185
+ grep -q "X-Content-Type-Options" vercel.json && echo "PASS: security headers" || echo "FAIL: security headers missing"
186
+
182
187
  # Check SPA rewrite
183
188
  grep -q '"/(.*)"' vercel.json && echo "PASS: SPA rewrite" || echo "FAIL: SPA rewrite missing"
184
189
  ```
@@ -546,7 +551,8 @@ gaps: [list of failed check IDs, empty if passed]
546
551
  </verification_rules_reference>
547
552
 
548
553
  <sdk_reference>
549
- @frontier-os-app-builder/references/sdk-surface.md
554
+ Focused SDK reference is provided via <files_to_read> in the spawn prompt.
555
+ Contains only modules relevant to this app (from references/sdk/*.md).
550
556
  </sdk_reference>
551
557
 
552
558
  <app_patterns_reference>