frontier-os-app-builder 1.0.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.
- package/README.md +92 -0
- package/agents/fos-executor.md +460 -0
- package/agents/fos-plan-checker.md +386 -0
- package/agents/fos-planner.md +416 -0
- package/agents/fos-researcher.md +358 -0
- package/agents/fos-verifier.md +491 -0
- package/bin/fos-tools.cjs +794 -0
- package/bin/install.js +234 -0
- package/commands/fos/add-feature.md +29 -0
- package/commands/fos/discuss.md +31 -0
- package/commands/fos/execute.md +35 -0
- package/commands/fos/new-app.md +39 -0
- package/commands/fos/new-milestone.md +28 -0
- package/commands/fos/next.md +29 -0
- package/commands/fos/plan.md +37 -0
- package/commands/fos/ship.md +29 -0
- package/commands/fos/status.md +22 -0
- package/package.json +30 -0
- package/references/app-patterns.md +501 -0
- package/references/deployment.md +395 -0
- package/references/module-inference.md +349 -0
- package/references/sdk-surface.md +1622 -0
- package/references/verification-rules.md +404 -0
- package/templates/app/gitignore +25 -0
- package/templates/app/index.css +111 -0
- package/templates/app/index.html +19 -0
- package/templates/app/layout.tsx +45 -0
- package/templates/app/main-router.tsx +17 -0
- package/templates/app/main-simple.tsx +19 -0
- package/templates/app/package.json +36 -0
- package/templates/app/postcss.config.js +5 -0
- package/templates/app/router.tsx +22 -0
- package/templates/app/sdk-context.tsx +33 -0
- package/templates/app/test-setup.ts +19 -0
- package/templates/app/tsconfig.json +22 -0
- package/templates/app/vercel.json +127 -0
- package/templates/app/vite.config.ts +15 -0
- package/templates/state/context.md +248 -0
- package/templates/state/manifest.json +11 -0
- package/templates/state/plan.md +187 -0
- package/templates/state/project.md +118 -0
- package/templates/state/requirements.md +133 -0
- package/templates/state/roadmap.md +129 -0
- package/templates/state/state.md +131 -0
- package/templates/state/summary.md +273 -0
- package/workflows/add-feature.md +234 -0
- package/workflows/discuss.md +310 -0
- package/workflows/execute-plan.md +222 -0
- package/workflows/execute.md +338 -0
- package/workflows/new-app.md +331 -0
- package/workflows/new-milestone.md +258 -0
- package/workflows/next.md +157 -0
- package/workflows/plan.md +310 -0
- package/workflows/ship.md +296 -0
- package/workflows/status.md +145 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createBrowserRouter } from 'react-router-dom';
|
|
2
|
+
import { Layout } from './views/Layout';
|
|
3
|
+
|
|
4
|
+
// {{ROUTES}}
|
|
5
|
+
// Import your view components and define routes below.
|
|
6
|
+
// Pattern:
|
|
7
|
+
// import { Home } from './views/Home';
|
|
8
|
+
// import { Detail } from './views/Detail';
|
|
9
|
+
//
|
|
10
|
+
// Then add route objects to the children array:
|
|
11
|
+
// { index: true, element: <Home /> },
|
|
12
|
+
// { path: 'detail/:id', element: <Detail /> },
|
|
13
|
+
|
|
14
|
+
export const router = createBrowserRouter([
|
|
15
|
+
{
|
|
16
|
+
path: '/',
|
|
17
|
+
element: <Layout />,
|
|
18
|
+
children: [
|
|
19
|
+
// {{ROUTES}}
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
]);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createContext, useContext, useEffect, useRef, useState, type ReactNode } from 'react';
|
|
2
|
+
import { FrontierSDK } from '@frontiertower/frontier-sdk';
|
|
3
|
+
|
|
4
|
+
const SdkContext = createContext<FrontierSDK | null>(null);
|
|
5
|
+
|
|
6
|
+
export const useSdk = (): FrontierSDK => {
|
|
7
|
+
const sdk = useContext(SdkContext);
|
|
8
|
+
if (!sdk) throw new Error('useSdk must be used within SdkProvider');
|
|
9
|
+
return sdk;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const SdkProvider = ({ children }: { children: ReactNode }) => {
|
|
13
|
+
const sdkRef = useRef<FrontierSDK | null>(null);
|
|
14
|
+
const [ready, setReady] = useState(false);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const sdk = new FrontierSDK();
|
|
18
|
+
sdkRef.current = sdk;
|
|
19
|
+
setReady(true);
|
|
20
|
+
|
|
21
|
+
return () => {
|
|
22
|
+
sdk.destroy();
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
|
|
26
|
+
if (!ready) return null;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<SdkContext.Provider value={sdkRef.current}>
|
|
30
|
+
{children}
|
|
31
|
+
</SdkContext.Provider>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import { vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
// Mock window.open for external links
|
|
5
|
+
vi.stubGlobal('open', vi.fn());
|
|
6
|
+
|
|
7
|
+
// Mock ResizeObserver
|
|
8
|
+
vi.stubGlobal('ResizeObserver', vi.fn().mockImplementation(() => ({
|
|
9
|
+
observe: vi.fn(),
|
|
10
|
+
unobserve: vi.fn(),
|
|
11
|
+
disconnect: vi.fn(),
|
|
12
|
+
})));
|
|
13
|
+
|
|
14
|
+
// Mock IntersectionObserver
|
|
15
|
+
vi.stubGlobal('IntersectionObserver', vi.fn().mockImplementation(() => ({
|
|
16
|
+
observe: vi.fn(),
|
|
17
|
+
unobserve: vi.fn(),
|
|
18
|
+
disconnect: vi.fn(),
|
|
19
|
+
})));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"types": ["vitest/globals", "@testing-library/jest-dom"]
|
|
19
|
+
},
|
|
20
|
+
"include": ["src"],
|
|
21
|
+
"exclude": ["src/test", "**/*.test.ts", "**/*.test.tsx"]
|
|
22
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rewrites": [
|
|
3
|
+
{ "source": "/(.*)", "destination": "/index.html" }
|
|
4
|
+
],
|
|
5
|
+
"headers": [
|
|
6
|
+
{
|
|
7
|
+
"source": "/(.*)",
|
|
8
|
+
"has": [
|
|
9
|
+
{
|
|
10
|
+
"type": "header",
|
|
11
|
+
"key": "Origin",
|
|
12
|
+
"value": "https://os.frontiertower.io"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"headers": [
|
|
16
|
+
{
|
|
17
|
+
"key": "Access-Control-Allow-Origin",
|
|
18
|
+
"value": "https://os.frontiertower.io"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"key": "Access-Control-Allow-Methods",
|
|
22
|
+
"value": "GET, OPTIONS"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"key": "Access-Control-Allow-Headers",
|
|
26
|
+
"value": "Content-Type"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"source": "/(.*)",
|
|
32
|
+
"has": [
|
|
33
|
+
{
|
|
34
|
+
"type": "header",
|
|
35
|
+
"key": "Origin",
|
|
36
|
+
"value": "https://alpha.os.frontiertower.io"
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"headers": [
|
|
40
|
+
{
|
|
41
|
+
"key": "Access-Control-Allow-Origin",
|
|
42
|
+
"value": "https://alpha.os.frontiertower.io"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"key": "Access-Control-Allow-Methods",
|
|
46
|
+
"value": "GET, OPTIONS"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"key": "Access-Control-Allow-Headers",
|
|
50
|
+
"value": "Content-Type"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"source": "/(.*)",
|
|
56
|
+
"has": [
|
|
57
|
+
{
|
|
58
|
+
"type": "header",
|
|
59
|
+
"key": "Origin",
|
|
60
|
+
"value": "https://beta.os.frontiertower.io"
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"headers": [
|
|
64
|
+
{
|
|
65
|
+
"key": "Access-Control-Allow-Origin",
|
|
66
|
+
"value": "https://beta.os.frontiertower.io"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"key": "Access-Control-Allow-Methods",
|
|
70
|
+
"value": "GET, OPTIONS"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"key": "Access-Control-Allow-Headers",
|
|
74
|
+
"value": "Content-Type"
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"source": "/(.*)",
|
|
80
|
+
"has": [
|
|
81
|
+
{
|
|
82
|
+
"type": "header",
|
|
83
|
+
"key": "Origin",
|
|
84
|
+
"value": "https://sandbox.os.frontiertower.io"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"headers": [
|
|
88
|
+
{
|
|
89
|
+
"key": "Access-Control-Allow-Origin",
|
|
90
|
+
"value": "https://sandbox.os.frontiertower.io"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"key": "Access-Control-Allow-Methods",
|
|
94
|
+
"value": "GET, OPTIONS"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"key": "Access-Control-Allow-Headers",
|
|
98
|
+
"value": "Content-Type"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"source": "/(.*)",
|
|
104
|
+
"has": [
|
|
105
|
+
{
|
|
106
|
+
"type": "header",
|
|
107
|
+
"key": "Origin",
|
|
108
|
+
"value": "http://localhost:5173"
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"headers": [
|
|
112
|
+
{
|
|
113
|
+
"key": "Access-Control-Allow-Origin",
|
|
114
|
+
"value": "http://localhost:5173"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"key": "Access-Control-Allow-Methods",
|
|
118
|
+
"value": "GET, OPTIONS"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"key": "Access-Control-Allow-Headers",
|
|
122
|
+
"value": "Content-Type"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
server: {
|
|
7
|
+
port: {{DEV_PORT}},
|
|
8
|
+
},
|
|
9
|
+
test: {
|
|
10
|
+
globals: true,
|
|
11
|
+
environment: 'jsdom',
|
|
12
|
+
setupFiles: ['./src/test/setup.ts'],
|
|
13
|
+
include: ['src/test/**/*.test.{ts,tsx}'],
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# Context Template
|
|
2
|
+
|
|
3
|
+
Template for `.frontier-app/phases/XX-name/{phase_num}-CONTEXT.md` — captures implementation decisions for a phase.
|
|
4
|
+
|
|
5
|
+
**Purpose:** Document decisions that downstream agents need. Planner uses this to know what choices are locked vs flexible. Executor uses this to know what to build.
|
|
6
|
+
|
|
7
|
+
**Key principle:** Categories emerge from what was actually discussed for THIS phase. An events phase has events-relevant sections, a payments phase has payments-relevant sections.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## File Template
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
# Phase {{PHASE_NUM}}: {{PHASE_NAME}} — Context
|
|
15
|
+
|
|
16
|
+
**Gathered:** {{DATE}}
|
|
17
|
+
**Status:** Ready for planning
|
|
18
|
+
|
|
19
|
+
<domain>
|
|
20
|
+
## Phase Boundary
|
|
21
|
+
|
|
22
|
+
[Clear statement of what this phase delivers — the scope anchor.
|
|
23
|
+
This comes from ROADMAP.md and is fixed.
|
|
24
|
+
Discussion during /fos:discuss clarifies implementation within this boundary.]
|
|
25
|
+
|
|
26
|
+
</domain>
|
|
27
|
+
|
|
28
|
+
<decisions>
|
|
29
|
+
## Implementation Decisions
|
|
30
|
+
|
|
31
|
+
### [Area 1 that was discussed]
|
|
32
|
+
- **D-01:** [Specific decision made]
|
|
33
|
+
- **D-02:** [Another decision if applicable]
|
|
34
|
+
|
|
35
|
+
### [Area 2 that was discussed]
|
|
36
|
+
- **D-03:** [Specific decision made]
|
|
37
|
+
|
|
38
|
+
### SDK Usage
|
|
39
|
+
- **D-XX:** [Which SDK module methods to use and how]
|
|
40
|
+
- **D-YY:** [Data flow: SDK → component state → UI]
|
|
41
|
+
|
|
42
|
+
### Claude's Discretion
|
|
43
|
+
[Areas where user explicitly said "you decide" — Claude has flexibility here during planning/implementation]
|
|
44
|
+
|
|
45
|
+
- [Area Claude can decide]
|
|
46
|
+
- [Area Claude can decide]
|
|
47
|
+
|
|
48
|
+
</decisions>
|
|
49
|
+
|
|
50
|
+
<specifics>
|
|
51
|
+
## Specific Ideas
|
|
52
|
+
|
|
53
|
+
[Any particular references, examples, or "I want it like X" moments from discussion.
|
|
54
|
+
Product references, specific behaviors, interaction patterns, visual references.]
|
|
55
|
+
|
|
56
|
+
[If none: "No specific requirements — open to standard Frontier OS app patterns"]
|
|
57
|
+
|
|
58
|
+
</specifics>
|
|
59
|
+
|
|
60
|
+
<sdk_context>
|
|
61
|
+
## SDK Module Context
|
|
62
|
+
|
|
63
|
+
### Modules Used in This Phase
|
|
64
|
+
|
|
65
|
+
| Module | Methods | Purpose |
|
|
66
|
+
|--------|---------|---------|
|
|
67
|
+
| [Module] | [method1(), method2()] | [What they enable] |
|
|
68
|
+
|
|
69
|
+
### Integration Pattern
|
|
70
|
+
[How SDK data flows into the UI for this phase.
|
|
71
|
+
Example: "Events.list() → React Query → EventList component → EventCard"]
|
|
72
|
+
|
|
73
|
+
### Known SDK Constraints
|
|
74
|
+
[Any SDK limitations that affect this phase's implementation.
|
|
75
|
+
Example: "Events.list() returns max 50 items — need pagination"]
|
|
76
|
+
|
|
77
|
+
[If no SDK modules: "No SDK modules in this phase — UI/scaffold only"]
|
|
78
|
+
|
|
79
|
+
</sdk_context>
|
|
80
|
+
|
|
81
|
+
<references>
|
|
82
|
+
## References to Read
|
|
83
|
+
|
|
84
|
+
**Planner and executor MUST read these before working on this phase.**
|
|
85
|
+
|
|
86
|
+
### SDK Documentation
|
|
87
|
+
- `frontier-sdk/docs/[module].md` — [What this doc covers]
|
|
88
|
+
|
|
89
|
+
### Existing App Patterns
|
|
90
|
+
- `[app-name]/src/[path]` — [What pattern to reference]
|
|
91
|
+
|
|
92
|
+
### Project State
|
|
93
|
+
- `.frontier-app/PROJECT.md` — App vision, constraints, SDK modules
|
|
94
|
+
- `.frontier-app/REQUIREMENTS.md` — Requirements this phase addresses
|
|
95
|
+
|
|
96
|
+
[If no external references: "No external references — requirements fully captured in decisions above"]
|
|
97
|
+
|
|
98
|
+
</references>
|
|
99
|
+
|
|
100
|
+
<deferred>
|
|
101
|
+
## Deferred Ideas
|
|
102
|
+
|
|
103
|
+
[Ideas that came up during /fos:discuss but belong in other phases.
|
|
104
|
+
Captured here so they're not lost, but explicitly out of scope for this phase.]
|
|
105
|
+
|
|
106
|
+
[If none: "None — discussion stayed within phase scope"]
|
|
107
|
+
|
|
108
|
+
</deferred>
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
*Phase: XX-name*
|
|
113
|
+
*Context gathered: {{DATE}}*
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Good Examples
|
|
119
|
+
|
|
120
|
+
**Example: Events feature phase**
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
# Phase 2: Event Listing — Context
|
|
124
|
+
|
|
125
|
+
**Gathered:** 2026-03-27
|
|
126
|
+
**Status:** Ready for planning
|
|
127
|
+
|
|
128
|
+
<domain>
|
|
129
|
+
## Phase Boundary
|
|
130
|
+
|
|
131
|
+
Display upcoming events from the Frontier Events module in a browsable list. Users can view event details and RSVP. Event creation is a separate phase.
|
|
132
|
+
|
|
133
|
+
</domain>
|
|
134
|
+
|
|
135
|
+
<decisions>
|
|
136
|
+
## Implementation Decisions
|
|
137
|
+
|
|
138
|
+
### Layout
|
|
139
|
+
- **D-01:** Card grid layout, responsive — 1 column mobile, 2 tablet, 3 desktop
|
|
140
|
+
- **D-02:** Each card shows: event name, date/time, location, attendee count, RSVP button
|
|
141
|
+
- **D-03:** Cards sorted by date (soonest first), past events filtered out
|
|
142
|
+
|
|
143
|
+
### RSVP Flow
|
|
144
|
+
- **D-04:** Single-tap RSVP — no confirmation modal (keep it fast)
|
|
145
|
+
- **D-05:** Optimistic UI update — show RSVP immediately, revert on error
|
|
146
|
+
- **D-06:** RSVP count updates in real-time for all viewers
|
|
147
|
+
|
|
148
|
+
### Empty State
|
|
149
|
+
- **D-07:** "No upcoming events" with illustration — no CTA to create (that's a different phase)
|
|
150
|
+
|
|
151
|
+
### SDK Usage
|
|
152
|
+
- **D-08:** Use Events.list() for fetching, Events.rsvp() for RSVP action
|
|
153
|
+
- **D-09:** Poll every 30 seconds for new events (no WebSocket available)
|
|
154
|
+
|
|
155
|
+
### Claude's Discretion
|
|
156
|
+
- Loading skeleton design
|
|
157
|
+
- Exact card spacing and border radius
|
|
158
|
+
- Error toast styling
|
|
159
|
+
- Animation for RSVP button state change
|
|
160
|
+
|
|
161
|
+
</decisions>
|
|
162
|
+
|
|
163
|
+
<specifics>
|
|
164
|
+
## Specific Ideas
|
|
165
|
+
|
|
166
|
+
- "I want the event cards to feel like Luma's event pages — clean, focused on the key info"
|
|
167
|
+
- RSVP should feel instant — "tap and done, like a Like button"
|
|
168
|
+
|
|
169
|
+
</specifics>
|
|
170
|
+
|
|
171
|
+
<sdk_context>
|
|
172
|
+
## SDK Module Context
|
|
173
|
+
|
|
174
|
+
### Modules Used in This Phase
|
|
175
|
+
|
|
176
|
+
| Module | Methods | Purpose |
|
|
177
|
+
|--------|---------|---------|
|
|
178
|
+
| Events | Events.list(), Events.rsvp(), Events.get() | Fetch events, handle RSVP |
|
|
179
|
+
|
|
180
|
+
### Integration Pattern
|
|
181
|
+
Events.list() → React Query with 30s refetch → EventGrid component → EventCard with RSVP button → Events.rsvp() on click → optimistic update
|
|
182
|
+
|
|
183
|
+
### Known SDK Constraints
|
|
184
|
+
- Events.list() returns max 50 items — sufficient for v1, pagination deferred
|
|
185
|
+
- Events.rsvp() requires user identity from SDK — no anonymous RSVP
|
|
186
|
+
|
|
187
|
+
</sdk_context>
|
|
188
|
+
|
|
189
|
+
<references>
|
|
190
|
+
## References to Read
|
|
191
|
+
|
|
192
|
+
### SDK Documentation
|
|
193
|
+
- `frontier-sdk/docs/events.md` — Events module API, method signatures, return types
|
|
194
|
+
|
|
195
|
+
### Existing App Patterns
|
|
196
|
+
- `frontier-tower-pwa/src/components/EventCard.tsx` — Card pattern from the main PWA
|
|
197
|
+
|
|
198
|
+
### Project State
|
|
199
|
+
- `.frontier-app/PROJECT.md` — App vision and SDK modules
|
|
200
|
+
- `.frontier-app/REQUIREMENTS.md` — REQ-01 through REQ-03
|
|
201
|
+
|
|
202
|
+
</references>
|
|
203
|
+
|
|
204
|
+
<deferred>
|
|
205
|
+
## Deferred Ideas
|
|
206
|
+
|
|
207
|
+
- Event creation form — Phase 3
|
|
208
|
+
- Event categories/filtering — add to backlog
|
|
209
|
+
- Calendar view — future milestone
|
|
210
|
+
|
|
211
|
+
</deferred>
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
*Phase: 02-event-listing*
|
|
216
|
+
*Context gathered: 2026-03-27*
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Guidelines
|
|
222
|
+
|
|
223
|
+
**This template captures DECISIONS for downstream planning and execution.**
|
|
224
|
+
|
|
225
|
+
The output should answer: "What choices are locked? What's flexible? Which SDK methods to use?"
|
|
226
|
+
|
|
227
|
+
**Good content (concrete decisions):**
|
|
228
|
+
- "Card grid, 1/2/3 columns responsive"
|
|
229
|
+
- "Use Events.list() with 30s polling"
|
|
230
|
+
- "Optimistic UI for RSVP"
|
|
231
|
+
- "Sort by date, filter out past events"
|
|
232
|
+
|
|
233
|
+
**Bad content (too vague):**
|
|
234
|
+
- "Should look nice"
|
|
235
|
+
- "Good user experience"
|
|
236
|
+
- "Fast loading"
|
|
237
|
+
- "Use the SDK"
|
|
238
|
+
|
|
239
|
+
**SDK Module Context is mandatory:**
|
|
240
|
+
- Every Frontier OS app phase that touches SDK modules must document which methods are used
|
|
241
|
+
- Include the data flow: SDK call → state management → UI
|
|
242
|
+
- Note any SDK constraints that affect implementation
|
|
243
|
+
|
|
244
|
+
**After creation:**
|
|
245
|
+
- File lives in phase directory: `.frontier-app/phases/XX-name/{phase_num}-CONTEXT.md`
|
|
246
|
+
- /fos:plan reads this to create specific tasks
|
|
247
|
+
- /fos:execute reads this to know what choices are locked
|
|
248
|
+
- Downstream agents should NOT need to ask the user again about captured decisions
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Plan Template
|
|
2
|
+
|
|
3
|
+
Template for `.frontier-app/phases/XX-name/{phase}-{plan}-PLAN.md` — executable plans for Frontier OS app phases.
|
|
4
|
+
|
|
5
|
+
**Naming:** Use `{phase}-{plan}-PLAN.md` format (e.g., `01-01-PLAN.md` for Phase 1, Plan 1)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## File Template
|
|
10
|
+
|
|
11
|
+
```markdown
|
|
12
|
+
---
|
|
13
|
+
phase: XX-name
|
|
14
|
+
plan: NN
|
|
15
|
+
wave: N
|
|
16
|
+
depends_on: []
|
|
17
|
+
requirements: []
|
|
18
|
+
files_modified: []
|
|
19
|
+
autonomous: true
|
|
20
|
+
|
|
21
|
+
must_haves:
|
|
22
|
+
truths: []
|
|
23
|
+
artifacts: []
|
|
24
|
+
key_links: []
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
<objective>
|
|
28
|
+
[What this plan accomplishes for the Frontier OS app]
|
|
29
|
+
|
|
30
|
+
Purpose: [Why this matters — which feature/capability it delivers]
|
|
31
|
+
Output: [What artifacts will be created]
|
|
32
|
+
SDK Modules: [Which SDK modules are used in this plan, if any]
|
|
33
|
+
</objective>
|
|
34
|
+
|
|
35
|
+
<execution_context>
|
|
36
|
+
@frontier-os-app-builder/workflows/execute-plan.md
|
|
37
|
+
@frontier-os-app-builder/templates/state/summary.md
|
|
38
|
+
</execution_context>
|
|
39
|
+
|
|
40
|
+
<context>
|
|
41
|
+
@.frontier-app/PROJECT.md
|
|
42
|
+
@.frontier-app/ROADMAP.md
|
|
43
|
+
@.frontier-app/STATE.md
|
|
44
|
+
|
|
45
|
+
# SDK reference for modules used in this plan:
|
|
46
|
+
@frontier-sdk/docs/[module].md
|
|
47
|
+
|
|
48
|
+
# Only reference prior plan SUMMARYs if genuinely needed:
|
|
49
|
+
# - This plan uses types/exports from prior plan
|
|
50
|
+
# - Prior plan made decision affecting this plan
|
|
51
|
+
|
|
52
|
+
[Relevant source files:]
|
|
53
|
+
@src/path/to/relevant.ts
|
|
54
|
+
</context>
|
|
55
|
+
|
|
56
|
+
<tasks>
|
|
57
|
+
|
|
58
|
+
<task type="auto">
|
|
59
|
+
<name>Task 1: [Action-oriented name]</name>
|
|
60
|
+
<files>path/to/file.ext, another/file.ext</files>
|
|
61
|
+
<read_first>path/to/reference.ext, path/to/source-of-truth.ext</read_first>
|
|
62
|
+
<action>[Specific implementation — what to do, how to do it, what to avoid and WHY.
|
|
63
|
+
Include CONCRETE values: exact identifiers, parameters, SDK method names, file paths.
|
|
64
|
+
For SDK usage: specify exact import path, method signature, expected return type.
|
|
65
|
+
Never say "align X with Y" without specifying the exact target state.]</action>
|
|
66
|
+
<verify>[Command or check to prove it worked]</verify>
|
|
67
|
+
<acceptance_criteria>
|
|
68
|
+
- [Grep-verifiable: "file.ext contains 'FrontierSDK'"]
|
|
69
|
+
- [Measurable: "component renders without console errors"]
|
|
70
|
+
</acceptance_criteria>
|
|
71
|
+
<done>[Measurable acceptance criteria]</done>
|
|
72
|
+
</task>
|
|
73
|
+
|
|
74
|
+
<task type="auto">
|
|
75
|
+
<name>Task 2: [Action-oriented name]</name>
|
|
76
|
+
<files>path/to/file.ext</files>
|
|
77
|
+
<read_first>path/to/reference.ext</read_first>
|
|
78
|
+
<action>[Specific implementation with concrete values]</action>
|
|
79
|
+
<verify>[Command or check]</verify>
|
|
80
|
+
<acceptance_criteria>
|
|
81
|
+
- [Grep-verifiable condition]
|
|
82
|
+
</acceptance_criteria>
|
|
83
|
+
<done>[Acceptance criteria]</done>
|
|
84
|
+
</task>
|
|
85
|
+
|
|
86
|
+
<task type="checkpoint:human-verify" gate="blocking">
|
|
87
|
+
<what-built>[What Claude built] — dev server at http://localhost:{{DEV_PORT}}</what-built>
|
|
88
|
+
<how-to-verify>Visit http://localhost:{{DEV_PORT}} and verify:
|
|
89
|
+
- [Visual check 1]
|
|
90
|
+
- [Visual check 2]
|
|
91
|
+
Open Frontier OS at localhost:3000 and verify app loads in iframe.</how-to-verify>
|
|
92
|
+
<resume-signal>Type "approved" or describe issues</resume-signal>
|
|
93
|
+
</task>
|
|
94
|
+
|
|
95
|
+
</tasks>
|
|
96
|
+
|
|
97
|
+
<verification>
|
|
98
|
+
Before declaring plan complete:
|
|
99
|
+
- [ ] `npm run build` succeeds with no errors
|
|
100
|
+
- [ ] `npm run dev` starts without errors on port {{DEV_PORT}}
|
|
101
|
+
- [ ] No TypeScript errors (`npx tsc --noEmit`)
|
|
102
|
+
- [ ] [Plan-specific verification]
|
|
103
|
+
</verification>
|
|
104
|
+
|
|
105
|
+
<success_criteria>
|
|
106
|
+
|
|
107
|
+
- All tasks completed
|
|
108
|
+
- All verification checks pass
|
|
109
|
+
- No console errors in browser
|
|
110
|
+
- App renders correctly in dark theme
|
|
111
|
+
- [Plan-specific criteria]
|
|
112
|
+
|
|
113
|
+
</success_criteria>
|
|
114
|
+
|
|
115
|
+
<output>
|
|
116
|
+
After completion, create `.frontier-app/phases/XX-name/{phase}-{plan}-SUMMARY.md`
|
|
117
|
+
</output>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Frontmatter Fields
|
|
123
|
+
|
|
124
|
+
| Field | Required | Purpose |
|
|
125
|
+
|-------|----------|---------|
|
|
126
|
+
| `phase` | Yes | Phase identifier (e.g., `01-scaffold`) |
|
|
127
|
+
| `plan` | Yes | Plan number within phase (e.g., `01`, `02`) |
|
|
128
|
+
| `wave` | Yes | Execution wave (1, 2, 3...) for parallel scheduling |
|
|
129
|
+
| `depends_on` | Yes | Plan IDs this plan requires (e.g., `["01-01"]`) |
|
|
130
|
+
| `requirements` | Yes | Requirement IDs this plan addresses (PLAT-01, REQ-03, etc.) |
|
|
131
|
+
| `files_modified` | Yes | Files this plan creates or modifies |
|
|
132
|
+
| `autonomous` | Yes | `true` if no checkpoints, `false` if has user verification |
|
|
133
|
+
| `must_haves` | Yes | Goal-backward verification criteria |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Frontier OS Specifics
|
|
138
|
+
|
|
139
|
+
**Phase 1 plans always include:**
|
|
140
|
+
- Vite scaffold from `templates/app/vite.config.ts`
|
|
141
|
+
- SdkProvider from `templates/app/sdk-context.tsx`
|
|
142
|
+
- Layout with iframe detection from `templates/app/layout.tsx`
|
|
143
|
+
- Dark theme setup via Tailwind
|
|
144
|
+
- Standalone fallback UI
|
|
145
|
+
- Dev server on assigned port
|
|
146
|
+
|
|
147
|
+
**SDK usage in tasks:**
|
|
148
|
+
- Always specify the exact import: `import { FrontierSDK } from '@frontiertower/frontier-sdk'`
|
|
149
|
+
- Always use `useSdk()` hook, never instantiate SDK directly in components
|
|
150
|
+
- Always wrap SDK calls in try/catch — SDK may not be available in standalone mode
|
|
151
|
+
- Reference the specific SDK module docs in `<context>` section
|
|
152
|
+
|
|
153
|
+
**Verification always includes:**
|
|
154
|
+
- Build succeeds (`npm run build`)
|
|
155
|
+
- Dev server starts on correct port
|
|
156
|
+
- No TypeScript errors
|
|
157
|
+
- Dark theme renders correctly (no white backgrounds)
|
|
158
|
+
- App works in both iframe and standalone modes
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Task Types
|
|
163
|
+
|
|
164
|
+
| Type | Use For | Autonomy |
|
|
165
|
+
|------|---------|----------|
|
|
166
|
+
| `auto` | Everything Claude can do independently | Fully autonomous |
|
|
167
|
+
| `checkpoint:human-verify` | Visual verification in browser/iframe | Pauses for user |
|
|
168
|
+
| `checkpoint:decision` | Implementation choices needing user input | Pauses for user |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Scope Guidance
|
|
173
|
+
|
|
174
|
+
**Plan sizing:**
|
|
175
|
+
- 2-3 tasks per plan
|
|
176
|
+
- Phase 1 (scaffold): Always 1 plan
|
|
177
|
+
- Feature phases: 1-3 plans depending on complexity
|
|
178
|
+
|
|
179
|
+
**Vertical slices preferred:**
|
|
180
|
+
```
|
|
181
|
+
PREFER: Plan 01 = Event listing (model + API hook + UI component)
|
|
182
|
+
Plan 02 = Event creation (form + validation + SDK call)
|
|
183
|
+
|
|
184
|
+
AVOID: Plan 01 = All data models
|
|
185
|
+
Plan 02 = All API hooks
|
|
186
|
+
Plan 03 = All UI components
|
|
187
|
+
```
|