@causyne/agent 0.0.0-stage → 1.10.1

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 (274) hide show
  1. package/LICENSE +102 -0
  2. package/README.md +31 -2
  3. package/SECURITY.md +24 -0
  4. package/bin/causyne.js +13 -0
  5. package/docs/ARCHITECTURE.md +63 -0
  6. package/docs/PROVENANCE.md +29 -0
  7. package/docs/SECURITY_REVIEW.md +89 -0
  8. package/docs/THIRD_PARTY_NOTICES.md +49 -0
  9. package/native-skills/ai-engineering/context-window-management/SKILL.md +43 -0
  10. package/native-skills/ai-engineering/llm-evaluation/SKILL.md +46 -0
  11. package/native-skills/ai-engineering/model-cost-and-latency/SKILL.md +46 -0
  12. package/native-skills/ai-engineering/prompt-construction/SKILL.md +42 -0
  13. package/native-skills/ai-engineering/retrieval-augmented-generation/SKILL.md +42 -0
  14. package/native-skills/ai-engineering/structured-output-and-schemas/SKILL.md +45 -0
  15. package/native-skills/ai-engineering/tool-calling-agents/SKILL.md +43 -0
  16. package/native-skills/android/app-performance-profiling/SKILL.md +42 -0
  17. package/native-skills/android/background-work-scheduling/SKILL.md +47 -0
  18. package/native-skills/android/compose-state-and-recomposition/SKILL.md +43 -0
  19. package/native-skills/android/gradle-build-configuration/SKILL.md +41 -0
  20. package/native-skills/android/lifecycle-and-leaks/SKILL.md +46 -0
  21. package/native-skills/android/play-store-release/SKILL.md +43 -0
  22. package/native-skills/android/room-and-persistence/SKILL.md +40 -0
  23. package/native-skills/backend/authentication-and-sessions/SKILL.md +45 -0
  24. package/native-skills/backend/background-jobs-and-queues/SKILL.md +42 -0
  25. package/native-skills/backend/caching-strategy/SKILL.md +44 -0
  26. package/native-skills/backend/graceful-shutdown/SKILL.md +42 -0
  27. package/native-skills/backend/rate-limiting-and-quotas/SKILL.md +40 -0
  28. package/native-skills/backend/rest-api-design/SKILL.md +40 -0
  29. package/native-skills/backend/webhook-delivery-and-receipt/SKILL.md +43 -0
  30. package/native-skills/cloud/cost-optimisation/SKILL.md +46 -0
  31. package/native-skills/cloud/iam-least-privilege/SKILL.md +43 -0
  32. package/native-skills/cloud/infrastructure-as-code/SKILL.md +43 -0
  33. package/native-skills/cloud/multi-region-and-failover/SKILL.md +43 -0
  34. package/native-skills/cloud/serverless-patterns/SKILL.md +47 -0
  35. package/native-skills/data/data-quality-monitoring/SKILL.md +51 -0
  36. package/native-skills/data/etl-pipeline-reliability/SKILL.md +43 -0
  37. package/native-skills/data/exploratory-analysis/SKILL.md +43 -0
  38. package/native-skills/data/metric-definition/SKILL.md +42 -0
  39. package/native-skills/data/notebook-to-production/SKILL.md +43 -0
  40. package/native-skills/database/backup-and-recovery/SKILL.md +43 -0
  41. package/native-skills/database/connection-pooling/SKILL.md +42 -0
  42. package/native-skills/database/data-integrity-and-constraints/SKILL.md +42 -0
  43. package/native-skills/database/query-optimisation/SKILL.md +38 -0
  44. package/native-skills/database/safe-migrations/SKILL.md +47 -0
  45. package/native-skills/database/schema-design/SKILL.md +38 -0
  46. package/native-skills/database/transactions-and-isolation/SKILL.md +41 -0
  47. package/native-skills/design/colour-system-construction/SKILL.md +38 -0
  48. package/native-skills/design/design-direction-brief/SKILL.md +41 -0
  49. package/native-skills/design/motion-and-transitions/SKILL.md +38 -0
  50. package/native-skills/design/responsive-strategy/SKILL.md +39 -0
  51. package/native-skills/design/spacing-and-rhythm/SKILL.md +38 -0
  52. package/native-skills/design/type-scale-and-hierarchy/SKILL.md +39 -0
  53. package/native-skills/design/visual-qa-loop/SKILL.md +42 -0
  54. package/native-skills/devops/docker-multi-stage-builds/SKILL.md +60 -0
  55. package/native-skills/devops/github-actions-ci/SKILL.md +60 -0
  56. package/native-skills/devops/incident-triage/SKILL.md +38 -0
  57. package/native-skills/devops/kubernetes-deployment-hardening/SKILL.md +64 -0
  58. package/native-skills/devops/observability-baseline/SKILL.md +38 -0
  59. package/native-skills/devops/secret-management/SKILL.md +40 -0
  60. package/native-skills/devops/terraform-state-and-modules/SKILL.md +36 -0
  61. package/native-skills/devops/zero-downtime-deploys/SKILL.md +40 -0
  62. package/native-skills/git/bisect-regression-hunt/SKILL.md +43 -0
  63. package/native-skills/git/branch-strategy/SKILL.md +39 -0
  64. package/native-skills/git/commit-hygiene/SKILL.md +41 -0
  65. package/native-skills/git/history-recovery/SKILL.md +44 -0
  66. package/native-skills/git/large-repository-surgery/SKILL.md +46 -0
  67. package/native-skills/git/merge-conflict-resolution/SKILL.md +42 -0
  68. package/native-skills/media/cinematic-3d-shot/SKILL.md +104 -0
  69. package/native-skills/mobile/app-startup-optimisation/SKILL.md +41 -0
  70. package/native-skills/mobile/cross-platform-tradeoffs/SKILL.md +42 -0
  71. package/native-skills/mobile/deep-linking/SKILL.md +39 -0
  72. package/native-skills/mobile/mobile-storage-security/SKILL.md +45 -0
  73. package/native-skills/mobile/offline-first-sync/SKILL.md +42 -0
  74. package/native-skills/mobile/push-notifications/SKILL.md +38 -0
  75. package/native-skills/performance/algorithmic-complexity/SKILL.md +43 -0
  76. package/native-skills/performance/concurrency-and-parallelism/SKILL.md +42 -0
  77. package/native-skills/performance/load-testing/SKILL.md +42 -0
  78. package/native-skills/performance/memory-and-leak-hunting/SKILL.md +41 -0
  79. package/native-skills/performance/network-and-payload-efficiency/SKILL.md +42 -0
  80. package/native-skills/performance/profiling-methodology/SKILL.md +46 -0
  81. package/native-skills/python/async-correctness/SKILL.md +40 -0
  82. package/native-skills/python/cli-tool-construction/SKILL.md +44 -0
  83. package/native-skills/python/data-processing-pipelines/SKILL.md +38 -0
  84. package/native-skills/python/environment-isolation/SKILL.md +41 -0
  85. package/native-skills/python/packaging-and-distribution/SKILL.md +56 -0
  86. package/native-skills/python/pytest-suite-design/SKILL.md +39 -0
  87. package/native-skills/python/type-hints-and-static-checking/SKILL.md +42 -0
  88. package/native-skills/security/authorization-model/SKILL.md +42 -0
  89. package/native-skills/security/crypto-usage/SKILL.md +48 -0
  90. package/native-skills/security/dependency-supply-chain/SKILL.md +42 -0
  91. package/native-skills/security/input-validation-and-injection/SKILL.md +44 -0
  92. package/native-skills/security/secure-file-uploads/SKILL.md +46 -0
  93. package/native-skills/security/security-headers-and-csp/SKILL.md +44 -0
  94. package/native-skills/security/threat-modelling/SKILL.md +46 -0
  95. package/native-skills/testing/end-to-end-test-stability/SKILL.md +42 -0
  96. package/native-skills/testing/property-based-testing/SKILL.md +46 -0
  97. package/native-skills/testing/regression-test-from-a-bug/SKILL.md +41 -0
  98. package/native-skills/testing/snapshot-and-visual-regression/SKILL.md +42 -0
  99. package/native-skills/testing/test-doubles-and-mocking/SKILL.md +43 -0
  100. package/native-skills/testing/test-strategy-and-pyramid/SKILL.md +39 -0
  101. package/native-skills/testing/writing-good-assertions/SKILL.md +42 -0
  102. package/native-skills/web/accessible-components/SKILL.md +45 -0
  103. package/native-skills/web/api-client-resilience/SKILL.md +39 -0
  104. package/native-skills/web/bundle-size-reduction/SKILL.md +38 -0
  105. package/native-skills/web/core-web-vitals/SKILL.md +40 -0
  106. package/native-skills/web/css-layout-systems/SKILL.md +41 -0
  107. package/native-skills/web/form-validation-ux/SKILL.md +39 -0
  108. package/native-skills/web/react-state-architecture/SKILL.md +41 -0
  109. package/native-skills/web/ssr-hydration-correctness/SKILL.md +45 -0
  110. package/package.json +68 -4
  111. package/src/agentLoop.js +2458 -0
  112. package/src/appChannel.js +109 -0
  113. package/src/approvalGrants.js +66 -0
  114. package/src/auditLog.js +52 -0
  115. package/src/autoUpdate.js +12 -0
  116. package/src/capabilities.js +36 -0
  117. package/src/checkpoints.js +1199 -0
  118. package/src/cliMode.js +638 -0
  119. package/src/commands.js +805 -0
  120. package/src/compiledSkills.js +540 -0
  121. package/src/config.js +130 -0
  122. package/src/contextManager.js +498 -0
  123. package/src/cortex/autoCondenser.js +192 -0
  124. package/src/cortex/provisioner.js +27 -0
  125. package/src/cortex/vectorDb.js +447 -0
  126. package/src/designPalettes.js +99 -0
  127. package/src/devMode.js +6 -0
  128. package/src/embodimentSession.js +180 -0
  129. package/src/entrypoint.js +194 -0
  130. package/src/execSafe.js +21 -0
  131. package/src/gitSnapshot.js +378 -0
  132. package/src/mcp/jsonRpc.js +165 -0
  133. package/src/mcp/mcpClient.js +136 -0
  134. package/src/mcp/mcpRegistry.js +207 -0
  135. package/src/memory.js +62 -0
  136. package/src/memoryManager.js +124 -0
  137. package/src/modelCatalogue.js +132 -0
  138. package/src/modelIds.js +42 -0
  139. package/src/modelRouter.js +145 -0
  140. package/src/outputStore.js +246 -0
  141. package/src/perception.js +124 -0
  142. package/src/planCache.js +437 -0
  143. package/src/procSignal.js +32 -0
  144. package/src/providers/anthropic.js +408 -0
  145. package/src/providers/base.js +328 -0
  146. package/src/providers/dashscope-byok.js +86 -0
  147. package/src/providers/deepseek.js +80 -0
  148. package/src/providers/factory.js +37 -0
  149. package/src/providers/gemini.js +346 -0
  150. package/src/providers/moonshot.js +73 -0
  151. package/src/providers/muse.js +169 -0
  152. package/src/providers/ollama.js +104 -0
  153. package/src/providers/openai-compatible.js +84 -0
  154. package/src/providers/openai.js +20 -0
  155. package/src/providers/qwen-byok.js +76 -0
  156. package/src/providers/xai.js +73 -0
  157. package/src/provisioning/capabilityConsent.js +24 -0
  158. package/src/provisioning/capabilityProvisioner.js +271 -0
  159. package/src/provisioning/capabilityTools.js +29 -0
  160. package/src/reporting.js +373 -0
  161. package/src/sandbox.js +529 -0
  162. package/src/sessionStore.js +279 -0
  163. package/src/skillsManager.js +288 -0
  164. package/src/slopDetector.js +307 -0
  165. package/src/taskBuffer.js +45 -0
  166. package/src/taskShape.js +241 -0
  167. package/src/textDiff.js +150 -0
  168. package/src/tokenTracker.js +560 -0
  169. package/src/tool-scripts/ax_snapshot.applescript +39 -0
  170. package/src/tool-scripts/ax_snapshot.ps1 +10 -0
  171. package/src/tool-scripts/desktop_act.applescript +58 -0
  172. package/src/tool-scripts/resolve_automator.py +119 -0
  173. package/src/toolPacks.js +524 -0
  174. package/src/tools/archive.js +63 -0
  175. package/src/tools/astryxOracle.js +78 -0
  176. package/src/tools/axSnapshot.js +165 -0
  177. package/src/tools/blenderAutomator.js +349 -0
  178. package/src/tools/browserAutomator.js +252 -0
  179. package/src/tools/checkSystemSpecs.js +64 -0
  180. package/src/tools/clipboard.js +36 -0
  181. package/src/tools/codeSearchAst.js +101 -0
  182. package/src/tools/codeSearcher.js +230 -0
  183. package/src/tools/codeTools.js +262 -0
  184. package/src/tools/codebaseSearch.js +75 -0
  185. package/src/tools/createSkill.js +129 -0
  186. package/src/tools/deferredMcpSearch.js +246 -0
  187. package/src/tools/desktopAct.js +208 -0
  188. package/src/tools/desktopOpen.js +34 -0
  189. package/src/tools/dynamicLoader.js +44 -0
  190. package/src/tools/executeProceduralMedia.js +93 -0
  191. package/src/tools/fsDelete.js +51 -0
  192. package/src/tools/fsEdit.js +105 -0
  193. package/src/tools/fsFind.js +128 -0
  194. package/src/tools/fsList.js +77 -0
  195. package/src/tools/fsMove.js +57 -0
  196. package/src/tools/fsRead.js +87 -0
  197. package/src/tools/fsSearch.js +198 -0
  198. package/src/tools/fsWrite.js +41 -0
  199. package/src/tools/gameAiBehaviorTree.js +208 -0
  200. package/src/tools/gameAnimationRig.js +194 -0
  201. package/src/tools/gameAssetFetcher.js +372 -0
  202. package/src/tools/gameAssetHarvester.js +210 -0
  203. package/src/tools/gameAudioSynth.js +267 -0
  204. package/src/tools/gameBuilder.js +886 -0
  205. package/src/tools/gameCanvasAudit.js +101 -0
  206. package/src/tools/gameCinematicSequencer.js +151 -0
  207. package/src/tools/gameDataForge.js +124 -0
  208. package/src/tools/gameDialogueTreeGen.js +166 -0
  209. package/src/tools/gameEconomyBalancer.js +161 -0
  210. package/src/tools/gameEntitySpawner.js +207 -0
  211. package/src/tools/gameLoreForge.js +153 -0
  212. package/src/tools/gameQuestArcBuilder.js +152 -0
  213. package/src/tools/gameSceneBuilder.js +158 -0
  214. package/src/tools/gameShaderForge.js +181 -0
  215. package/src/tools/gameTilemapGenerator.js +164 -0
  216. package/src/tools/gameUiHudBuilder.js +292 -0
  217. package/src/tools/gameVfxEmitterGen.js +108 -0
  218. package/src/tools/gameWebRuntimeInspector.js +91 -0
  219. package/src/tools/generateMediaViaApi.js +358 -0
  220. package/src/tools/gitExec.js +54 -0
  221. package/src/tools/godotAutomator.js +437 -0
  222. package/src/tools/manageLocalAiDependencies.js +220 -0
  223. package/src/tools/memoryWrite.js +99 -0
  224. package/src/tools/multiEdit.js +107 -0
  225. package/src/tools/palmierAutomator.js +104 -0
  226. package/src/tools/pdfReader.js +112 -0
  227. package/src/tools/persistentShell.js +148 -0
  228. package/src/tools/printer.js +316 -0
  229. package/src/tools/procTerm.js +91 -0
  230. package/src/tools/processList.js +52 -0
  231. package/src/tools/readNativeSkill.js +39 -0
  232. package/src/tools/registry.js +277 -0
  233. package/src/tools/resolveAutomator.js +102 -0
  234. package/src/tools/screenshot.js +75 -0
  235. package/src/tools/subagentOrchestrator.js +305 -0
  236. package/src/tools/sysRun.js +125 -0
  237. package/src/tools/todoWrite.js +75 -0
  238. package/src/tools/toolDispatch.js +127 -0
  239. package/src/tools/toolForge.js +124 -0
  240. package/src/tools/updatePlan.js +88 -0
  241. package/src/tools/viewImage.js +82 -0
  242. package/src/tools/visionInspector.js +154 -0
  243. package/src/tools/webFetch.js +74 -0
  244. package/src/tools/webSearch.js +82 -0
  245. package/src/tui/ask.js +164 -0
  246. package/src/tui/banner.js +158 -0
  247. package/src/tui/block.js +152 -0
  248. package/src/tui/chatRenderer.js +953 -0
  249. package/src/tui/completion.js +424 -0
  250. package/src/tui/dialogs.js +606 -0
  251. package/src/tui/diff.js +296 -0
  252. package/src/tui/history.js +135 -0
  253. package/src/tui/home.js +217 -0
  254. package/src/tui/invocation.js +105 -0
  255. package/src/tui/keys.js +443 -0
  256. package/src/tui/lineEditor.js +256 -0
  257. package/src/tui/overlay.js +256 -0
  258. package/src/tui/prompt.js +1258 -0
  259. package/src/tui/selectList.js +335 -0
  260. package/src/tui/stage.js +330 -0
  261. package/src/tui/stageSurface.js +609 -0
  262. package/src/tui/statusLine.js +254 -0
  263. package/src/tui/text.js +345 -0
  264. package/src/tui/theme.js +393 -0
  265. package/src/tui/toolDisplay.js +176 -0
  266. package/src/tui/transcript.js +235 -0
  267. package/src/tui/viewport.js +337 -0
  268. package/src/uncertainty.js +271 -0
  269. package/src/userSkills.js +265 -0
  270. package/src/utils/cli_ui.js +0 -0
  271. package/src/utils/inquirer.js +12 -0
  272. package/src/utils/paths.js +37 -0
  273. package/src/version.js +38 -0
  274. package/src/vfeTracker.js +220 -0
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: cross-platform-tradeoffs
3
+ description: Decide between native and cross-platform, or work within Flutter or React Native. Use when choosing a mobile stack, or when a cross-platform app hits a platform limit.
4
+ ---
5
+
6
+ # Cross-Platform Trade-offs
7
+
8
+ ## The honest framing
9
+
10
+ Cross-platform buys shared business logic and one team. It costs latency on new platform features, a harder time with deep platform integration, and a debugging path that crosses a bridge. Neither answer is universally right; the wrong move is choosing without naming the trade.
11
+
12
+ ## Workflow
13
+
14
+ 1. Name the platform-specific surface first.
15
+ - Widgets, watch apps, background processing, camera and audio pipelines, accessibility services, deep OS integration. If the product depends on several of these, the shared-code saving is smaller than it looks.
16
+ - **Done when:** the platform-specific requirements are listed before the framework is chosen.
17
+
18
+ 2. Match the choice to the team, not to the benchmark.
19
+ - A team fluent in one ecosystem will ship better software in it than in a technically superior one they are learning. This usually dominates the technical comparison.
20
+ - **Done when:** the decision states the team's existing skills as an input.
21
+
22
+ 3. Isolate the platform boundary.
23
+ - Whatever the choice, platform-specific code lives behind one interface. This keeps the shared code testable and keeps a future migration bounded.
24
+ - **Done when:** platform APIs are reached through a single abstraction per capability.
25
+
26
+ 4. Follow each platform's conventions in the UI.
27
+ - Navigation patterns, back behaviour, share sheets and system fonts differ. An app that ignores this is immediately recognisable as a port, and users read that as low quality.
28
+ - **Done when:** navigation and system interactions match each platform's convention.
29
+
30
+ 5. Test on both, on real devices.
31
+ - A simulator hides performance, permissions, and hardware differences. Cross-platform bugs concentrate exactly where the two platforms differ.
32
+ - **Done when:** every release is exercised on a physical device of each platform.
33
+
34
+ 6. Budget for the bridge.
35
+ - Frequent crossings — per-frame updates, large payloads, high-rate sensors — are the usual performance cliff. Keep hot paths on one side.
36
+ - **Done when:** no hot path crosses the boundary per frame.
37
+
38
+ ## Verification
39
+
40
+ - The decision is written down with the platform-specific requirements that informed it.
41
+ - Platform code sits behind one abstraction per capability.
42
+ - Both platforms are tested on physical hardware.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: deep-linking
3
+ description: Implement deep links or universal links. Use when a link should open the app, when links open the browser instead, or when a link cannot restore a screen directly.
4
+ ---
5
+
6
+ # Deep Linking
7
+
8
+ ## Workflow
9
+
10
+ 1. Use verified links, not custom schemes.
11
+ - A custom scheme can be claimed by any app and does not work from most messaging clients. Verified HTTP links (app links / universal links) are owned by your domain and fall back to the web when the app is absent.
12
+ - **Done when:** links use https and are verified against the domain.
13
+
14
+ 2. Publish and verify the association file.
15
+ - The association file must be served over https, with the right content type, no redirect, and the correct fingerprint or team identifier. Verification failing silently is the single most common cause of links opening the browser.
16
+ - **Done when:** platform verification reports the domain as verified on a real device.
17
+
18
+ 3. Make every screen reachable by URL.
19
+ - Design the route table as URLs first. A screen that can only be reached by navigating from the home screen cannot be linked, notified into, or restored.
20
+ - **Done when:** every meaningful screen has a URL.
21
+
22
+ 4. Rebuild the back stack, do not just push.
23
+ - Opening a detail screen from a link with an empty back stack traps the user. Synthesise the parent chain so back goes somewhere sensible.
24
+ - **Done when:** pressing back from a linked screen reaches a reasonable parent, not an exit.
25
+
26
+ 5. Handle the pre-ready link.
27
+ - A link can arrive before authentication or before data is loaded. Store the pending destination, complete the prerequisite, then navigate. Never drop it.
28
+ - **Done when:** a link that requires login lands on the target after login, not on the home screen.
29
+
30
+ 6. Validate the parameters.
31
+ - A link is untrusted input. Validate identifiers and reject anything malformed rather than passing it into a query.
32
+ - **Done when:** a malformed link shows an error rather than crashing.
33
+
34
+ ## Verification
35
+
36
+ - Links open the app from a message, a browser and a notification, on a real device.
37
+ - Back from a linked screen behaves correctly.
38
+ - A link requiring authentication survives the login flow.
39
+ - A malformed link fails safely.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: mobile-storage-security
3
+ description: Store sensitive data on a mobile device. Use when saving tokens, credentials, or personal data locally, or when a security review flags local storage.
4
+ ---
5
+
6
+ # Mobile Storage Security
7
+
8
+ ## The threat
9
+
10
+ A lost or stolen device, a backup extracted to a computer, and on a rooted or jailbroken device, another process reading your files. Plain preferences and plain files are readable in all three cases.
11
+
12
+ ## Workflow
13
+
14
+ 1. Classify before choosing storage.
15
+ - Secrets (tokens, keys, passwords) → the platform keystore or keychain.
16
+ - Personal data → encrypted database or encrypted files.
17
+ - Cache and preferences → plain storage is fine.
18
+ - **Done when:** every stored item has a classification.
19
+
20
+ 2. Put secrets in hardware-backed storage.
21
+ - The platform keystore keeps key material outside the app's address space, and hardware backing means it cannot be extracted even from a rooted device. Require user authentication for the highest-value keys.
22
+ - **Done when:** no token or key is written to plain preferences or a plain file.
23
+
24
+ 3. Never ship a secret inside the app.
25
+ - An API key in the binary is extractable in minutes, whatever the obfuscation. If a key must exist, it belongs on a server that proxies the call.
26
+ - **Done when:** no long-lived credential exists in the shipped artefact.
27
+
28
+ 4. Control what leaves the device in a backup.
29
+ - Exclude secrets and caches from automatic cloud backup explicitly. A backup restored to another device must not carry a session token.
30
+ - **Done when:** the backup rules name what is excluded, and a restore does not carry a live session.
31
+
32
+ 5. Protect data at rest as well as in transit.
33
+ - Encrypted database for personal data, so a file pulled from a backup is not readable.
34
+ - **Done when:** the database file alone is not readable without the device key.
35
+
36
+ 6. Clear on logout.
37
+ - Tokens, cached personal data and derived keys. Leaving them behind means the next user of the device inherits the session.
38
+ - **Done when:** after logout, no personal data or credential remains on disk.
39
+
40
+ ## Verification
41
+
42
+ - Pulling the app's data directory yields no readable secret.
43
+ - The shipped artefact contains no long-lived credential.
44
+ - Logout leaves no personal data on disk.
45
+ - A restored backup does not carry a live session.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: offline-first-sync
3
+ description: Make a mobile app work without a network connection. Use when the app shows an error offline, when data is lost on a failed request, or when local and server state diverge.
4
+ ---
5
+
6
+ # Offline-First Sync
7
+
8
+ ## The premise
9
+
10
+ The local store is the source of truth for the UI. The network is a background synchroniser. Every screen reads local data and renders immediately; nothing waits on a request. Getting this backwards is why most apps are unusable on a train.
11
+
12
+ ## Workflow
13
+
14
+ 1. Write locally first, always.
15
+ - A user action commits to the local database and the UI updates from it. A sync record is queued separately. The user never waits for a round trip to see their own action.
16
+ - **Done when:** every mutation succeeds and is visible with the network disabled.
17
+
18
+ 2. Queue mutations durably.
19
+ - The outbox survives app death and reboot. Each entry has a stable identifier so a retry cannot duplicate the server-side effect.
20
+ - **Done when:** killing the app mid-sync loses nothing and duplicates nothing.
21
+
22
+ 3. Decide the conflict rule per field, not per record.
23
+ - Last-write-wins is acceptable for a note body and wrong for a counter or a set. State the rule for each field that can be edited on two devices.
24
+ - **Done when:** every conflict-capable field has a stated resolution rule.
25
+
26
+ 4. Sync incrementally.
27
+ - Track a server cursor or updated-at watermark and request only what changed. A full re-fetch on every launch is slow, expensive and pointless.
28
+ - **Done when:** a sync after a small change transfers a small amount of data.
29
+
30
+ 5. Show sync state without blocking.
31
+ - A subtle indicator for pending and failed items. A modal spinner over the whole screen defeats the entire design.
32
+ - **Done when:** pending and failed states are visible and non-blocking.
33
+
34
+ 6. Make failure recoverable by the user.
35
+ - An item that fails permanently needs a visible retry or discard. Silent permanent failure loses user data without telling them.
36
+ - **Done when:** a permanently failed mutation is surfaced with an action.
37
+
38
+ ## Verification
39
+
40
+ - Every screen renders and every action succeeds in airplane mode.
41
+ - Reconnecting syncs the queue exactly once.
42
+ - Editing the same record on two devices resolves by the stated rule.
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: push-notifications
3
+ description: Implement push notifications. Use when adding push, when notifications do not arrive on some devices, or when permission is requested at launch.
4
+ ---
5
+
6
+ # Push Notifications
7
+
8
+ ## Workflow
9
+
10
+ 1. Ask for permission in context, never at launch.
11
+ - A permission prompt on first open is denied by most users, and on both platforms a denial is close to permanent. Ask at the moment the value is obvious, after explaining it in your own UI first.
12
+ - **Done when:** the system prompt appears only after an in-app explanation and a user action.
13
+
14
+ 2. Treat the token as volatile.
15
+ - It rotates on reinstall, restore, and sometimes on update. Refresh on every launch and on the rotation callback, and send it to the server with a device identifier so old tokens can be replaced rather than accumulated.
16
+ - **Done when:** reinstalling produces a working token without a duplicate device record.
17
+
18
+ 3. Send data, render locally.
19
+ - A notification payload containing final display text cannot be localised, personalised, or deduplicated. Send identifiers and render from local data where the platform allows.
20
+ - **Done when:** the notification respects the device language and the app's current state.
21
+
22
+ 4. Handle all three app states.
23
+ - Foreground, background, and terminated behave differently on both platforms. The terminated case is the one that is usually missed, and it is the one that matters for a cold launch from a notification.
24
+ - **Done when:** tapping a notification opens the right screen from all three states.
25
+
26
+ 5. Route the tap deterministically.
27
+ - The payload carries a deep link. Handle a link that arrives before the app is ready by queueing it until navigation exists.
28
+ - **Done when:** a cold-start notification tap lands on the correct screen.
29
+
30
+ 6. Respect the user's attention.
31
+ - Channels or categories so the user can mute a class rather than all notifications. Collapse keys so ten updates do not become ten notifications. Never send a notification with no user value.
32
+ - **Done when:** every notification type is in a channel the user can control separately.
33
+
34
+ ## Verification
35
+
36
+ - Delivery works in foreground, background and terminated states on physical devices.
37
+ - Reinstalling refreshes the token and does not duplicate the device.
38
+ - Muting one channel leaves the others working.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: algorithmic-complexity
3
+ description: Fix code that slows down disproportionately as data grows. Use when performance is fine in testing and bad in production, or when a loop contains a lookup.
4
+ ---
5
+
6
+ # Algorithmic Complexity
7
+
8
+ ## Where the real wins are
9
+
10
+ Constant-factor optimisation buys a few percent. Removing a factor of n buys orders of magnitude. On real data, the difference between a nested loop and a hash lookup dwarfs every micro-optimisation combined — and the nested loop is invisible on a test fixture of ten items.
11
+
12
+ ## Workflow
13
+
14
+ 1. Find the nested iteration.
15
+ - A loop containing a search, a filter, an `includes`, or a query. This is the single most common cause of "fine in dev, unusable in production".
16
+ - Fix: build a map or set once, then look up in constant time.
17
+ - **Done when:** no loop body performs a linear search over another collection.
18
+
19
+ 2. Look for repeated work that could be done once.
20
+ - A value recomputed on every iteration, a regular expression compiled inside a loop, a sort inside a loop. Hoist it.
21
+ - **Done when:** nothing invariant is computed inside a loop.
22
+
23
+ 3. Choose the structure for the dominant operation.
24
+ - Frequent membership tests: a set. Frequent lookup by key: a map. Ordered range queries: a sorted structure or an index. Using an array for membership testing is the same mistake as the nested loop.
25
+ - **Done when:** the data structure matches the most frequent operation.
26
+
27
+ 4. Push filtering to where the data lives.
28
+ - Fetching ten thousand rows to keep five is ten thousand rows of transfer, allocation and parsing. Filter in the query.
29
+ - **Done when:** the volume fetched is proportional to the volume used.
30
+
31
+ 5. Do not process what you will not show.
32
+ - Paginate, limit, and stream. A list endpoint with no limit is unbounded work triggered by a stranger.
33
+ - **Done when:** every collection operation has a bound.
34
+
35
+ 6. Verify the complexity empirically.
36
+ - Time with n, 10n and 100n. Linear growth is fine; quadratic shows up immediately at 100n.
37
+ - **Done when:** timing scales as the intended complexity predicts.
38
+
39
+ ## Verification
40
+
41
+ - Timing at three input sizes matches the intended complexity.
42
+ - No loop body contains a linear search.
43
+ - Every collection endpoint is bounded.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: concurrency-and-parallelism
3
+ description: Make code faster by running work concurrently, or fix a concurrency bug. Use when work is serialised unnecessarily, or when parallel code produces wrong results.
4
+ ---
5
+
6
+ # Concurrency and Parallelism
7
+
8
+ ## The distinction that decides the mechanism
9
+
10
+ Concurrency is dealing with many things at once; parallelism is doing many things at once. I/O-bound work needs concurrency — async or threads. CPU-bound work needs parallelism — processes or real threads. Applying the wrong one gives no speedup and sometimes a slowdown.
11
+
12
+ ## Workflow
13
+
14
+ 1. Classify the bottleneck before choosing a tool.
15
+ - Watch CPU during the slow operation. Near 100% on one core is CPU-bound. Low CPU with the process waiting is I/O-bound.
16
+ - **Done when:** the bottleneck is classified with a measurement.
17
+
18
+ 2. Find the actual serialisation point.
19
+ - Parallelising around a shared lock, a single database connection, or a rate-limited API gives no improvement — the queue just moves. Find what everything waits on.
20
+ - **Done when:** the shared resource is identified and shown not to be the limit.
21
+
22
+ 3. Bound the concurrency.
23
+ - Unbounded parallelism exhausts connections, file descriptors, or memory, and usually performs worse than a sensible limit. Use a semaphore or a worker pool sized from measurement.
24
+ - **Done when:** peak concurrency is capped at a measured number.
25
+
26
+ 4. Eliminate shared mutable state, do not lock it.
27
+ - Give each worker its own data and combine at the end. Locks are correct and slow, and every lock is a potential deadlock. Immutability and message passing avoid the whole class.
28
+ - **Done when:** workers share nothing mutable, or every shared item's protection is documented.
29
+
30
+ 5. Order lock acquisition consistently.
31
+ - Deadlock is two paths taking the same locks in different orders. A global order — by identifier — removes it structurally.
32
+ - **Done when:** every multi-lock path acquires in the same order.
33
+
34
+ 6. Test under real contention.
35
+ - A race that never appears with two workers appears with two hundred. Run the concurrency test with many workers, repeatedly, and with a race detector where the language has one.
36
+ - **Done when:** a high-contention test passes repeatedly.
37
+
38
+ ## Verification
39
+
40
+ - Speedup is measured, not assumed, and is close to what the bottleneck class predicts.
41
+ - A high-contention test produces the correct result over many runs.
42
+ - No shared mutable state is accessed without documented protection.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: load-testing
3
+ description: Find out how a system behaves under load. Use before a launch, before a traffic event, or after a capacity-related incident.
4
+ ---
5
+
6
+ # Load Testing
7
+
8
+ ## What you are looking for
9
+
10
+ Not the maximum throughput. The point at which latency degrades, and what happens beyond it. A system that quietly falls over at 2× normal traffic is the problem; the exact breaking number is secondary.
11
+
12
+ ## Workflow
13
+
14
+ 1. Define the scenario from real traffic.
15
+ - Endpoint mix, think time, payload sizes and the cache-hit ratio, taken from production logs. A test hammering one endpoint with no think time measures something no user will ever do.
16
+ - **Done when:** the scenario's mix is derived from observed traffic.
17
+
18
+ 2. Test against production-like infrastructure and data.
19
+ - Same instance sizes, same database size, same cache state. A test against an empty database measures the empty database.
20
+ - **Done when:** the environment's differences from production are listed and their effect stated.
21
+
22
+ 3. Ramp rather than spike.
23
+ - Increase load gradually and watch where latency turns upward. That knee is the useful number. A spike test is a separate scenario for autoscaling behaviour.
24
+ - **Done when:** the latency knee is identified.
25
+
26
+ 4. Watch the system, not just the client.
27
+ - CPU, memory, connection pool saturation, database load, queue depth, and error rate. The client only sees the symptom; the cause is inside.
28
+ - **Done when:** the first resource to saturate is named.
29
+
30
+ 5. Push past the knee deliberately.
31
+ - Graceful degradation — shedding load, returning 429, serving stale — is a design property, not an accident. Confirm the system does something sensible rather than collapsing.
32
+ - **Done when:** behaviour beyond capacity is characterised and acceptable.
33
+
34
+ 6. Soak at a sustainable level.
35
+ - Several hours at a realistic load finds leaks, connection exhaustion, and log-disk growth — none of which appear in a ten-minute run.
36
+ - **Done when:** a multi-hour run shows flat memory and stable latency.
37
+
38
+ ## Verification
39
+
40
+ - The latency knee and the first saturating resource are both reported.
41
+ - Behaviour beyond capacity is documented.
42
+ - A soak run shows no resource growth over time.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: memory-and-leak-hunting
3
+ description: Diagnose growing memory or an out-of-memory failure. Use when a process grows over time, when it is killed by the platform, or when garbage collection pauses become long.
4
+ ---
5
+
6
+ # Memory and Leak Hunting
7
+
8
+ ## Growth versus leak
9
+
10
+ A leak is unbounded retention: memory that is reachable but never used again. High usage that plateaus is not a leak — it is a cache or a pool doing its job. Distinguish these before investigating, because they need opposite responses.
11
+
12
+ ## Workflow
13
+
14
+ 1. Establish the shape of the growth.
15
+ - Plot resident memory over hours. Linear with traffic suggests per-request retention. Stepwise suggests a cache without a bound. A plateau is not a leak.
16
+ - **Done when:** the growth pattern is characterised.
17
+
18
+ 2. Take two heap snapshots and compare.
19
+ - One after warm-up, one after a period of load, having returned to the same logical state. The DIFFERENCE is the leak; a single snapshot mostly shows normal working set.
20
+ - **Done when:** you have the object types that grew between snapshots.
21
+
22
+ 3. Follow the retaining path.
23
+ - The profiler shows what holds the object. The answer is almost always one of: a module-level collection that only grows, a listener never removed, a closure capturing a large scope, a cache with no eviction, or a timer holding its context.
24
+ - **Done when:** the retaining reference is named.
25
+
26
+ 4. Bound every cache.
27
+ - A map used as a cache with no maximum size and no eviction is the most common leak in any language. Give it a bound and a policy.
28
+ - **Done when:** every long-lived collection has a maximum size.
29
+
30
+ 5. Pair every registration with a removal.
31
+ - Listeners, subscriptions, intervals, and observers. Where the language supports it, use a scope guard so the pairing cannot be forgotten.
32
+ - **Done when:** every registration has a guaranteed removal.
33
+
34
+ 6. Re-measure over the same window.
35
+ - **Done when:** memory returns to baseline after load, over the duration that previously showed growth.
36
+
37
+ ## Verification
38
+
39
+ - Memory plateaus rather than growing over a long soak test.
40
+ - The retained set returns to baseline after load stops.
41
+ - Every cache has a stated bound.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: network-and-payload-efficiency
3
+ description: Reduce time spent on the network. Use when an app is slow on a mobile connection, when payloads are large, or when a screen makes many requests.
4
+ ---
5
+
6
+ # Network and Payload Efficiency
7
+
8
+ ## What dominates on a real connection
9
+
10
+ Round trips, not bandwidth. On a mobile network each round trip costs tens to hundreds of milliseconds regardless of payload size. Eliminating a request is worth far more than shrinking one.
11
+
12
+ ## Workflow
13
+
14
+ 1. Count the requests on the critical path.
15
+ - Waterfall view. Look for sequential chains — a request whose response is needed to start the next. Each link is a full round trip.
16
+ - **Done when:** the length of the longest sequential chain is known.
17
+
18
+ 2. Break the chains.
19
+ - Return what the screen needs in one response, or issue independent requests in parallel. A screen that fetches a user, then their orders, then each order's items is three round trips deep before anything renders.
20
+ - **Done when:** no chain on the critical path is longer than two.
21
+
22
+ 3. Send only what is used.
23
+ - A response with forty fields where the screen shows four wastes serialisation, transfer and parsing. Support field selection, or provide a purpose-built endpoint.
24
+ - **Done when:** responses contain no field the client ignores.
25
+
26
+ 4. Compress and cache correctly.
27
+ - Compression on for text responses. `Cache-Control` with a real max-age for anything stable, and `ETag` for anything revalidatable. A correct 304 costs one round trip and no body.
28
+ - **Done when:** repeat loads are served from cache or revalidated without a body.
29
+
30
+ 5. Paginate and stream large results.
31
+ - Cursor pagination for lists, streaming for large payloads so the client can begin before the end arrives.
32
+ - **Done when:** no endpoint returns an unbounded body.
33
+
34
+ 6. Move the data closer.
35
+ - A CDN for static assets and cacheable responses. Geography is a fixed cost that no amount of optimisation removes.
36
+ - **Done when:** static assets are served from an edge location.
37
+
38
+ ## Verification
39
+
40
+ - Requests on the critical path are counted before and after.
41
+ - Repeat loads produce 304 responses or cache hits.
42
+ - The app is tested on a throttled connection with added latency, not on the local network.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: profiling-methodology
3
+ description: Investigate a performance problem. Use whenever something is slow, before optimising anything, and when an optimisation did not help.
4
+ ---
5
+
6
+ # Profiling Methodology
7
+
8
+ ## The rule that saves the most time
9
+
10
+ Measure first. Developer intuition about where time goes is wrong most of the time, and an optimisation applied to the wrong place costs the effort plus the added complexity plus the bug it introduces, for no gain.
11
+
12
+ ## Workflow
13
+
14
+ 1. State the goal as a number.
15
+ - "p95 under 200ms", not "faster". Without a target there is no way to know when to stop, and optimisation has no natural end.
16
+ - **Done when:** the target and the current value are both written down.
17
+
18
+ 2. Measure the right layer.
19
+ - A slow page can be the network, the server, the database, or the client. Establish which before profiling inside one of them. The waterfall or a distributed trace answers this in a minute.
20
+ - **Done when:** the dominant layer is identified.
21
+
22
+ 3. Profile under realistic conditions.
23
+ - Production-scale data, realistic concurrency, a release build, and a representative device or instance. A profile on ten rows on a workstation finds nothing that matters.
24
+ - **Done when:** the profile was taken under conditions resembling production.
25
+
26
+ 4. Read the profile for self time and for the call tree.
27
+ - Self time finds a slow function. The tree finds a fast function called a million times, which is the more common and more valuable finding.
28
+ - **Done when:** you can name the specific call path consuming the time.
29
+
30
+ 5. Change one thing and re-measure.
31
+ - Several changes at once make attribution impossible, and one of them may have made things worse.
32
+ - **Done when:** each change has a before and after number.
33
+
34
+ 6. Stop at the target.
35
+ - Beyond it, further optimisation buys complexity nobody asked for.
36
+ - **Done when:** the target is met and the work has stopped.
37
+
38
+ ## The usual suspects, in order
39
+
40
+ Repeated work in a loop, an N+1 query, a missing index, unnecessary serialisation, a synchronous call in an async path, and an unbounded collection.
41
+
42
+ ## Verification
43
+
44
+ - Before and after numbers are reported for the stated metric.
45
+ - The measurement conditions are described.
46
+ - The change is attributable to one modification.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: async-correctness
3
+ description: Write or debug asyncio code. Use when async code runs slower than sync, when a coroutine is never awaited, or when the event loop appears to block.
4
+ ---
5
+
6
+ # Asyncio Correctness
7
+
8
+ ## The failure that causes most of the others
9
+
10
+ A blocking call inside a coroutine stops the ENTIRE event loop, not just that task. `time.sleep`, `requests.get`, a synchronous file read, or a CPU-heavy loop will serialise everything the program is doing. Async code that is slower than sync code almost always has one of these.
11
+
12
+ ## Workflow
13
+
14
+ 1. Find the blocking calls.
15
+ - Any synchronous I/O library, any `time.sleep`, any long pure-Python computation.
16
+ - Fix: use the async equivalent (`httpx` over `requests`, `aiofiles` or a thread for files), or push the work off the loop with `asyncio.to_thread` for I/O and a process pool for CPU.
17
+ - **Done when:** no coroutine performs synchronous I/O or long computation.
18
+
19
+ 2. Make concurrency explicit.
20
+ - `await` in sequence is sequential. To run concurrently, use `asyncio.TaskGroup` (3.11+), which also propagates exceptions and cancels siblings correctly.
21
+ - `asyncio.gather` without `return_exceptions` leaves siblings running after one fails.
22
+ - **Done when:** work intended to be concurrent uses a TaskGroup and finishes in roughly the time of the slowest item.
23
+
24
+ 3. Never create a task without keeping a reference.
25
+ - The loop holds only a weak reference; a bare `asyncio.create_task(...)` can be garbage-collected mid-flight and the work silently vanishes. Hold the task, or use a TaskGroup.
26
+ - **Done when:** every created task is owned by something.
27
+
28
+ 4. Handle cancellation as a normal path.
29
+ - `CancelledError` must propagate. Catching it broadly makes a task uncancellable and hangs shutdown. Cleanup belongs in `finally`, and must not await anything slow.
30
+ - **Done when:** cancelling the top-level task exits promptly.
31
+
32
+ 5. Bound the concurrency.
33
+ - Ten thousand simultaneous requests will exhaust file descriptors or get the client blocked. Use a `Semaphore`.
34
+ - **Done when:** peak concurrency is capped at a stated number.
35
+
36
+ ## Verification
37
+
38
+ - Run with `PYTHONASYNCIODEBUG=1`; there are no "coroutine was never awaited" or slow-callback warnings.
39
+ - Concurrent work completes in about the time of the slowest item, not the sum.
40
+ - Interrupting the program exits cleanly rather than hanging.
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: cli-tool-construction
3
+ description: Build a Python command-line tool. Use when a script parses sys.argv by hand, when it has no help output, or when it cannot be used in a pipeline.
4
+ ---
5
+
6
+ # Python CLI Construction
7
+
8
+ ## What separates a tool from a script
9
+
10
+ Discoverable help, correct exit codes, stdout carrying only the result, and behaviour that composes with other tools. A script that prints progress to stdout cannot be piped, and that is usually the first thing a user tries.
11
+
12
+ ## Workflow
13
+
14
+ 1. Use a parser, not manual argument handling.
15
+ - `argparse` is in the standard library and sufficient. `typer` or `click` add ergonomics at the cost of a dependency.
16
+ - Every option gets a help string. `--help` is the tool's primary documentation.
17
+ - **Done when:** `--help` alone explains how to use the tool.
18
+
19
+ 2. Separate the streams.
20
+ - Results to stdout. Progress, warnings and errors to stderr. Mixing them makes the tool unpipeable and its output unparseable.
21
+ - **Done when:** `tool ... > out.txt` leaves a file containing only results, with progress still visible on the terminal.
22
+
23
+ 3. Exit with meaning.
24
+ - 0 for success, non-zero for failure. A tool that exits 0 after failing breaks every script that calls it.
25
+ - **Done when:** a deliberate failure produces a non-zero exit code.
26
+
27
+ 4. Read from stdin when no file is given.
28
+ - `-` conventionally means stdin. This makes the tool a filter and lets it compose.
29
+ - **Done when:** `cat file | tool` behaves as `tool file`.
30
+
31
+ 5. Keep the logic out of the entry point.
32
+ - `main()` parses arguments and calls a function that takes plain values. That function is testable without spawning a process.
33
+ - **Done when:** the core behaviour has tests that do not invoke the CLI.
34
+
35
+ 6. Handle interruption quietly.
36
+ - Catch the keyboard interrupt at the top level and exit 130 without a traceback. A stack trace on Ctrl+C looks like a crash.
37
+ - **Done when:** interrupting prints nothing alarming and exits 130.
38
+
39
+ ## Verification
40
+
41
+ - `--help` documents every option.
42
+ - Redirecting stdout captures only results.
43
+ - A failure path exits non-zero.
44
+ - The core logic has tests that bypass argument parsing.
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: data-processing-pipelines
3
+ description: Process files or datasets in Python. Use when a script loads an entire file into memory, when processing is slow, or when a pipeline fails partway through with no recovery.
4
+ ---
5
+
6
+ # Data Processing Pipelines
7
+
8
+ ## The two failures
9
+
10
+ Loading everything into memory, and having no way to resume. Both are invisible on the sample file and fatal on the real one.
11
+
12
+ ## Workflow
13
+
14
+ 1. Stream rather than load.
15
+ - Iterate the file; do not read it whole. `csv.reader` over a file object, `json` lines one per line, `pandas.read_csv(chunksize=...)`, or Polars in lazy mode.
16
+ - **Done when:** peak memory is roughly constant regardless of input size.
17
+
18
+ 2. Make the pipeline a chain of generators.
19
+ - Each stage takes an iterable and yields an iterable. Nothing materialises a list. This composes, stays constant-memory, and is testable stage by stage.
20
+ - **Done when:** no stage builds a list of the whole dataset.
21
+
22
+ 3. Validate at the boundary and quarantine the failures.
23
+ - Bad rows are normal in real data. Validate on entry, write rejects to a separate file with the reason, and continue. A pipeline that stops on row 400,000 wastes the previous 399,999.
24
+ - **Done when:** a deliberately malformed row lands in the reject file and processing continues.
25
+
26
+ 4. Make the whole thing resumable and idempotent.
27
+ - Checkpoint progress, and key output by a stable identifier so re-running overwrites rather than duplicates. Write to a temporary path and rename on completion so a partial file is never mistaken for a finished one.
28
+ - **Done when:** interrupting mid-run and restarting produces the same result as an uninterrupted run.
29
+
30
+ 5. Parallelise only after measuring.
31
+ - Find out whether the bottleneck is I/O or CPU. Threads help I/O; processes help CPU; neither helps if the bottleneck is a single slow query upstream.
32
+ - **Done when:** the bottleneck is named and the chosen mechanism matches it.
33
+
34
+ ## Verification
35
+
36
+ - Peak memory stays flat as input size grows tenfold.
37
+ - A malformed row is quarantined, not fatal.
38
+ - Killing the process mid-run and restarting yields the same output.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: environment-isolation
3
+ description: Install Python dependencies or run a Python script. Use before any pip install, when no virtual environment is active, or when a project has no dependency manifest.
4
+ ---
5
+
6
+ # Python Environment Isolation
7
+
8
+ ## The rule that has no exceptions
9
+
10
+ Never install into the system interpreter. On macOS and most Linux distributions the system Python is a dependency of the operating system, and a global install can break packaging tools, the desktop, or the boot path. Modern pip refuses by default (PEP 668) — that refusal is correct and must not be defeated with `--break-system-packages`.
11
+
12
+ ## Workflow
13
+
14
+ 1. Detect what is already there before creating anything.
15
+ - Active environment: the `VIRTUAL_ENV` variable is set.
16
+ - Project-local: a `.venv/` or `venv/` directory.
17
+ - Managed: `poetry.lock`, `uv.lock`, `Pipfile.lock`, or `environment.yml` — each implies its own tool and its own commands.
18
+ - **Done when:** you know which manager the project uses, or that it has none.
19
+
20
+ 2. Use the project's manager if it has one.
21
+ - `uv sync`, `poetry install`, `pipenv install`, `conda env create -f environment.yml`. Mixing plain pip into a managed project desynchronises the lock file.
22
+ - **Done when:** dependencies are installed through the project's own tool.
23
+
24
+ 3. Create an environment if none exists.
25
+ - `python3 -m venv .venv` then activate. `uv venv` is faster where uv is available.
26
+ - Add `.venv/` to `.gitignore`.
27
+ - **Done when:** `VIRTUAL_ENV` is set and points into the project.
28
+
29
+ 4. Chain activation into every command you run.
30
+ - A tool invocation is a fresh shell, so activation does not persist between them. Every command must carry it: `source .venv/bin/activate && pytest`. On Windows: `.venv\Scripts\activate`.
31
+ - **Done when:** every command that touches Python includes activation.
32
+
33
+ 5. Record what you installed.
34
+ - Add the dependency to `pyproject.toml` or `requirements.txt`. An install that is not recorded disappears on the next clean checkout.
35
+ - **Done when:** a fresh clone plus an install reproduces the environment.
36
+
37
+ ## Verification
38
+
39
+ - `which python` resolves inside the project directory.
40
+ - `python -c "import sys; print(sys.prefix)"` prints the environment path, not the system path.
41
+ - The new dependency appears in the manifest.