@chinhae/atw-cli 0.5.0 → 0.7.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 (257) hide show
  1. package/README.md +128 -451
  2. package/dist/cli/index.d.ts.map +1 -1
  3. package/dist/cli/index.js +24 -1
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/commands/channel/adapters/claude.d.ts +44 -2
  6. package/dist/commands/channel/adapters/claude.d.ts.map +1 -1
  7. package/dist/commands/channel/adapters/claude.js +124 -23
  8. package/dist/commands/channel/adapters/claude.js.map +1 -1
  9. package/dist/commands/channel/adapters/codex.d.ts +36 -6
  10. package/dist/commands/channel/adapters/codex.d.ts.map +1 -1
  11. package/dist/commands/channel/adapters/codex.js +150 -10
  12. package/dist/commands/channel/adapters/codex.js.map +1 -1
  13. package/dist/commands/channel/adapters/index.d.ts +33 -4
  14. package/dist/commands/channel/adapters/index.d.ts.map +1 -1
  15. package/dist/commands/channel/adapters/index.js +159 -6
  16. package/dist/commands/channel/adapters/index.js.map +1 -1
  17. package/dist/commands/channel/adapters/omp.d.ts +106 -0
  18. package/dist/commands/channel/adapters/omp.d.ts.map +1 -0
  19. package/dist/commands/channel/adapters/omp.js +405 -0
  20. package/dist/commands/channel/adapters/omp.js.map +1 -0
  21. package/dist/commands/channel/adapters/pi.d.ts +123 -0
  22. package/dist/commands/channel/adapters/pi.d.ts.map +1 -0
  23. package/dist/commands/channel/adapters/pi.js +387 -0
  24. package/dist/commands/channel/adapters/pi.js.map +1 -0
  25. package/dist/commands/channel/adapters/types.d.ts +16 -0
  26. package/dist/commands/channel/adapters/types.d.ts.map +1 -1
  27. package/dist/commands/channel/agent-loader.d.ts +1 -0
  28. package/dist/commands/channel/agent-loader.d.ts.map +1 -1
  29. package/dist/commands/channel/agent-loader.js +45 -5
  30. package/dist/commands/channel/agent-loader.js.map +1 -1
  31. package/dist/commands/channel/dev-parse-trace.d.ts +1 -1
  32. package/dist/commands/channel/dev-parse-trace.d.ts.map +1 -1
  33. package/dist/commands/channel/dev-parse-trace.js +25 -2
  34. package/dist/commands/channel/dev-parse-trace.js.map +1 -1
  35. package/dist/commands/channel/index.d.ts.map +1 -1
  36. package/dist/commands/channel/index.js +44 -12
  37. package/dist/commands/channel/index.js.map +1 -1
  38. package/dist/commands/channel/run.d.ts +39 -2
  39. package/dist/commands/channel/run.d.ts.map +1 -1
  40. package/dist/commands/channel/run.js +227 -68
  41. package/dist/commands/channel/run.js.map +1 -1
  42. package/dist/commands/channel/spawn.d.ts +7 -2
  43. package/dist/commands/channel/spawn.d.ts.map +1 -1
  44. package/dist/commands/channel/spawn.js +35 -1
  45. package/dist/commands/channel/spawn.js.map +1 -1
  46. package/dist/commands/channel/store/events.d.ts +2 -2
  47. package/dist/commands/channel/store/events.d.ts.map +1 -1
  48. package/dist/commands/channel/store/events.js +1 -1
  49. package/dist/commands/channel/store/events.js.map +1 -1
  50. package/dist/commands/channel/supervisor/shutdown.d.ts +2 -0
  51. package/dist/commands/channel/supervisor/shutdown.d.ts.map +1 -1
  52. package/dist/commands/channel/supervisor/shutdown.js +6 -1
  53. package/dist/commands/channel/supervisor/shutdown.js.map +1 -1
  54. package/dist/commands/channel/supervisor.d.ts +2 -2
  55. package/dist/commands/channel/supervisor.d.ts.map +1 -1
  56. package/dist/commands/channel/supervisor.js +26 -3
  57. package/dist/commands/channel/supervisor.js.map +1 -1
  58. package/dist/commands/init.d.ts.map +1 -1
  59. package/dist/commands/init.js +6 -1
  60. package/dist/commands/init.js.map +1 -1
  61. package/dist/commands/mem.d.ts +2 -1
  62. package/dist/commands/mem.d.ts.map +1 -1
  63. package/dist/commands/mem.js +162 -13
  64. package/dist/commands/mem.js.map +1 -1
  65. package/dist/commands/mode.d.ts.map +1 -1
  66. package/dist/commands/mode.js +5 -3
  67. package/dist/commands/mode.js.map +1 -1
  68. package/dist/commands/uninstall.d.ts +5 -3
  69. package/dist/commands/uninstall.d.ts.map +1 -1
  70. package/dist/commands/uninstall.js +40 -16
  71. package/dist/commands/uninstall.js.map +1 -1
  72. package/dist/commands/update.d.ts +34 -0
  73. package/dist/commands/update.d.ts.map +1 -1
  74. package/dist/commands/update.js +209 -11
  75. package/dist/commands/update.js.map +1 -1
  76. package/dist/commands/verify.d.ts +18 -0
  77. package/dist/commands/verify.d.ts.map +1 -0
  78. package/dist/commands/verify.js +75 -0
  79. package/dist/commands/verify.js.map +1 -0
  80. package/dist/configurators/index.d.ts.map +1 -1
  81. package/dist/configurators/index.js +3 -2
  82. package/dist/configurators/index.js.map +1 -1
  83. package/dist/configurators/omp.d.ts +22 -0
  84. package/dist/configurators/omp.d.ts.map +1 -1
  85. package/dist/configurators/omp.js +101 -2
  86. package/dist/configurators/omp.js.map +1 -1
  87. package/dist/configurators/shared.d.ts.map +1 -1
  88. package/dist/configurators/shared.js +39 -7
  89. package/dist/configurators/shared.js.map +1 -1
  90. package/dist/configurators/workflow.d.ts.map +1 -1
  91. package/dist/configurators/workflow.js +5 -1
  92. package/dist/configurators/workflow.js.map +1 -1
  93. package/dist/constants/paths.d.ts +4 -0
  94. package/dist/constants/paths.d.ts.map +1 -1
  95. package/dist/constants/paths.js +4 -0
  96. package/dist/constants/paths.js.map +1 -1
  97. package/dist/migrations/manifests/0.6.0.json +442 -0
  98. package/dist/migrations/manifests/0.7.0.json +1378 -0
  99. package/dist/templates/atw/definition-of-done.md +65 -0
  100. package/dist/templates/atw/gitignore.txt +7 -0
  101. package/dist/templates/atw/index.d.ts +11 -0
  102. package/dist/templates/atw/index.d.ts.map +1 -1
  103. package/dist/templates/atw/index.js +22 -0
  104. package/dist/templates/atw/index.js.map +1 -1
  105. package/dist/templates/atw/scripts/common/active_task.py +2 -2
  106. package/dist/templates/atw/scripts/common/workflow_phase.py +33 -0
  107. package/dist/templates/atw/scripts/cross_model_review.py +3312 -0
  108. package/dist/templates/atw/scripts/decision_log.py +2002 -0
  109. package/dist/templates/atw/scripts/floor_guard.py +642 -0
  110. package/dist/templates/atw/scripts/task.py +25 -6
  111. package/dist/templates/atw/scripts/tickets.py +480 -10
  112. package/dist/templates/atw/workflow-general.md +6 -1
  113. package/dist/templates/atw/workflow.md +346 -26
  114. package/dist/templates/claude/settings.json +12 -0
  115. package/dist/templates/codex/hooks/session-start.py +2 -2
  116. package/dist/templates/common/bundled-skills/atw-askme/SKILL.md +1 -1
  117. package/dist/templates/common/bundled-skills/atw-askme-with-docs/SKILL.md +1 -1
  118. package/dist/templates/common/bundled-skills/atw-channel/SKILL.md +5 -2
  119. package/dist/templates/common/bundled-skills/atw-channel/references/command-reference.md +44 -5
  120. package/dist/templates/common/bundled-skills/atw-channel/references/progress-debugging.md +9 -0
  121. package/dist/templates/common/bundled-skills/atw-channel/references/workers.md +48 -4
  122. package/dist/templates/common/bundled-skills/atw-code-review/SKILL.md +78 -3
  123. package/dist/templates/common/bundled-skills/atw-codebase-design/SKILL.md +2 -2
  124. package/dist/templates/common/bundled-skills/atw-codebase-design/{DESIGN-IT-TWICE.md → design-it-twice.md} +3 -3
  125. package/dist/templates/common/bundled-skills/atw-cross-model-review/SKILL.md +361 -0
  126. package/dist/templates/common/bundled-skills/atw-cross-model-review/agents/openai.yaml +5 -0
  127. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/four-tiers.md +42 -0
  128. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/log-review-questions.md +38 -0
  129. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/questions.md +54 -0
  130. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/recheck-questions.md +42 -0
  131. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/report-format.md +22 -0
  132. package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/SKILL.md +13 -2
  133. package/dist/templates/common/bundled-skills/atw-domain-modeling/SKILL.md +2 -2
  134. package/dist/templates/common/bundled-skills/atw-handoff/SKILL.md +1 -1
  135. package/dist/templates/common/bundled-skills/atw-implement/SKILL.md +37 -1
  136. package/dist/templates/common/bundled-skills/atw-implement-all/SKILL.md +219 -24
  137. package/dist/templates/common/bundled-skills/atw-implement-spec/SKILL.md +237 -18
  138. package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/SKILL.md +2 -2
  139. package/dist/templates/common/bundled-skills/atw-init-repo/SKILL.md +1 -1
  140. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw-local.md +7 -1
  141. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw.md +7 -1
  142. package/dist/templates/common/bundled-skills/atw-map/SKILL.md +1 -1
  143. package/dist/templates/common/bundled-skills/atw-meta/SKILL.md +1 -1
  144. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/add-project-local-conventions.md +4 -3
  145. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-skills-or-commands.md +21 -16
  146. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-task-lifecycle.md +1 -1
  147. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/overview.md +1 -0
  148. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/task-system.md +2 -1
  149. package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/hooks-and-settings.md +1 -0
  150. package/dist/templates/common/bundled-skills/atw-noob-mode/SKILL.md +1 -1
  151. package/dist/templates/common/bundled-skills/atw-performance/SKILL.md +134 -0
  152. package/dist/templates/common/bundled-skills/atw-performance/agents/openai.yaml +3 -0
  153. package/dist/templates/common/bundled-skills/atw-performance/references/optimization-patterns.md +250 -0
  154. package/dist/templates/common/bundled-skills/atw-performance/references/performance-checklist.md +238 -0
  155. package/dist/templates/common/bundled-skills/atw-performance/references/performance-optimization.md +264 -0
  156. package/dist/templates/common/bundled-skills/atw-prototype/SKILL.md +3 -3
  157. package/dist/templates/common/bundled-skills/atw-prototype/{LOGIC.md → logic.md} +1 -1
  158. package/dist/templates/common/bundled-skills/atw-prototype/references/design-direction.md +91 -58
  159. package/dist/templates/common/bundled-skills/atw-prototype/references/direction-persuasion.md +25 -0
  160. package/dist/templates/common/bundled-skills/atw-prototype/references/style-explorer.md +1 -1
  161. package/dist/templates/common/bundled-skills/atw-prototype/ui.md +194 -0
  162. package/dist/templates/common/bundled-skills/atw-reflect/SKILL.md +77 -0
  163. package/dist/templates/common/bundled-skills/atw-reflect/agents/openai.yaml +5 -0
  164. package/dist/templates/common/bundled-skills/atw-reflect/references/divergent-reviewer.md +38 -0
  165. package/dist/templates/common/bundled-skills/atw-reflect/references/judgment-reviewer.md +37 -0
  166. package/dist/templates/common/bundled-skills/atw-reflect/references/synthesizer.md +63 -0
  167. package/dist/templates/common/bundled-skills/atw-reflect/references/tooling-reviewer.md +48 -0
  168. package/dist/templates/common/bundled-skills/atw-security/SKILL.md +248 -0
  169. package/dist/templates/common/bundled-skills/atw-security/agents/openai.yaml +3 -0
  170. package/dist/templates/common/bundled-skills/atw-security/references/hardening-patterns.md +324 -0
  171. package/dist/templates/common/bundled-skills/atw-security/references/security-checklist.md +248 -0
  172. package/dist/templates/common/bundled-skills/atw-session-insight/SKILL.md +1 -1
  173. package/dist/templates/common/bundled-skills/atw-session-insight/references/cli-quick-reference.md +11 -2
  174. package/dist/templates/common/bundled-skills/atw-spec/SKILL.md +1 -1
  175. package/dist/templates/common/bundled-skills/atw-tdd/SKILL.md +25 -0
  176. package/dist/templates/common/bundled-skills/atw-tickets/SKILL.md +1 -1
  177. package/dist/templates/common/bundled-skills/atw-triage/SKILL.md +5 -5
  178. package/dist/templates/common/bundled-skills/atw-ui/SKILL.md +99 -31
  179. package/dist/templates/common/bundled-skills/atw-ui/references/accessibility-checklist.md +160 -0
  180. package/dist/templates/common/bundled-skills/atw-ui/references/layout-and-viewport.md +7 -5
  181. package/dist/templates/common/bundled-skills/atw-ui/references/media.md +117 -20
  182. package/dist/templates/common/bundled-skills/atw-ui/references/motion.md +47 -23
  183. package/dist/templates/common/bundled-skills/atw-ui/references/play.md +18 -0
  184. package/dist/templates/common/bundled-skills/atw-ui/references/reviewer-manual.md +73 -0
  185. package/dist/templates/common/bundled-skills/atw-ui/references/scroll-narrative.md +98 -0
  186. package/dist/templates/common/bundled-skills/atw-ui/references/tools.md +46 -0
  187. package/dist/templates/common/bundled-skills/atw-ui/references/visual-language.md +40 -24
  188. package/dist/templates/common/bundled-skills/atw-ui/references/visual-review.md +26 -82
  189. package/dist/templates/common/bundled-skills/atw-ui/scripts/shoot.mjs +1721 -0
  190. package/dist/templates/common/bundled-skills/atw-verify-skill/SKILL.md +58 -0
  191. package/dist/templates/common/bundled-skills/atw-verify-skill/agents/openai.yaml +5 -0
  192. package/dist/templates/common/bundled-skills/atw-verify-skill/references/feature-map-example/README.md +47 -0
  193. package/dist/templates/common/bundled-skills/atw-verify-skill/references/feature-map-example/create-note.md +39 -0
  194. package/dist/templates/common/bundled-skills/atw-verify-skill/references/feature-map-example/search.md +45 -0
  195. package/dist/templates/common/bundled-skills/atw-verify-skill/references/generate.md +107 -0
  196. package/dist/templates/common/bundled-skills/atw-verify-skill/references/health-check.md +100 -0
  197. package/dist/templates/common/bundled-skills/atw-verify-skill/references/verify-skill-template.md +99 -0
  198. package/dist/templates/common/bundled-skills/atw-what-happened/SKILL.md +49 -0
  199. package/dist/templates/common/bundled-skills/atw-what-happened/agents/openai.yaml +5 -0
  200. package/dist/templates/common/commands/finish-work.md +10 -1
  201. package/dist/templates/common/commands/start.md +3 -1
  202. package/dist/templates/common/skills/update-spec.md +40 -4
  203. package/dist/templates/copilot/hooks/session-start.py +2 -2
  204. package/dist/templates/dsh/DSH.md +2 -2
  205. package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +10 -0
  206. package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +10 -0
  207. package/dist/templates/omp/config.yml +15 -0
  208. package/dist/templates/omp/extensions/atw/index.ts.txt +135 -18
  209. package/dist/templates/omp/index.d.ts +1 -0
  210. package/dist/templates/omp/index.d.ts.map +1 -1
  211. package/dist/templates/omp/index.js +3 -0
  212. package/dist/templates/omp/index.js.map +1 -1
  213. package/dist/templates/opencode/lib/session-utils.js +4 -2
  214. package/dist/templates/opencode/plugins/inject-workflow-state.js +5 -1
  215. package/dist/templates/pi/extensions/atw/index.ts.txt +80 -7
  216. package/dist/templates/shared-hooks/index.d.ts +8 -1
  217. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  218. package/dist/templates/shared-hooks/index.js +8 -0
  219. package/dist/templates/shared-hooks/index.js.map +1 -1
  220. package/dist/templates/shared-hooks/inject-workflow-state.py +131 -14
  221. package/dist/templates/shared-hooks/session-start.py +4 -2
  222. package/dist/templates/shared-hooks/show-notice.py +135 -0
  223. package/dist/templates/snow/SNOW.md +1 -1
  224. package/dist/utils/initialized.d.ts +9 -0
  225. package/dist/utils/initialized.d.ts.map +1 -0
  226. package/dist/utils/initialized.js +24 -0
  227. package/dist/utils/initialized.js.map +1 -0
  228. package/dist/utils/managed-removal.d.ts +2 -0
  229. package/dist/utils/managed-removal.d.ts.map +1 -1
  230. package/dist/utils/managed-removal.js +23 -3
  231. package/dist/utils/managed-removal.js.map +1 -1
  232. package/dist/utils/optional-skills.d.ts +2 -0
  233. package/dist/utils/optional-skills.d.ts.map +1 -1
  234. package/dist/utils/optional-skills.js +1 -1
  235. package/dist/utils/optional-skills.js.map +1 -1
  236. package/dist/utils/template-hash.d.ts.map +1 -1
  237. package/dist/utils/template-hash.js +3 -0
  238. package/dist/utils/template-hash.js.map +1 -1
  239. package/dist/utils/uninstall-scrubbers.d.ts +10 -0
  240. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  241. package/dist/utils/uninstall-scrubbers.js +50 -0
  242. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  243. package/dist/utils/verify-entries.d.ts +51 -0
  244. package/dist/utils/verify-entries.d.ts.map +1 -0
  245. package/dist/utils/verify-entries.js +399 -0
  246. package/dist/utils/verify-entries.js.map +1 -0
  247. package/package.json +2 -2
  248. package/dist/templates/common/bundled-skills/atw-prototype/UI.md +0 -174
  249. package/dist/templates/common/bundled-skills/atw-prototype/references/visual-language.md +0 -88
  250. package/dist/templates/common/bundled-skills/atw-prototype/references/visual-review.md +0 -63
  251. package/dist/templates/common/bundled-skills/atw-ui/references/imagery.md +0 -69
  252. /package/dist/templates/common/bundled-skills/atw-codebase-design/{DEEPENING.md → deepening.md} +0 -0
  253. /package/dist/templates/common/bundled-skills/atw-domain-modeling/{ADR-FORMAT.md → adr-format.md} +0 -0
  254. /package/dist/templates/common/bundled-skills/atw-domain-modeling/{GLOSSARY-FORMAT.md → glossary-format.md} +0 -0
  255. /package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/{HTML-REPORT.md → html-report.md} +0 -0
  256. /package/dist/templates/common/bundled-skills/atw-triage/{AGENT-BRIEF.md → agent-brief.md} +0 -0
  257. /package/dist/templates/common/bundled-skills/atw-triage/{OUT-OF-SCOPE.md → out-of-scope.md} +0 -0
@@ -0,0 +1,324 @@
1
+ # Hardening Patterns
2
+
3
+ Code patterns and decision aids for the `atw-security` skill. The skill states each rule; this file shows one concrete implementation of it. Open the section you need when you reach that code — it is not meant to be read top to bottom.
4
+
5
+ Shared checklists (threat modeling, pre-commit checks, security headers, CORS, the package-manager matrix, install-script gate, and the OWASP quick-reference tables) live in `./security-checklist.md`.
6
+
7
+ ## OWASP Top 10 Prevention Patterns
8
+
9
+ These are prevention patterns, not a ranking. For the 2021 ordering, see the quick-reference table in `./security-checklist.md#owasp-top-10-quick-reference`.
10
+
11
+ ### Injection
12
+
13
+ ```typescript
14
+ // BAD: SQL injection via string concatenation
15
+ const query = `SELECT * FROM users WHERE id = '${userId}'`;
16
+
17
+ // GOOD: Parameterized query
18
+ const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
19
+
20
+ // GOOD: ORM with parameterized input
21
+ const user = await prisma.user.findUnique({ where: { id: userId } });
22
+ ```
23
+
24
+ ### Broken Authentication
25
+
26
+ ```typescript
27
+ // Password hashing
28
+ import { hash, compare } from 'bcrypt';
29
+
30
+ const SALT_ROUNDS = 12;
31
+ const hashedPassword = await hash(plaintext, SALT_ROUNDS);
32
+ const isValid = await compare(plaintext, hashedPassword);
33
+
34
+ // Session management
35
+ app.use(session({
36
+ secret: process.env.SESSION_SECRET, // From environment, not code
37
+ resave: false,
38
+ saveUninitialized: false,
39
+ cookie: {
40
+ httpOnly: true, // Not accessible via JavaScript
41
+ secure: true, // HTTPS only
42
+ sameSite: 'lax', // CSRF protection
43
+ maxAge: 24 * 60 * 60 * 1000, // 24 hours
44
+ },
45
+ }));
46
+ ```
47
+
48
+ ### Cross-Site Scripting (XSS)
49
+
50
+ ```typescript
51
+ // BAD: Rendering user input as HTML
52
+ element.innerHTML = userInput;
53
+
54
+ // GOOD: Use framework auto-escaping (React does this by default)
55
+ return <div>{userInput}</div>;
56
+
57
+ // If you MUST render HTML, sanitize first
58
+ import DOMPurify from 'dompurify';
59
+ const clean = DOMPurify.sanitize(userInput);
60
+ ```
61
+
62
+ ### Broken Access Control
63
+
64
+ ```typescript
65
+ // Always check authorization, not just authentication
66
+ app.patch('/api/tasks/:id', authenticate, async (req, res) => {
67
+ const task = await taskService.findById(req.params.id);
68
+
69
+ // Check that the authenticated user owns this resource
70
+ if (task.ownerId !== req.user.id) {
71
+ return res.status(403).json({
72
+ error: { code: 'FORBIDDEN', message: 'Not authorized to modify this task' }
73
+ });
74
+ }
75
+
76
+ // Proceed with update
77
+ const updated = await taskService.update(req.params.id, req.body);
78
+ return res.json(updated);
79
+ });
80
+ ```
81
+
82
+ ### Security Misconfiguration
83
+
84
+ ```typescript
85
+ // Security headers (use helmet for Express)
86
+ import helmet from 'helmet';
87
+ app.use(helmet());
88
+
89
+ // Content Security Policy
90
+ app.use(helmet.contentSecurityPolicy({
91
+ directives: {
92
+ defaultSrc: ["'self'"],
93
+ scriptSrc: ["'self'"],
94
+ styleSrc: ["'self'", "'unsafe-inline'"], // Tighten if possible
95
+ imgSrc: ["'self'", 'data:', 'https:'],
96
+ connectSrc: ["'self'"],
97
+ },
98
+ }));
99
+
100
+ // CORS — restrict to known origins
101
+ app.use(cors({
102
+ origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
103
+ credentials: true,
104
+ }));
105
+ ```
106
+
107
+ ### Sensitive Data Exposure
108
+
109
+ ```typescript
110
+ // Never return sensitive fields in API responses
111
+ function sanitizeUser(user: UserRecord): PublicUser {
112
+ const { passwordHash, resetToken, ...publicFields } = user;
113
+ return publicFields;
114
+ }
115
+
116
+ // Use environment variables for secrets
117
+ const API_KEY = process.env.STRIPE_API_KEY;
118
+ if (!API_KEY) throw new Error('STRIPE_API_KEY not configured');
119
+ ```
120
+
121
+ ### Server-Side Request Forgery (SSRF)
122
+
123
+ Any time the server fetches a URL the user influenced — webhooks, "import from URL", image proxies, link previews — an attacker can aim it at internal services (cloud metadata, `localhost`, private IPs).
124
+
125
+ ```typescript
126
+ // BAD: fetch whatever the user gives you
127
+ await fetch(req.body.webhookUrl);
128
+
129
+ // GOOD: allowlist scheme + host, reject if ANY resolved IP is private, forbid redirects
130
+ import { lookup } from 'node:dns/promises';
131
+ import ipaddr from 'ipaddr.js';
132
+
133
+ const ALLOWED_HOSTS = new Set(['hooks.example.com']);
134
+
135
+ async function assertSafeUrl(raw: string): Promise<URL> {
136
+ const url = new URL(raw);
137
+ if (url.protocol !== 'https:') throw new Error('https only');
138
+ if (!ALLOWED_HOSTS.has(url.hostname)) throw new Error('host not allowed');
139
+ // Resolve ALL records; a single private/reserved address fails the check.
140
+ const addrs = await lookup(url.hostname, { all: true });
141
+ if (addrs.some((a) => ipaddr.parse(a.address).range() !== 'unicast')) {
142
+ throw new Error('private/reserved IP');
143
+ }
144
+ return url;
145
+ }
146
+
147
+ await fetch(await assertSafeUrl(req.body.webhookUrl), { redirect: 'error' });
148
+ ```
149
+
150
+ The `range() !== 'unicast'` check covers loopback, link-local `169.254.169.254` (cloud metadata, the #1 SSRF target), private, and unique-local ranges across IPv4 and IPv6.
151
+
152
+ **Caveat — this still has a TOCTOU gap.** `fetch` resolves DNS again after the check, so an attacker using a short-TTL record can rebind to an internal IP between validation and connection. For high-risk surfaces, resolve once and connect to the pinned IP, or put a filtering agent in front (`request-filtering-agent` / `ssrf-req-filter`).
153
+
154
+ ## Input Validation Patterns
155
+
156
+ ### Schema Validation at Boundaries
157
+
158
+ ```typescript
159
+ import { z } from 'zod';
160
+
161
+ const CreateTaskSchema = z.object({
162
+ title: z.string().max(200).trim().min(1),
163
+ description: z.string().max(2000).optional(),
164
+ priority: z.enum(['low', 'medium', 'high']).default('medium'),
165
+ dueDate: z.string().datetime().optional(),
166
+ });
167
+
168
+ // Validate at the route handler
169
+ app.post('/api/tasks', async (req, res) => {
170
+ const result = CreateTaskSchema.safeParse(req.body);
171
+ if (!result.success) {
172
+ return res.status(422).json({
173
+ error: {
174
+ code: 'VALIDATION_ERROR',
175
+ message: 'Invalid input',
176
+ details: result.error.flatten(),
177
+ },
178
+ });
179
+ }
180
+ // result.data is now typed and validated
181
+ const task = await taskService.create(result.data);
182
+ return res.status(201).json(task);
183
+ });
184
+ ```
185
+
186
+ ### File Upload Safety
187
+
188
+ ```typescript
189
+ // Restrict file types and sizes
190
+ const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
191
+ const MAX_SIZE = 5 * 1024 * 1024; // 5MB
192
+
193
+ function validateUpload(file: UploadedFile) {
194
+ if (!ALLOWED_TYPES.includes(file.mimetype)) {
195
+ throw new ValidationError('File type not allowed');
196
+ }
197
+ if (file.size > MAX_SIZE) {
198
+ throw new ValidationError('File too large (max 5MB)');
199
+ }
200
+ // Don't trust the file extension — check magic bytes if critical
201
+ }
202
+ ```
203
+
204
+ ### Destructive Operations on Derived Paths
205
+
206
+ A delete, move, or overwrite is only as safe as the value that names its target. Reading that value from the kernel, a job payload, or a sibling service proves where it *arrived from*, not who *wrote* it — another process's command line is as attacker-controlled as a form field. A shape check ("absolute path, at least one directory deep") proves well-formedness and gets mistaken for authorization; that is how a cleanup routine deletes the root instead of the leaf.
207
+
208
+ Before a destructive call, require all three: the resolved target sits under an **allowlisted root** (compare after resolving symlinks, never on the raw string); it is at least one level **below** that root, so a root is never itself the target; and it carries **evidence that it is yours**, read *before* the operation and before any teardown that removes it — otherwise "absent" and "not mine" are indistinguishable. On refusal, log the rejected target and stop: a cleanup that falls back to a broader default path is the failure this guards against. Worked example in `./security-checklist.md#destructive-path-operations`.
209
+
210
+ Two limits, because the check reads stronger than it is. A marker inside the tree is self-attestation — anything that can write there can write the marker — so the expected owner has to come from authenticated state, and the marker needs integrity protection (restrictive ownership, or a MAC) before it counts as authorization. And resolving a path and then operating on the *name* is a check/use race wherever an untrusted process can swap an ancestor: on a shared volume, hold the target by descriptor and use no-follow, beneath-the-root operations, or make sure the hierarchy cannot change for the duration.
211
+
212
+ ## Dependency Audit Triage
213
+
214
+ Package-manager audits report known advisories; they do not prove a package is trustworthy or that vulnerable code is reachable. Use this decision tree:
215
+
216
+ ```
217
+ The native package-manager audit reports a vulnerability
218
+ ├── Severity: critical or high
219
+ │ ├── Is the vulnerable code reachable in runtime, build, test, or deployment paths?
220
+ │ │ ├── YES --> Fix immediately (update, patch, or replace the dependency)
221
+ │ │ └── NO (confirmed unused across those paths) --> Fix soon, but not a blocker
222
+ │ └── Is a fix available?
223
+ │ ├── YES --> Update to the patched version
224
+ │ └── NO --> Check for workarounds, consider replacing the dependency, or add to allowlist with a review date
225
+ ├── Severity: moderate
226
+ │ ├── Reachable in production? --> Fix in the next release cycle
227
+ │ └── Dev-only? --> Fix when convenient, track in backlog
228
+ └── Severity: low
229
+ └── Track and fix during regular dependency updates
230
+ ```
231
+
232
+ **Key questions:**
233
+ - Is the vulnerable function actually called in your code path?
234
+ - Is the dependency a runtime dependency or dev-only?
235
+ - Is the vulnerability exploitable given your deployment context (e.g., a server-side vulnerability in a client-only app)?
236
+
237
+ When you defer a fix, document the reason and set a review date.
238
+
239
+ ## Rate Limiting
240
+
241
+ ```typescript
242
+ import rateLimit from 'express-rate-limit';
243
+
244
+ // General API rate limit
245
+ app.use('/api/', rateLimit({
246
+ windowMs: 15 * 60 * 1000, // 15 minutes
247
+ max: 100, // 100 requests per window
248
+ standardHeaders: true,
249
+ legacyHeaders: false,
250
+ }));
251
+
252
+ // Stricter limit for auth endpoints
253
+ app.use('/api/auth/', rateLimit({
254
+ windowMs: 15 * 60 * 1000,
255
+ max: 10, // 10 attempts per 15 minutes
256
+ }));
257
+ ```
258
+
259
+ **Count in a shared store once there is more than one process.** `express-rate-limit` keeps its counters in process memory by default. Behind a load balancer each instance holds its own count, so the effective limit is `max × instances`; on serverless or edge runtimes a fresh invocation starts from zero, so the auth limit above may never fire. Pass a shared `store` (Redis via `rate-limit-redis`), or use an HTTP-based limiter that works where a long-lived TCP connection does not (for example `@upstash/ratelimit`):
260
+
261
+ ```typescript
262
+ import { Ratelimit } from '@upstash/ratelimit';
263
+ import { Redis } from '@upstash/redis';
264
+
265
+ const authLimiter = new Ratelimit({
266
+ redis: Redis.fromEnv(), // UPSTASH_REDIS_REST_URL + _TOKEN
267
+ limiter: Ratelimit.slidingWindow(10, '15 m'), // 10 attempts per 15 minutes, across all instances
268
+ });
269
+ const { success } = await authLimiter.limit(`login:${req.ip}`);
270
+ if (!success) return res.status(429).end();
271
+ ```
272
+
273
+ ## Secrets Management
274
+
275
+ ```
276
+ .env files:
277
+ ├── .env.example → Committed (template with placeholder values)
278
+ ├── .env → NOT committed (contains real secrets)
279
+ └── .env.local → NOT committed (local overrides)
280
+
281
+ .gitignore must include:
282
+ .env
283
+ .env.local
284
+ .env.*.local
285
+ *.pem
286
+ *.key
287
+ ```
288
+
289
+ **Always check before committing:**
290
+ ```bash
291
+ # Check for accidentally staged secrets
292
+ git diff --cached | grep -i "password\|secret\|api_key\|token"
293
+ ```
294
+
295
+ **If a secret is ever committed, rotate it.** Deleting the line or rewriting history is not enough — assume it's compromised the moment it reaches a remote. Revoke and reissue the key first, then purge it from history.
296
+
297
+ ## Data Classification
298
+
299
+ Classify personal data as you add fields, so export and deletion requests can find it later:
300
+
301
+ | Class | Examples | Handling |
302
+ |---|---|---|
303
+ | **Non-personal** | Aggregates, anonymized counts | Normal handling |
304
+ | **Personal (PII)** | Name, email, IP, device/user IDs | Minimize, access-control, include in export/delete |
305
+ | **Sensitive** | Health, finance, location, biometrics, gov IDs, anything about minors | Extra basis to collect, stricter access, often encryption + audit logging |
306
+
307
+ ## LLM Output Handling
308
+
309
+ ```typescript
310
+ // BAD: trusting model output as a command or as markup
311
+ const sql = await llm.generate(`Write SQL for: ${userQuestion}`);
312
+ await db.query(sql); // arbitrary query execution
313
+ container.innerHTML = await llm.reply(userMessage); // stored XSS, via the model
314
+
315
+ // GOOD: model output is data — parse defensively, then validate, then encode
316
+ let intent;
317
+ try {
318
+ intent = CommandSchema.parse(JSON.parse(await llm.replyJson(userMessage)));
319
+ } catch {
320
+ throw new ValidationError('unexpected model output'); // JSON.parse or schema failed
321
+ }
322
+ await runAllowlistedAction(intent.action, intent.params);
323
+ container.textContent = await llm.reply(userMessage);
324
+ ```
@@ -0,0 +1,248 @@
1
+ # Security Checklist
2
+
3
+ Quick reference for web application security. Use alongside the `atw-security` skill.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Threat Modeling (Start Here)](#threat-modeling-start-here)
8
+ - [Pre-Commit Checks](#pre-commit-checks)
9
+ - [Authentication](#authentication)
10
+ - [Authorization](#authorization)
11
+ - [Input Validation](#input-validation)
12
+ - [Security Headers](#security-headers)
13
+ - [CORS Configuration](#cors-configuration)
14
+ - [Data Protection](#data-protection)
15
+ - [Dependency Security](#dependency-security)
16
+ - [AI / LLM Security](#ai--llm-security)
17
+ - [Error Handling](#error-handling)
18
+ - [OWASP Top 10 Quick Reference](#owasp-top-10-quick-reference)
19
+ - [OWASP Top 10 for LLMs Quick Reference](#owasp-top-10-for-llms-quick-reference)
20
+
21
+ ## Threat Modeling (Start Here)
22
+
23
+ Before reaching for controls, spend five minutes thinking like an attacker:
24
+
25
+ - [ ] Trust boundaries mapped (requests, uploads, webhooks, third-party APIs, LLM output, and local values written by processes you don't control)
26
+ - [ ] Assets named (credentials, PII, payment data, admin actions, money movement)
27
+ - [ ] STRIDE run per boundary (Spoofing, Tampering, Repudiation, Info disclosure, DoS, Elevation)
28
+ - [ ] Abuse cases written next to use cases ("how would I misuse this?")
29
+
30
+ ## Pre-Commit Checks
31
+
32
+ - [ ] No secrets in code (`git diff --cached | grep -i "password\|secret\|api_key\|token"`)
33
+ - [ ] `.gitignore` covers: `.env`, `.env.local`, `*.pem`, `*.key`
34
+ - [ ] `.env.example` uses placeholder values (not real secrets)
35
+
36
+ ## Authentication
37
+
38
+ - [ ] Passwords hashed with bcrypt (≥12 rounds), scrypt, or argon2
39
+ - [ ] Session cookies: `httpOnly`, `secure`, `sameSite: 'lax'`
40
+ - [ ] Session expiration configured (reasonable max-age)
41
+ - [ ] Rate limiting on login endpoint (≤10 attempts per 15 minutes)
42
+ - [ ] Password reset tokens: time-limited (≤1 hour), single-use
43
+ - [ ] Account lockout after repeated failures (optional, with notification)
44
+ - [ ] MFA supported for sensitive operations (optional but recommended)
45
+
46
+ ## Authorization
47
+
48
+ - [ ] Every protected endpoint checks authentication
49
+ - [ ] Every resource access checks ownership/role (prevents IDOR)
50
+ - [ ] Admin endpoints require admin role verification
51
+ - [ ] API keys scoped to minimum necessary permissions
52
+ - [ ] JWT tokens validated (signature, expiration, issuer)
53
+
54
+ ## Input Validation
55
+
56
+ - [ ] All user input validated at system boundaries (API routes, form handlers)
57
+ - [ ] Validation uses allowlists (not denylists)
58
+ - [ ] String lengths constrained (min/max)
59
+ - [ ] Numeric ranges validated
60
+ - [ ] Email, URL, and date formats validated with proper libraries
61
+ - [ ] File uploads: type restricted, size limited, content verified
62
+ - [ ] SQL queries parameterized (no string concatenation)
63
+ - [ ] HTML output encoded (use framework auto-escaping)
64
+ - [ ] URLs validated before redirect (prevent open redirect)
65
+ - [ ] Server-side URL fetches allowlisted; private/reserved IPs blocked (prevent SSRF)
66
+ - [ ] Destructive path operations (delete/move/overwrite): symlinks resolved, allowlisted root, minimum depth, ownership evidence read before the call
67
+
68
+ ### Destructive Path Operations
69
+
70
+ Containment for a target named by data. Resolve first, then decide — and treat the
71
+ result as a candidate, not as authorization:
72
+
73
+ ```typescript
74
+ import { realpath, readFile } from 'node:fs/promises';
75
+ import { resolve, relative, isAbsolute, join, sep } from 'node:path';
76
+
77
+ const ALLOWED_ROOTS = ['/var/lib/myapp/sessions']; // an allowlist, not a pattern
78
+ const MIN_DEPTH = 1; // so a root is never the target
79
+
80
+ async function resolveDeletable(candidate: string, expectedOwner: string) {
81
+ const target = await realpath(resolve(candidate)); // symlinks resolved BEFORE the check
82
+ const inRoot = ALLOWED_ROOTS.some((root) => {
83
+ const rel = relative(root, target);
84
+ // `rel === '..'` / `'../'` only — a plain `startsWith('..')` would also
85
+ // reject a legitimate child named `..cache`.
86
+ if (rel === '' || rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) return false;
87
+ return rel.split(sep).length >= MIN_DEPTH;
88
+ });
89
+ if (!inRoot) throw new Error(`refusing: outside allowed roots (${target})`);
90
+
91
+ const owner = await readFile(join(target, '.owner'), 'utf8').catch(() => null);
92
+ if (owner?.trim() !== expectedOwner) throw new Error(`refusing: unproven owner (${target})`);
93
+ return target;
94
+ }
95
+ ```
96
+
97
+ What this does not do, and must be said where the snippet is copied from:
98
+
99
+ - **The marker is self-attestation.** Anything that can write inside the root can write
100
+ `.owner`. `expectedOwner` has to come from authenticated state, and the marker needs
101
+ integrity protection (restrictive ownership, or a MAC) before it is authorization
102
+ rather than a consistency check against a misderived target.
103
+ - **Returning a path leaves a check/use race.** Where an untrusted process can swap an
104
+ ancestor between the check and the call, operate on a descriptor with no-follow,
105
+ beneath-the-root semantics, or guarantee the hierarchy is immutable for the duration.
106
+
107
+ ## Security Headers
108
+
109
+ ```
110
+ Content-Security-Policy: default-src 'self'; script-src 'self'
111
+ Strict-Transport-Security: max-age=31536000; includeSubDomains
112
+ X-Content-Type-Options: nosniff
113
+ X-Frame-Options: DENY
114
+ X-XSS-Protection: 0 (disabled, rely on CSP)
115
+ Referrer-Policy: strict-origin-when-cross-origin
116
+ Permissions-Policy: camera=(), microphone=(), geolocation=()
117
+ ```
118
+
119
+ ## CORS Configuration
120
+
121
+ ```typescript
122
+ // Restrictive (recommended)
123
+ cors({
124
+ origin: ['https://yourdomain.com', 'https://app.yourdomain.com'],
125
+ credentials: true,
126
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
127
+ allowedHeaders: ['Content-Type', 'Authorization'],
128
+ })
129
+
130
+ // NEVER use in production:
131
+ cors({ origin: '*' }) // Allows any origin
132
+ ```
133
+
134
+ ## Data Protection
135
+
136
+ - [ ] Sensitive fields excluded from API responses (`passwordHash`, `resetToken`, etc.)
137
+ - [ ] Sensitive data not logged (passwords, tokens, full CC numbers)
138
+ - [ ] PII encrypted at rest (if required by regulation)
139
+ - [ ] HTTPS for all external communication
140
+ - [ ] Database backups encrypted
141
+ - [ ] Personal data is classified, collected against a stated purpose, and minimized
142
+ - [ ] Personal data has a retention limit and a working deletion path (incl. backups, caches, indexes)
143
+ - [ ] Export/delete (data-subject) requests are supported where required; third-party sharing has consent and a data-processing agreement
144
+
145
+ ## Dependency Security
146
+
147
+ First locate the **installation boundary**. If the package is matched by a parent `workspaces` declaration, use that workspace root; otherwise use the nearest project root that owns both its manifest and dependency graph. At that boundary, corroborate `packageManager` (when present), the lockfile, and CI commands. Stop if they disagree or competing manager lockfiles exist there. A nested project is independent only when it is outside the parent workspace; independent subprojects may legitimately use different managers.
148
+
149
+ | Manager/version signal | Frozen/immutable CI install | Known-advisory audit |
150
+ |---|---|---|
151
+ | npm (`package-lock.json` or `npm-shrinkwrap.json`) | `npm ci` | `npm audit` |
152
+ | pnpm | `pnpm install --frozen-lockfile` | `pnpm audit` |
153
+ | Yarn 2+ | `yarn install --immutable` | `yarn npm audit -A -R` |
154
+ | Yarn 1 | `yarn install --frozen-lockfile` | `yarn audit` |
155
+
156
+ For an unlisted manager or version, consult its official documentation; do not substitute another manager's commands or newer defaults.
157
+
158
+ ### Install-Script Gate
159
+
160
+ Never discover dependency lifecycle scripts by first executing an ordinary install on a client whose defaults have not been verified.
161
+
162
+ 1. Bootstrap with dependency scripts disabled, or with a documented default-deny policy plus fail-closed enforcement.
163
+ 2. Inspect the exact script source and package version before approval.
164
+ 3. Record the narrowest native allow/deny policy at the installation boundary and commit it.
165
+ 4. Run a clean frozen/immutable install with that policy and verify the required packages still build.
166
+
167
+ **Point-in-time snapshot:** Package-manager defaults and command names change quickly. Verify this matrix against the pinned client's current official documentation before relying on it.
168
+
169
+ | Manager version | Native policy |
170
+ |---|---|
171
+ | npm without verified granular approvals | Bootstrap with `npm ci --ignore-scripts`, or persist `ignore-scripts=true` when project-wide blocking is intended. Keep scripts disabled or deliberately upgrade before allowing any reviewed dependency script. |
172
+ | npm 11.18.x (verified on 11.18.0) | Unreviewed dependency scripts run with a warning by default. Enforce `strict-allow-scripts=true` before a normal install, then use the workspace-unaware `npm install-scripts ls` from the installation boundary; keep approvals version-pinned and denials name-wide. |
173
+ | npm 12.x (verified on 12.0.1) | Unreviewed dependency scripts are skipped by default; `strict-allow-scripts=true` makes their presence fail the install before execution. Use the same `npm install-scripts` review and approval flow. |
174
+ | pnpm 11+ | Use `pnpm approve-builds` and commit `allowBuilds` decisions; `strictDepBuilds` defaults to `true`, so unreviewed builds fail. |
175
+ | pnpm 10.26–10.x | Configure `allowBuilds` explicitly, or use `pnpm approve-builds` with the legacy `onlyBuiltDependencies` / `ignoredBuiltDependencies` lists. Set `strictDepBuilds: true`; its v10 default is `false`. |
176
+ | pnpm 10.1–10.25 | `pnpm approve-builds` records the legacy lists; enable `strictDepBuilds` where supported (10.3+). |
177
+ | Older or unknown pnpm | Bootstrap with `pnpm install --frozen-lockfile --ignore-scripts`. Keep scripts disabled unless the pinned version documents an enforceable policy. |
178
+ | Yarn 4.14+ | Dependency postinstalls are disabled by default. Grant only required exceptions with top-level `dependenciesMeta.<package>.built: true`. |
179
+ | Yarn 2–4.13 | Set `enableScripts: false` in `.yarnrc.yml`, then grant only required exceptions with top-level `dependenciesMeta.<package>.built: true`; do not enable scripts globally. |
180
+ | Yarn 1 | Bootstrap with `yarn install --ignore-scripts`; keep scripts disabled unless each required exception is reviewed under the pinned client's documented workflow. |
181
+
182
+ Authoritative checks: [npm install-scripts](https://docs.npmjs.com/cli/v11/commands/npm-install-scripts/), [install policy](https://docs.npmjs.com/cli/v11/commands/npm-install/), and [CLI releases](https://github.com/npm/cli/releases); [pnpm approve-builds](https://pnpm.io/cli/approve-builds) and [build settings](https://pnpm.io/settings#allowbuilds); [Yarn security](https://yarnpkg.com/features/security) and [manifest](https://yarnpkg.com/configuration/manifest#dependenciesMeta).
183
+
184
+ **Supply-chain hygiene** (advisory audits do not catch newly malicious packages):
185
+ - [ ] Exactly one authoritative lockfile per project/workspace root is committed and CI never rewrites it
186
+ - [ ] Critical/high findings are triaged for reachability; deferrals have a reason and review date
187
+ - [ ] Forced audit remediation (`npm audit fix --force` or equivalent) is never automatic; remediation diffs and changelogs are reviewed
188
+ - [ ] Registry signatures/provenance are verified where the manager supports it
189
+ - [ ] Dependency lifecycle scripts are blocked before first execution and approved only through the pinned manager's native policy
190
+ - [ ] New dependencies are reviewed for ownership, maintenance, release age, provenance, transitive graph, and typosquatting
191
+
192
+ ## AI / LLM Security
193
+
194
+ For any feature that calls an LLM (chatbots, summarizers, agents, RAG):
195
+
196
+ - [ ] Model output treated as untrusted — never into `eval`/SQL/shell/`innerHTML`/file paths
197
+ - [ ] Prompt injection assumed; permissions enforced in code, not in the system prompt
198
+ - [ ] Secrets, cross-tenant data, and full system prompts kept out of the context window
199
+ - [ ] Tool/agent permissions scoped; destructive or irreversible actions require confirmation
200
+ - [ ] Token, rate, and recursion/loop limits set (bound consumption)
201
+
202
+ ## Error Handling
203
+
204
+ ```typescript
205
+ // Production: generic error, no internals
206
+ res.status(500).json({
207
+ error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' }
208
+ });
209
+
210
+ // NEVER in production:
211
+ res.status(500).json({
212
+ error: err.message,
213
+ stack: err.stack, // Exposes internals
214
+ query: err.sql, // Exposes database details
215
+ });
216
+ ```
217
+
218
+ ## OWASP Top 10 Quick Reference
219
+
220
+ | # | Vulnerability | Prevention |
221
+ |---|---|---|
222
+ | 1 | Broken Access Control | Auth checks on every endpoint, ownership verification |
223
+ | 2 | Cryptographic Failures | HTTPS, strong hashing, no secrets in code |
224
+ | 3 | Injection | Parameterized queries, input validation |
225
+ | 4 | Insecure Design | Threat modeling, spec-driven development |
226
+ | 5 | Security Misconfiguration | Security headers, minimal permissions, audit deps |
227
+ | 6 | Vulnerable Components | The ecosystem's dependency audit (`npm audit`, `pip-audit`, ...), keep deps updated, minimal deps |
228
+ | 7 | Auth Failures | Strong passwords, rate limiting, session management |
229
+ | 8 | Data Integrity Failures | Verify updates/dependencies, signed artifacts |
230
+ | 9 | Logging Failures | Log security events, don't log secrets |
231
+ | 10 | SSRF | Validate/allowlist URLs, restrict outbound requests |
232
+
233
+ ## OWASP Top 10 for LLMs Quick Reference
234
+
235
+ For apps with LLM features. See the [OWASP GenAI Security Project](https://genai.owasp.org/llm-top-10/).
236
+
237
+ | ID | Risk | Prevention |
238
+ |---|---|---|
239
+ | LLM01 | Prompt Injection | Don't trust the system prompt as a boundary; enforce permissions in code |
240
+ | LLM02 | Sensitive Information Disclosure | Keep secrets/PII out of prompts; filter outputs |
241
+ | LLM03 | Supply Chain | Vet models, datasets, and plugins like any dependency |
242
+ | LLM04 | Data and Model Poisoning | Use trusted model sources, verify integrity; vet fine-tuning and RAG data |
243
+ | LLM05 | Improper Output Handling | Treat model output as untrusted; validate, parameterize, encode |
244
+ | LLM06 | Excessive Agency | Scope tool permissions; confirm destructive actions |
245
+ | LLM07 | System Prompt Leakage | Assume the system prompt can leak; put no secrets in it |
246
+ | LLM08 | Vector and Embedding Weaknesses | Partition RAG embeddings per tenant; validate documents before indexing |
247
+ | LLM09 | Misinformation | Ground answers with citations; validate critical claims; keep a human in the loop |
248
+ | LLM10 | Unbounded Consumption | Cap tokens, request rate, and loop/recursion depth |
@@ -11,7 +11,7 @@ It is intentionally a **capability skill, not a workflow**. There is no fixed ou
11
11
 
12
12
  ## What `atw mem` is
13
13
 
14
- A local CLI that indexes the user's past Claude Code, Codex, Pi Agent, and ZCode conversation logs and lets you list, search, slice by ATW task boundaries, and dump cleaned dialogue from them. Claude and Codex use `~/.claude/projects/` and `~/.codex/sessions/`. Pi uses its default or environment-configured session root, global `~/.pi/agent/settings.json`, and the scoped project's `.pi/settings.json`; relative `sessionDir` values resolve from the settings file directory. Project-local Pi settings require project-scoped lookup through the current cwd or `--cwd`. ZCode uses `~/.zcode/cli/db/db.sqlite`. OpenCode logs are not yet indexable (provider adapter pending) — when an OpenCode session is the obvious target, surface that limitation rather than guessing.
14
+ A local CLI that indexes the user's past Claude Code, Codex, Pi Agent, omp, and ZCode conversation logs and lets you list, search, slice by ATW task boundaries, and dump cleaned dialogue from them. Claude and Codex use `~/.claude/projects/` and `~/.codex/sessions/`. Pi uses its default or environment-configured session root, global `~/.pi/agent/settings.json`, and the scoped project's `.pi/settings.json`; relative `sessionDir` values resolve from the settings file directory. Project-local Pi settings require project-scoped lookup through the current cwd or `--cwd`. omp uses `~/.omp/agent/sessions/` (sub-agent transcripts nested under a session are not listed). ZCode uses `~/.zcode/cli/db/db.sqlite`. OpenCode logs are not yet indexable (provider adapter pending) — when an OpenCode session is the obvious target, surface that limitation rather than guessing.
15
15
 
16
16
  Nothing in `mem` is uploaded. All reads are local.
17
17
 
@@ -9,14 +9,15 @@ Full flag reference for the five subcommands. Pin this as the authoritative sour
9
9
  | `list` | List sessions. Default subcommand when none is given. |
10
10
  | `search <keyword>` | Find sessions whose contents match a keyword. |
11
11
  | `context <session-id>` | Drill into one session: top-N hit turns + surrounding context. Pair with `--grep` for keyword anchoring. |
12
- | `extract <session-id>` | Dump cleaned dialogue. Combine with `--phase` / `--grep` to slice. |
12
+ | `extract <session-id>` | Dump cleaned dialogue. Combine with `--phase` / `--grep` to slice, or `--tools` / `--after` for the tools reading. |
13
+ | `extract --context <id>` | Same, finding the session by its ATW context id instead of a session id. |
13
14
  | `projects` | List active project `cwd` values with session counts. Use this to discover which `--cwd` to pass to other subcommands. |
14
15
 
15
16
  ## Flags (apply where meaningful)
16
17
 
17
18
  | Flag | Subcommands | Meaning |
18
19
  | --------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
19
- | `--platform claude\|codex\|opencode\|pi\|all` | all | Default `all`. OpenCode sessions are read, but `--phase` does not apply to them — see "Caveats" below. |
20
+ | `--platform claude\|codex\|omp\|opencode\|pi\|all` | all | Default `all`. OpenCode sessions are read, but `--phase` does not apply to them — see "Caveats" below. |
20
21
  | `--since YYYY-MM-DD` | list / search | Inclusive lower date bound. |
21
22
  | `--until YYYY-MM-DD` | list / search | Inclusive upper date bound. |
22
23
  | `--global` | list / search | Include sessions from every project on this machine. Default is the current project `cwd`. |
@@ -24,6 +25,10 @@ Full flag reference for the five subcommands. Pin this as the authoritative sour
24
25
  | `--limit N` | list / search | Cap output rows. Default `50`. |
25
26
  | `--grep KW` | extract / context | Filter turns by keyword. Multi-token AND when whitespace-separated. |
26
27
  | `--phase brainstorm\|implement\|all` | extract | Slice session by ATW task boundaries. `brainstorm` = `[task.py create, task.py start)`. `implement` = turns outside brainstorm windows. Default `all`. |
28
+ | `--tools` | extract | Tools reading: in recorded order, the dialogue plus each tool call (name + command, or a `key: value` argument summary) and its result, and on Claude Code each message a hook had it show the user (`## Hook message`). Thinking is never shown. Claude Code, Codex, Pi, omp only. Cannot be combined with `--phase` / `--grep`. |
29
+ | `--result-lines N` | extract --tools | Lines kept at the start and at the end of a long call input or result; the cut is written as `[... K lines omitted ...]`. Default `20`. |
30
+ | `--after <ISO time>` | extract | Only what was recorded at or after this time (e.g. `2026-10-18T15:30:12+08:00`). Without `--tools` it gives the dialogue only. Claude Code, Codex, Pi, omp only. |
31
+ | `--context <id>` | extract | Find the session by ATW context id — copy it from the evidence cell of the decision-log `start` row (`claude_<session-id>`, `omp_transcript_<hash>`, `session_<id>`, …). Exact match only; no match, or more than one, is an error — nothing is guessed. |
27
32
  | `--turns N` | context | Number of hit turns to return. Default `3`. |
28
33
  | `--around N` | context | Surrounding turns to include per hit. Default `1`. |
29
34
  | `--max-chars N` | context | Total character budget. Default `6000` (~1500 tokens). |
@@ -44,6 +49,10 @@ atw mem context 5842592d --grep "lock contention" --turns 5 --around 2
44
49
  # the user started a week ago.
45
50
  atw mem extract 5842592d --phase brainstorm
46
51
 
52
+ # Re-read a run's commands and results: take the context id from the evidence
53
+ # cell of the run's decision-log `start` row and the time from its time cell.
54
+ atw mem extract --context claude_<session-id> --tools --after 2026-10-18T15:30:12+08:00
55
+
47
56
  # List every project this machine has ATW sessions for, with counts.
48
57
  atw mem projects
49
58
  ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: atw-spec
3
- description: "将当前的讨论内容整理成一份需求规格说明书,并发布到项目问题跟踪系统中——无需进行访谈,只需对已讨论的内容进行总结即可。"
3
+ description: "将当前的讨论内容整理成一份需求规格说明书,并发布到项目问题跟踪系统中——无需进行访谈,只需对已讨论的内容进行总结即可。讨论得差不多、用户要把聊过的内容整理成规格说明书时使用。"
4
4
  disable-model-invocation: true
5
5
  ---
6
6