-
Notifications
You must be signed in to change notification settings - Fork 0
Implement bitwarden-software-engineer Claude Code Plugin with Agent Skills #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 18 commits
d0710d1
9b8de8b
60f5594
d847042
61812c3
edff708
2ce853e
42ddf68
7c4f463
b55f3fa
1485e81
7651203
22b9a4e
355194d
da5f71d
d764a3f
5321dea
68898b2
adfb364
4647eea
9e9d061
8bfd4b6
1b6070b
dab205f
023990f
aa35c87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| --- | ||
| name: writing-client-code | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. βΉοΈ We must be mindful of what's in the various repos instructing and defining these approaches, and eliminate that content in favor of this one at the right time. Have to have one single source of truth, as a skill, here. |
||
| 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 | ||
| <div class="tw-bg-background-alt2 tw-p-4"> | ||
| <!-- β --> | ||
| <div class="bg-background-alt2 p-4"><!-- β --></div> | ||
| </div> | ||
| ``` | ||
|
|
||
| Use Component Library (`libs/components/`) for common UI patterns. | ||
|
|
||
| ## Testing | ||
|
|
||
| Use Jest with `jest-mock-extended`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| 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 <MigrationName>` | ||
|
|
||
| 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). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <MigrationName> | ||
| ``` | ||
|
|
||
| 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 | ||
| } | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| # T-SQL Guide | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π¨ Per your other guide, this is meant to be ORM-focused right? So we'd write this with a Dapper mindset, but still include the T-SQL references which it uses. |
||
|
|
||
| ## Stored Procedure Naming | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment applies in several other places. My understanding is these guides document approach and rationale, but we should have the actual "how" in close-to-code or the docs site; traditionally I'd want just the former but these are company-wide and can't be just in individual repos. |
||
|
|
||
| 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); | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
β Just found out while experimenting that this should be named
AGENT.md.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not technically required. I'm for making it a Bitwarden practice though. We just need to document it somewhere. By default, when using Claude Code to generate a new agent it does not name the file
AGENT.md. It uses a descriptive name likepr-knowledge-extractor.mdortest-forge-engineer.md, so devs would have to manually rename them when created this way.