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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/adapters/claude-code/README.md +25 -0
  4. package/adapters/codex/AGENTS.section.md +53 -0
  5. package/adapters/codex/README.md +20 -0
  6. package/bin/appkit.js +171 -0
  7. package/install.sh +131 -0
  8. package/kit/agents/builder-agent.md +49 -0
  9. package/kit/agents/product-agent.md +48 -0
  10. package/kit/agents/release-agent.md +46 -0
  11. package/kit/agents/reviewer-agent.md +42 -0
  12. package/kit/commands/build.md +30 -0
  13. package/kit/commands/fix.md +33 -0
  14. package/kit/commands/idea.md +28 -0
  15. package/kit/commands/init.md +29 -0
  16. package/kit/commands/release.md +32 -0
  17. package/kit/commands/shape.md +33 -0
  18. package/kit/commands/verify.md +35 -0
  19. package/kit/constitution.md +79 -0
  20. package/kit/orchestrator.md +63 -0
  21. package/kit/policy-rules/admob.md +25 -0
  22. package/kit/policy-rules/apple-app-store.md +31 -0
  23. package/kit/policy-rules/google-play.md +33 -0
  24. package/kit/policy-rules/privacy.md +25 -0
  25. package/kit/profiles/android.md +31 -0
  26. package/kit/profiles/flutter.md +45 -0
  27. package/kit/profiles/ios.md +32 -0
  28. package/kit/scripts/_common.sh +24 -0
  29. package/kit/scripts/analyze.sh +6 -0
  30. package/kit/scripts/build-android.sh +12 -0
  31. package/kit/scripts/build-ios.sh +23 -0
  32. package/kit/scripts/capture-screenshots.sh +20 -0
  33. package/kit/scripts/compare-goldens.sh +21 -0
  34. package/kit/scripts/extract-dependencies.sh +23 -0
  35. package/kit/scripts/extract-permissions.sh +22 -0
  36. package/kit/scripts/format.sh +11 -0
  37. package/kit/scripts/scan-secrets.sh +15 -0
  38. package/kit/scripts/test.sh +12 -0
  39. package/kit/scripts/validate-ad-ids.sh +22 -0
  40. package/kit/scripts/validate-release.sh +30 -0
  41. package/kit/skills/admob-best-practices/SKILL.md +74 -0
  42. package/kit/skills/mobile-app-development/SKILL.md +69 -0
  43. package/kit/skills/mobile-privacy-and-permissions/SKILL.md +71 -0
  44. package/kit/skills/mobile-store-release/SKILL.md +74 -0
  45. package/kit/skills/mobile-testing-and-visual-qa/SKILL.md +79 -0
  46. package/kit/skills/small-app-product-design/SKILL.md +68 -0
  47. package/kit/templates/app-spec.template.md +89 -0
  48. package/kit/templates/idea.template.md +60 -0
  49. package/kit/templates/privacy-policy.template.md +41 -0
  50. package/kit/templates/release-manifest.template.yaml +46 -0
  51. package/kit/templates/store-listing.template.md +37 -0
  52. package/kit/templates/tasks.template.md +46 -0
  53. package/kit/templates/verification-report.template.md +58 -0
  54. 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).