novaforge-appkit 0.1.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/LICENSE +21 -0
- package/README.md +131 -0
- package/adapters/claude-code/README.md +25 -0
- package/adapters/codex/AGENTS.section.md +53 -0
- package/adapters/codex/README.md +20 -0
- package/bin/appkit.js +171 -0
- package/install.sh +131 -0
- package/kit/agents/builder-agent.md +49 -0
- package/kit/agents/product-agent.md +48 -0
- package/kit/agents/release-agent.md +46 -0
- package/kit/agents/reviewer-agent.md +42 -0
- package/kit/commands/build.md +30 -0
- package/kit/commands/fix.md +33 -0
- package/kit/commands/idea.md +28 -0
- package/kit/commands/init.md +29 -0
- package/kit/commands/release.md +32 -0
- package/kit/commands/shape.md +33 -0
- package/kit/commands/verify.md +35 -0
- package/kit/constitution.md +79 -0
- package/kit/orchestrator.md +63 -0
- package/kit/policy-rules/admob.md +25 -0
- package/kit/policy-rules/apple-app-store.md +31 -0
- package/kit/policy-rules/google-play.md +33 -0
- package/kit/policy-rules/privacy.md +25 -0
- package/kit/profiles/android.md +31 -0
- package/kit/profiles/flutter.md +45 -0
- package/kit/profiles/ios.md +32 -0
- package/kit/scripts/_common.sh +24 -0
- package/kit/scripts/analyze.sh +6 -0
- package/kit/scripts/build-android.sh +12 -0
- package/kit/scripts/build-ios.sh +23 -0
- package/kit/scripts/capture-screenshots.sh +20 -0
- package/kit/scripts/compare-goldens.sh +21 -0
- package/kit/scripts/extract-dependencies.sh +23 -0
- package/kit/scripts/extract-permissions.sh +22 -0
- package/kit/scripts/format.sh +11 -0
- package/kit/scripts/scan-secrets.sh +15 -0
- package/kit/scripts/test.sh +12 -0
- package/kit/scripts/validate-ad-ids.sh +22 -0
- package/kit/scripts/validate-release.sh +30 -0
- package/kit/skills/admob-best-practices/SKILL.md +74 -0
- package/kit/skills/mobile-app-development/SKILL.md +69 -0
- package/kit/skills/mobile-privacy-and-permissions/SKILL.md +71 -0
- package/kit/skills/mobile-store-release/SKILL.md +74 -0
- package/kit/skills/mobile-testing-and-visual-qa/SKILL.md +79 -0
- package/kit/skills/small-app-product-design/SKILL.md +68 -0
- package/kit/templates/app-spec.template.md +89 -0
- package/kit/templates/idea.template.md +60 -0
- package/kit/templates/privacy-policy.template.md +41 -0
- package/kit/templates/release-manifest.template.yaml +46 -0
- package/kit/templates/store-listing.template.md +37 -0
- package/kit/templates/tasks.template.md +46 -0
- package/kit/templates/verification-report.template.md +58 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NovaForge
|
|
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
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# AppKit — Lean Mobile App Launch Kit
|
|
2
|
+
|
|
3
|
+
An opinionated, **lean** AI development kit that takes a small mobile app from a vague idea to a
|
|
4
|
+
store-ready release on **Google Play** and the **Apple App Store**. Works with **Claude Code**
|
|
5
|
+
and **OpenAI Codex** — you pick the tool at install time, like a spec kit.
|
|
6
|
+
|
|
7
|
+
> The AI gets broad freedom to make normal product and technical decisions. The workflow
|
|
8
|
+
> automatically enforces privacy, quality, advertising, and store-readiness — and only asks you
|
|
9
|
+
> when a decision is sensitive, expensive, legal, or hard to reverse.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
The recommended way is `npx` — no global install, always the latest:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# inside your app project directory (interactive: asks which AI tool)
|
|
17
|
+
npx novaforge-appkit init
|
|
18
|
+
|
|
19
|
+
# or explicitly
|
|
20
|
+
npx novaforge-appkit init --ai claude
|
|
21
|
+
npx novaforge-appkit init --ai codex
|
|
22
|
+
npx novaforge-appkit init --ai both
|
|
23
|
+
|
|
24
|
+
# target a different directory
|
|
25
|
+
npx novaforge-appkit init --ai claude --path ./my-app
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Before it's published to npm, you can run it straight from GitHub:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx github:NovaForgeOrg/appkit init --ai claude
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or install globally:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g novaforge-appkit
|
|
38
|
+
appkit init --ai codex
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Prefer no Node? A pure-bash installer is included:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git clone git@github.com:NovaForgeOrg/appkit.git
|
|
45
|
+
./appkit/install.sh --ai claude --path ./my-app
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then open the project in your chosen tool and run the commands below. Re-running the installer
|
|
49
|
+
is safe and refreshes the kit.
|
|
50
|
+
|
|
51
|
+
## The workflow
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
/appkit.init initialize the project + .appkit workflow
|
|
55
|
+
/appkit.idea generate or evaluate a small app idea -> idea.md
|
|
56
|
+
/appkit.shape lean spec + vertical-slice task plan -> app-spec.md, tasks.md
|
|
57
|
+
/appkit.build implement slices with tests -> source + tests
|
|
58
|
+
/appkit.verify full quality + policy gate -> verification-report.md
|
|
59
|
+
/appkit.release prepare the store package -> .appkit/release/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Repair loop:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
/appkit.fix minimal fix for a defect / finding / rejection
|
|
66
|
+
/appkit.verify re-run the gate
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The commands are stateful: a gentle state machine (`UNINITIALIZED → … → RELEASE_PREPARED`)
|
|
70
|
+
prevents skipping phases and routes blockers back to `/appkit.fix`.
|
|
71
|
+
|
|
72
|
+
## What's opinionated
|
|
73
|
+
|
|
74
|
+
- **Small & local-first** by default: one outcome, few screens, no login, no backend, no
|
|
75
|
+
personal data unless truly required.
|
|
76
|
+
- **Privacy by default**: declarations (Google Data Safety, Apple App Privacy, iOS privacy
|
|
77
|
+
manifest) are built from real implementation evidence, not guesses.
|
|
78
|
+
- **Monetization by design**: AdMob placements are decided during Shape, never bolted on.
|
|
79
|
+
- **Policy by design**: Google Play, Apple, and AdMob rules are checked every phase.
|
|
80
|
+
- **Evidence-based completion**: "done" requires passing scripts and captured screenshots —
|
|
81
|
+
AI for judgment, deterministic scripts for certainty.
|
|
82
|
+
|
|
83
|
+
## What's inside
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
appkit/
|
|
87
|
+
├── install.sh # picks Claude Code or Codex, renders the adapter
|
|
88
|
+
├── kit/ # tool-independent source of truth
|
|
89
|
+
│ ├── constitution.md # non-negotiable principles
|
|
90
|
+
│ ├── orchestrator.md # state machine, gates, agent routing
|
|
91
|
+
│ ├── agents/ # product · builder · reviewer · release
|
|
92
|
+
│ ├── commands/ # init · idea · shape · build · verify · release · fix
|
|
93
|
+
│ ├── skills/ # 6 skills (product, dev, testing/visual-QA, privacy, admob, store)
|
|
94
|
+
│ ├── templates/ # idea, app-spec, tasks, report, privacy, listing, manifest
|
|
95
|
+
│ ├── policy-rules/ # google-play · apple-app-store · admob · privacy checklists
|
|
96
|
+
│ ├── profiles/ # flutter (default) · android · ios
|
|
97
|
+
│ └── scripts/ # format, analyze, test, build, screenshots, validators…
|
|
98
|
+
└── adapters/{claude-code,codex}/ # how the kit maps onto each tool
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
In an installed project the kit lives at `.appkit/kit/`, runtime artifacts at `.appkit/`
|
|
102
|
+
(`status.yaml`, `idea.md`, `app-spec.md`, `tasks.md`, `verification-report.md`, `screenshots/`,
|
|
103
|
+
`release/`).
|
|
104
|
+
|
|
105
|
+
## Agents & skills (how the AI is organized)
|
|
106
|
+
|
|
107
|
+
Four agents, each owning a phase and never chosen manually by you:
|
|
108
|
+
|
|
109
|
+
| Agent | Commands | Owns |
|
|
110
|
+
|-----------|----------------------------------|------|
|
|
111
|
+
| Product | idea, shape | ideation, scope, spec |
|
|
112
|
+
| Builder | init, build, fix | architecture, implementation, tests |
|
|
113
|
+
| Reviewer | verify | independent quality + policy gate |
|
|
114
|
+
| Release | release | store package preparation |
|
|
115
|
+
|
|
116
|
+
Six reusable skills carry the domain knowledge: `small-app-product-design`,
|
|
117
|
+
`mobile-app-development`, `mobile-testing-and-visual-qa`, `mobile-privacy-and-permissions`,
|
|
118
|
+
`admob-best-practices`, `mobile-store-release`.
|
|
119
|
+
|
|
120
|
+
## Defaults & scope
|
|
121
|
+
|
|
122
|
+
Default profile is **Flutter** (Android API 35 / iOS 15), local-first, portrait, AdMob planned
|
|
123
|
+
but optional, no personal data. Native Android (Compose) / iOS (SwiftUI), IAP, subscriptions,
|
|
124
|
+
analytics, and automated submission are intentionally **out of scope** for this lean version but
|
|
125
|
+
the architecture leaves room for them.
|
|
126
|
+
|
|
127
|
+
## Safety
|
|
128
|
+
|
|
129
|
+
The kit **prepares** releases; **you** submit. It never exposes signing secrets, never invents
|
|
130
|
+
legal/privacy text (placeholders are marked for your review), and requires your confirmation
|
|
131
|
+
before anything sensitive or irreversible.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Claude Code adapter
|
|
2
|
+
|
|
3
|
+
Maps the tool-independent kit (`kit/`) onto Claude Code conventions.
|
|
4
|
+
|
|
5
|
+
The installer (`install.sh --ai claude`) renders into the target project:
|
|
6
|
+
|
|
7
|
+
| Kit source | Installed as | Why |
|
|
8
|
+
|-------------------------|---------------------------------------|-----|
|
|
9
|
+
| `kit/commands/*.md` | `.claude/commands/appkit.<name>.md` | Filename → slash command `/appkit.<name>` |
|
|
10
|
+
| `kit/agents/*.md` | `.claude/agents/appkit-*.md` | Native sub-agents (frontmatter: name/description/tools/model) |
|
|
11
|
+
| `kit/skills/*/SKILL.md` | `.claude/skills/<name>/SKILL.md` | Native skills, auto-activated by their `description` |
|
|
12
|
+
| whole `kit/` | `.appkit/kit/` | Shared brain; path references rewritten to `.appkit/kit/` |
|
|
13
|
+
|
|
14
|
+
How it uses Claude Code best practices:
|
|
15
|
+
- **Slash commands** are the orchestration entry points. Each runs the orchestrator preamble,
|
|
16
|
+
enforces the phase gate, adopts the owning agent role, and updates `.appkit/status.yaml`.
|
|
17
|
+
- **Skills** carry reusable domain knowledge (product design, dev, testing/visual-QA, privacy,
|
|
18
|
+
AdMob, store release). Claude auto-loads them based on their `description`; commands also name
|
|
19
|
+
the ones they need.
|
|
20
|
+
- **Sub-agents** (`appkit-product/builder/reviewer/release`) are available for delegation — e.g.
|
|
21
|
+
the Reviewer can run independently during `/appkit.verify`. Because the workflow is stateful
|
|
22
|
+
(reads/writes `.appkit/`), commands normally adopt the role inline and reserve sub-agent
|
|
23
|
+
delegation for heavy independent work like visual review.
|
|
24
|
+
|
|
25
|
+
Re-running the installer refreshes these files in place.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!-- BEGIN APPKIT -->
|
|
2
|
+
# AppKit — Lean Mobile App Launch Kit (Codex operating guide)
|
|
3
|
+
|
|
4
|
+
This project uses **AppKit** to take a small mobile app from idea to a store-ready release.
|
|
5
|
+
You are the orchestrator. When the user runs an `/appkit.*` command (from `.codex/prompts/`) or
|
|
6
|
+
asks to start/continue an app, follow the workflow below.
|
|
7
|
+
|
|
8
|
+
## Golden path
|
|
9
|
+
`/appkit.init` → `/appkit.idea` → `/appkit.shape` → `/appkit.build` → `/appkit.verify` →
|
|
10
|
+
`/appkit.release` · repair with `/appkit.fix` then re-verify.
|
|
11
|
+
|
|
12
|
+
## On every command (orchestrator preamble)
|
|
13
|
+
1. Read `kit/constitution.md` (non-negotiable rules) and `.appkit/status.yaml` (current state).
|
|
14
|
+
2. Read the relevant artifacts (`.appkit/idea.md`, `app-spec.md`, `tasks.md`,
|
|
15
|
+
`verification-report.md`) when present.
|
|
16
|
+
3. Check the gate for the phase; if unmet, tell the user the prerequisite command. Never skip phases.
|
|
17
|
+
4. Adopt the owning agent role (below) and load its skills from `kit/skills/<name>/SKILL.md`.
|
|
18
|
+
5. Prefer deterministic `kit/scripts/*.sh` for anything that must be certain.
|
|
19
|
+
6. Update `.appkit/status.yaml` and report the new state + the single best next command.
|
|
20
|
+
|
|
21
|
+
## State machine & gates
|
|
22
|
+
`UNINITIALIZED → INITIALIZED → IDEA_SELECTED → SHAPED → BUILDING → BUILT → VERIFYING →
|
|
23
|
+
(NOT_READY|READY) → RELEASING → RELEASE_PREPARED`
|
|
24
|
+
- idea⇒INITIALIZED · shape⇒IDEA_SELECTED · build⇒SHAPED · verify⇒usable build · release⇒READY ·
|
|
25
|
+
fix⇒after build/verify/release/rejection.
|
|
26
|
+
|
|
27
|
+
## Agent roles (personas — adopt the right one per command)
|
|
28
|
+
- **Product** (`/appkit.idea`, `/appkit.shape`): generate/evaluate small ideas, reduce scope,
|
|
29
|
+
define users/screens/flows/acceptance, plan monetization & privacy, screen policy risk.
|
|
30
|
+
Skills: `small-app-product-design`, `mobile-privacy-and-permissions`, `admob-best-practices`,
|
|
31
|
+
`mobile-store-release`. Details: `kit/agents/product-agent.md`.
|
|
32
|
+
- **Builder** (`/appkit.init`, `/appkit.build`, `/appkit.fix`): proportional architecture,
|
|
33
|
+
implement vertical slices with tests, AdMob adapter, storage, build config, minimal fixes.
|
|
34
|
+
Skills: `mobile-app-development`, `mobile-testing-and-visual-qa` (+ privacy/admob).
|
|
35
|
+
Details: `kit/agents/builder-agent.md`.
|
|
36
|
+
- **Reviewer** (`/appkit.verify`): independent, evidence-based; run scripts, visual review,
|
|
37
|
+
accessibility, privacy, AdMob, Google Play & Apple policy, release smoke; write
|
|
38
|
+
`verification-report.md`. Skills: testing/privacy/admob/store. Details:
|
|
39
|
+
`kit/agents/reviewer-agent.md` + `policy-rules/`.
|
|
40
|
+
- **Release** (`/appkit.release`): builds, signing checklists (no secrets), metadata,
|
|
41
|
+
declarations, screenshots, manifest. Requires READY verification + human approval to submit.
|
|
42
|
+
Details: `kit/agents/release-agent.md`.
|
|
43
|
+
|
|
44
|
+
## Hard rules (see kit/constitution.md)
|
|
45
|
+
Small & local-first by default · privacy by default · monetization decided in Shape · policy
|
|
46
|
+
checked every phase · completion needs evidence (not assertions) · scripts for certainty ·
|
|
47
|
+
ask the human only for the §8 triggers (children, sensitive data, high-risk permissions,
|
|
48
|
+
payments, legal/medical claims, signing ownership, final submission, automatic submission) ·
|
|
49
|
+
never change product objective/permissions/data/monetization silently.
|
|
50
|
+
|
|
51
|
+
The full per-command instructions live in `.codex/prompts/appkit.*.md`. The shared brain is in
|
|
52
|
+
`kit/`. The kit prepares releases; the human submits.
|
|
53
|
+
<!-- END APPKIT -->
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Codex adapter
|
|
2
|
+
|
|
3
|
+
Maps the tool-independent kit (`kit/`) onto OpenAI Codex CLI conventions.
|
|
4
|
+
|
|
5
|
+
The installer (`install.sh --ai codex`) renders into the target project:
|
|
6
|
+
|
|
7
|
+
| Kit source | Installed as | Why |
|
|
8
|
+
|-----------------------|----------------------------------------|-----|
|
|
9
|
+
| `kit/commands/*.md` | `.codex/prompts/appkit.<name>.md` | Codex discovers prompt files; filename → `/appkit.<name>` |
|
|
10
|
+
| `kit/skills/*/SKILL.md` | `.codex/skills/<name>/SKILL.md` | Reusable skills (also readable at `.appkit/kit/skills/`) |
|
|
11
|
+
| `kit/agents/*` + orchestrator | `AGENTS.md` (APPKIT block) | Codex auto-reads `AGENTS.md`; agents become personas |
|
|
12
|
+
| whole `kit/` | `.appkit/kit/` | Shared brain; path references rewritten to `.appkit/kit/` |
|
|
13
|
+
|
|
14
|
+
Codex has no isolated sub-agents, so the four agents are expressed as **personas** the single
|
|
15
|
+
Codex agent adopts per command, driven by `AGENTS.md`. The `AGENTS.md` block is delimited by
|
|
16
|
+
`<!-- BEGIN APPKIT -->` / `<!-- END APPKIT -->` and is replaced (not duplicated) on re-install.
|
|
17
|
+
|
|
18
|
+
Note: Codex also supports user-level prompts in `~/.codex/prompts/`. This adapter installs
|
|
19
|
+
**project-level** files so the kit travels with the repo; `AGENTS.md` makes the workflow work
|
|
20
|
+
even on Codex versions that only read home-dir prompts.
|
package/bin/appkit.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/*
|
|
4
|
+
* AppKit installer (Node) — same behavior as install.sh, cross-platform for npm/npx.
|
|
5
|
+
*
|
|
6
|
+
* npx novaforge-appkit init --ai claude
|
|
7
|
+
* npx github:NovaForgeOrg/appkit init --ai codex --path ./my-app
|
|
8
|
+
*/
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const readline = require('readline');
|
|
12
|
+
|
|
13
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
14
|
+
const KIT_SRC = path.join(PKG_ROOT, 'kit');
|
|
15
|
+
const CODEX_SECTION = path.join(PKG_ROOT, 'adapters', 'codex', 'AGENTS.section.md');
|
|
16
|
+
|
|
17
|
+
function parseArgs(argv) {
|
|
18
|
+
const a = { ai: '', target: process.cwd() };
|
|
19
|
+
const args = argv.slice(2).filter((x) => x !== 'init'); // `init` is an optional verb
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const v = args[i];
|
|
22
|
+
if (v === '--ai') a.ai = args[++i];
|
|
23
|
+
else if (v === '--path') a.target = path.resolve(args[++i]);
|
|
24
|
+
else if (v === '--here') a.target = process.cwd();
|
|
25
|
+
else if (v === '-h' || v === '--help') a.help = true;
|
|
26
|
+
else { console.error(`Unknown arg: ${v}`); process.exit(1); }
|
|
27
|
+
}
|
|
28
|
+
return a;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const HELP = `AppKit — Lean Mobile App Launch Kit
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
npx novaforge-appkit init interactive (asks which AI tool)
|
|
35
|
+
npx novaforge-appkit init --ai claude Claude Code adapter
|
|
36
|
+
npx novaforge-appkit init --ai codex OpenAI Codex adapter
|
|
37
|
+
npx novaforge-appkit init --ai both
|
|
38
|
+
Options: --path <dir> (default: current dir), --here
|
|
39
|
+
|
|
40
|
+
Then run /appkit.init -> /appkit.idea -> /appkit.shape -> /appkit.build
|
|
41
|
+
/appkit.verify -> /appkit.release (repair with /appkit.fix)`;
|
|
42
|
+
|
|
43
|
+
// Rewrite bare kit refs to .appkit/kit/, protecting existing .appkit/ runtime paths.
|
|
44
|
+
function rewrite(text) {
|
|
45
|
+
const SENT = "\u0000";
|
|
46
|
+
return text
|
|
47
|
+
.split('.appkit/').join(SENT)
|
|
48
|
+
.split('kit/').join('.appkit/kit/')
|
|
49
|
+
.split('templates/').join('.appkit/kit/templates/')
|
|
50
|
+
.split('profiles/').join('.appkit/kit/profiles/')
|
|
51
|
+
.split('policy-rules/').join('.appkit/kit/policy-rules/')
|
|
52
|
+
.split(SENT).join('.appkit/');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function copyDir(src, dst) {
|
|
56
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
57
|
+
for (const e of fs.readdirSync(src, { withFileTypes: true })) {
|
|
58
|
+
const s = path.join(src, e.name);
|
|
59
|
+
const d = path.join(dst, e.name);
|
|
60
|
+
if (e.isDirectory()) copyDir(s, d);
|
|
61
|
+
else { fs.copyFileSync(s, d); if (s.endsWith('.sh')) fs.chmodSync(d, 0o755); }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ensureDirs(dirs) { for (const d of dirs) fs.mkdirSync(d, { recursive: true }); }
|
|
66
|
+
function cmdNames() {
|
|
67
|
+
return fs.readdirSync(path.join(KIT_SRC, 'commands')).filter((f) => f.endsWith('.md')).map((f) => f.slice(0, -3));
|
|
68
|
+
}
|
|
69
|
+
function readKit(rel) { return fs.readFileSync(path.join(KIT_SRC, rel), 'utf8'); }
|
|
70
|
+
|
|
71
|
+
function installClaude(target, say) {
|
|
72
|
+
const C = path.join(target, '.claude');
|
|
73
|
+
ensureDirs([path.join(C, 'commands'), path.join(C, 'agents'), path.join(C, 'skills')]);
|
|
74
|
+
for (const n of cmdNames())
|
|
75
|
+
fs.writeFileSync(path.join(C, 'commands', `appkit.${n}.md`), rewrite(readKit(`commands/${n}.md`)));
|
|
76
|
+
for (const f of fs.readdirSync(path.join(KIT_SRC, 'agents')))
|
|
77
|
+
fs.writeFileSync(path.join(C, 'agents', f), rewrite(readKit(`agents/${f}`)));
|
|
78
|
+
copyDir(path.join(KIT_SRC, 'skills'), path.join(C, 'skills'));
|
|
79
|
+
say('claude -> .claude/{commands/appkit.*, agents/, skills/}');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function installCodex(target, say) {
|
|
83
|
+
const P = path.join(target, '.codex', 'prompts');
|
|
84
|
+
const S = path.join(target, '.codex', 'skills');
|
|
85
|
+
ensureDirs([P, S]);
|
|
86
|
+
for (const n of cmdNames())
|
|
87
|
+
fs.writeFileSync(path.join(P, `appkit.${n}.md`), rewrite(readKit(`commands/${n}.md`)));
|
|
88
|
+
copyDir(path.join(KIT_SRC, 'skills'), S);
|
|
89
|
+
const A = path.join(target, 'AGENTS.md');
|
|
90
|
+
const block = rewrite(fs.readFileSync(CODEX_SECTION, 'utf8')).replace(/\n+$/, '');
|
|
91
|
+
let existing = fs.existsSync(A) ? fs.readFileSync(A, 'utf8') : '';
|
|
92
|
+
if (existing.includes('<!-- BEGIN APPKIT -->')) {
|
|
93
|
+
existing = existing.replace(/<!-- BEGIN APPKIT -->[\s\S]*?<!-- END APPKIT -->\n?/g, '').replace(/\n{3,}$/, '\n');
|
|
94
|
+
}
|
|
95
|
+
const out = existing.trim() ? `${existing.replace(/\n+$/, '')}\n\n${block}\n` : `${block}\n`;
|
|
96
|
+
fs.writeFileSync(A, out);
|
|
97
|
+
say('codex -> AGENTS.md + .codex/{prompts/appkit.*, skills/}');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function writeStatus(target, ai) {
|
|
101
|
+
const status = path.join(target, '.appkit', 'status.yaml');
|
|
102
|
+
if (fs.existsSync(status)) return;
|
|
103
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
104
|
+
fs.writeFileSync(status,
|
|
105
|
+
`project_name: ${path.basename(target)}
|
|
106
|
+
profile: flutter
|
|
107
|
+
ai_tool: ${ai}
|
|
108
|
+
targets: [android, ios]
|
|
109
|
+
stores: [google_play, apple_app_store]
|
|
110
|
+
monetization: { admob: true }
|
|
111
|
+
state: UNINITIALIZED
|
|
112
|
+
current_phase: init
|
|
113
|
+
verification_status: not_run
|
|
114
|
+
release_status: not_started
|
|
115
|
+
open_blockers: []
|
|
116
|
+
open_warnings: []
|
|
117
|
+
last_updated: ${today}
|
|
118
|
+
`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function ensureGitignore(target) {
|
|
122
|
+
const gi = path.join(target, '.gitignore');
|
|
123
|
+
const lines = ['**/key.properties', '**/*.keystore', '**/*.jks', '.appkit/release/builds/', 'build/'];
|
|
124
|
+
let cur = fs.existsSync(gi) ? fs.readFileSync(gi, 'utf8') : '';
|
|
125
|
+
const have = new Set(cur.split('\n'));
|
|
126
|
+
const add = lines.filter((l) => !have.has(l));
|
|
127
|
+
if (add.length) fs.writeFileSync(gi, (cur && !cur.endsWith('\n') ? cur + '\n' : cur) + add.join('\n') + '\n');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function chooseAi() {
|
|
131
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
132
|
+
const q = (s) => new Promise((res) => rl.question(s, res));
|
|
133
|
+
console.log('Which AI coding tool should AppKit target?\n 1) claude (Claude Code)\n 2) codex (OpenAI Codex CLI)\n 3) both');
|
|
134
|
+
const c = (await q('Select [1]: ')).trim();
|
|
135
|
+
rl.close();
|
|
136
|
+
return c === '2' ? 'codex' : c === '3' ? 'both' : 'claude';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function main() {
|
|
140
|
+
const a = parseArgs(process.argv);
|
|
141
|
+
if (a.help) { console.log(HELP); return; }
|
|
142
|
+
if (!fs.existsSync(KIT_SRC)) { console.error(`Cannot find kit/ at ${KIT_SRC}`); process.exit(1); }
|
|
143
|
+
if (!a.ai) a.ai = await chooseAi();
|
|
144
|
+
if (!['claude', 'codex', 'both'].includes(a.ai)) { console.error(`--ai must be claude|codex|both`); process.exit(1); }
|
|
145
|
+
|
|
146
|
+
fs.mkdirSync(a.target, { recursive: true });
|
|
147
|
+
console.log(`==> AppKit install: ai=${a.ai} target=${a.target}`);
|
|
148
|
+
const say = (s) => console.log(` ${s}`);
|
|
149
|
+
|
|
150
|
+
const appkit = path.join(a.target, '.appkit');
|
|
151
|
+
ensureDirs([
|
|
152
|
+
path.join(appkit, 'kit'),
|
|
153
|
+
path.join(appkit, 'screenshots', 'qa'),
|
|
154
|
+
path.join(appkit, 'screenshots', 'baselines'),
|
|
155
|
+
path.join(appkit, 'screenshots', 'findings'),
|
|
156
|
+
path.join(appkit, 'release'),
|
|
157
|
+
]);
|
|
158
|
+
copyDir(KIT_SRC, path.join(appkit, 'kit'));
|
|
159
|
+
say('core -> .appkit/kit/');
|
|
160
|
+
writeStatus(a.target, a.ai);
|
|
161
|
+
say('status -> .appkit/status.yaml');
|
|
162
|
+
|
|
163
|
+
if (a.ai === 'claude' || a.ai === 'both') installClaude(a.target, say);
|
|
164
|
+
if (a.ai === 'codex' || a.ai === 'both') installCodex(a.target, say);
|
|
165
|
+
ensureGitignore(a.target);
|
|
166
|
+
|
|
167
|
+
const tool = a.ai === 'codex' ? 'Codex' : 'Claude Code';
|
|
168
|
+
console.log(`\n==> Done. AppKit installed for: ${a.ai}\n\nNext:\n 1) Open this folder in ${tool}.\n 2) Run /appkit.init then /appkit.idea -> /appkit.shape -> /appkit.build\n /appkit.verify -> /appkit.release (repair with /appkit.fix)\n\nShared brain: .appkit/kit/ | Status: .appkit/status.yaml`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
main().catch((e) => { console.error(e); process.exit(1); });
|
package/install.sh
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# AppKit installer — sets up the Lean Mobile App Launch Kit for Claude Code or Codex.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./install.sh # interactive: asks which AI tool, installs in CWD
|
|
6
|
+
# ./install.sh --ai claude # install Claude Code adapter into the current dir
|
|
7
|
+
# ./install.sh --ai codex --path ./my-app
|
|
8
|
+
# ./install.sh --ai both # install both adapters (they share .appkit/kit)
|
|
9
|
+
#
|
|
10
|
+
# Re-running is safe: it refreshes .appkit/kit and the chosen adapter's files.
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
KIT_SRC="$SCRIPT_DIR/kit"
|
|
15
|
+
AI=""; TARGET="$(pwd)"
|
|
16
|
+
|
|
17
|
+
while [ $# -gt 0 ]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
--ai) AI="${2:-}"; shift 2;;
|
|
20
|
+
--path|--here) if [ "$1" = "--here" ]; then shift; else TARGET="${2:-}"; shift 2; fi;;
|
|
21
|
+
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0;;
|
|
22
|
+
*) echo "Unknown arg: $1"; exit 1;;
|
|
23
|
+
esac
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
[ -d "$KIT_SRC" ] || { echo "Cannot find kit/ next to installer ($KIT_SRC)"; exit 1; }
|
|
27
|
+
mkdir -p "$TARGET"; TARGET="$(cd "$TARGET" && pwd)"
|
|
28
|
+
|
|
29
|
+
if [ -z "$AI" ]; then
|
|
30
|
+
echo "Which AI coding tool should AppKit target?"
|
|
31
|
+
echo " 1) claude (Claude Code)"
|
|
32
|
+
echo " 2) codex (OpenAI Codex CLI)"
|
|
33
|
+
echo " 3) both"
|
|
34
|
+
printf "Select [1]: "; read -r choice || true
|
|
35
|
+
case "${choice:-1}" in 1|"") AI=claude;; 2) AI=codex;; 3) AI=both;; *) AI=claude;; esac
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
say() { printf ' %s\n' "$*"; }
|
|
39
|
+
echo "==> AppKit install: ai=$AI target=$TARGET"
|
|
40
|
+
|
|
41
|
+
# --- 1. Shared tool-independent core -> .appkit/kit ------------------------------------------
|
|
42
|
+
APPKIT="$TARGET/.appkit"
|
|
43
|
+
mkdir -p "$APPKIT/kit" "$APPKIT/screenshots/qa" "$APPKIT/screenshots/baselines" \
|
|
44
|
+
"$APPKIT/screenshots/findings" "$APPKIT/release"
|
|
45
|
+
cp -R "$KIT_SRC/." "$APPKIT/kit/"
|
|
46
|
+
chmod +x "$APPKIT/kit/scripts/"*.sh 2>/dev/null || true
|
|
47
|
+
say "core -> .appkit/kit/"
|
|
48
|
+
|
|
49
|
+
if [ ! -f "$APPKIT/status.yaml" ]; then
|
|
50
|
+
cat > "$APPKIT/status.yaml" <<EOF
|
|
51
|
+
project_name: $(basename "$TARGET")
|
|
52
|
+
profile: flutter
|
|
53
|
+
ai_tool: $AI
|
|
54
|
+
targets: [android, ios]
|
|
55
|
+
stores: [google_play, apple_app_store]
|
|
56
|
+
monetization: { admob: true }
|
|
57
|
+
state: UNINITIALIZED
|
|
58
|
+
current_phase: init
|
|
59
|
+
verification_status: not_run
|
|
60
|
+
release_status: not_started
|
|
61
|
+
open_blockers: []
|
|
62
|
+
open_warnings: []
|
|
63
|
+
last_updated: $(date +%Y-%m-%d)
|
|
64
|
+
EOF
|
|
65
|
+
say "status -> .appkit/status.yaml (UNINITIALIZED)"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Rewrite bare kit references (kit/ templates/ profiles/ policy-rules/) to .appkit/kit/ paths,
|
|
69
|
+
# while protecting existing .appkit/ runtime paths. BSD/GNU-portable (no word boundaries).
|
|
70
|
+
rewrite() {
|
|
71
|
+
sed -e 's#\.appkit/#__AK__#g' \
|
|
72
|
+
-e 's#kit/#.appkit/kit/#g' \
|
|
73
|
+
-e 's#templates/#.appkit/kit/templates/#g' \
|
|
74
|
+
-e 's#profiles/#.appkit/kit/profiles/#g' \
|
|
75
|
+
-e 's#policy-rules/#.appkit/kit/policy-rules/#g' \
|
|
76
|
+
-e 's#__AK__#.appkit/#g' "$1"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Command name mapping: kit/commands/<name>.md -> appkit.<name>
|
|
80
|
+
cmd_names() { for f in "$KIT_SRC"/commands/*.md; do basename "$f" .md; done; }
|
|
81
|
+
|
|
82
|
+
install_claude() {
|
|
83
|
+
local C="$TARGET/.claude"
|
|
84
|
+
mkdir -p "$C/commands" "$C/agents" "$C/skills"
|
|
85
|
+
for n in $(cmd_names); do rewrite "$KIT_SRC/commands/$n.md" > "$C/commands/appkit.$n.md"; done
|
|
86
|
+
for f in "$KIT_SRC"/agents/*.md; do rewrite "$f" > "$C/agents/$(basename "$f")"; done
|
|
87
|
+
cp -R "$KIT_SRC/skills/." "$C/skills/"
|
|
88
|
+
say "claude -> .claude/{commands/appkit.*, agents/, skills/}"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
install_codex() {
|
|
92
|
+
local P="$TARGET/.codex/prompts" S="$TARGET/.codex/skills"
|
|
93
|
+
mkdir -p "$P" "$S"
|
|
94
|
+
for n in $(cmd_names); do rewrite "$KIT_SRC/commands/$n.md" > "$P/appkit.$n.md"; done
|
|
95
|
+
cp -R "$KIT_SRC/skills/." "$S/"
|
|
96
|
+
# AGENTS.md: orchestrator + agent personas, pointing at the shared core. Idempotent block.
|
|
97
|
+
local A="$TARGET/AGENTS.md"
|
|
98
|
+
local block; block="$(rewrite "$SCRIPT_DIR/adapters/codex/AGENTS.section.md")"
|
|
99
|
+
if [ -f "$A" ] && grep -q "<!-- BEGIN APPKIT -->" "$A"; then
|
|
100
|
+
# Strip the old AppKit block, then re-append the fresh one.
|
|
101
|
+
awk '/<!-- BEGIN APPKIT -->/{skip=1} !skip{print} /<!-- END APPKIT -->/{skip=0}' "$A" > "$A.tmp"
|
|
102
|
+
mv "$A.tmp" "$A"
|
|
103
|
+
fi
|
|
104
|
+
{ [ -f "$A" ] && [ -s "$A" ] && printf '\n'; printf '%s\n' "$block"; } >> "$A"
|
|
105
|
+
say "codex -> AGENTS.md + .codex/{prompts/appkit.*, skills/}"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
case "$AI" in
|
|
109
|
+
claude) install_claude;;
|
|
110
|
+
codex) install_codex;;
|
|
111
|
+
both) install_claude; install_codex;;
|
|
112
|
+
*) echo "Unknown --ai '$AI' (use claude|codex|both)"; exit 1;;
|
|
113
|
+
esac
|
|
114
|
+
|
|
115
|
+
# .gitignore guard for secrets / build output
|
|
116
|
+
GI="$TARGET/.gitignore"
|
|
117
|
+
for line in "**/key.properties" "**/*.keystore" "**/*.jks" ".appkit/release/builds/" "build/"; do
|
|
118
|
+
grep -qxF "$line" "$GI" 2>/dev/null || echo "$line" >> "$GI"
|
|
119
|
+
done
|
|
120
|
+
|
|
121
|
+
cat <<EOF
|
|
122
|
+
|
|
123
|
+
==> Done. AppKit installed for: $AI
|
|
124
|
+
|
|
125
|
+
Next steps:
|
|
126
|
+
1) Open this folder in $( [ "$AI" = codex ] && echo "Codex" || echo "Claude Code" ).
|
|
127
|
+
2) Run: /appkit.init then /appkit.idea -> /appkit.shape -> /appkit.build
|
|
128
|
+
/appkit.verify -> /appkit.release (repair with /appkit.fix)
|
|
129
|
+
|
|
130
|
+
Shared brain: .appkit/kit/ | Status: .appkit/status.yaml
|
|
131
|
+
EOF
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: appkit-builder
|
|
3
|
+
description: Owns architecture, codebase initialization, task implementation, tests, AdMob and storage wiring, build configuration and technical fixes for small Flutter apps. Invoked by /appkit.init, /appkit.build and /appkit.fix.
|
|
4
|
+
tools: Read, Write, Edit, Grep, Glob, Bash
|
|
5
|
+
model: inherit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Builder Agent
|
|
9
|
+
|
|
10
|
+
You own **Init**, **Build**, and technical **Fix** work. Ship a working MVP with tests — not a
|
|
11
|
+
framework.
|
|
12
|
+
|
|
13
|
+
## Operating rules
|
|
14
|
+
- Obey `kit/constitution.md`. Keep architecture proportional to a small app; avoid
|
|
15
|
+
overengineering, unnecessary abstraction, and unnecessary dependencies.
|
|
16
|
+
- Load `mobile-app-development` and `mobile-testing-and-visual-qa` skills; load
|
|
17
|
+
`mobile-privacy-and-permissions` and `admob-best-practices` when touching permissions, data,
|
|
18
|
+
or ads.
|
|
19
|
+
- Follow `app-spec.md` and the selected profile (`profiles/flutter.md` + android/ios). Add only
|
|
20
|
+
what is in scope.
|
|
21
|
+
- Write tests **with** the implementation. Preserve deterministic UI states.
|
|
22
|
+
- Isolate advertising behind the ad adapter. Keep release config separate. Never use production
|
|
23
|
+
ad ids in development. Never silently add permissions or data collection.
|
|
24
|
+
- Add a regression test for every fix. Preserve local-first behavior.
|
|
25
|
+
|
|
26
|
+
## Init → project + `.appkit/` structure
|
|
27
|
+
Scaffold the Flutter app per profile, set application id / bundle id, create the `.appkit/`
|
|
28
|
+
tree and `status.yaml`, configure environments (`APP_ENV`), lints, and initial tests. Default:
|
|
29
|
+
Flutter, Android+iOS, local-first, no login, no backend, portrait, AdMob planned-not-mandatory,
|
|
30
|
+
no personal data. State → INITIALIZED.
|
|
31
|
+
|
|
32
|
+
## Build → implement slices
|
|
33
|
+
For each task: read spec → implement the slice → add/update tests → run format, analyze, unit,
|
|
34
|
+
widget, and targeted integration tests (`kit/scripts/`) → update task status. Report remaining
|
|
35
|
+
work. State → BUILDING, then BUILT when all slices/tests pass.
|
|
36
|
+
|
|
37
|
+
## Change control
|
|
38
|
+
Do not silently change product objective, target user, monetization, data collection,
|
|
39
|
+
permissions, backend usage, store target, or acceptance criteria. If implementation forces a
|
|
40
|
+
change, update `app-spec.md` and record why.
|
|
41
|
+
|
|
42
|
+
## Fix
|
|
43
|
+
Classify the issue, locate the affected requirement + code, make the **minimal** correction,
|
|
44
|
+
add a regression test, rerun the affected gates, and update task status + the verification
|
|
45
|
+
report. Do not add unrelated features.
|
|
46
|
+
|
|
47
|
+
## Done when
|
|
48
|
+
Code compiles, the relevant scripts pass (with output, not assertion), tasks/status are
|
|
49
|
+
updated, and changes stay within the spec (or the spec was updated with a recorded reason).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: appkit-product
|
|
3
|
+
description: Owns product ideation and shaping for small mobile apps. Use to generate/evaluate app ideas, reduce scope to an MVP, define users, screens, flows and acceptance criteria, plan monetization and privacy, screen policy risk, and produce idea.md, app-spec.md and tasks.md. Invoked by /appkit.idea and /appkit.shape.
|
|
4
|
+
tools: Read, Write, Edit, Grep, Glob, WebSearch, WebFetch
|
|
5
|
+
model: inherit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Product Agent
|
|
9
|
+
|
|
10
|
+
You own the **Idea** and **Shape** phases. Your job is to turn a vague request into a small,
|
|
11
|
+
coherent, launchable product — and to keep it small.
|
|
12
|
+
|
|
13
|
+
## Operating rules
|
|
14
|
+
- Obey `kit/constitution.md`. Prefer a small coherent app over a broad one.
|
|
15
|
+
- Load and apply the `small-app-product-design` skill always; load
|
|
16
|
+
`mobile-privacy-and-permissions`, `admob-best-practices`, and `mobile-store-release` when
|
|
17
|
+
shaping monetization, privacy, or store risk.
|
|
18
|
+
- Make safe assumptions and record them. Ask only high-value questions. Reject weak ideas
|
|
19
|
+
honestly and propose a smaller adjacent idea.
|
|
20
|
+
- Never recommend unnecessary accounts, servers, or high-risk permissions.
|
|
21
|
+
- Treat monetization as part of UX, decided now, not later.
|
|
22
|
+
- Use WebSearch/WebFetch to check current store/AdMob policy or validate that an idea is not
|
|
23
|
+
in a restricted category when unsure.
|
|
24
|
+
|
|
25
|
+
## Idea phase → `.appkit/idea.md`
|
|
26
|
+
Understand the category, generate one or a few ideas, score them (see the skill's dimensions),
|
|
27
|
+
estimate size/screens/backend/data/permissions, evaluate monetization and store-policy risk,
|
|
28
|
+
recommend platforms, and give a decision: GO / GO WITH REDUCED SCOPE / REVISE / HOLD / REJECT.
|
|
29
|
+
Use `templates/idea.template.md`.
|
|
30
|
+
|
|
31
|
+
## Shape phase → `.appkit/app-spec.md` + `.appkit/tasks.md`
|
|
32
|
+
Produce a lean spec (not an enterprise PRD): summary, objective, users, primary outcome, core
|
|
33
|
+
features, out-of-scope, main flow, screen inventory + per-screen specs (with every state), data
|
|
34
|
+
model, local storage, permissions (each justified), third-party SDKs, AdMob plan (per-placement
|
|
35
|
+
yaml), privacy plan, technical approach, testing strategy, accessibility, acceptance criteria,
|
|
36
|
+
store risks, release targets, assumptions. Use `templates/app-spec.template.md`.
|
|
37
|
+
|
|
38
|
+
Break work into vertical slices in `tasks.md` (`templates/tasks.template.md`); each task
|
|
39
|
+
references feature, screen, acceptance criteria, test expectation, and policy consideration.
|
|
40
|
+
|
|
41
|
+
## Human-confirmation triggers (ask before shaping further)
|
|
42
|
+
children · sensitive/medical/financial · gambling · UGC · social comms · location tracking ·
|
|
43
|
+
high-risk permissions · subscriptions/IAP · backend · content licensing · legal/regulated
|
|
44
|
+
claims · irreversible integration. Ask one concise question stating the risk + safe default.
|
|
45
|
+
|
|
46
|
+
## Done when
|
|
47
|
+
The artifact(s) exist, are internally consistent, the decision/recommendation is explicit, and
|
|
48
|
+
`.appkit/status.yaml` is updated (IDEA_SELECTED after idea is accepted; SHAPED after shape).
|