diff --git a/plugins/bitwarden-software-engineer/.claude-plugin/plugin.json b/plugins/bitwarden-software-engineer/.claude-plugin/plugin.json new file mode 100644 index 0000000..87868ff --- /dev/null +++ b/plugins/bitwarden-software-engineer/.claude-plugin/plugin.json @@ -0,0 +1,19 @@ +{ + "name": "bitwarden-software-engineer", + "version": "0.1.0", + "description": "Comprehensive full-stack software engineering assistant proficient in modern software development at Bitwarden.", + "author": { + "name": "Bitwarden", + "url": "https://github.com/bitwarden" + }, + "homepage": "https://github.com/bitwarden/ai-plugins/tree/main/plugins/bitwarden-software-engineer", + "repository": "https://github.com/bitwarden/ai-plugins", + "keywords": [ + "typescript", + "csharp", + "rust", + "sql", + "fullstack" + ], + "agents": ["./agents/bitwarden-software-engineer.md"] +} diff --git a/plugins/bitwarden-software-engineer/README.md b/plugins/bitwarden-software-engineer/README.md new file mode 100644 index 0000000..e57ab6a --- /dev/null +++ b/plugins/bitwarden-software-engineer/README.md @@ -0,0 +1,3 @@ +# Bitwarden Software Engineer Plugin + +Claude Code skills for Bitwarden development patterns. Generic AI coding assistance doesn't know our conventions, architecture decisions, or anti-patterns we've learned the hard way. These skills keep Claude focused on how we build software here. diff --git a/plugins/bitwarden-software-engineer/agents/bitwarden-software-engineer.md b/plugins/bitwarden-software-engineer/agents/bitwarden-software-engineer.md new file mode 100644 index 0000000..cedac5b --- /dev/null +++ b/plugins/bitwarden-software-engineer/agents/bitwarden-software-engineer.md @@ -0,0 +1,20 @@ +--- +name: bitwarden-software-engineer +description: Full-stack software engineer specializing in C#, JavaScript, TypeScript, Rust, and SQL. Coordinates complex development tasks across languages. Use for feature implementation, and cross-language refactoring. +model: sonnet +tools: Read, Write, Edit, Bash, Glob, Grep +color: blue +--- + +You are a senior full-stack software engineer with expertise across C#, JavaScript, TypeScript, Rust, and SQL. You're an engineer working with the team, not just executing commands. Focus intently on code quality **over** code quantity. You avoid over-engineering because you focus on what's needed, not what might be needed. + +## Purpose + +Coordinate complex software development tasks that span multiple languages, architectural concerns, or require full-stack reasoning. + +## Working Approach + +1. **Understand context:** Before creating or modifying code, read the relevant existing files to understand current patterns. Don't assume — verify. +2. **Clarify, don't invent.** If requirements are ambiguous or incomplete, ask the human rather than making assumptions. State what you're uncertain about. +3. **Stay in scope.** Implement what was asked. Don't add features, abstractions, or "nice-to-haves" that weren't requested. If you see an improvement opportunity, mention it — don't just build it. +4. **Build incrementally, validate continuously.** Start with core functionality, run tests, check for regressions, and confirm the implementation meets requirements before declaring done. diff --git a/plugins/bitwarden-software-engineer/skills/writing-client-code/SKILL.md b/plugins/bitwarden-software-engineer/skills/writing-client-code/SKILL.md new file mode 100644 index 0000000..4f0d6f6 --- /dev/null +++ b/plugins/bitwarden-software-engineer/skills/writing-client-code/SKILL.md @@ -0,0 +1,81 @@ +--- +name: writing-client-code +description: Bitwarden client code conventions for Angular and TypeScript. Use when working in the clients mono-repo, creating components, services, or modifying web/browser/desktop apps. +tools: Read, Write, Edit, Bash, Glob, Grep +--- + +## Repository Structure + +The `clients` mono-repo contains: + +- `apps/web`, `apps/browser`, `apps/desktop`, `apps/cli` — client applications +- `libs/common` — shared code for ALL clients including CLI (no Angular dependencies) +- `libs/angular` — Angular-specific code for visual clients only +- `libs/components` — Angular Component Library + +## Angular Requirements + +**New components** must use: + +- OnPush change detection +- New control flow syntax (`@if`, `@for`, `@switch`) +- Standalone components +- `inject()` function for dependency injection +- Reactive Forms + +**Existing components:** Follow the patterns already in the file. Don't migrate `*ngIf` → `@if`, `@Input()` decorators → `input()` signals, or other modernizations unless explicitly asked. Keep changes focused on the task. + +**If asked to refactor/migrate:** Then apply modern patterns to the files in scope — but don't expand to "while we're here" refactors in other files. + +## Component Patterns + +**Thin components:** Components contain only view logic. Business logic belongs in services. + +**Composition over inheritance:** Avoid extending components across clients. Compose using shared child components. + +**Cross-client services** (in `libs/common`): Use abstract classes as interfaces — CLI uses Node, not Angular DI. Implementation prefixes: `Default*`, `Web*`, `Browser*`, `Desktop*`, `Cli*`. + +## File Naming + +Dashes for words, dots for types: + +- `folder.service.ts` → `FolderService` +- `folder-list.component.ts` → `FolderListComponent` +- `folder.view.ts` → `FolderView` +- `cipher-type.enum.ts` → `CipherType` (const object, not enum) + +## TypeScript Rules + +**No enums.** Use frozen const objects with `Object.freeze()` and `as const`. Always explicitly type variables using the derived type. + +**Imports:** + +- Within same package (`@bitwarden/common`): relative imports +- Across packages: absolute imports (`@bitwarden/common/platform/...`) + +## State Management + +| Context | Use | +| ----------------------------------- | ------- | +| Component local state | Signals | +| Angular-only services | Signals | +| Cross-client services (libs/common) | RxJS | + +**Avoid manual subscriptions.** Prefer `| async` pipe. When subscriptions are necessary, pipe through `takeUntilDestroyed()` — enforced by `prefer-takeUntil` lint rule. + +## Styling + +All Tailwind classes require **`tw-` prefix**: + +```html +
+ +
+
+``` + +Use Component Library (`libs/components/`) for common UI patterns. + +## Testing + +Use Jest with `jest-mock-extended`. diff --git a/plugins/bitwarden-software-engineer/skills/writing-database-queries/SKILL.md b/plugins/bitwarden-software-engineer/skills/writing-database-queries/SKILL.md new file mode 100644 index 0000000..3a5bcd1 --- /dev/null +++ b/plugins/bitwarden-software-engineer/skills/writing-database-queries/SKILL.md @@ -0,0 +1,86 @@ +--- +name: writing-database-queries +description: Bitwarden database queries, stored procedures, and migrations. Use when working with .sql files, stored procedures, EF migrations, or database schema changes. +tools: Read, Write, Edit, Bash, Glob, Grep +--- + +## Repository Architecture + +MSSQL uses Dapper with stored procedures. All other databases (PostgreSQL, MySQL, SQLite) use Entity Framework Core. Every database change requires both implementations. + +- Dapper: `Repository Method → Stored Procedure → View (for reads)` +- EF: `Repository Method → DbContext → Generated SQL` + +Repository interfaces abstract both. When a stored procedure performs specific operations, the EF implementation must replicate identical behavior. + +## Migration Workflow (Evolutionary Database Design) + +Zero-downtime deployments require three-phase migrations: + +**Phase 1 — Initial** (`util/Migrator/DbScripts`): Runs before code deployment. Must be fast, backwards-compatible. Adds support for new features without breaking current release. + +**Phase 2 — Transition** (`util/Migrator/DbScripts_transition`): Runs after deployment as background task. Handles slow data migrations. Must be batched. NO schema changes. + +**Phase 3 — Finalization** (`util/Migrator/DbScripts_finalization`): Runs at next release. Removes backwards-compatibility scaffolding. + +Other locations: + +- `src/Sql/dbo` — Master schema source of truth +- `src/Sql/dbo_finalization` — Future schema state +- `util/Migrator/DbScripts_manual` — Exceptional cases (index rebuilds) + +## Migration Naming + +MSSQL: `YYYY-MM-DD_##_MigrationName.sql` (e.g., `2024-01-15_00_AddUserColumn.sql`) + +Finalization: `YYYY-0M-FinalizationMigration.sql` + +EF migration class names must exactly match the MSSQL migration name portion. + +Generate EF migrations: `pwsh ef_migrate.ps1 ` + +Apply migrations: `pwsh migrate.ps1 -all` (all databases) or `pwsh migrate.ps1` (MSSQL only) + +## All Migrations Must Be Idempotent + +```sql +-- Tables +IF OBJECT_ID('[dbo].[TableName]') IS NULL +BEGIN + CREATE TABLE [dbo].[TableName] (...) +END +GO + +-- Columns +IF COL_LENGTH('[dbo].[TableName]', 'ColumnName') IS NULL +BEGIN + ALTER TABLE [dbo].[TableName] + ADD [ColumnName] INT NOT NULL CONSTRAINT DF_Table_Column DEFAULT 0 +END +GO + +-- Procedures: always use CREATE OR ALTER +CREATE OR ALTER PROCEDURE [dbo].[Entity_Action] +``` + +## Testing + +Use `[DatabaseData]` attribute to run tests against all configured databases: + +```csharp +[Theory, DatabaseData] +public async Task TestMethod(IOrganizationRepository repo) +{ + // Runs for MSSQL/Dapper, Postgres/EF, MySQL/EF, SQLite/EF +} +``` + +For migration testing, use `MigrationName` parameter matching both SQL file suffix and EF class name. + +Use separate test databases (`vault_test`) from development (`vault_dev`). + +## Database-Specific Guidance + +For T-SQL patterns (MSSQL, stored procedures, Dapper), read [guides/tsql.md](guides/tsql.md). + +For Entity Framework patterns (PostgreSQL, MySQL, SQLite, EF migrations), read [guides/entity-framework.md](guides/entity-framework.md). diff --git a/plugins/bitwarden-software-engineer/skills/writing-database-queries/guides/entity-framework.md b/plugins/bitwarden-software-engineer/skills/writing-database-queries/guides/entity-framework.md new file mode 100644 index 0000000..63eaa41 --- /dev/null +++ b/plugins/bitwarden-software-engineer/skills/writing-database-queries/guides/entity-framework.md @@ -0,0 +1,27 @@ +# Entity Framework Guide + +Entity Framework (EF) is used for PostgreSQL, MySQL, MariaDB, and SQLite. The Dapper ORM is used for MSSQL. + +## Generating Migrations + +```powershell +pwsh ef_migrate.ps1 +``` + +Creates migrations for all EF targets simultaneously. + +## Key Differences from MSSQL + +- Queries working against MySQL may fail against Postgres (e.g., Postgres doesn't support `Min` on boolean values) +- Always run integration tests with `[DatabaseData]` rather than manually testing each database +- EF implementation must replicate exact behavior of corresponding stored procedures + +## Testing + +```csharp +[Theory, DatabaseData] +public async Task TestMethod(IOrganizationRepository repo) +{ + // Automatically runs against all configured EF databases +} +``` diff --git a/plugins/bitwarden-software-engineer/skills/writing-database-queries/guides/tsql.md b/plugins/bitwarden-software-engineer/skills/writing-database-queries/guides/tsql.md new file mode 100644 index 0000000..11ec702 --- /dev/null +++ b/plugins/bitwarden-software-engineer/skills/writing-database-queries/guides/tsql.md @@ -0,0 +1,100 @@ +# T-SQL Guide + +## Stored Procedure Naming + +Use `{Entity}_{Action}[_Descriptor]` pattern: + +| Operation | Pattern | Example | +| ---------------- | ----------------------------- | ------------------------------ | +| Create | `Entity_Create` | `User_Create` | +| Read single | `Entity_ReadById` | `Organization_ReadById` | +| Read by criteria | `Entity_ReadBy{Criteria}` | `User_ReadByEmail` | +| Read many | `Entity_ReadManyBy{Criteria}` | `Cipher_ReadManyByUserId` | +| Update | `Entity_Update` | `User_Update` | +| Delete | `Entity_DeleteById` | `Cipher_Delete` | +| Soft delete | `Entity_SoftDelete` | `Cipher_SoftDelete` | +| Special | `Entity_{ActionDescription}` | `User_BumpAccountRevisionDate` | + +## Procedure Structure + +```sql +CREATE OR ALTER PROCEDURE [dbo].[Entity_Action] + @Id UNIQUEIDENTIFIER, + @OptionalParam NVARCHAR(50) = NULL -- Nullable default for backwards compatibility +AS +BEGIN + SET NOCOUNT ON + -- Logic here +END +GO +``` + +## Code Style + +- Keywords: `UPPERCASE` +- Objects: Square brackets — `[dbo].[TableName]`, `[ColumnName]` +- Tables/Columns: PascalCase +- Parameters: `@PascalCase` +- Constraints: `PK_{Table}`, `FK_{Table}_{RefTable}`, `DF_{Table}_{Column}`, `IX_{Table}_{Columns}` + +Standard columns: + +```sql +[Id] UNIQUEIDENTIFIER NOT NULL +[CreationDate] DATETIME2(7) NOT NULL +[RevisionDate] DATETIME2(7) NOT NULL +``` + +## Anti-Patterns to Avoid + +### Index creation on large tables + +Creating indexes on `dbo.Cipher`, `dbo.OrganizationUser`, or other large tables can cause outages. Never specify `ONLINE = ON` in scripts — production handles this automatically, and the option fails on unsupported SQL Server editions. + +### NOT NULL columns done wrong + +```sql +-- BAD: Full table scan +ALTER TABLE [dbo].[Table] ADD [Column] INT NULL +UPDATE [dbo].[Table] SET [Column] = 0 +ALTER TABLE [dbo].[Table] ALTER COLUMN [Column] INT NOT NULL + +-- GOOD: Metadata-only operation +ALTER TABLE [dbo].[Table] + ADD [Column] INT NOT NULL CONSTRAINT DF_Table_Column DEFAULT 0 +``` + +### Defaults on string types + +Use defaults only for numeric types (`BIT`, `TINYINT`, `INT`, `BIGINT`). Never use defaults for `VARCHAR`, `NVARCHAR`, or MAX types. + +### Missing view metadata refresh + +After modifying tables, refresh views: + +```sql +EXECUTE sp_refreshview N'[dbo].[ViewName]' +GO +``` + +After altering views, refresh dependent procedures: + +```sql +IF OBJECT_ID('[dbo].[ProcName]') IS NOT NULL + EXECUTE sp_refreshsqlmodule N'[dbo].[ProcName]' +GO +``` + +## Backwards Compatibility + +New parameters must have nullable defaults: + +```sql +@NewParameter DATATYPE = NULL +``` + +When renaming columns during EDD transition: + +```sql +SET @FirstName = COALESCE(@FirstName, @FName); +``` diff --git a/plugins/bitwarden-software-engineer/skills/writing-server-code/SKILL.md b/plugins/bitwarden-software-engineer/skills/writing-server-code/SKILL.md new file mode 100644 index 0000000..a9ee062 --- /dev/null +++ b/plugins/bitwarden-software-engineer/skills/writing-server-code/SKILL.md @@ -0,0 +1,90 @@ +--- +name: writing-server-code +description: Bitwarden server code conventions for C# and .NET. Use when working in the server repo, creating commands, queries, services, or API endpoints. +tools: Read, Write, Edit, Bash, Glob, Grep +--- + +## Repository Structure + +The `server` repo contains: + +- `src/Api` — REST API endpoints +- `src/Identity` — Authentication/identity service +- `src/Core` — Business logic, commands, queries, services +- `src/Infrastructure` — Data access, repositories + +Run with `dotnet run` from service directories. Migrations: `pwsh dev/migrate.ps1`. + +## Command Query Separation (CQS) + +New features should use the CQS pattern — discrete action classes instead of large entity-focused services [ADR-0008](https://contributing.bitwarden.com/architecture/adr/server-CQRS-pattern). + +**Commands** = write operations (e.g., `CreateCipherCommand`). Change state, may return result. + +**Queries** = read operations (e.g., `GetOrganizationApiKeyQuery`). Return data, never change state. + +Name classes after the action: `RotateOrganizationApiKeyCommand`. Each command/query has single responsibility. + +**Existing code:** The codebase includes service-based patterns developed over time. When modifying existing services, follow the patterns already in the file. Don't refactor to CQS unless explicitly asked. + +**If asked to refactor to CQS:** Then apply the pattern to the scope requested — but don't expand beyond what was asked. + +## Naming Conventions + +- Private fields: `_camelCase` with underscore prefix +- Properties: `PascalCase`, spelled out (e.g., `OrganizationConfiguration` not `OrgConfig`) +- Blank line between property groups and methods + +## Code Style + +- Spaces (not tabs), 4-space indentation +- Always use curly braces for control blocks (even single-line) +- Long conditionals: trailing operators when split across lines +- Constructors with multiple arguments: one argument per line +- `var` for `using` and `foreach` contextual variables + +## Dependency Injection + +Use `TryAdd*` overloads, not `AddSingleton`/`AddTransient`: + +```csharp +// ✅ Correct +services.TryAddSingleton(); + +// ❌ Wrong +services.AddSingleton(); +``` + +Consider creating dependency groups for related services. + +## GUID Generation + +Always use `CoreHelpers.GenerateComb()` for entity IDs — prevents SQL Server index fragmentation: + +```csharp +// ✅ Correct +var id = CoreHelpers.GenerateComb(); + +// ❌ Wrong +var id = Guid.NewGuid(); +``` + +## Controller Actions + +- Avoid function overloads — use distinct names (`Get` vs `GetAll`) +- Name after the action (`CreateThing`, `UpdateThing`), not HTTP method (`PostThing`, `PutThing`) +- One route per action — don't expose same function under multiple routes + +## Caching + +**Don't implement caching unless requested.** If a user describes a performance problem where caching might help, suggest it — but don't implement without confirmation. Caching adds complexity and isn't always the right solution. + +When caching is needed, use `IFusionCache` instead of `IDistributedCache` [ADR-0028](https://contributing.bitwarden.com/architecture/adr/adopt-fusion-cache). Register with `AddExtendedCache` and inject via keyed services. + +FusionCache provides automatic key prefixing, L1/L2 caching, stampede protection, and backplane sync across nodes. + +**Existing code:** Don't migrate existing `IDistributedCache` usage to FusionCache unless explicitly asked. + +## Testing + +Use xUnit. Run integration tests with `dotnet test` from `test/Infrastructure.IntegrationTest`.