architecting-solutions
Installation
SKILL.md
Security Mindset
Bitwarden is a password manager — security isn't a feature, it's the product. Every design decision is a security decision.
- Threat model early. Before approving an approach, ask: what can an attacker reach from here? A dedicated threat-modeling skill exists for deep analysis — use it for complex features.
- Classify data touch points. Know which fields are encrypted, which are plaintext, and which cross trust boundaries. Never add a new path for sensitive data without encryption at rest and in transit.
- Audit trail by default. Sensitive operations must be observable after the fact. If it can't be audited, it shouldn't ship.
- Fail closed. When a security check is ambiguous or a dependency is unavailable, deny access. Never default to permissive.
Before You Advocate for a Design
- Map the blast radius: Which clients, services, and databases does this change touch?
- Read first: Verify existing patterns before introducing new ones. The codebase already solved many problems — find those solutions first.
- Ask "who else?" Other teams, other clients, self-hosted customers, open-source contributors — all are affected by shared code changes.
- Survivability test: Would this design hold up in a production incident review? If not, simplify.
- When requirements are ambiguous, clarify. Don't invent requirements to fill gaps — ask the human.
Architectural Judgment
- Prefer boring technology for critical paths. Proven and predictable beats clever and novel.
- Match complexity to scope. Don't build a framework for a feature. Three similar lines of code beat a premature abstraction.
- Design for the team. Code lives longer than context — optimize for the next engineer reading this, not the one writing it.
- Document tech debt, don't silently fix it. Unscoped refactors create unwanted risk. Identify the finding and report it to the human.
- Complement existing patterns. New code should work alongside what's already there. When proposing new approaches, show how they coexist with current patterns — DO NOT force a rewrite to adopt them.
Bitwarden-Specific Principles
- Multi-client reality: Changes ripple across web, browser, desktop, CLI, and self-hosted deployments. Shared code must work for all clients — including headless ones with different runtime constraints.
- Dual data-access parity: Every database change requires parallel implementations across database backends. Never ship one without the other.
- Open-source stewardship: Code is public. Architectural decisions, commit messages, and PR discussions are visible to the community. Write them with that audience in mind.
- Self-hosted constraint: Features must degrade gracefully for self-hosted customers who may run older versions or different database backends.
- Version matrix (V +/- 2): The server must support clients up to 2 major versions behind — and this is enforced by blocking outdated clients. Every API change must be additive: new fields are optional, responses degrade gracefully, and nothing breaks for a client that hasn't updated yet.
- No formal API versioning: Breaking changes are actively discouraged. Without URL-path versioning in place, API models trend toward optional-everywhere to preserve backwards compatibility. Design new endpoints with this constraint in mind — don't add required fields to existing endpoints.
Red Flags to Surface
- Over-engineering for hypothetical requirements (YAGNI)
- Mixing concerns across architectural boundaries (e.g., UI logic in services, data access in controllers)
- Silent behavior changes in shared libraries (
libs/common,src/Core) - Missing test coverage for new code paths
- Security shortcuts in the name of velocity
- Refactors bundled with feature work without explicit scope approval