howone 0.1.23 → 0.1.25

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 (24) hide show
  1. package/package.json +1 -1
  2. package/templates/vite/.howone/skills/howone-sdk/01-architect/01-app-generation.md +180 -91
  3. package/templates/vite/.howone/skills/howone-sdk/01-architect/02-manifest-codegen.md +67 -4
  4. package/templates/vite/.howone/skills/howone-sdk/02-database/01-schema-design.md +463 -69
  5. package/templates/vite/.howone/skills/howone-sdk/02-database/02-schema-operations.md +366 -64
  6. package/templates/vite/.howone/skills/howone-sdk/02-database/03-data-access-patterns.md +204 -67
  7. package/templates/vite/.howone/skills/howone-sdk/02-database/04-query-dsl-and-responses.md +237 -0
  8. package/templates/vite/.howone/skills/howone-sdk/02-database/05-ai-persistence-patterns.md +372 -0
  9. package/templates/vite/.howone/skills/howone-sdk/03-sdk/01-client-setup.md +58 -36
  10. package/templates/vite/.howone/skills/howone-sdk/03-sdk/02-entity-operations.md +67 -0
  11. package/templates/vite/.howone/skills/howone-sdk/03-sdk/03-auth.md +267 -469
  12. package/templates/vite/.howone/skills/howone-sdk/03-sdk/04-react-integration.md +113 -320
  13. package/templates/vite/.howone/skills/howone-sdk/03-sdk/07-ai-action-calls.md +66 -16
  14. package/templates/vite/.howone/skills/howone-sdk/03-sdk/08-extension-boundaries.md +226 -0
  15. package/templates/vite/.howone/skills/howone-sdk/04-ai/01-ai-capability-architecture.md +159 -96
  16. package/templates/vite/.howone/skills/howone-sdk/04-ai/02-workflow-contract-rules.md +353 -96
  17. package/templates/vite/.howone/skills/howone-sdk/04-ai/03-ai-sdk-handoff.md +181 -42
  18. package/templates/vite/.howone/skills/howone-sdk/04-ai/04-service-capability-catalog.md +281 -0
  19. package/templates/vite/.howone/skills/howone-sdk/04-ai/05-workflow-operations.md +256 -0
  20. package/templates/vite/.howone/skills/howone-sdk/04-ai/06-ai-feature-playbooks.md +296 -0
  21. package/templates/vite/.howone/skills/howone-sdk/SKILL.md +29 -12
  22. package/templates/vite/.howone/skills/howone-sdk/agents/openai.yaml +2 -2
  23. package/templates/vite/package.json +1 -1
  24. package/templates/vite/.howone/skills/howone-sdk/04-ai/.gitkeep +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "howone",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "private": false,
5
5
  "description": "HowOne command line tools for creating app templates.",
6
6
  "type": "module",
@@ -1,126 +1,215 @@
1
1
  # App Generation Architect
2
2
 
3
- Use this file to decide the HowOne app implementation path before reading low-level SDK or
4
- database references.
3
+ Use this file before building or changing a HowOne generated app. It decides which platform tracks
4
+ must be used and what order to execute them in.
5
5
 
6
- ## Responsibility Split
6
+ This is the planning layer. It should prevent the agent from jumping straight into UI code while
7
+ missing schema, auth, AI, manifest, or SDK binding contracts.
7
8
 
8
- HowOne generated apps have three layers:
9
+ ## Platform Shape
9
10
 
10
- 1. **Backend contract**: dynamic entities, access rules, indexes, schema versions, and synced
11
- manifests.
12
- 2. **AI contract + workflow implementation**: AI capability contracts are versioned by HowOne;
13
- external workflow create/update is submitted from synced AI manifests.
14
- 3. **SDK binding**: `src/lib/sdk.ts` converts manifests into typed entity and AI clients.
15
- 4. **Frontend experience**: React/UI code calls the SDK and owns app-specific interaction design.
11
+ HowOne generated apps have four product layers:
16
12
 
17
- Do not skip the binding layer. The UI should call `src/lib/sdk.ts`, not raw entity names guessed
18
- from the user prompt.
13
+ | Layer | Source of truth | App code should do |
14
+ |---|---|---|
15
+ | Backend database | synced `.howone/database/manifest.json` | generate entity types/bindings and call SDK |
16
+ | AI capabilities | synced `.howone/ai/manifest.json` + workflow status | generate AI action bindings and call SDK |
17
+ | SDK runtime | `@howone/sdk` + `src/lib/sdk.ts` | centralize env/auth/entities/AI/upload |
18
+ | Frontend app | user experience | own UI, state, feedback, forms, navigation |
19
19
 
20
- Core source-of-truth rule from the HowOne docs:
20
+ The agent may propose schema/capability changes, but the validated/synced manifests drive code.
21
21
 
22
22
  ```text
23
- agent proposal != source of truth
24
- validated backend manifest = source of truth
25
- generated files = compiler/binding output
23
+ user request -> architecture decision -> backend/AI contracts -> sync manifests -> sdk binding -> UI
26
24
  ```
27
25
 
28
- The agent proposes structured changes and writes app code. The runtime/schema tools validate,
29
- apply, version, and sync manifest facts.
26
+ Do not skip the binding layer. UI code should import `howone` from `src/lib/sdk.ts`, not construct
27
+ raw URLs or guessed entity/action names.
28
+
29
+ ## First Decision: What Surfaces Are Touched?
30
+
31
+ Classify the request before editing.
32
+
33
+ | User request says | Touched surfaces | Required references |
34
+ |---|---|---|
35
+ | "store/save/history/list/my data" | database + SDK + UI | `02-database/`, `03-sdk/02-entity-operations.md` |
36
+ | "login/account/my/private" | auth + database access | `03-sdk/03-auth.md`, `03-sdk/04-react-integration.md` |
37
+ | "public page/share/link/landing/catalog" | public access + SDK public namespace | `02-database/03-data-access-patterns.md` |
38
+ | "AI/generate/analyze/summarize/research/edit image/video/audio" | AI contract + workflow + SDK | `04-ai/` |
39
+ | "upload file/image/audio/pdf" | upload + maybe AI URL input | `03-sdk/05-file-upload.md`, `04-ai/02-workflow-contract-rules.md` |
40
+ | "change schema/add field/new table" | schema operations + manifest codegen | `02-database/02-schema-operations.md`, `01-architect/02-manifest-codegen.md` |
41
+ | "frontend only" | SDK usage + UI | `03-sdk/01-client-setup.md` and relevant SDK docs |
42
+
43
+ If multiple surfaces are touched, read one reference from each surface before editing.
30
44
 
31
- ## Choose Data Posture First
45
+ ## Data Posture Decision
32
46
 
33
- Before designing schema or UI calls, classify the data:
47
+ Choose data posture before schema and UI.
34
48
 
35
- | Posture | Backend Access | Frontend Read |
49
+ | Product need | Access contract | SDK read |
36
50
  |---|---|---|
37
- | Private user data | `authenticated: own`, `public: none` | `howone.entities.Entity.query.mine(...)` |
38
- | Authenticated shared app data | `authenticated: all`, `public: none` | `howone.entities.Entity.query(...)` |
39
- | Public list data | `authenticated: all`, `public: list` | `howone.public.entities.Entity.query(...)` |
40
- | Public scoped share data | usually `authenticated: own`, `public: scoped` | `howone.public.entities.Entity.queryScoped(...)` |
51
+ | per-user private data | authenticated own, public none | `howone.entities.X.query.mine()` |
52
+ | logged-in shared admin/team data | authenticated all, public none | `howone.entities.X.query()` |
53
+ | anonymous public catalog/feed | authenticated all, public list | `howone.public.entities.X.query()` |
54
+ | one public share/detail page | authenticated own/all, public scoped | `howone.public.entities.X.queryScoped()` |
55
+ | anonymous form submission | authenticated all, public create scoped/any | `howone.public.entities.X.create()` |
56
+ | AI generation history | authenticated own, public none | `runAiActionAndPersist()` + `query.mine()` |
57
+ | AI public share | private history + public scoped share entity | two entities |
58
+
59
+ Defaults:
41
60
 
42
- If the user says "my todos", "my notes", "per user", "login required", or "data isolation",
43
- default to private user data.
61
+ - "my" / "per user" / "private" -> authenticated own.
62
+ - "landing page" / "blog" / "gallery" -> public list only if fields are safe.
63
+ - "share link" / "QR" / "public result" -> public scoped, small `maxLimit`.
64
+ - "AI history" -> private history entity; do not make it public just for sharing.
65
+
66
+ ## Auth Decision
67
+
68
+ | Need | SDK config | Provider behavior |
69
+ |---|---|---|
70
+ | default HowOne login | `createClient({ projectId, env })` | hosted login |
71
+ | custom designed login page using HowOne auth APIs | `auth: 'custom'`, `HowOneProvider auth="none"` | app owns login UI |
72
+ | external identity provider/JWT | `auth: { mode: 'headless', adapter }` | adapter owns token/user |
73
+ | public-only app | `auth: 'none'` | no auth guard |
74
+
75
+ Rules:
76
+
77
+ - Keep the bottom-right HowOne `FloatingButton` by default unless explicitly hidden.
78
+ - SDK must not add toast/overlay/login-page UI.
79
+ - Use `client.me()` or `client.requireMe()` for first-load user resolution.
80
+ - Do not use `auth.isAuthenticated()` as the only initial truth when user data must be loaded.
44
81
 
45
82
  ## Backend Feature Workflow
46
83
 
47
- When a request adds persistence or changes data shape:
84
+ Use when persistence or schema changes are needed:
48
85
 
49
- 1. Read `02-database/01-schema-design.md` and `02-database/02-schema-operations.md`.
50
- 2. Inspect the current schema/manifest.
51
- 3. Design one complete schema patch for the feature.
52
- 4. Preview the schema patch.
53
- 5. Apply the exact previewed operations if risk is acceptable.
54
- 6. Sync schema artifacts using the returned `next.versionId`.
55
- 7. Read `.howone/database/manifest.json`.
56
- 8. Read `01-architect/02-manifest-codegen.md`.
57
- 9. Update `src/lib/sdk.ts`.
58
- 10. Read the needed SDK file, usually `03-sdk/02-entity-operations.md` and sometimes `03-sdk/03-auth.md`.
59
- 11. Update the UI.
60
- 12. Validate.
86
+ 1. Read `02-database/01-schema-design.md`.
87
+ 2. Read `02-database/02-schema-operations.md`.
88
+ 3. Inspect current schema state/manifest.
89
+ 4. Design complete entity contract: fields, required, access, indexes, presentation.
90
+ 5. Preview one complete schema patch.
91
+ 6. Apply the exact previewed patch if risk is acceptable.
92
+ 7. Sync schema artifacts from returned version.
93
+ 8. Read `.howone/database/manifest.json`.
94
+ 9. Update `src/lib/sdk.ts` from manifest using `01-architect/02-manifest-codegen.md`.
95
+ 10. Implement UI with `howone.entities.*` or `howone.public.entities.*`.
96
+ 11. Validate build/tests.
61
97
 
62
- Do not preview a patch and then execute different single operations. Related schema changes for
63
- one feature should be grouped into one preview/apply cycle.
98
+ Risk stops:
99
+
100
+ - deleting entity/field;
101
+ - making required field without default;
102
+ - broadening public access;
103
+ - enabling public write;
104
+ - changing owner/public scope semantics.
64
105
 
65
106
  ## AI Feature Workflow
66
107
 
67
- When a request adds an AI capability or changes an AI workflow:
68
-
69
- 1. Read `04-ai/01-ai-capability-architecture.md` and
70
- `04-ai/02-workflow-contract-rules.md`.
71
- 2. Inspect current AI capability state.
72
- 3. Design one complete AI capability patch for the feature.
73
- 4. Preview the AI patch.
74
- 5. Apply the exact previewed operations.
75
- 6. Sync AI artifacts.
76
- 7. Read `.howone/ai/manifest.json`.
77
- 8. Submit external workflow create/update with `external-ai-capability`.
78
- 9. Preserve returned request IDs for the status/background-task layer.
79
- 10. Read `04-ai/03-ai-sdk-handoff.md`, `01-architect/02-manifest-codegen.md`, and
80
- `03-sdk/07-ai-action-calls.md`.
81
- 11. Update `src/lib/sdk.ts` from the synced manifest.
82
- 12. Update the UI.
83
- 13. Validate.
84
-
85
- If generated output must be saved, design the AI capability first. Then derive persistence entities
86
- from the synced AI `outputSchema`, plus only necessary request metadata.
108
+ Use when AI capability/workflow is needed:
87
109
 
88
- ## Auth Decision
110
+ 1. Read `04-ai/01-ai-capability-architecture.md`.
111
+ 2. Read `04-ai/04-service-capability-catalog.md` to verify support.
112
+ 3. Pick a playbook from `04-ai/06-ai-feature-playbooks.md` when applicable.
113
+ 4. Design schemas with `04-ai/02-workflow-contract-rules.md`.
114
+ 5. Preview/apply AI capability patch.
115
+ 6. Sync `.howone/ai/manifest.json`.
116
+ 7. Submit external workflow create/update using `04-ai/05-workflow-operations.md`.
117
+ 8. Preserve returned `request_id`.
118
+ 9. Poll status until terminal; preserve `workflowConfigID` on success.
119
+ 10. Update `src/lib/sdk.ts` with `04-ai/03-ai-sdk-handoff.md`.
120
+ 11. Implement UI through `howone.ai.*`.
121
+ 12. If output persists, use `02-database/05-ai-persistence-patterns.md`.
89
122
 
90
- Use hosted auth when the app just needs login:
123
+ Do not build fake AI. If the required capability is unsupported, report the exact gap.
91
124
 
92
- ```tsx
93
- <HowOneProvider auth="required">
94
- <App />
95
- </HowOneProvider>
96
- ```
125
+ ## Manifest Codegen Workflow
126
+
127
+ Run after database or AI sync:
128
+
129
+ 1. Read current `src/lib/sdk.ts`.
130
+ 2. Read synced manifests.
131
+ 3. Preserve existing exports and naming style.
132
+ 4. Generate/update:
133
+ - entity `Record/Create/Update` types;
134
+ - optional exported `*EntityDefinition` for guards;
135
+ - `client.entity<...>()` bindings;
136
+ - AI Zod schemas and `defineAiAction(...)`;
137
+ - composed `howone` export.
138
+ 5. Never write generated source under `.howone/`.
139
+
140
+ ## Common User Situations
97
141
 
98
- Use custom in-app auth when the user asks for a designed login page or multiple login methods:
142
+ ### User asks for "just a frontend"
99
143
 
100
- ```tsx
101
- <HowOneProvider auth="none" brand="hidden">
102
- <App />
103
- </HowOneProvider>
144
+ Still check whether UI needs stored data, auth, upload, or AI. If it only renders static/local state,
145
+ do not invent schema or workflow. If it saves anything, use database flow.
146
+
147
+ ### User asks for "AI app" but no persistence
148
+
149
+ Design AI capability and SDK binding only. Keep results in app state. Do not create entities unless
150
+ history, refresh resilience, user library, or share page is needed.
151
+
152
+ ### User asks for "AI app with history"
153
+
154
+ Design AI first, then database:
155
+
156
+ ```text
157
+ AI output contract -> Generation entity -> runAiActionAndPersist -> history query.mine()
104
158
  ```
105
159
 
106
- Custom login must call `howone.auth.setToken(token)` after Email OTP, Phone OTP, Google, or
107
- GitHub succeeds, then verify the session with `await howone.me({ refresh: true })`.
160
+ Do not put history fields into workflow output unless the AI itself must generate them.
161
+
162
+ ### User asks for "public AI result"
163
+
164
+ Use two entities:
165
+
166
+ - private `Generation` for owner history and retry;
167
+ - public scoped `SharedGeneration` for anonymous viewing.
168
+
169
+ Do not expose private prompt/history broadly.
170
+
171
+ ### User asks for "latest/current/research"
172
+
173
+ Use AI workflow with web search/crawling capability. If app also lists saved briefings, add entity
174
+ persistence after output contract.
175
+
176
+ ### User asks to modify existing AI behavior
177
+
178
+ If only behavior changes, use external workflow update with `workflowConfigID`.
179
+ If input/output changes, update AI capability contract first, sync manifest, then update workflow
180
+ and SDK bindings.
181
+
182
+ ### User asks to change schema used by UI
183
+
184
+ Change backend schema first, sync, regenerate SDK, then update UI. Do not patch UI types from memory.
185
+
186
+ ### User asks for custom auth
187
+
188
+ Use `auth: 'custom'` or headless `AuthAdapter`. App owns visible login UI. Keep SDK callbacks/data
189
+ only.
190
+
191
+ ## Implementation Guardrails
108
192
 
109
- ## Generated Binding Rules
193
+ - Use `@howone/sdk` typed clients before `raw`.
194
+ - Use `howone.raw` only when typed surface is missing.
195
+ - Do not hardcode HowOne API URLs.
196
+ - Do not pass owner fields for authenticated own records.
197
+ - Do not import or create SDK toast APIs.
198
+ - Do not remove HowOne floating logo unless explicitly requested.
199
+ - Do not call AI workflows from render.
200
+ - Do not persist workflow envelopes or UI-only fields.
201
+ - Do not assume unavailable AI capabilities.
110
202
 
111
- - Read manifests after sync, not before.
112
- - Preserve existing bindings unless the manifest changed.
113
- - Export explicit `Record`, `Create`, and `Update` types.
114
- - Do not include system fields in create/update payloads.
115
- - Do not infer public access from `visibility` alone; inspect `access.public`.
203
+ ## Final Architecture Checklist
116
204
 
117
- ## Common Failure Modes
205
+ Before writing final code:
118
206
 
119
- - Repeated login after refresh: app used `auth.isAuthenticated()` as first-load truth or stored
120
- token outside SDK. Read `03-sdk/03-auth.md`.
121
- - Data is not isolated: app used `query()` instead of `query.mine()` for `authenticated.read =
122
- "own"`, or wrote owner fields manually.
123
- - Public page 401/403: app used authenticated namespace for public content or schema does not
124
- allow public access.
125
- - Generated types drift from backend: app edited `src/lib/sdk.ts` from memory instead of synced
126
- manifest.
207
+ - Data posture is explicit.
208
+ - Auth mode is explicit.
209
+ - Public access has filters/sorts/scopes/limits.
210
+ - AI capability is supported by service catalog.
211
+ - Workflow count follows one-feature rule or RAG exception.
212
+ - Persistence is separate from AI workflow.
213
+ - Manifests are synced before SDK codegen.
214
+ - `src/lib/sdk.ts` is the only app SDK entrypoint.
215
+ - UI owns visible states and feedback.
@@ -260,6 +260,8 @@ import {
260
260
  defineAiAction,
261
261
  defineAiActions,
262
262
  defineEntities,
263
+ runAiActionAndPersist,
264
+ type EntityDefinition,
263
265
  type EntityRecord,
264
266
  withAiActions,
265
267
  withEntities,
@@ -304,6 +306,41 @@ export type CommentCreate = {
304
306
  }
305
307
  export type CommentUpdate = Partial<CommentCreate>
306
308
 
309
+ export const storyEntityDefinition = {
310
+ name: 'Story',
311
+ type: 'object',
312
+ properties: {
313
+ title: { type: 'string' },
314
+ content: { type: 'string' },
315
+ authorId: { type: 'string' },
316
+ status: { type: 'string', enum: ['draft', 'published', 'archived'] },
317
+ wordCount: { type: 'integer' },
318
+ tags: { type: 'array', items: { type: 'string' } },
319
+ coverUrl: { type: 'string' },
320
+ },
321
+ required: ['title', 'content', 'authorId', 'status', 'wordCount'],
322
+ access: {
323
+ authenticated: { read: 'own', create: 'own', update: 'own', delete: 'own' },
324
+ public: { read: 'none', create: 'none', update: 'none', delete: 'none' },
325
+ },
326
+ } satisfies EntityDefinition
327
+
328
+ export const commentEntityDefinition = {
329
+ name: 'Comment',
330
+ type: 'object',
331
+ properties: {
332
+ storyId: { type: 'string' },
333
+ authorId: { type: 'string' },
334
+ body: { type: 'string' },
335
+ likes: { type: 'integer' },
336
+ },
337
+ required: ['storyId', 'authorId', 'body'],
338
+ access: {
339
+ authenticated: { read: 'own', create: 'own', update: 'own', delete: 'own' },
340
+ public: { read: 'none', create: 'none', update: 'none', delete: 'none' },
341
+ },
342
+ } satisfies EntityDefinition
343
+
307
344
  // ═══════════════════════════════════════════════════════════════
308
345
  // AI SCHEMAS & TYPES
309
346
  // ═══════════════════════════════════════════════════════════════
@@ -377,6 +414,7 @@ export default howone
377
414
  Before finalising generated code, verify:
378
415
 
379
416
  - [ ] Every entity from `.howone/database/manifest.json` has a `Record`, `Create`, and `Update` type
417
+ - [ ] Entity definitions are exported as `*EntityDefinition` when app code needs payload/query guards
380
418
  - [ ] `Create` types are defined **explicitly** (not via `Omit`)
381
419
  - [ ] Create optionality accounts for `required`, `default`, `defaultValue`, `autoGenerate`, and nullable types
382
420
  - [ ] System fields are not present in create/update input types
@@ -423,10 +461,14 @@ export const entities = defineEntities({
423
461
 
424
462
  When the app generates data with AI and saves it to an entity:
425
463
 
426
- 1. Read `.howone/ai/manifest.json` determine AI output shape.
427
- 2. Define entity fields that mirror the AI output fields.
428
- 3. Add any app-specific metadata fields (status, userId, createdAt, etc.).
429
- 4. Generate the entity type, then the AI action binding.
464
+ 1. Read `.howone/ai/manifest.json` to know the typed AI output.
465
+ 2. Decide which output fields are durable product fields.
466
+ 3. Add app-specific persistence fields such as `status`, `errorMessage`, `requestedAt`,
467
+ `completedAt`, source URLs, prompt/options, or share state.
468
+ 4. Define/update the entity schema from product persistence needs, not by blindly copying
469
+ `outputSchema`.
470
+ 5. Generate entity types and AI action bindings from synced manifests.
471
+ 6. Use `runAiActionAndPersist()` for history-style products.
430
472
 
431
473
  ```ts
432
474
  // AI generates: { title: string, content: string, summary: string }
@@ -444,3 +486,24 @@ async function generateAndSave(input: GenerateStoryInput, authorId: string) {
444
486
  })
445
487
  }
446
488
  ```
489
+
490
+ History-style generation should create a pending record before running AI:
491
+
492
+ ```ts
493
+ await runAiActionAndPersist({
494
+ entity: howone.entities.Generation,
495
+ input,
496
+ createPending: (input) => ({
497
+ prompt: input.topic,
498
+ status: 'pending',
499
+ requestedAt: new Date().toISOString(),
500
+ }),
501
+ run: (input) => howone.ai.generateStory.run(input),
502
+ mapCompleted: ({ output }) => ({
503
+ status: 'completed',
504
+ title: output.title,
505
+ content: output.content,
506
+ completedAt: new Date().toISOString(),
507
+ }),
508
+ })
509
+ ```