argos-harness 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 (217) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/assets/agents/auditor.md +140 -0
  4. package/assets/agents/commit-pr-pilot.md +154 -0
  5. package/assets/agents/explorer.md +93 -0
  6. package/assets/agents/implementer.md +117 -0
  7. package/assets/agents/leader.md +149 -0
  8. package/assets/agents/researcher.md +89 -0
  9. package/assets/agents/review-readability.md +87 -0
  10. package/assets/agents/review-reliability.md +100 -0
  11. package/assets/agents/review-resilience.md +87 -0
  12. package/assets/agents/review-risk.md +87 -0
  13. package/assets/agents/reviewer.md +167 -0
  14. package/assets/agents/ticket-audit.md +129 -0
  15. package/assets/hooks/argos-guard-destructive.sh +127 -0
  16. package/assets/hooks/argos-quality-gate.sh +129 -0
  17. package/assets/managed/aterrizaje.md +24 -0
  18. package/assets/managed/formato-respuesta.md +21 -0
  19. package/assets/managed/identidad.md +48 -0
  20. package/assets/managed/operaciones-seguras.md +14 -0
  21. package/assets/managed/orquestacion.md +169 -0
  22. package/assets/output-styles/argos.md +71 -0
  23. package/assets/skills/ai-sdk-5/SKILL.md +230 -0
  24. package/assets/skills/angular/SKILL.md +19 -0
  25. package/assets/skills/angular/references/architecture.md +137 -0
  26. package/assets/skills/angular/references/core.md +197 -0
  27. package/assets/skills/angular/references/forms.md +115 -0
  28. package/assets/skills/angular/references/performance.md +124 -0
  29. package/assets/skills/apollo-client/SKILL.md +61 -0
  30. package/assets/skills/app-blueprint/SKILL.md +45 -0
  31. package/assets/skills/app-blueprint/assets/module-template.md +48 -0
  32. package/assets/skills/app-blueprint/assets/system-template.md +38 -0
  33. package/assets/skills/app-blueprint/references/workflow.md +101 -0
  34. package/assets/skills/app-builder/SKILL.md +43 -0
  35. package/assets/skills/app-builder/phases/0-product.md +58 -0
  36. package/assets/skills/app-builder/phases/1-scaffold.md +33 -0
  37. package/assets/skills/app-builder/phases/10-store.md +40 -0
  38. package/assets/skills/app-builder/phases/2-data.md +34 -0
  39. package/assets/skills/app-builder/phases/3-domain.md +33 -0
  40. package/assets/skills/app-builder/phases/4-ui-nav.md +32 -0
  41. package/assets/skills/app-builder/phases/5-identity.md +30 -0
  42. package/assets/skills/app-builder/phases/6-polish.md +34 -0
  43. package/assets/skills/app-builder/phases/7-brand.md +31 -0
  44. package/assets/skills/app-builder/phases/8-web.md +30 -0
  45. package/assets/skills/app-builder/phases/9-docs.md +31 -0
  46. package/assets/skills/app-ia/SKILL.md +54 -0
  47. package/assets/skills/astro/SKILL.md +39 -0
  48. package/assets/skills/axios/SKILL.md +61 -0
  49. package/assets/skills/branch-pr/SKILL.md +200 -0
  50. package/assets/skills/bullmq/SKILL.md +55 -0
  51. package/assets/skills/chained-pr/SKILL.md +48 -0
  52. package/assets/skills/chained-pr/references/chaining-details.md +99 -0
  53. package/assets/skills/cognitive-doc-design/SKILL.md +81 -0
  54. package/assets/skills/comment-writer/SKILL.md +74 -0
  55. package/assets/skills/dashboard-ia/SKILL.md +54 -0
  56. package/assets/skills/django-drf/SKILL.md +180 -0
  57. package/assets/skills/go-testing/SKILL.md +47 -0
  58. package/assets/skills/go-testing/references/examples.md +89 -0
  59. package/assets/skills/issue-creation/SKILL.md +223 -0
  60. package/assets/skills/jira-epic/SKILL.md +306 -0
  61. package/assets/skills/jira-task/SKILL.md +382 -0
  62. package/assets/skills/judgment-day/SKILL.md +52 -0
  63. package/assets/skills/judgment-day/references/prompts-and-formats.md +98 -0
  64. package/assets/skills/lightsail-deploy/SKILL.md +44 -0
  65. package/assets/skills/lightsail-deploy/references/runbook.md +102 -0
  66. package/assets/skills/loop-back-debug/SKILL.md +102 -0
  67. package/assets/skills/mantine-form/SKILL.md +57 -0
  68. package/assets/skills/mongoose/SKILL.md +66 -0
  69. package/assets/skills/nextjs-15/SKILL.md +144 -0
  70. package/assets/skills/not-boring-mobile/SKILL.md +43 -0
  71. package/assets/skills/not-boring-mobile/references/not-boring-playbook.md +65 -0
  72. package/assets/skills/playwright/SKILL.md +315 -0
  73. package/assets/skills/pr-comments/SKILL.md +93 -0
  74. package/assets/skills/pr-create/SKILL.md +64 -0
  75. package/assets/skills/promo-video/SKILL.md +52 -0
  76. package/assets/skills/promo-video/assets/package.template.json +22 -0
  77. package/assets/skills/promo-video/assets/promo.template.tsx +469 -0
  78. package/assets/skills/promo-video/assets/theme.template.ts +27 -0
  79. package/assets/skills/promo-video/references/pipeline.md +119 -0
  80. package/assets/skills/promo-video-web/SKILL.md +51 -0
  81. package/assets/skills/promo-video-web/assets/browser-promo.template.tsx +385 -0
  82. package/assets/skills/promo-video-web/assets/capture.template.ts +70 -0
  83. package/assets/skills/promo-video-web/assets/package.template.json +26 -0
  84. package/assets/skills/promo-video-web/references/pipeline.md +84 -0
  85. package/assets/skills/pytest/SKILL.md +180 -0
  86. package/assets/skills/react-19/SKILL.md +118 -0
  87. package/assets/skills/react-hook-form/SKILL.md +59 -0
  88. package/assets/skills/react-router/SKILL.md +60 -0
  89. package/assets/skills/redux-toolkit/SKILL.md +60 -0
  90. package/assets/skills/review-diff/SKILL.md +101 -0
  91. package/assets/skills/ship-docs/SKILL.md +45 -0
  92. package/assets/skills/ship-docs/references/ship-docs-playbook.md +31 -0
  93. package/assets/skills/skill-creator/SKILL.md +97 -0
  94. package/assets/skills/skill-creator/assets/SKILL-TEMPLATE.md +68 -0
  95. package/assets/skills/skill-creator/references/skill-style-guide.md +79 -0
  96. package/assets/skills/skill-improver/SKILL.md +50 -0
  97. package/assets/skills/skill-improver/references/skill-style-guide.md +79 -0
  98. package/assets/skills/socketio/SKILL.md +58 -0
  99. package/assets/skills/spec-bootstrap/SKILL.md +62 -0
  100. package/assets/skills/store-ship/SKILL.md +52 -0
  101. package/assets/skills/store-ship/assets/android-supply.template.md +22 -0
  102. package/assets/skills/store-ship/assets/eas.template.json +32 -0
  103. package/assets/skills/store-ship/assets/maestro-flow.template.yaml +27 -0
  104. package/assets/skills/store-ship/assets/store.config.template.json +28 -0
  105. package/assets/skills/store-ship/references/pipeline.md +198 -0
  106. package/assets/skills/stripe/SKILL.md +83 -0
  107. package/assets/skills/tailwind-4/SKILL.md +193 -0
  108. package/assets/skills/tamagui/SKILL.md +60 -0
  109. package/assets/skills/tanstack-query/SKILL.md +58 -0
  110. package/assets/skills/ticket-intake/SKILL.md +55 -0
  111. package/assets/skills/typescript/SKILL.md +134 -0
  112. package/assets/skills/verify-before-done/SKILL.md +111 -0
  113. package/assets/skills/webapp-rebuilder/SKILL.md +48 -0
  114. package/assets/skills/webapp-rebuilder/assets/charter-template.md +46 -0
  115. package/assets/skills/webapp-rebuilder/references/workflow.md +47 -0
  116. package/assets/skills/winston-logging/SKILL.md +61 -0
  117. package/assets/skills/work-unit-commits/SKILL.md +84 -0
  118. package/assets/skills/zod-4/SKILL.md +210 -0
  119. package/assets/skills/zustand-5/SKILL.md +216 -0
  120. package/bin/argos.js +6 -0
  121. package/dist/commands/adopt.d.ts +35 -0
  122. package/dist/commands/adopt.d.ts.map +1 -0
  123. package/dist/commands/adopt.js +347 -0
  124. package/dist/commands/adopt.js.map +1 -0
  125. package/dist/commands/doctor.d.ts +20 -0
  126. package/dist/commands/doctor.d.ts.map +1 -0
  127. package/dist/commands/doctor.js +478 -0
  128. package/dist/commands/doctor.js.map +1 -0
  129. package/dist/commands/init.d.ts +32 -0
  130. package/dist/commands/init.d.ts.map +1 -0
  131. package/dist/commands/init.js +358 -0
  132. package/dist/commands/init.js.map +1 -0
  133. package/dist/commands/remove.d.ts +62 -0
  134. package/dist/commands/remove.d.ts.map +1 -0
  135. package/dist/commands/remove.js +487 -0
  136. package/dist/commands/remove.js.map +1 -0
  137. package/dist/commands/workspace.d.ts +73 -0
  138. package/dist/commands/workspace.d.ts.map +1 -0
  139. package/dist/commands/workspace.js +354 -0
  140. package/dist/commands/workspace.js.map +1 -0
  141. package/dist/index.d.ts +2 -0
  142. package/dist/index.d.ts.map +1 -0
  143. package/dist/index.js +24 -0
  144. package/dist/index.js.map +1 -0
  145. package/dist/lib/assets.d.ts +29 -0
  146. package/dist/lib/assets.d.ts.map +1 -0
  147. package/dist/lib/assets.js +57 -0
  148. package/dist/lib/assets.js.map +1 -0
  149. package/dist/lib/atomic-write.d.ts +17 -0
  150. package/dist/lib/atomic-write.d.ts.map +1 -0
  151. package/dist/lib/atomic-write.js +41 -0
  152. package/dist/lib/atomic-write.js.map +1 -0
  153. package/dist/lib/backup.d.ts +11 -0
  154. package/dist/lib/backup.d.ts.map +1 -0
  155. package/dist/lib/backup.js +42 -0
  156. package/dist/lib/backup.js.map +1 -0
  157. package/dist/lib/config.d.ts +36 -0
  158. package/dist/lib/config.d.ts.map +1 -0
  159. package/dist/lib/config.js +52 -0
  160. package/dist/lib/config.js.map +1 -0
  161. package/dist/lib/detect.d.ts +58 -0
  162. package/dist/lib/detect.d.ts.map +1 -0
  163. package/dist/lib/detect.js +330 -0
  164. package/dist/lib/detect.js.map +1 -0
  165. package/dist/lib/ficha.d.ts +10 -0
  166. package/dist/lib/ficha.d.ts.map +1 -0
  167. package/dist/lib/ficha.js +38 -0
  168. package/dist/lib/ficha.js.map +1 -0
  169. package/dist/lib/git.d.ts +27 -0
  170. package/dist/lib/git.d.ts.map +1 -0
  171. package/dist/lib/git.js +79 -0
  172. package/dist/lib/git.js.map +1 -0
  173. package/dist/lib/managed-files.d.ts +35 -0
  174. package/dist/lib/managed-files.d.ts.map +1 -0
  175. package/dist/lib/managed-files.js +97 -0
  176. package/dist/lib/managed-files.js.map +1 -0
  177. package/dist/lib/markers.d.ts +64 -0
  178. package/dist/lib/markers.d.ts.map +1 -0
  179. package/dist/lib/markers.js +157 -0
  180. package/dist/lib/markers.js.map +1 -0
  181. package/dist/lib/navori-import.d.ts +42 -0
  182. package/dist/lib/navori-import.d.ts.map +1 -0
  183. package/dist/lib/navori-import.js +65 -0
  184. package/dist/lib/navori-import.js.map +1 -0
  185. package/dist/lib/openclaw-agents.d.ts +53 -0
  186. package/dist/lib/openclaw-agents.d.ts.map +1 -0
  187. package/dist/lib/openclaw-agents.js +118 -0
  188. package/dist/lib/openclaw-agents.js.map +1 -0
  189. package/dist/lib/package-root.d.ts +11 -0
  190. package/dist/lib/package-root.d.ts.map +1 -0
  191. package/dist/lib/package-root.js +23 -0
  192. package/dist/lib/package-root.js.map +1 -0
  193. package/dist/lib/paths.d.ts +11 -0
  194. package/dist/lib/paths.d.ts.map +1 -0
  195. package/dist/lib/paths.js +16 -0
  196. package/dist/lib/paths.js.map +1 -0
  197. package/dist/lib/settings-merge.d.ts +125 -0
  198. package/dist/lib/settings-merge.d.ts.map +1 -0
  199. package/dist/lib/settings-merge.js +373 -0
  200. package/dist/lib/settings-merge.js.map +1 -0
  201. package/dist/lib/version.d.ts +3 -0
  202. package/dist/lib/version.d.ts.map +1 -0
  203. package/dist/lib/version.js +13 -0
  204. package/dist/lib/version.js.map +1 -0
  205. package/dist/lib/which.d.ts +8 -0
  206. package/dist/lib/which.d.ts.map +1 -0
  207. package/dist/lib/which.js +30 -0
  208. package/dist/lib/which.js.map +1 -0
  209. package/dist/lib/workspaces.d.ts +133 -0
  210. package/dist/lib/workspaces.d.ts.map +1 -0
  211. package/dist/lib/workspaces.js +241 -0
  212. package/dist/lib/workspaces.js.map +1 -0
  213. package/dist/lib/zod-messages.d.ts +4 -0
  214. package/dist/lib/zod-messages.d.ts.map +1 -0
  215. package/dist/lib/zod-messages.js +28 -0
  216. package/dist/lib/zod-messages.js.map +1 -0
  217. package/package.json +44 -0
@@ -0,0 +1,198 @@
1
+ # Store Ship — Pipeline Runbook
2
+
3
+ Full reference for executing a store submission. The SKILL.md contract governs; this file holds the operational detail. Real order: prereqs → scaffold → metadata as code → one-time ASC manual fixes → screenshots (Maestro) → build + submit → final metadata push → manual checklist.
4
+
5
+ ## 1. Prerequisites (verify before anything)
6
+
7
+ | Item | How to verify | Blocking? |
8
+ |---|---|---|
9
+ | Apple Developer Program membership + App Store Connect app record | ascAppId exists | Yes (iOS) |
10
+ | Play Console developer account + app record | package name registered | Yes (Android) |
11
+ | EAS project linked | `eas init` done, `extra.eas.projectId` in app config | Yes |
12
+ | Privacy policy + support URLs live | Phase 8 output, HTTP 200 | Yes — App Store Connect rejects without them |
13
+ | App Store Connect API key (p8) | stored as EAS secret / local path outside repo | Yes for `eas submit -p ios` |
14
+ | Play service-account JSON with release permission | stored outside repo | Yes for `eas submit -p android` (after first manual upload) |
15
+ | Demo account for App Review | seeded credentials that WORK in production backend | Yes — auth-gated apps are rejected without one |
16
+ | Maestro CLI + Java | `maestro --version` succeeds | Yes (screenshots) |
17
+ | EAS env vars set for every `EXPO_PUBLIC_*` the app consumes | push once with `eas env:push <environment> --path .env.local` (from the app dir); verify with `eas env:list <environment>` cross-checked against `rg -o 'EXPO_PUBLIC_[A-Z_]+' apps/<app>` output | Yes — gitignored `.env` files are NOT uploaded to EAS builds |
18
+
19
+ Maestro install: `brew install maestro` installs a different, unrelated product — do NOT use it. Install with `curl -Ls "https://get.maestro.mobile.dev" | bash`; it requires Java (`brew install openjdk`). Verify with `maestro --version`.
20
+
21
+ ## 2. eas.json
22
+
23
+ Start from `assets/eas.template.json`. Key decisions:
24
+
25
+ - `appVersionSource: "remote"` + `autoIncrement: true` on production — EAS owns build numbers; never hand-bump.
26
+ - Submit profiles reference credentials by path/env, never inline.
27
+ - Android `track: "internal"` first; promote in console or with a later `eas submit --track production`.
28
+ - Pin `"environment": "production" | "preview" | "development"` on each build profile so the matching EAS env set loads at build time. EAS cloud builds do NOT upload gitignored `.env` files — without EAS env vars, every `EXPO_PUBLIC_*` var is undefined and inlined as missing into the bundle (unfixable post-build; requires a rebuild). See §1 for the push/verify commands.
29
+ - First-ever iOS submission: `eas submit` format-validates `submit.<profile>.ios` fields (`ascAppId`, `appleTeamId`, `ascApiKeyId`, `ascApiKeyIssuerId`) before any interactive prompt — `TODO_*` placeholders hard-fail the command before you ever see a login screen. Leave `ios` as an empty object `{}` for the first submission instead: `eas submit` then prompts an Apple ID login and auto-creates the ASC app record. Fill in the real ids afterward for unattended/CI use. JSON has no comments, so this convention lives here, not in the file: an empty `"ios": {}` under `submit.<profile>` means "first submission, not yet wired for CI."
30
+
31
+ ## 3. Metadata as code
32
+
33
+ ### iOS — `eas metadata` (`store/store.config.json`)
34
+
35
+ Template: `assets/store.config.template.json`. Field limits (hard, validated by `eas metadata:validate`):
36
+
37
+ | Field | Limit |
38
+ |---|---|
39
+ | title | 30 chars |
40
+ | subtitle | 30 chars |
41
+ | keywords | 100 chars total, comma-separated |
42
+ | description | 4000 chars |
43
+ | promoText | 170 chars (editable without new build) |
44
+
45
+ The schema field is `promoText`, NOT `promotionalText` — the wrong name fails `eas metadata:push` validation. Allowed `info.<locale>` properties: `title`, `subtitle`, `description`, `keywords`, `releaseNotes`, `promoText`, `marketingUrl`, `supportUrl`, `privacyPolicyText`, `privacyPolicyUrl`, `privacyChoicesUrl`, `screenshots`, `previews`. Notably absent: `copyright`, pricing, content rights — those are never push-able (§4).
46
+
47
+ Derivation from `docs/product-definition.md`: title = product name; subtitle = the one-line value promise; description = core promise + feature list (§ features) rewritten as user benefits; keywords = domain nouns the target user searches, no competitor names, no duplicates of title words (wasted chars). Locale: use the app's UI language as primary (`es-MX` for Spanish-market apps); add `en-US` only if the app actually ships English.
48
+
49
+ es-MX copy rule: display fields the user reads (`description`, `promoText`, `subtitle`, Android `short_description`/`full_description`) MUST carry proper Spanish accents. `keywords` are the one field to write deliberately accentless — App Store search normalizes diacritics and users type without accents.
50
+
51
+ Push: `eas metadata:push` (validates first). Pull existing console state before first push: `eas metadata:pull`.
52
+
53
+ `metadataPath` wiring: when `store.config.json` lives at repo-root `store/` (this skill's layout), the submit profile in `eas.json` MUST set `"metadataPath": "../../store/store.config.json"` — `eas metadata` otherwise looks for the config next to `eas.json` and reports it missing.
54
+
55
+ Fresh ASC app: `eas metadata:push` against a just-created App Store Connect app fails with API errors ("must provide versionString", "appInfo relationship missing") until Apple initializes the 1.0 version — which happens once the FIRST binary finishes processing. This is not a config error; retry after TestFlight shows the build processed. If it still fails once the build has processed, see the one-time manual fixes in §4.
56
+
57
+ Screenshot schema: `apple.info.<locale>.screenshots` maps Apple's `screenshotDisplayType` enum keys — `APP_IPHONE_67`, `APP_IPHONE_65`, `APP_IPHONE_61`, `APP_IPAD_PRO_3GEN_129`, `APP_IPAD_PRO_3GEN_11` are the common ones — to arrays of image paths. EAS local validation does NOT catch a wrong key; only ASC rejects it at push time, and that API error helpfully lists the full enum. Paths resolve relative to the PROJECT DIRECTORY (the app dir where `eas.json` lives), NOT relative to `store.config.json` — with the repo-root `store/` layout:
58
+
59
+ ```json
60
+ "screenshots": {
61
+ "APP_IPHONE_67": ["../../store/screenshots/ios/iphone-6.9/01-signature.png"]
62
+ }
63
+ ```
64
+
65
+ This is the config shape only — the files don't exist yet until §5 captures them, and the real push (with real paths and the real demo password) is the final push in §6.
66
+
67
+ ### Android — supply tree (`store/android/`)
68
+
69
+ `eas metadata` does NOT support Play. Keep the fastlane `supply` layout (see `assets/android-supply.template.md`) so it works with fastlane or manual paste:
70
+
71
+ ```
72
+ store/android/metadata/{locale}/
73
+ title.txt # 30 chars
74
+ short_description.txt # 80 chars
75
+ full_description.txt # 4000 chars
76
+ images/phoneScreenshots/ …
77
+ ```
78
+
79
+ Upload: `fastlane supply --metadata_path store/android/metadata` if fastlane is available; otherwise paste once — the repo copy remains the source of truth.
80
+
81
+ ## 4. One-time ASC manual fixes (API-created apps)
82
+
83
+ Apps auto-created by `eas submit` (the empty `"ios": {}` first-submission convention, §2) often need manual fixes in App Store Connect before metadata syncs cleanly. Two are conditional on the API-creation path; three are ALWAYS manual for every app, API-created or not, because the `eas metadata` schema (§3) has no field for them.
84
+
85
+ | Fix | Trigger | Symptom if skipped |
86
+ |---|---|---|
87
+ | "1.0 Prepare for Submission" version exists (create if not) | Conditional — check once the first build has processed | "versionString missing", `appInfoLocalizations` relationship errors |
88
+ | App Information → Primary Language = app's locale (e.g. Spanish (Mexico)) | Conditional — same trigger | "Skipping screenshots - locale not found" |
89
+ | Copyright | ALWAYS manual — `apple.copyright` in `store.config.json` triggers a broken version-info PATCH on API-created apps that persists even after the 1.0 version exists | "must provide versionString" keeps failing after the 1.0 version exists |
90
+ | Pricing and availability | ALWAYS manual — not in the `eas metadata` schema | n/a |
91
+ | Content Rights declaration | ALWAYS manual — not in the `eas metadata` schema | n/a |
92
+
93
+ Fix once in App Store Connect, then re-push metadata (§3). Omit `copyright` from `store.config.json` — the template omits it deliberately (JSON has no comments, so this note lives here).
94
+
95
+ ## 5. Screenshots (Maestro)
96
+
97
+ ### Device matrix
98
+
99
+ | Store slot | Device | Size | Required |
100
+ |---|---|---|---|
101
+ | iPhone 6.9" | iPhone 16 Pro Max sim | 1320×2868 | Yes (covers smaller sizes since 2024) |
102
+ | iPad 13" | iPad Pro 13" sim | 2064×2752 | Only if `supportsTablet: true` |
103
+ | Play phone | Pixel emulator | ≥1080 wide, 16:9–9:16 | Yes (2–8 shots) |
104
+ | Play 7"/10" tablet | tablet emulator | ≥1080 wide | Only if tablet UI exists |
105
+
106
+ Device matrix drift: newer Xcode may ship simulator runtimes for only the latest iPhones (e.g. 17-series), so the required 6.9" device (iPhone 16 Pro Max, 1320×2868) may not exist yet — create it: `xcrun simctl create "iPhone 16 Pro Max" <devicetype-id>`. Never substitute a device with a different resolution and never resize images to fit; a wrong-resolution screenshot must be retaken on the correct device.
107
+
108
+ ### Local-backend screenshot env (recommended, self-contained)
109
+
110
+ Running screenshots against a local Supabase backend avoids polluting shared/staging data and needs no network:
111
+
112
+ 1. `supabase start` — under colima, the `vector` log-shipping container can fail to start; if it does, use `supabase start --exclude vector` instead of debugging it.
113
+ 2. After `supabase db push` to the local instance, PostgREST may return `42501 permission denied` on app tables even though the schema is correct — local `db push` does not carry over table GRANTs for the `authenticated` role. Apply `GRANT SELECT` (and any other roles the app needs) on the app tables manually. Re-apply after every `supabase db reset`, since reset wipes GRANTs too.
114
+ 3. Pass backend overrides (Supabase URL, anon key) INLINE as env vars to the build command, not via a temp `.env` file — nothing to clean up afterward and no risk of clobbering `.env.local`.
115
+
116
+ ### Procedure
117
+
118
+ 1. Seed demo data first — screenshots of empty states don't sell. Use the project's seed script with a dedicated demo user; pick data that shows the app at its best (populated lists, active membership, real-looking names).
119
+ 2. Build a dev/simulator build (`eas build --profile development` or `npx expo run:ios --configuration Release` locally, with backend env vars passed inline). Expo Go screenshots are not acceptable (dev menu chrome, wrong icon). Note: `npx expo run:ios` on a managed app generates `ios/` (verify it's gitignored), rewrites the `package.json` `ios`/`android` scripts to `expo run:*`, and may add `expo-updates` — this is expected native-project scaffolding, not damage; don't "fix" it back on a later run.
120
+ 3. Write one Maestro flow per screenshot set from `assets/maestro-flow.template.yaml`: `launchApp` → `waitForAnimationToEnd` → login as demo user → navigate → `takeScreenshot` per key screen. Always wait for animations to end before the FIRST screenshot too — the first frame after launch (and after any navigation) can still show launch-transition chrome, and a shot taken mid-transition needs retaking. 4–6 screens: the signature screen first (it is the store card image), then core loop, then differentiators.
121
+ 4. Watch for Keychain/SecureStore state surviving `clearState`: anything the app persists via SecureStore (e.g. a one-shot celebration/onboarding acknowledgement) is NOT reset by Maestro's `clearState` and will not re-trigger on a normal re-run — it needs a fresh simulator or `xcrun simctl erase <device>` to fire again. Write flows so they pass either way (don't assert on a one-shot state that may already be dismissed). One-shot moments make great store screenshots — plan a device reset into the run when you need one.
122
+ 5. Run per device: boot the simulator/emulator at the matrix size, `maestro test store/flows/screenshots.yaml -e DEMO_PASSWORD=...` (env values via `-e`, never hardcoded — see SKILL.md hard rules), move output to `store/screenshots/{platform}/{device}/NN-name.png`. Keep the screenshot output directory under `store/` next to `store.config.json` — the config's `screenshots` paths resolve relative to the PROJECT DIRECTORY, not this directory (§3).
123
+ 6. Verify: correct resolution, no status-bar clutter (simulator status bar is fine; `xcrun simctl status_bar override` to clean it), no personal data.
124
+
125
+ Framing (device bezels + captions) is optional; if requested use fastlane `frameit` or skip — plain screenshots are store-compliant.
126
+
127
+ ## 6. Build + submit
128
+
129
+ ```
130
+ eas build --platform all --profile production # wait for both artifacts
131
+ eas submit -p ios --latest # → TestFlight
132
+ eas submit -p android --latest # → internal track (fails before first manual AAB upload — expected)
133
+ ```
134
+
135
+ Verify: TestFlight shows the build processing; Play internal track lists the release. Report actual command output, not intent.
136
+
137
+ `eas submit` ALWAYS runs the submission job on EAS servers — even with `--path <local-ipa>` it uploads your ipa and an EAS worker delivers it to Apple, so the build/submit queue applies either way.
138
+
139
+ ### Queue-free local submission (iOS)
140
+
141
+ Fully local paths that skip the EAS queue, all present on a standard Mac setup:
142
+
143
+ - `xcrun altool --upload-app -f <ipa> -t ios` (still shipping in Xcode 26) — auth with an app-specific password (`-u`/`-p`) or an ASC API key (`--apiKey`/`--apiIssuer`, `.p8` at `~/.appstoreconnect/private_keys/AuthKey_<KEYID>.p8`).
144
+ - Transporter.app GUI, or its CLI: `/Applications/Transporter.app/Contents/itms/bin/iTMSTransporter`.
145
+ - `fastlane pilot upload`.
146
+
147
+ Recommended durable path: create the team's OWN ASC API key (App Manager role, `.p8` in gitignored `secrets/`) — one key powers altool, pilot, and non-interactive automation. Note: the EAS-generated ASC key lives on EAS servers and cannot be downloaded, so it cannot back these local paths.
148
+
149
+ ### `eas build --local`
150
+
151
+ - Requires fastlane (fails with `spawn fastlane ENOENT`) and CocoaPods installed locally.
152
+ - Credentials, EAS env vars, and remote `autoIncrement` all still sync from EAS servers — a local build is not an offline build.
153
+ - The artifact lands as `build-<timestamp>.ipa` in the app dir.
154
+ - SECURITY: the local build job payload echoed to the terminal embeds the provisioning profile AND the distribution certificate with its password (base64). Build logs are sensitive — never paste them publicly; rotate via `eas credentials` if exposed.
155
+
156
+ ### Wrap the working chain in npm scripts
157
+
158
+ Once the chain works end to end, freeze it as root `package.json` scripts so future runs are one command: `deploy:<web-surface>` (build + deploy + alias + HTTP-200 verification), `deploy:ios` (preflight fastlane/pods → local build → pick newest `build-*.ipa` → submit), `env:push:mobile`, and `metadata:push`. Deliberately add NO `deploy:android` until a Play presence exists — it would be a dead script.
159
+
160
+ ### Final metadata push (after build + submit)
161
+
162
+ Screenshots (§5) and the demo password only belong in the config once they're real, and the password should spend the least possible time on disk — so this push is last, not part of the initial metadata authoring in §3:
163
+
164
+ 1. Add the real screenshot paths to `apple.info.<locale>.screenshots` (key/path format in §3).
165
+ 2. Inject the real demo account password into `apple.review.demoPassword`.
166
+ 3. `eas metadata:push`.
167
+ 4. Immediately revert the password field to its placeholder.
168
+ 5. Verify with `rg` that no real credential remains in `store/` before committing — this is what keeps the "no credentials in repo" hard rule true.
169
+
170
+ ## 7. Manual checklist (cannot be automated — always deliver)
171
+
172
+ - App Store Connect: App Privacy questionnaire (data collection declarations — derive answers from what the app actually collects and hands to Supabase/analytics).
173
+ - App Store Connect: age rating questionnaire.
174
+ - App Review notes: demo account credentials + any reviewer instructions (e.g. "accounts are admin-created; use the demo login").
175
+ - Play Console: content rating questionnaire, data safety form, first AAB upload by hand.
176
+ - Both: confirm pricing/availability, territories, and (iOS) the Content Rights declaration — always manual, see §4.
177
+
178
+ ## 8. Troubleshooting
179
+
180
+ | Symptom | Cause / fix |
181
+ |---|---|
182
+ | `eas metadata:push` auth error | ASC API key missing/expired — recreate in App Store Connect → Users and Access → Keys |
183
+ | Submit rejected: missing privacy URL | Phase 8 not deployed — hard prerequisite |
184
+ | Play submit 403 | service account lacks release permission, or first AAB never uploaded manually |
185
+ | Screenshot wrong size | simulator device ≠ matrix device; do not resize with sips — retake |
186
+ | Metadata rejected for claims | copy promised features the build doesn't have — re-derive from product definition, not marketing wishes |
187
+ | `eas submit` fails instantly, no login prompt | `TODO_*` placeholder ids in `submit.<profile>.ios` — use `"ios": {}` for the first submission (§2) |
188
+ | `maestro --version` not found / wrong tool | installed via `brew install maestro` (wrong product) — reinstall per §1 |
189
+ | PostgREST `42501 permission denied` on local Supabase | table GRANTs missing after local `db push`/`db reset` (§5 local-backend env) |
190
+ | `supabase start` hangs/fails under colima | `vector` container failing (§5 local-backend env) |
191
+ | Screenshot shows launch chrome / blank frame | missing `waitForAnimationToEnd` after `launchApp` or a nav tap (§5 procedure) |
192
+ | One-shot UI (celebration/onboarding) never appears for its screenshot | SecureStore/Keychain survives Maestro `clearState` (§5 procedure step 4) |
193
+ | Build/TestFlight can't reach backend, dev works locally | `EXPO_PUBLIC_*` vars missing at EAS build time — push env vars (§1) and REBUILD |
194
+ | `eas metadata:push` fails: "must provide versionString" / "appInfo relationship missing" | before first build processes: ASC hasn't initialized the 1.0 version yet, retry later; persists after: either the §4 manual fixes are still needed, or `apple.copyright` is set in the config |
195
+ | "Skipping screenshots - locale not found" / `appInfoLocalizations` errors | wrong primary language or no 1.0 version — see §4 |
196
+ | Screenshot key rejected at push time only | wrong `screenshotDisplayType` enum key (e.g. `iphone67`) — must be `APP_IPHONE_67` etc.; EAS local validation doesn't catch it (§3) |
197
+ | `eas metadata:push` validation rejects a field name | field not in the schema (e.g. `promotionalText` — real name is `promoText`, §3) |
198
+ | `eas build --local` fails: `spawn fastlane ENOENT` | fastlane (and CocoaPods) missing locally — install both (§6) |
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: stripe
3
+ description: Integración de pagos con Stripe — selección de API (Checkout/Payment/Setup Intents), claves restringidas, idempotencia y verificación de webhooks. Trigger: al crear cobros, checkout, suscripciones o handlers de webhook de Stripe.
4
+ ---
5
+
6
+ # Stripe — el patrón canónico
7
+
8
+ Alineado con la skill oficial `stripe-best-practices`. El server manda: la lógica de cobro y las claves `sk_`/`rk_` viven en el backend; el cliente solo toca la publishable key.
9
+
10
+ ## Cuándo usar este skill
11
+
12
+ Al crear un cobro, checkout, suscripciones, o un handler de webhook de Stripe.
13
+
14
+ ## Qué API usar
15
+
16
+ | Caso | API |
17
+ |---|---|
18
+ | Pago único on-session | **Checkout Session** |
19
+ | Form propio embebido | Checkout Session + **Payment Element** |
20
+ | Guardar método de pago (sin cobrar) | **Setup Intent** |
21
+ | Suscripciones / recurrente | **Billing** + Checkout Session |
22
+ | Marketplace / plataforma | **Accounts v2** (`/v2/core/accounts`) |
23
+ | Impuestos (IVA/VAT/GST) | **Stripe Tax** + Registrations API |
24
+
25
+ **Nunca uses la Charges API** (legacy): si te topas con ella, migra a Checkout Session o Payment Intent — no le agregues features.
26
+
27
+ ## Seguridad de claves
28
+
29
+ Tres tipos: **publishable** (`pk_`, cliente), **secret** (`sk_`, server) y **restricted** (`rk_`, server con scope acotado). Prefiere **`rk_` sobre `sk_`**. Las claves van en env vars; la `sk_`/`rk_` **jamás** entra al bundle del cliente.
30
+
31
+ ## El patrón (server-side)
32
+
33
+ ```ts
34
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
35
+ apiVersion: '2026-06-24.dahlia', // fija la última; no dejes el default de la cuenta
36
+ });
37
+
38
+ // idempotencyKey: reintentar la misma request NO crea un segundo cobro.
39
+ const session = await stripe.checkout.sessions.create(
40
+ {
41
+ mode: 'payment',
42
+ line_items: [{ price: priceId, quantity: 1 }],
43
+ success_url: `${base}/ok?session_id={CHECKOUT_SESSION_ID}`,
44
+ cancel_url: `${base}/cancel`,
45
+ // Sin payment_method_types: deja los dynamic payment methods del Dashboard.
46
+ },
47
+ { idempotencyKey: `checkout:${orderId}` },
48
+ );
49
+ ```
50
+
51
+ ## Webhooks
52
+
53
+ El estado real llega por webhook, no por el `success_url`. Verifica **siempre** la firma y hazlo idempotente:
54
+
55
+ ```ts
56
+ // rawBody = cuerpo crudo, NO el JSON parseado (el body-parser rompe la firma).
57
+ const event = stripe.webhooks.constructEvent(rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET!);
58
+ if (await alreadyProcessed(event.id)) return res.sendStatus(200); // el event.id puede repetirse
59
+ ```
60
+
61
+ Responde `2xx` rápido; el trabajo pesado va a una cola.
62
+
63
+ ## Gotchas que muerden
64
+
65
+ - **`payment_method_types` fijo** apaga los dynamic payment methods del Dashboard. Omítelo (única excepción: Terminal → `['card_present']`); para restringir usa `payment_method_configurations` o `excluded_payment_method_types`.
66
+ - **`automatic_tax: { enabled: true }` sin registro fiscal activo** cobra **cero** impuesto pareciendo habilitado — el error más común y silencioso. Verifica el registro antes.
67
+ - **Montos en la unidad mínima y enteros** (centavos: $10.00 → `1000`). Nunca floats.
68
+
69
+ ## Reglas duras
70
+
71
+ 1. Cobro y claves `sk_`/`rk_` solo en el server (env vars); el cliente solo con `pk_`. Prefiere `rk_` sobre `sk_`.
72
+ 2. `apiVersion` fija a la última; nada de default implícito.
73
+ 3. Charges API prohibida en código nuevo.
74
+ 4. `idempotencyKey` en toda request de creación que mueva dinero.
75
+ 5. Webhooks: firma verificada con `rawBody` + handler idempotente por `event.id`.
76
+ 6. Sin `payment_method_types` salvo Terminal.
77
+
78
+ ## Antes de declarar listo
79
+
80
+ - Ninguna `sk_`/`rk_` quedó en el cliente ni en el repo.
81
+ - Cada cobro lleva `idempotencyKey`; el pago se confirma por webhook (firma + idempotente), no por el redirect.
82
+ - Si hay impuestos: registro fiscal activo verificado.
83
+ - El quality gate del repo (`qualityGate.fast` en `argos.config.json`) en verde.
@@ -0,0 +1,193 @@
1
+ ---
2
+ name: tailwind-4
3
+ description: Tailwind CSS 4 patterns and best practices. Trigger: When styling with Tailwind - cn(), theme variables, no var() in className.
4
+ ---
5
+
6
+ ## Styling Decision Tree
7
+
8
+ ```
9
+ Tailwind class exists? → className="..."
10
+ Dynamic value? → style={{ width: `${x}%` }}
11
+ Conditional styles? → cn("base", condition && "variant")
12
+ Static only? → className="..." (no cn() needed)
13
+ Library can't use class?→ style prop with var() constants
14
+ ```
15
+
16
+ ## Critical Rules
17
+
18
+ ### Never Use var() in className
19
+
20
+ ```typescript
21
+ // ❌ NEVER: var() in className
22
+ <div className="bg-[var(--color-primary)]" />
23
+ <div className="text-[var(--text-color)]" />
24
+
25
+ // ✅ ALWAYS: Use Tailwind semantic classes
26
+ <div className="bg-primary" />
27
+ <div className="text-slate-400" />
28
+ ```
29
+
30
+ ### Never Use Hex Colors
31
+
32
+ ```typescript
33
+ // ❌ NEVER: Hex colors in className
34
+ <p className="text-[#ffffff]" />
35
+ <div className="bg-[#1e293b]" />
36
+
37
+ // ✅ ALWAYS: Use Tailwind color classes
38
+ <p className="text-white" />
39
+ <div className="bg-slate-800" />
40
+ ```
41
+
42
+ ## The cn() Utility
43
+
44
+ ```typescript
45
+ import { clsx } from "clsx";
46
+ import { twMerge } from "tailwind-merge";
47
+
48
+ export function cn(...inputs: ClassValue[]) {
49
+ return twMerge(clsx(inputs));
50
+ }
51
+ ```
52
+
53
+ ### When to Use cn()
54
+
55
+ ```typescript
56
+ // ✅ Conditional classes
57
+ <div className={cn("base-class", isActive && "active-class")} />
58
+
59
+ // ✅ Merging with potential conflicts
60
+ <button className={cn("px-4 py-2", className)} /> // className might override
61
+
62
+ // ✅ Multiple conditions
63
+ <div className={cn(
64
+ "rounded-lg border",
65
+ variant === "primary" && "bg-blue-500 text-white",
66
+ variant === "secondary" && "bg-gray-200 text-gray-800",
67
+ disabled && "opacity-50 cursor-not-allowed"
68
+ )} />
69
+ ```
70
+
71
+ ### When NOT to Use cn()
72
+
73
+ ```typescript
74
+ // ❌ Static classes - unnecessary wrapper
75
+ <div className={cn("flex items-center gap-2")} />
76
+
77
+ // ✅ Just use className directly
78
+ <div className="flex items-center gap-2" />
79
+ ```
80
+
81
+ ## Style Constants for Charts/Libraries
82
+
83
+ When libraries don't accept className (like Recharts):
84
+
85
+ ```typescript
86
+ // ✅ Constants with var() - ONLY for library props
87
+ const CHART_COLORS = {
88
+ primary: "var(--color-primary)",
89
+ secondary: "var(--color-secondary)",
90
+ text: "var(--color-text)",
91
+ gridLine: "var(--color-border)",
92
+ };
93
+
94
+ // Usage with Recharts (can't use className)
95
+ <XAxis tick={{ fill: CHART_COLORS.text }} />
96
+ <CartesianGrid stroke={CHART_COLORS.gridLine} />
97
+ ```
98
+
99
+ ## Dynamic Values
100
+
101
+ ```typescript
102
+ // ✅ style prop for truly dynamic values
103
+ <div style={{ width: `${percentage}%` }} />
104
+ <div style={{ opacity: isVisible ? 1 : 0 }} />
105
+
106
+ // ✅ CSS custom properties for theming
107
+ <div style={{ "--progress": `${value}%` } as React.CSSProperties} />
108
+ ```
109
+
110
+ ## Common Patterns
111
+
112
+ ### Flexbox
113
+
114
+ ```typescript
115
+ <div className="flex items-center justify-between gap-4" />
116
+ <div className="flex flex-col gap-2" />
117
+ <div className="inline-flex items-center" />
118
+ ```
119
+
120
+ ### Grid
121
+
122
+ ```typescript
123
+ <div className="grid grid-cols-3 gap-4" />
124
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6" />
125
+ ```
126
+
127
+ ### Spacing
128
+
129
+ ```typescript
130
+ // Padding
131
+ <div className="p-4" /> // All sides
132
+ <div className="px-4 py-2" /> // Horizontal, vertical
133
+ <div className="pt-4 pb-2" /> // Top, bottom
134
+
135
+ // Margin
136
+ <div className="m-4" />
137
+ <div className="mx-auto" /> // Center horizontally
138
+ <div className="mt-8 mb-4" />
139
+ ```
140
+
141
+ ### Typography
142
+
143
+ ```typescript
144
+ <h1 className="text-2xl font-bold text-white" />
145
+ <p className="text-sm text-slate-400" />
146
+ <span className="text-xs font-medium uppercase tracking-wide" />
147
+ ```
148
+
149
+ ### Borders & Shadows
150
+
151
+ ```typescript
152
+ <div className="rounded-lg border border-slate-700" />
153
+ <div className="rounded-full shadow-lg" />
154
+ <div className="ring-2 ring-blue-500 ring-offset-2" />
155
+ ```
156
+
157
+ ### States
158
+
159
+ ```typescript
160
+ <button className="hover:bg-blue-600 focus:ring-2 active:scale-95" />
161
+ <input className="focus:border-blue-500 focus:outline-none" />
162
+ <div className="group-hover:opacity-100" />
163
+ ```
164
+
165
+ ### Responsive
166
+
167
+ ```typescript
168
+ <div className="w-full md:w-1/2 lg:w-1/3" />
169
+ <div className="hidden md:block" />
170
+ <div className="text-sm md:text-base lg:text-lg" />
171
+ ```
172
+
173
+ ### Dark Mode
174
+
175
+ ```typescript
176
+ <div className="bg-white dark:bg-slate-900" />
177
+ <p className="text-gray-900 dark:text-white" />
178
+ ```
179
+
180
+ ## Arbitrary Values (Escape Hatch)
181
+
182
+ ```typescript
183
+ // ✅ OK for one-off values not in design system
184
+ <div className="w-[327px]" />
185
+ <div className="top-[117px]" />
186
+ <div className="grid-cols-[1fr_2fr_1fr]" />
187
+
188
+ // ❌ Don't use for colors - use theme instead
189
+ <div className="bg-[#1e293b]" /> // NO
190
+ ```
191
+
192
+ ## Keywords
193
+ tailwind, css, styling, cn, utility classes, responsive
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: tamagui
3
+ description: UI con Tamagui v4 — styled() + variants, tokens de tema y qué mantiene contento al compiler. Trigger: al crear componentes con estilo, definir el design system o tocar la config/tema.
4
+ ---
5
+
6
+ # Tamagui — el patrón canónico
7
+
8
+ Componentes con `styled()` y **variants**; estilos por **tokens** de tema (`$`), no por valores hardcodeados. El compiler extrae en build lo que sea estático — el trabajo es no romperlo.
9
+
10
+ ## Cuándo usar este skill
11
+
12
+ Al crear un componente con estilo, definir tokens/themes del design system, o tocar `createTamagui`.
13
+
14
+ ## Config
15
+
16
+ ```tsx
17
+ import { defaultConfig } from '@tamagui/config/v4'
18
+ import { createTamagui, styled, View } from 'tamagui'
19
+
20
+ export const config = createTamagui({
21
+ ...defaultConfig,
22
+ settings: { ...defaultConfig.settings, styleCompat: 'react-native' },
23
+ })
24
+ declare module 'tamagui' { interface TamaguiCustomConfig extends typeof config {} }
25
+ ```
26
+
27
+ El `declare module` da props tipadas y autocompletado en todo el proyecto. Elige **un solo paquete de import** (`tamagui` o `@tamagui/core`), no ambos.
28
+
29
+ ## styled() + variants (no condicionales inline)
30
+
31
+ ```tsx
32
+ const Box = styled(View, {
33
+ variants: {
34
+ tone: { danger: { bg: '$red10' }, ok: { bg: '$green10' } },
35
+ } as const,
36
+ })
37
+ ```
38
+
39
+ Prefiere variants sobre `bg={isError ? '$red10' : '$green10'}`: los valores runtime rompen el flattening del compiler. Usa `as const` en `variants`.
40
+
41
+ ## Reglas duras
42
+
43
+ 1. **Tokens en props** (`bg="$blue10"`, `p="$4"`, `color="$color"`), nunca `style={{...}}` con variables ni `StyleSheet` de RN (no resuelven tokens).
44
+ 2. **No rompas el compiler:** evita valores runtime (`width={w*0.5}`), funciones inline y spreads no deterministas en props de estilo. Muévelos a variants.
45
+ 3. **Themes semánticos** (`success`/`warning`/`error`) vía `createThemes`; colorea por contexto con `<Theme name="...">`, no con hex hardcodeado. Al definir el theme, sin `$`; al consumir, con `$`.
46
+ 4. **Orden de props = prioridad:** lo que va después de un `{...spread}` gana; en `variants`, la primera listada gana.
47
+ 5. **Animaciones:** driver `react-native-reanimated` en native; anima con `enterStyle`/`exitStyle`, `pressStyle`/`hoverStyle` y `AnimatePresence` para salidas.
48
+ 6. **Ramifica plataforma con `Adapt`** (Dialog/Sheet), no con `Platform.OS`.
49
+ 7. Al envolver un `styled`, usa `.styleable()` para preservar variantes.
50
+
51
+ ## Dev vs prod
52
+
53
+ `disableExtraction: true` en dev (HMR más rápido); extracción completa en prod. Ignora `.tamagui/` en git.
54
+
55
+ ## Antes de declarar listo
56
+
57
+ - Estilos por tokens `$`, no hardcodeados ni `style` inline con variables.
58
+ - Lógica condicional de estilo en `variants`, no inline (compiler-friendly).
59
+ - Un solo paquete de import; `declare module` registrado.
60
+ - El quality gate del repo (`qualityGate.fast` en `argos.config.json`) en verde.
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: tanstack-query
3
+ description: Patrones de TanStack Query (React Query) — query keys, mutations, invalidación, staleTime. Trigger: al tocar fetching, cache de servidor o mutaciones de datos remotos.
4
+ ---
5
+
6
+ # TanStack Query — convenciones
7
+
8
+ ## Cuándo usar este skill
9
+
10
+ Al leer/escribir datos del servidor: un `useQuery`, un `useMutation`, invalidar cache, o paginar. TanStack Query es la fuente de verdad del **estado de servidor** (fetch + cache + revalidación). No lo uses para estado de cliente puro (eso es useState/Redux), ni dupliques su data en otro store.
11
+
12
+ ## El patrón
13
+
14
+ Query keys estructuradas y centralizadas para invalidar sin strings sueltos:
15
+
16
+ ```ts
17
+ const sessionKeys = {
18
+ all: ['sessions'] as const,
19
+ detail: (id: string) => [...sessionKeys.all, id] as const,
20
+ };
21
+
22
+ const { data, isPending, error } = useQuery({
23
+ queryKey: sessionKeys.detail(id),
24
+ queryFn: () => api.getSession(id),
25
+ staleTime: 30_000,
26
+ enabled: Boolean(id),
27
+ });
28
+
29
+ const mutation = useMutation({
30
+ mutationFn: api.updateSession,
31
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: sessionKeys.all }),
32
+ });
33
+ ```
34
+
35
+ ## Gotchas que muerden
36
+
37
+ - **Query keys como datos, no strings.** Una factory (`sessionKeys`) evita typos y permite invalidar por prefijo (`sessionKeys.all` invalida todos los detalles).
38
+ - **`staleTime` vs `gcTime`.** `staleTime` decide cuándo refetchea; con `0` (default) refetchea agresivo. Súbelo para data estable y evita parpadeos/llamadas extra.
39
+ - **No espejes la data en useState/Redux.** Lee de `data` directo; copiarla a otro estado crea dos verdades que se desincronizan.
40
+ - **`enabled`** para queries dependientes — no dispares con el id aún `undefined`.
41
+ - **`useQuery` NO tiene `onSuccess`/`onError`/`onSettled`** (v5 los eliminó; solo sobreviven en `useMutation`). Para reaccionar a la data, hazlo en render o con `select`. Es el gotcha #1 al migrar de v4: el callback simplemente nunca corre.
42
+ - **Update optimista completo**: en `onMutate` haz `await queryClient.cancelQueries({ queryKey })` (sin esto, un refetch en vuelo pisa tu update), snapshot con `getQueryData`, aplica con `setQueryData`; restaura el snapshot en `onError`; `invalidateQueries` en `onSettled`.
43
+ - **`isPending` vs `isFetching`**: `isPending` es la primera carga sin data; `isFetching` es cualquier fetch en curso (incluye revalidación). Paginación: `placeholderData: keepPreviousData` (v5 reemplazó `keepPreviousData: true`).
44
+
45
+ ## Reglas duras
46
+
47
+ 1. Estado de servidor vive en Query; no se copia a otro store.
48
+ 2. Query keys desde una factory tipada, nunca arrays literales dispersos.
49
+ 3. Tras una mutation, invalida las keys afectadas.
50
+ 4. `enabled` en queries dependientes; nada de queries con params inválidos.
51
+ 5. `staleTime` explícito cuando la data no cambia cada segundo.
52
+
53
+ ## Antes de declarar listo
54
+
55
+ - Las keys nuevas salen de la factory y se invalidan tras mutar.
56
+ - Ningún dato de query duplicado en useState/Redux.
57
+ - Las queries dependientes usan `enabled`.
58
+ - El quality gate del repo (`qualityGate.fast` en `argos.config.json`) en verde.
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: ticket-intake
3
+ description: Aterrizaje en el repo + pipeline canónico de 8 fases para procesar un ticket (ID, URL o texto pegado) con gates objetivos, en cualquier repo con argos.config.json. Trigger: llega un ticket o una tarea no trivial y hay que auditar, implementar, revisar y abrir el PR.
4
+ ---
5
+
6
+ # ticket-intake — aterrizaje + pipeline de 8 fases
7
+
8
+ ## Cuándo usar este skill
9
+
10
+ Cuando llega un ticket (ID, URL o texto pegado) y la tarea no es trivial. Orquesta el ciclo encadenando agentes y skills del motor global de Argos con gates objetivos: el contexto que pagas con tokens en una fase queda escrito para la siguiente, sin depender de la memoria del modelo. Los agentes de rol (`ticket-audit`, `explorer`, `implementer`, `reviewer`, las lentes 4R, `commit-pr-pilot`) viven una sola vez en `~/.claude/agents/` y están disponibles en cualquier sesión — pero los hooks globales parametrizados y sus gates automáticos solo disparan dentro de una sesión anclada en la raíz del repo (ver Fase 0).
11
+
12
+ ## Fase 0 — Aterrizaje + Triage
13
+
14
+ Antes de tocar el ticket, verifica el contexto del repo. No asumas nada de sesiones anteriores.
15
+
16
+ 1. **Sesión anclada**: si el cwd de la sesión está por debajo de la raíz real del repo, Claude Code descubre agentes/skills/hooks solo desde el cwd hacia arriba, nunca hacia abajo — la config que vive en la raíz puede no cargar. Recomienda anclar la sesión en la raíz del repo antes de encarar trabajo no trivial.
17
+ 2. **`argos.config.json` presente**: si falta, sugiere correr `argos adopt`. Nunca lo corras unilateralmente — propónlo y espera confirmación explícita del usuario.
18
+ 3. **Ficha fresca**: si la ficha del repo (el CLAUDE.md delgado) se ve desactualizada, o el stack/las dependencias del repo divergieron de lo que declara (nueva librería, otro quality gate, otro framework), sugiere `argos adopt --refresh`.
19
+ 4. **Repo no clonado**: si el ticket referencia un repo que todavía no existe en esta máquina, primero clónalo respetando las reglas de identidad — el remote debe usar el alias SSH que matchea el workspace correcto (`bonum` / `personal`, según las match rules por remote/path registradas en `~/.argos/workspaces.json`) — y recién ahí corre `argos adopt`.
20
+ 5. **Triage propiamente dicho**: `mem_search`, `cat progress/current.md`, `git status`/`git log`. Trivial (≤1 archivo, ≤5 líneas, sin lógica) → salta directo a Fase 5. Si `current.md` no está en `idle` con OTRO ticket, pregunta antes de seguir; nunca dos tickets en paralelo sobre el mismo `current.md`.
21
+
22
+ **Gate de Fase 0**: no entres al pipeline (Fase 1 en adelante) hasta que 1-3 queden resueltos, o el usuario haya confirmado explícitamente seguir sin ellos a sabiendas de que algún gate automático puede no disparar.
23
+
24
+ ## Pipeline (fases 1–8)
25
+
26
+ Cada fase escribe en `.claude/progress/` — ruta relativa a la raíz de ESTE repo, nunca al motor global; crea el directorio si no existe. El gate de cada fase es bloqueante.
27
+
28
+ | Fase | Quién la cubre | Artefacto / Gate |
29
+ |---|---|---|
30
+ | 1 · Context (opc.) | tú: CLI del tracker (`acli` / `jira` / `gh issue view`) | Si solo hay texto pegado, salta a 2 con él. |
31
+ | 2 · AUDIT | agente `ticket-audit` | `audit_<ID>.md`: root cause/approach, archivos, alternativas, preguntas, tasks. **Gate: el usuario lo aprueba.** |
32
+ | 3 · EXPLORE (opc.) | 2-3 agentes `explorer` en un solo mensaje (paralelo real, ver orquestación) | Un `explore_<dim>.md` por dimensión (handler, schema, side-effects, caller, memoria). **Gate: validas que el approach del audit sigue vivo.** |
33
+ | 4 · DESIGN (opc.) | agente `implementer` | Solo si hay patrón o librería nueva: presenta 2-3 approaches con tradeoffs y espera OK explícito. Si no aplica, salta a 5. |
34
+ | 5 · IMPLEMENT | UN agente `implementer` | Lee la ficha del repo (CLAUDE.md delgado) → `audit_<ID>.md` → `explore_*.md` → skill aplicable. Produce `impl_<feature>.md`. **Gate: el quality gate fast del repo — resuelto en runtime desde `qualityGate.fast` en `argos.config.json` o la ficha, nunca un comando asumido — verde en este turno.** |
35
+ | 6 · VERIFY | skill `verify-before-done` (la corre el `implementer`) | `impl_<feature>.md` con "Verify ejecutado en este turno" en exit 0 + smoke del endpoint. Sin evidencia fresca → vuelve a 5. |
36
+ | 7 · REVIEW | agente `reviewer` + skill `review-diff` (+ lentes 4R en paralelo si el diff es de riesgo — ver tabla de perfil en el bloque de orquestación) | `review_<feature>.md`. Two-stage; Stage 1 falla → `CHANGES_REQUESTED`, vuelve a 5 con un `implementer` FRESCO (agente nuevo, no el mismo con el transcript viejo). `APPROVED` → sigue. **Cap: 2 ciclos `CHANGES_REQUESTED` sobre el mismo ticket → escala al usuario en vez de reintentar en loop.** |
37
+ | 8 · PR + CLOSE | agente `commit-pr-pilot` (aplica skill `pr-create`) | Pre-flight del pilot: working tree limpio, no estás en la rama base ni en la `prTarget` del repo (resueltas del `argos.config.json`/ficha), quality gate verde, `gh auth status` ok. PR creado y URL al usuario; luego `mem_save`, entrada en `history.md`, `current.md` a `idle` y `mem_session_summary`. |
38
+
39
+ ## Reglas duras
40
+
41
+ - **La Fase 2 no se salta en tarea no-trivial** "porque ya entendiste el ticket". El audit es para el `implementer` (y para ti en 3 días); delégalo a `ticket-audit`.
42
+ - **El `implementer` arranca leyendo `audit_<ID>.md`** o pierdes contexto ya pagado con tokens.
43
+ - **El `reviewer` no aprueba sin Stage 1;** la aprobación NO depende del `implementer`.
44
+ - **No hay PR sin `APPROVED`** ni dos tickets en paralelo sobre el mismo `current.md`.
45
+ - **Trivial** = ≤1 archivo, ≤5 líneas, sin lógica.
46
+ - **Sin `argos.config.json` ni ficha**, no asumas un quality gate ni una `prTarget` fija — léelos del repo (o de `package.json`/scripts si ninguno existe) antes de declarar un gate verde, y sugiere `argos adopt` (Fase 0) antes de avanzar.
47
+
48
+ ## Antes de declarar listo
49
+
50
+ - La Fase 0 corrió: sesión anclada (o advertida), `argos.config.json`/ficha resueltos o el usuario confirmó seguir sin ellos.
51
+ - El ciclo cerró con un PR vía `commit-pr-pilot` (skill `pr-create`) y su URL al usuario; `current.md` en `idle`.
52
+ - Hubo `mem_save` de toda decisión no obvia y `mem_session_summary`.
53
+ - Si fue no-trivial: existen `audit_<ID>.md` aprobado, `impl_<feature>.md` con verify en exit 0 y `review_<feature>.md` en `APPROVED`.
54
+
55
+ Este skill vive una sola vez en el motor global (`~/.claude/skills/`) y aplica a cualquier repo con `argos.config.json`. Ningún comando de quality gate, rama base/destino o alias de identidad vive hardcodeado aquí: todo se resuelve en runtime leyendo la config o la ficha del repo donde se está trabajando.