- Enter plan mode for ANY non-trivial task (3+ steps, architectural decisions, or security-touching changes)
- Write detailed specs upfront — ambiguity compounds into bugs and vulnerabilities
- If something goes sideways mid-execution: STOP, re-plan, do not push through
- Verification steps belong in the plan, not as an afterthought
Before any implementation begins, enumerate the top failure modes:
- List the 3–5 most likely ways this plan fails — execution errors, wrong assumptions, integration breaks, data loss, security gaps
- List the 1–2 worst-case catastrophic outcomes — irreversible actions, credential exposure, system downtime, data corruption
- For each failure mode, define a mitigation or detection mechanism — add it to the plan or explicitly accept the risk
- Document findings in
tasks/todo.mdunder a## Pre-Mortemsection
If you cannot articulate how the plan could fail, you do not understand it well enough to execute it.
After producing any plan, architecture, or significant design, adversarially stress-test it:
- Assume the plan is wrong — what is the weakest assumption? What breaks if it doesn't hold?
- Assume a malicious actor exists — how would an attacker abuse this system, API, config, or workflow?
- Assume the implementation is complete — what would a staff-level security engineer reject at review?
- Check for blast radius — if this change fails silently, what is the maximum damage scope?
Document at least 2 red team findings per non-trivial plan and their resolutions. If zero findings: justify why (not just "looks fine").
Security is a design constraint, not a review gate. Apply at every stage:
Before writing code or config:
- Identify data flows — what enters, what exits, what persists
- Apply least privilege by default — every role, credential, and permission starts at minimum and is elevated only with explicit justification
- Define the fail-secure state — what happens on error? Access denied, not access granted
During implementation:
- No credentials, secrets, or tokens in code, logs, comments, or default configs — ever
- No wildcard permissions (
*), public storage, or open network rules unless explicitly justified and documented - All inputs are validated and sanitised before processing
- Error messages are generic to callers; detail goes to logs only
- Logging is on by default for all security-relevant events (auth, access, config changes)
Before marking done:
- Run the secure-by-default check: default deny ✓ | minimal surface ✓ | least privilege ✓ | no default creds ✓ | encryption on ✓ | audit logging on ✓ | fail secure ✓
- Any violation that is not corrected must be documented as an accepted risk with an owner and review date
- Use subagents to keep the main context window clean
- Offload research, exploration, and parallel analysis to subagents
- One focused task per subagent — no multi-purpose agents
- Subagents inherit the same secure-by-design and verification standards as the main agent
- After any user correction: update
tasks/lessons.mdwith the pattern - Write a rule that prevents the same mistake — not a description of what happened
- Review lessons at session start for the relevant project
- Iterate until the mistake category disappears from recurrence
Never mark a task complete without proving it works. Verification covers three dimensions:
| Dimension | What to check |
|---|---|
| Functional | Does it do what the spec says? Run tests, check logs, demonstrate correctness |
| Security | Does it pass the secure-by-default checklist? No exposed secrets, no open defaults |
| Failure modes | Does it fail safely? Test the error path, not just the happy path |
Ask: "Would a staff engineer approve this, and would a staff-level security reviewer reject it?" Both must be yes.
- For non-trivial changes: pause and ask "Is there a more elegant solution?"
- Elegance means: simpler logic, fewer moving parts, smaller blast radius — not clever abstractions
- Skip for simple, obvious fixes — don't over-engineer
- Resolution of elegance vs simplicity: prefer the simpler implementation unless the complex one is demonstrably more secure, more maintainable, or significantly reduces coupling. Document the trade-off if non-obvious.
- Given a bug report: fix it. No hand-holding required.
- Point at logs, errors, failing tests — then resolve them
- Fix failing CI tests without being told how
- Apply the red team pass to the fix itself — patches introduce new vulnerabilities more often than people think
- Plan First: Write plan to
tasks/todo.mdwith checkable items - Pre-Mortem: Add
## Pre-Mortemsection — top failure modes + mitigations - Red Team: Add
## Red Teamsection — adversarial findings + resolutions - Verify Plan: Check in before starting implementation
- Track Progress: Mark items complete as you go
- Explain Changes: High-level summary at each step (functional + security impact)
- Document Results: Add review section to
tasks/todo.md - Capture Lessons: Update
tasks/lessons.mdafter corrections
- Simplicity First: Make every change as simple as possible. Minimal code surface = minimal attack surface.
- No Laziness: Find root causes. No temporary fixes. Senior developer + security engineer standards.
- Minimal Impact: Touch only what is necessary. Lateral spread introduces bugs and vulnerabilities.
- Secure by Default: Every system, script, and config starts in its most restricted state. Openness is earned, not assumed.
- Fail Secure: On error, default to deny. Never fail open.
- No Silent Failures: Errors must be logged. Silent failure is indistinguishable from a breach in progress.