security-strategy
On-demand maintenance of the per-repo security memory: bootstrap an initial threat model + add/append incidents to docs/security-strategy.md with proper marker comments, then refresh the Supabase index. NEVER gates planning — /plan reads the resulting memory automatically via Phase 0.5b. Triggers on: "security strategy", "add security incident", "draft incident", "/security-strategy", "bootstrap security memory". Usage: /security-strategy bootstrap — interview to seed initial threat model + first incident /security-strategy add-incident — interactive draft of one new incident entry /security-strategy add-incident from-commit <sha> — pre-fill from commit subject + changed files
- License 许可
- MIT
- 最近更新
- 2026-11-10
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- security-strategy
- description
- On-demand maintenance of the per-repo security memory: bootstrap an initial threat model + add/append incidents to docs/security-strategy.md with proper marker comments, then refresh the Supabase index. NEVER gates planning — /plan reads the resulting memory automatically via Phase 0.5b. Triggers on: "security strategy", "add security incident", "draft incident", "/security-strategy", "bootstrap security memory". Usage: /security-strategy bootstrap — interview to seed initial threat model + first incident /security-strategy add-incident — interactive draft of one new incident entry /security-strategy add-incident from-commit <sha> — pre-fill from commit subject + changed files
- disable-model-invocation
- true
02 资源文件 1
- 参考文档references/worktree-preflight.md3.3 KB
03 SKILL.md 正文
/security-strategy — proactive security memory maintenance
Explicit invocation only — host-neutral.
disable-model-invocation: trueenforces this in Claude Code and in VS Code Copilot, which reads.claude/skills/and honours that key (verified against VS Code Agent Skills docs 2026-09-02). Hosts beyond those two are unverified, and a key cannot carry the reasoning anyway, so the rule is stated here as well.Run this only when the user asked for it. It writes
docs/security-strategy.mdand publishes to the shared index, and an incident drafted from a passing mention is a false record in a security memory other people will later trust.
This skill maintains the markdown source-of-truth at
docs/security-strategy.md. After any edit, it runs
node scripts/security-memory/refresh-incidents.mjs so the Supabase embedding
index stays current.
Always by path, never via an npm run alias. The sync never merges npm
scripts into a consumer's package.json, so a security:refresh alias exists
in the source repo only. The earlier workaround appended --if-present to that
alias, which made the Missing script error disappear by exiting 0 without
running anything — so a consumer's index silently never refreshed. The
refresher is itself synced, so the path always resolves.
The skill is on-demand only — it never blocks /cycle, /plan, or
/ship. The planner (Phase 0.5b) consults the memory via the cross-skill
bridge regardless of whether this skill has run recently.
Worktree preflight — in a linked git worktree the synced tooling tree
scripts/.claude-skills/is absent — it is gitignored, sogit worktree adddoes not populate it, and every command below that uses it dies on a bareMODULE_NOT_FOUND. Runnpm run skills:hydratefirst. If this repo defines no such script,references/worktree-preflight.mdholds the entry to add — ask the user first, since it edits theirpackage.json.
Step 0 — Parse Mode
| Input | Mode |
|---|---|
/security-strategy bootstrap |
BOOTSTRAP — first-time seed of threat model + optional first incident |
/security-strategy add-incident |
ADD — interactive draft of one new incident |
/security-strategy add-incident from-commit <sha> |
ADD_FROM_COMMIT — pre-fill from a security-relevant commit |
If no mode given → ask the user which one.
Step 1a — BOOTSTRAP
The repo template at docs/security-strategy.md is the canonical
skeleton. Bootstrap fills in placeholders rather than emitting a
parallel template — so changes to the template's structure (parser
sections, comment markers, header text) only need to happen in one
place and bootstrap stays automatically in sync.
If the file is already populated (the threat-model placeholder text
"_(no threat model recorded yet" is absent), ask: "File appears already
bootstrapped — overwrite the threat-model section, or skip to add-incident?"
On overwrite, take a .bak copy first.
Otherwise interview the user briefly:
- "What does this app/repo handle? (1-2 sentences)" → assets
- "Who is the realistic attacker model? (drive-by/insider/state-level)" → actors
- "Compliance regime that applies, if any? (PCI / GDPR / SOC2 / HIPAA / none)"
- "Top 1-2 security concerns you currently have for this repo, in plain English"
Then read the existing checked-in template at
docs/security-strategy.md, replace the ## Threat model body
between the heading and ## Incidents with a paragraph synthesising
the user's answers (Assets / Actors / Compliance / Concerns), and
write back via the round-trip parse + atomicWriteFileSync protocol
(R3-M4):
- Read current file; locate
## Threat model…## Incidentsspan. - Substitute the body, leave headings + the
## Incidentsplaceholder comments untouched. - Pass full new content through
parseSecurityStrategy()— assert no parse warnings; if any, fail loudly and don't write. - Call
atomicWriteFileSync('docs/security-strategy.md', content).
Then run node scripts/security-memory/refresh-incidents.mjs and surface its summary line.
Step 1b — ADD or ADD_FROM_COMMIT
Determine the incident's id: scan existing markdown for highest
INC-NNN, increment by 1. Pad to 3 digits (INC-001, INC-002, …).
For ADD_FROM_COMMIT: pre-fill from git show <sha>:
- description: commit subject line (sanitised — no AI co-authoring trailers)
- affected_paths:
git show --name-only <sha>filtered to source files - mitigation_ref: try to detect: if commit added a Semgrep rule under
semgrep/, reference it; else "manual" - lessons_learned: empty initially — prompt user to fill in
For interactive ADD, prompt the user for each field with examples.
Write protocol (R3-M4):
- Read current
docs/security-strategy.md. - Insert the new incident block at the END of the
## Incidentssection, BEFORE any## Historical incidentsheading if present. - The block format:
<!-- incident:start id="INC-NNN" --> **Description**: <text> **Affected paths**: `<path1>`, `<path2>` **Mitigation**: `<semgrep:rule-id | scripts/path | manual>` **Lessons learned**: <text> <!-- incident:end --> - Round-trip parse the new full file content via
parseSecurityStrategy()— assert the new entry appears inincidents[]with non-nulldescriptionAND no parse warnings reference the new ID. - Only on round-trip success →
atomicWriteFileSync(). - Run
node scripts/security-memory/refresh-incidents.mjsand surface result summary. - If round-trip fails → output the parsed warnings, do NOT write, ask the user to revise.
Step 2 — Surface results
═══════════════════════════════════════
/security-strategy — DONE
Mode: <BOOTSTRAP | ADD | ADD_FROM_COMMIT>
File: docs/security-strategy.md (<N> incidents total)
Refresh: <upserted N, swept M, on-default-branch=Y/N>
═══════════════════════════════════════
If on a feature branch and the user added an incident, gently note: "Incidents from feature branches UPSERT but don't trigger sweep — the canonical retired-set updates when the default branch refreshes."
Hard rules
- Never write
docs/security-strategy.mdwithout round-trip parse first. A malformed entry that the parser silently skips is worse than a noisy warning. - Never include real secrets (API keys, passwords, payment data) in the markdown — even though
redactSecrets()runs before egress, the markdown itself goes to PR review and git history. - Never inflate the threat model. Real assets + realistic actors only. A false threat model misleads /plan worse than no threat model.
- One incident per security-relevant fix — not per CVE in a third-party dep, not per Dependabot bump. Genuine post-incident learning material.
Reference files
| File | Summary | Read when |
|---|---|---|
references/worktree-preflight.md |
Worktree preflight remedy — the skills:hydrate npm script to add when a linked worktree lacks the tooling tree. | A command dies with MODULE_NOT_FOUND in a linked worktree AND this repo has no skills:hydrate script. |
04 同仓库更多 Skills
stated-absent
Negative fixture — the contract's stated string never appears in this file.
nonexistent-implementation
Negative fixture — contract references an implementation file that does not exist.
document-only-with-params
Negative fixture — a document-only gate illegally carries params (schema must refuse this fake-check pattern).
lying-skill
Fixture skill for the gate-honesty self-check — every gate here is deliberately dishonest.
visual-audit
Math-first, deterministic visual/paint inspection — the 4th UX lens, complementing persona-test (journey), click-test (page), and nav-audit (system). Drives Playwright + computed styles + bounding boxes + CDP forced-pseudo-state to audit declared-token conformance, light/dark theme parity, layout physics, and affordance signifiers. A VLM is advisory-only and never gates. CI gate is drift-only on the changed contracted surface. Triggers on: "visual audit", "check styling consistency", "theme parity", "dark mode parity", "design token drift", "paint audit", "button/card consistency", "focus ring audit", "/visual-audit".
ux-lock
Generate Playwright e2e specs. Two modes: 1. LOCK mode — pin a fix's DOM contract so it doesn't regress (default). 2. VERIFY mode — check that a /plan plan was actually implemented by parsing its Acceptance Criteria section and driving the live URL. VERIFY mode grades a plan against a RUNNING app. To judge the plan document itself, before anything is built, that is /audit-plan. Triggers on: "ux lock", "lock ux", "lock in the fix", "write regression spec", "generate e2e test for", "regression test for commit", "lock this fix", "verify the plan", "verify plan implementation", "check the plan was built", "audit frontend implementation", "did we ship the plan". Full command syntax: see the Usage section in this skill.