RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/bitwarden-server-claude-claude ↔ bitwarden-server-util-seeder-claude

Comparison

A · CLAUDE.md · bitwarden/serverB · CLAUDE.md · bitwarden/server
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections09230%
Commands0330%
Section tags31630%

What each file covers

Sections

0 shared · 9 only in A · 23 only in B
  • − Bitwarden Server - Claude Code Configuration
  • − Project Context Files
  • − Critical Rules
  • − Project Structure
  • − Security Requirements
  • − Common Commands
  • − Development Workflow
  • − Key Architectural Decisions
  • − References
  • + Bitwarden Seeder Library - Claude Code Configuration
  • + Quick Reference
  • + Commands
  • + Build
  • + Run tests
  • + Run single test
  • + Pattern Decision Tree
  • + Pipeline Architecture
  • + Parallelism
  • + Performance A/B Testing
  • + Density Profiles
  • + Data/ File Organization
  • + The Recipe Contract
  • + Zero-Knowledge Architecture
  • + Data Flow
  • + Pipeline path (fixture → entity)
  • + Core encryption (shared by all paths)
  • + Rust Crypto Dependency
  • + Encryption Schemes (crypto taxonomy)
  • + Deterministic Data Generation
  • + Scenarios
  • + Collection Management Settings
  • + Security Reminders

Commands

0 shared · 3 only in A · 3 only in B
  • − dotnet build
  • − dotnet test
  • − dotnet run --project src/Api
  • + dotnet build util/Seeder/Seeder.csproj
  • + dotnet test test/SeederApi.IntegrationTest/
  • + dotnet test test/SeederApi.IntegrationTest/ --filter "FullyQualifiedName~TestMethodName"

Section tags

3 shared · 1 only in A · 6 only in B
  • − architecture
  • + build
  • + test
  • + testing-strategy
  • + api
  • + performance
  • + deployment
  •   security
  •   do-not
  •   agent-behaviour

Line diff

+190 added−54 removed18 unchanged8.6% identical
bitwarden/server · .claude/CLAUDE.md
@@ −1 @@
1# Bitwarden Server - Claude Code Configuration
2 
3## Project Context Files
4 
5**Read these files before reviewing to ensure that you fully understand the project and contributing guidelines**
6 
71. @README.md
82. @CONTRIBUTING.md
93. @.github/PULL_REQUEST_TEMPLATE.md
10 
11## Critical Rules
12 
13- **NEVER** use code regions: If complexity suggests regions, refactor for better readability
14- **NEVER** compromise zero-knowledge principles: User vault data must remain encrypted and inaccessible to Bitwarden
15- **NEVER** log or expose sensitive data: No PII, passwords, keys, or vault data in logs or error messages
16- **ALWAYS** use secure communication channels: Enforce confidentiality, integrity, and authenticity
17- **ALWAYS** encrypt sensitive data: All vault data must be encrypted at rest, in transit, and in use
18- **ALWAYS** prioritize cryptographic integrity and data protection
19- **ALWAYS** add unit tests (with mocking) for any new feature development
20 
21## Project Structure
 
22 
23- **Source Code**: `/src/` - Services and core infrastructure
24- **Tests**: `/test/` - Test logic aligning with the source structure, albeit with a `.Test` suffix
25- **Utilities**: `/util/` - Migration tools, seeders, and setup scripts
26- **Dev Tools**: `/dev/` - Local development helpers
27- **Configuration**: `appsettings.{Environment}.json`, `/dev/secrets.json` for local development
28 
29## Security Requirements
30 
31- **Compliance**: SOC 2 Type II, SOC 3, HIPAA, ISO 27001, GDPR, CCPA
32- **Principles**: Zero-knowledge, end-to-end encryption, secure defaults
33- **Validation**: Input sanitization, parameterized queries, rate limiting
34- **Logging**: Structured logs, no PII/sensitive data in logs
 
 
 
 
 
 
35 
36## Common Commands
37 
38- **Build**: `dotnet build`
39- **Test**: `dotnet test`
40- **Run locally**: `dotnet run --project src/Api`
41- **Database update**: `pwsh dev/migrate.ps1`
42- **Generate OpenAPI**: `pwsh dev/generate_openapi_files.ps1`
43 
44## Development Workflow
45 
46- Security impact assessed
47- xUnit tests added / updated
48- Performance impact considered
49- Error handling implemented
50- Breaking changes documented
51- CI passes: build, test, lint
52- Feature flags considered for new features
53- CODEOWNERS file respected
54 
55### Key Architectural Decisions
 
 
 
 
 
56 
57- Use .NET nullable reference types (ADR 0024)
58- TryAdd dependency injection pattern (ADR 0026)
59- Authorization patterns (ADR 0022)
60- OpenTelemetry for observability (ADR 0020)
61- Log to standard output (ADR 0021)
62 
63## References
64 
65- [Server architecture](https://contributing.bitwarden.com/architecture/server/)
66- [Architectural Decision Records (ADRs)](https://contributing.bitwarden.com/architecture/adr/)
67- [Contributing guidelines](https://contributing.bitwarden.com/contributing/)
68- [Setup guide](https://contributing.bitwarden.com/getting-started/server/guide/)
69- [Code style](https://contributing.bitwarden.com/contributing/code-style/)
70- [Bitwarden security whitepaper](https://bitwarden.com/help/bitwarden-security-white-paper/)
71- [Bitwarden security definitions](https://contributing.bitwarden.com/architecture/security/definitions)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72 
bitwarden/server · util/Seeder/CLAUDE.md
@@ +1 @@
1# Bitwarden Seeder Library - Claude Code Configuration
2 
3## Quick Reference
4 
5**For detailed pattern descriptions (Factories, Recipes, Models, Scenes, Queries, Data), read `README.md`.**
6 
7**For detailed usages of the Seeder library, read `util/SeederUtility/README.md` and `util/SeederApi/README.md`**
 
 
8 
9## Commands
10 
11```bash
12# Build
13dotnet build util/Seeder/Seeder.csproj
 
 
 
 
14 
15# Run tests
16dotnet test test/SeederApi.IntegrationTest/
17 
18# Run single test
19dotnet test test/SeederApi.IntegrationTest/ --filter "FullyQualifiedName~TestMethodName"
20```
 
 
21 
22## Pattern Decision Tree
23 
24```
25Need to create test data?
26├─ ONE entity with encryption? → Factory
27├─ ONE cipher from a SeedVaultItem? → CipherSeed.FromSeedItem() + {Type}CipherSeeder.Create()
28├─ MANY entities as cohesive operation? → Recipe or Pipeline
29├─ Flexible preset-based seeding? → Pipeline (RecipeBuilder + Steps)
30├─ Complete test scenario with ID mangling? → Scene
31├─ READ existing seeded data? → Query
32└─ Data transformation plaintext ↔ encrypted? → Model
33```
34 
35## Pipeline Architecture
36 
37**Modern pattern for composable fixture-based and generated seeding.**
 
 
 
 
38 
39**Flow**: Preset JSON or Options → RecipeOrchestrator → RecipeBuilder → IStep/IAsyncStep[] → RecipeExecutor → SeederContext → BulkCommitter → IPostCommitStep[]
40 
41**Key actors**:
 
 
 
 
 
 
 
42 
43- **RecipeBuilder**: Fluent API with dependency validation
44- **IStep / IAsyncStep**: Isolated units of work (CreateOrganizationStep, CreateUsersStep, etc.). Use `IAsyncStep` for steps that do real I/O. A step additionally marked `IPostCommitStep` is deferred until after the bulk commit, so it observes committed rows — but sees cleared entity lists, since only the `EntityRegistry` and the context's scalar properties survive the commit.
45- **SeederContext**: Shared mutable state bag (NOT thread-safe)
46- **RecipeExecutor**: Awaits steps sequentially, captures statistics, commits via BulkCommitter, then runs any post-commit steps
47- **RecipeOrchestrator**: Orchestrates recipe building and execution (from presets or options)
48- **SeederDependencies** (`Options/`): Bundles infrastructure services (`DatabaseContext`, `IMapper`, `IPasswordHasher<User>`, `IManglerService`, `ILicensingService`, `IAttachmentStorageService`) into a single record. Recipes and the Orchestrator accept this instead of loose parameters. The CLI utility builds it via `SeederServiceFactory.Create().ToDependencies()`.
49 
50**Why two step interfaces, not one async contract?** Deliberate — don't unify. Collapsing to one `Task ExecuteAsync(SeederContext)` costs: rewrite 22 step classes (18 in `Steps/`, 4 test doubles); force 20 `.Execute(context)` sites in `test/SeederApi.IntegrationTest/Steps/` to `await`, their test methods to `async`; and `TreatWarningsAsErrors` is on repo-wide (`Directory.Build.props`), so CS1998 makes `async` without `await` a build error — every sync step needs `return Task.CompletedTask`. Permanent trap. The split costs less: two-arm union in `OrderedStep`, `object`-typed `Inner`, one duplicated `RecipeBuilder` registration. Diverges from `IScene`/`IQuery` — single `Task`-returning, no sync twin.
 
 
 
 
51 
52**Fixture/preset separation**: Fixtures (organizations, rosters, ciphers) are independent and never reference each other. The preset is the only layer that composes fixtures and defines cross-cutting relationships (folder assignments, favorites). See `Seeds/docs/architecture.md`.
53 
54**Phase order (org presets)**: Org → OrgApiKey → Roster → Owner (conditional) → Generator (conditional) → Users → Groups → Collections → Folders → Ciphers → CipherAttachments → CipherCollections → CipherFolders → CipherFavorites → PersonalCiphers
55**Phase order (individual presets)**: IndividualUser → NamedFolders → Generator → Folders → Ciphers → CipherAttachments → FolderAssignments → FavoriteAssignments
56 
57**Individual user presets** use the Pipeline with `CreateIndividualUserStep` (no org, no groups, no collections). These presets live in `Seeds/fixtures/presets/individual/` and are identified by having a `"user"` key instead of `"organization"`. They support `folderNames`, `folderAssignments`, and `favoriteAssignments` for fixture-driven personal vault organization. See `Seeds/docs/presets.md` for the catalog.
58 
59See `Pipeline/` folder for implementation.
60 
61## Parallelism
62 
63Steps execute sequentially (phase order preserved by RecipeExecutor). Async steps are awaited one at a time and MUST NOT be batched with `Task.WhenAll` — `SeederContext` is not thread-safe and each step reads state written by the ones before it. Within a step, `CreateUsersStep` and `GeneratePersonalCiphersStep` use `Parallel.For` internally for CPU-bound Rust FFI work (key generation, encryption).
64 
65**Thread-safety requirements:**
66 
67- `GeneratorContext` lazy properties (`??=`) must be force-initialized before any `Parallel.For` loop to prevent a data race
68- Generators use `ThreadLocal<Faker>` for thread-safe deterministic data generation
69- `ManglerService` and `SeederContext` are NOT thread-safe -- pre-compute their outputs before entering parallel loops
70 
71## Performance A/B Testing
72 
73When measuring step-level performance changes, use paired worktrees:
74 
75- Create `server-PM-XXXXX/perf-baseline` and `server-PM-XXXXX/perf-optimized` worktrees
76- Both worktrees get `Stopwatch` timing in `RecipeExecutor.ExecuteAsync()` (the baseline measurement)
77- Only the optimized worktree gets actual code changes
78- Run presets with `--mangle` flag to avoid DB collisions between runs
79- Compare per-step timings across 3+ runs each, discard the first run (JIT warmup)
80- `.worktrees/` is already in `.gitignore`
81 
82## Density Profiles
83 
84Steps accept an optional `DensityProfile` that controls relationship patterns between users, groups, collections, and ciphers. When null, steps use the original round-robin behavior. When present, steps branch into density-aware algorithms.
85 
86**Key files**:
87 
88- `Options/DensityProfile.cs` — strongly-typed options (public class)
89- `Models/SeedPresetDensity.cs` — JSON preset deserialization targets (internal records)
90- `Data/Enums/MembershipDistributionShape.cs` — Uniform, PowerLaw, MegaGroup
91- `Data/Enums/CollectionFanOutShape.cs` — Uniform, PowerLaw, FrontLoaded
92- `Data/Enums/CipherCollectionSkew.cs` — Uniform, HeavyRight
93- `Data/Distributions/PermissionDistributions.cs` — 11 named distributions by org tier
94 
95**Backward compatibility contract**: `DensityProfile? == null` MUST produce identical output to the original code. Every step guards this with `if (_density == null) { /* original path */ }`.
96 
97**Preset JSON**: Add an optional `"density": { ... }` block. See `Seeds/schemas/preset.schema.json` for the full schema.
98 
99**Presets**: Organized into `features/`, `qa/`, `scale/`, `validation/` folders under `Seeds/fixtures/presets/`. See `Seeds/docs/presets.md` for the full catalog.
100 
101**Verification**: SQL queries for validating density algorithms are in `Seeds/docs/verification.md`.
102 
103## Data/ File Organization
104 
105New files under `Data/` belong in the matching subfolder (`Distributions/`, `Enums/`, `Generators/`, `Static/`) — never loose at the top level. See `Data/README.md` for what each subfolder holds. If a new file's concern doesn't fit an existing subfolder, that's a signal to create one, not to drop it loose.
106 
107**Two Enums homes, by concern:** `Data/Enums/` (namespace `Bit.Seeder.Data.Enums`) holds the generation-config surface (`CompanyType`, `PasswordStrength`, distribution shapes, etc. — "Enums are the API"). Crypto-taxonomy enums that describe how seeded vault data is encrypted (`CipherEncryptionType`, `AttachmentSchemeType`) live in the top-level `Enums/` folder (namespace `Bit.Seeder.Enums`), one enum per file.
108 
109## The Recipe Contract
110 
111Recipes follow strict rules:
112 
1131. A Recipe SHALL accept `SeederDependencies` as its single constructor parameter
1142. A Recipe SHALL have exactly one public entry point — `Seed()` when synchronous, `SeedAsync()` when it returns `Task`/`Task<T>`. Pipeline-backed Recipes (`OrganizationRecipe`, `IndividualUserRecipe`) are async; the direct-to-database Recipes (`CollectionsRecipe`, `GroupsRecipe`, `OrganizationDomainRecipe`, `OrganizationWithUsersRecipe`) remain synchronous.
1153. A Recipe MUST produce one cohesive result
1164. A Recipe MAY overload that entry point with different parameters
1175. A Recipe SHALL use private helper methods for internal steps
1186. A Recipe SHALL use BulkCopy for performance when creating multiple entities
1197. A Recipe SHALL compose Factories for individual entity creation
1208. A Recipe SHALL NOT expose implementation details as public methods
121 
122## Zero-Knowledge Architecture
123 
124**Critical:** Unencrypted vault data never leaves the client. The server never sees plaintext.
125 
126The Seeder uses the Rust SDK via FFI because it must behave like a real Bitwarden client:
127 
1281. Generate encryption keys (like client account setup)
1292. Encrypt vault data client-side (same SDK as real clients)
1303. Store only encrypted result
131 
132## Data Flow
133 
134### Pipeline path (fixture → entity)
135 
136```
137SeedVaultItem → CipherSeed.FromSeedItem() → CipherSeed → {Type}CipherSeeder.Create(options) → CipherViewDto → encrypt_fields (Rust FFI) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
138```
139 
140### Core encryption (shared by all paths)
141 
142```
143CipherViewDto → JSON + [EncryptProperty] field paths → encrypt_fields (Rust FFI, bitwarden_crypto) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
144```
145 
146Shared logic: `Factories/CipherEncryption.cs`, `Models/EncryptedCipherDtoExtensions.cs`
147 
148## Rust Crypto Dependency
149 
150The Rust shim (`util/RustSdk/rust/`) depends only on `bitwarden_crypto`. It does **not** depend on `bitwarden_vault` — the seeder drives field selection via `[EncryptProperty]` attributes, not SDK cipher types.
151 
152Before modifying encryption integration, run `RustSdkCipherTests` to validate roundtrip encryption.
153 
154## Encryption Schemes (crypto taxonomy)
155 
156Seeded data spans two orthogonal encryption axes, named with Bitwarden's canonical vocabulary (defined in `Enums/CipherEncryptionType.cs` and `Enums/AttachmentSchemeType.cs`):
157 
158- **Cipher encryption** (`cipherEncryption`): `userKey` (no cipher key; `Cipher.Key` null) or `cipherKey` (per-cipher key wrapped by the vault key).
159- **Attachment scheme version** (`attachmentVersion`): `v0` (no attachment key), `v1` (attachment key wrapped by the vault key), `v2` (attachment key wrapped by the cipher key).
160 
161**Invariant:** a cipher and its attachments use the same strategy — `v2` requires a `cipherKey` host. `Steps/CreateCipherAttachmentsStep.cs` and `Seeds/schemas/cipher.schema.json` both enforce this; keep them in sync.
162 
163**Wire mapping:** `AttachmentSchemeType.{V0,V1,V2}` casts to `u32 {0,1,2}` and is matched verbatim in `util/RustSdk/rust/src/attachment.rs`. The value *is* the version number — do not reintroduce an offset.
164 
165**Do not conflate with account Encryption V1/V2.** Attachment `v0/v1/v2` is key-wrapping only. Everything the seeder emits is Encryption-V1 type-2 `EncString` (AES-256-CBC-HMAC); no COSE/type-7 path exists. A future V2/COSE capability is a **separate** axis (a new enum), never a new attachment version.
166 
167## Deterministic Data Generation
168 
169Same domain = same seed = reproducible data:
170 
171```csharp
172var seed = options.Seed ?? DeriveStableSeed(options.Domain);
173```
174 
175## Scenarios
176 
177Developer-facing documentation in `Seeds/docs/scenarios/`. Each file maps an engineering problem to a Seeder command.
178 
179**Maintenance rules:**
180 
181- When adding a new preset, check if an existing scenario should reference it as a variation
182- When adding a new command or flag, check if it enables a new scenario or changes an existing one
183- When CLI flags, commands, or preset names change, scan all `*.md` files under `Seeds/` and `SeederUtility/` for stale references
184- Scenario files follow the template in `Seeds/docs/scenarios/README.md`
185- Never duplicate CLI flag documentation — link to `SeederUtility/README.md`
186- Never duplicate preset catalog details — link to `Seeds/docs/presets.md`
187- Scenarios describe _why_ (the problem). READMEs describe _how_ (the tool). Keep the split clean.
188 
189**File relationships:**
190 
191- `SeederUtility/README.md` → CLI reference (commands, flags, examples) → links to scenarios
192- `Seeds/docs/presets.md` → what exists (the catalog) → scenarios link back to it
193- `Seeds/docs/scenarios/` → why you'd use it (problem → command)
194 
195## Collection Management Settings
196 
197**Collection management settings are not plan-gated.** `AllowAdminAccessToAllCollectionItems`, `LimitCollectionCreation`, `LimitCollectionDeletion`, and `LimitItemDeletion` apply identically across all plan types. They are org-level admin settings, not billing-plan features.
198 
199**These settings alter access control behavior.** When seeding scenarios that test member vs. admin permissions, collection creation/deletion policies, or item-level access, set them explicitly in the preset rather than relying on defaults.
200 
201**Configurable in presets and CLI.** Use the JSON preset `organization` block (e.g. `"limitCollectionCreation": true`) or the CLI flags: `--limit-collection-creation`, `--limit-collection-deletion`, `--limit-item-deletion`, `--allow-admin-collection-access`.
202 
203## Security Reminders
204 
205- Default test password: `asdfasdfasdf` (overridable via `--password` CLI flag or `SeederSettings`)
206- Never commit database dumps with seeded data
207- Seeded keys are for testing only
208 
@@ −1 +1 @@
1−# Bitwarden Server - Claude Code Configuration
1+# Bitwarden Seeder Library - Claude Code Configuration
22  
3−## Project Context Files
3+## Quick Reference
44  
5−**Read these files before reviewing to ensure that you fully understand the project and contributing guidelines**
5+**For detailed pattern descriptions (Factories, Recipes, Models, Scenes, Queries, Data), read `README.md`.**
66  
7−1. @README.md
8−2. @CONTRIBUTING.md
9−3. @.github/PULL_REQUEST_TEMPLATE.md
7+**For detailed usages of the Seeder library, read `util/SeederUtility/README.md` and `util/SeederApi/README.md`**
108  
11−## Critical Rules
9+## Commands
1210  
13−- **NEVER** use code regions: If complexity suggests regions, refactor for better readability
14−- **NEVER** compromise zero-knowledge principles: User vault data must remain encrypted and inaccessible to Bitwarden
15−- **NEVER** log or expose sensitive data: No PII, passwords, keys, or vault data in logs or error messages
16−- **ALWAYS** use secure communication channels: Enforce confidentiality, integrity, and authenticity
17−- **ALWAYS** encrypt sensitive data: All vault data must be encrypted at rest, in transit, and in use
18−- **ALWAYS** prioritize cryptographic integrity and data protection
19−- **ALWAYS** add unit tests (with mocking) for any new feature development
11+```bash
12+# Build
13+dotnet build util/Seeder/Seeder.csproj
2014  
21−## Project Structure
15+# Run tests
16+dotnet test test/SeederApi.IntegrationTest/
2217  
23−- **Source Code**: `/src/` - Services and core infrastructure
24−- **Tests**: `/test/` - Test logic aligning with the source structure, albeit with a `.Test` suffix
25−- **Utilities**: `/util/` - Migration tools, seeders, and setup scripts
26−- **Dev Tools**: `/dev/` - Local development helpers
27−- **Configuration**: `appsettings.{Environment}.json`, `/dev/secrets.json` for local development
18+# Run single test
19+dotnet test test/SeederApi.IntegrationTest/ --filter "FullyQualifiedName~TestMethodName"
20+```
2821  
29−## Security Requirements
22+## Pattern Decision Tree
3023  
31−- **Compliance**: SOC 2 Type II, SOC 3, HIPAA, ISO 27001, GDPR, CCPA
32−- **Principles**: Zero-knowledge, end-to-end encryption, secure defaults
33−- **Validation**: Input sanitization, parameterized queries, rate limiting
34−- **Logging**: Structured logs, no PII/sensitive data in logs
24+```
25+Need to create test data?
26+├─ ONE entity with encryption? → Factory
27+├─ ONE cipher from a SeedVaultItem? → CipherSeed.FromSeedItem() + {Type}CipherSeeder.Create()
28+├─ MANY entities as cohesive operation? → Recipe or Pipeline
29+├─ Flexible preset-based seeding? → Pipeline (RecipeBuilder + Steps)
30+├─ Complete test scenario with ID mangling? → Scene
31+├─ READ existing seeded data? → Query
32+└─ Data transformation plaintext ↔ encrypted? → Model
33+```
3534  
36−## Common Commands
35+## Pipeline Architecture
3736  
38−- **Build**: `dotnet build`
39−- **Test**: `dotnet test`
40−- **Run locally**: `dotnet run --project src/Api`
41−- **Database update**: `pwsh dev/migrate.ps1`
42−- **Generate OpenAPI**: `pwsh dev/generate_openapi_files.ps1`
37+**Modern pattern for composable fixture-based and generated seeding.**
4338  
44−## Development Workflow
39+**Flow**: Preset JSON or Options → RecipeOrchestrator → RecipeBuilder → IStep/IAsyncStep[] → RecipeExecutor → SeederContext → BulkCommitter → IPostCommitStep[]
4540  
46−- Security impact assessed
47−- xUnit tests added / updated
48−- Performance impact considered
49−- Error handling implemented
50−- Breaking changes documented
51−- CI passes: build, test, lint
52−- Feature flags considered for new features
53−- CODEOWNERS file respected
41+**Key actors**:
5442  
55−### Key Architectural Decisions
43+- **RecipeBuilder**: Fluent API with dependency validation
44+- **IStep / IAsyncStep**: Isolated units of work (CreateOrganizationStep, CreateUsersStep, etc.). Use `IAsyncStep` for steps that do real I/O. A step additionally marked `IPostCommitStep` is deferred until after the bulk commit, so it observes committed rows — but sees cleared entity lists, since only the `EntityRegistry` and the context's scalar properties survive the commit.
45+- **SeederContext**: Shared mutable state bag (NOT thread-safe)
46+- **RecipeExecutor**: Awaits steps sequentially, captures statistics, commits via BulkCommitter, then runs any post-commit steps
47+- **RecipeOrchestrator**: Orchestrates recipe building and execution (from presets or options)
48+- **SeederDependencies** (`Options/`): Bundles infrastructure services (`DatabaseContext`, `IMapper`, `IPasswordHasher<User>`, `IManglerService`, `ILicensingService`, `IAttachmentStorageService`) into a single record. Recipes and the Orchestrator accept this instead of loose parameters. The CLI utility builds it via `SeederServiceFactory.Create().ToDependencies()`.
5649  
57−- Use .NET nullable reference types (ADR 0024)
58−- TryAdd dependency injection pattern (ADR 0026)
59−- Authorization patterns (ADR 0022)
60−- OpenTelemetry for observability (ADR 0020)
61−- Log to standard output (ADR 0021)
50+**Why two step interfaces, not one async contract?** Deliberate — don't unify. Collapsing to one `Task ExecuteAsync(SeederContext)` costs: rewrite 22 step classes (18 in `Steps/`, 4 test doubles); force 20 `.Execute(context)` sites in `test/SeederApi.IntegrationTest/Steps/` to `await`, their test methods to `async`; and `TreatWarningsAsErrors` is on repo-wide (`Directory.Build.props`), so CS1998 makes `async` without `await` a build error — every sync step needs `return Task.CompletedTask`. Permanent trap. The split costs less: two-arm union in `OrderedStep`, `object`-typed `Inner`, one duplicated `RecipeBuilder` registration. Diverges from `IScene`/`IQuery` — single `Task`-returning, no sync twin.
6251  
63−## References
52+**Fixture/preset separation**: Fixtures (organizations, rosters, ciphers) are independent and never reference each other. The preset is the only layer that composes fixtures and defines cross-cutting relationships (folder assignments, favorites). See `Seeds/docs/architecture.md`.
6453  
65−- [Server architecture](https://contributing.bitwarden.com/architecture/server/)
66−- [Architectural Decision Records (ADRs)](https://contributing.bitwarden.com/architecture/adr/)
67−- [Contributing guidelines](https://contributing.bitwarden.com/contributing/)
68−- [Setup guide](https://contributing.bitwarden.com/getting-started/server/guide/)
69−- [Code style](https://contributing.bitwarden.com/contributing/code-style/)
70−- [Bitwarden security whitepaper](https://bitwarden.com/help/bitwarden-security-white-paper/)
71−- [Bitwarden security definitions](https://contributing.bitwarden.com/architecture/security/definitions)
54+**Phase order (org presets)**: Org → OrgApiKey → Roster → Owner (conditional) → Generator (conditional) → Users → Groups → Collections → Folders → Ciphers → CipherAttachments → CipherCollections → CipherFolders → CipherFavorites → PersonalCiphers
55+**Phase order (individual presets)**: IndividualUser → NamedFolders → Generator → Folders → Ciphers → CipherAttachments → FolderAssignments → FavoriteAssignments
56+ 
57+**Individual user presets** use the Pipeline with `CreateIndividualUserStep` (no org, no groups, no collections). These presets live in `Seeds/fixtures/presets/individual/` and are identified by having a `"user"` key instead of `"organization"`. They support `folderNames`, `folderAssignments`, and `favoriteAssignments` for fixture-driven personal vault organization. See `Seeds/docs/presets.md` for the catalog.
58+ 
59+See `Pipeline/` folder for implementation.
60+ 
61+## Parallelism
62+ 
63+Steps execute sequentially (phase order preserved by RecipeExecutor). Async steps are awaited one at a time and MUST NOT be batched with `Task.WhenAll` — `SeederContext` is not thread-safe and each step reads state written by the ones before it. Within a step, `CreateUsersStep` and `GeneratePersonalCiphersStep` use `Parallel.For` internally for CPU-bound Rust FFI work (key generation, encryption).
64+ 
65+**Thread-safety requirements:**
66+ 
67+- `GeneratorContext` lazy properties (`??=`) must be force-initialized before any `Parallel.For` loop to prevent a data race
68+- Generators use `ThreadLocal<Faker>` for thread-safe deterministic data generation
69+- `ManglerService` and `SeederContext` are NOT thread-safe -- pre-compute their outputs before entering parallel loops
70+ 
71+## Performance A/B Testing
72+ 
73+When measuring step-level performance changes, use paired worktrees:
74+ 
75+- Create `server-PM-XXXXX/perf-baseline` and `server-PM-XXXXX/perf-optimized` worktrees
76+- Both worktrees get `Stopwatch` timing in `RecipeExecutor.ExecuteAsync()` (the baseline measurement)
77+- Only the optimized worktree gets actual code changes
78+- Run presets with `--mangle` flag to avoid DB collisions between runs
79+- Compare per-step timings across 3+ runs each, discard the first run (JIT warmup)
80+- `.worktrees/` is already in `.gitignore`
81+ 
82+## Density Profiles
83+ 
84+Steps accept an optional `DensityProfile` that controls relationship patterns between users, groups, collections, and ciphers. When null, steps use the original round-robin behavior. When present, steps branch into density-aware algorithms.
85+ 
86+**Key files**:
87+ 
88+- `Options/DensityProfile.cs` — strongly-typed options (public class)
89+- `Models/SeedPresetDensity.cs` — JSON preset deserialization targets (internal records)
90+- `Data/Enums/MembershipDistributionShape.cs` — Uniform, PowerLaw, MegaGroup
91+- `Data/Enums/CollectionFanOutShape.cs` — Uniform, PowerLaw, FrontLoaded
92+- `Data/Enums/CipherCollectionSkew.cs` — Uniform, HeavyRight
93+- `Data/Distributions/PermissionDistributions.cs` — 11 named distributions by org tier
94+ 
95+**Backward compatibility contract**: `DensityProfile? == null` MUST produce identical output to the original code. Every step guards this with `if (_density == null) { /* original path */ }`.
96+ 
97+**Preset JSON**: Add an optional `"density": { ... }` block. See `Seeds/schemas/preset.schema.json` for the full schema.
98+ 
99+**Presets**: Organized into `features/`, `qa/`, `scale/`, `validation/` folders under `Seeds/fixtures/presets/`. See `Seeds/docs/presets.md` for the full catalog.
100+ 
101+**Verification**: SQL queries for validating density algorithms are in `Seeds/docs/verification.md`.
102+ 
103+## Data/ File Organization
104+ 
105+New files under `Data/` belong in the matching subfolder (`Distributions/`, `Enums/`, `Generators/`, `Static/`) — never loose at the top level. See `Data/README.md` for what each subfolder holds. If a new file's concern doesn't fit an existing subfolder, that's a signal to create one, not to drop it loose.
106+ 
107+**Two Enums homes, by concern:** `Data/Enums/` (namespace `Bit.Seeder.Data.Enums`) holds the generation-config surface (`CompanyType`, `PasswordStrength`, distribution shapes, etc. — "Enums are the API"). Crypto-taxonomy enums that describe how seeded vault data is encrypted (`CipherEncryptionType`, `AttachmentSchemeType`) live in the top-level `Enums/` folder (namespace `Bit.Seeder.Enums`), one enum per file.
108+ 
109+## The Recipe Contract
110+ 
111+Recipes follow strict rules:
112+ 
113+1. A Recipe SHALL accept `SeederDependencies` as its single constructor parameter
114+2. A Recipe SHALL have exactly one public entry point — `Seed()` when synchronous, `SeedAsync()` when it returns `Task`/`Task<T>`. Pipeline-backed Recipes (`OrganizationRecipe`, `IndividualUserRecipe`) are async; the direct-to-database Recipes (`CollectionsRecipe`, `GroupsRecipe`, `OrganizationDomainRecipe`, `OrganizationWithUsersRecipe`) remain synchronous.
115+3. A Recipe MUST produce one cohesive result
116+4. A Recipe MAY overload that entry point with different parameters
117+5. A Recipe SHALL use private helper methods for internal steps
118+6. A Recipe SHALL use BulkCopy for performance when creating multiple entities
119+7. A Recipe SHALL compose Factories for individual entity creation
120+8. A Recipe SHALL NOT expose implementation details as public methods
121+ 
122+## Zero-Knowledge Architecture
123+ 
124+**Critical:** Unencrypted vault data never leaves the client. The server never sees plaintext.
125+ 
126+The Seeder uses the Rust SDK via FFI because it must behave like a real Bitwarden client:
127+ 
128+1. Generate encryption keys (like client account setup)
129+2. Encrypt vault data client-side (same SDK as real clients)
130+3. Store only encrypted result
131+ 
132+## Data Flow
133+ 
134+### Pipeline path (fixture → entity)
135+ 
136+```
137+SeedVaultItem → CipherSeed.FromSeedItem() → CipherSeed → {Type}CipherSeeder.Create(options) → CipherViewDto → encrypt_fields (Rust FFI) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
138+```
139+ 
140+### Core encryption (shared by all paths)
141+ 
142+```
143+CipherViewDto → JSON + [EncryptProperty] field paths → encrypt_fields (Rust FFI, bitwarden_crypto) → EncryptedCipherDto → EncryptedCipherDtoExtensions → Server Cipher Entity
144+```
145+ 
146+Shared logic: `Factories/CipherEncryption.cs`, `Models/EncryptedCipherDtoExtensions.cs`
147+ 
148+## Rust Crypto Dependency
149+ 
150+The Rust shim (`util/RustSdk/rust/`) depends only on `bitwarden_crypto`. It does **not** depend on `bitwarden_vault` — the seeder drives field selection via `[EncryptProperty]` attributes, not SDK cipher types.
151+ 
152+Before modifying encryption integration, run `RustSdkCipherTests` to validate roundtrip encryption.
153+ 
154+## Encryption Schemes (crypto taxonomy)
155+ 
156+Seeded data spans two orthogonal encryption axes, named with Bitwarden's canonical vocabulary (defined in `Enums/CipherEncryptionType.cs` and `Enums/AttachmentSchemeType.cs`):
157+ 
158+- **Cipher encryption** (`cipherEncryption`): `userKey` (no cipher key; `Cipher.Key` null) or `cipherKey` (per-cipher key wrapped by the vault key).
159+- **Attachment scheme version** (`attachmentVersion`): `v0` (no attachment key), `v1` (attachment key wrapped by the vault key), `v2` (attachment key wrapped by the cipher key).
160+ 
161+**Invariant:** a cipher and its attachments use the same strategy — `v2` requires a `cipherKey` host. `Steps/CreateCipherAttachmentsStep.cs` and `Seeds/schemas/cipher.schema.json` both enforce this; keep them in sync.
162+ 
163+**Wire mapping:** `AttachmentSchemeType.{V0,V1,V2}` casts to `u32 {0,1,2}` and is matched verbatim in `util/RustSdk/rust/src/attachment.rs`. The value *is* the version number — do not reintroduce an offset.
164+ 
165+**Do not conflate with account Encryption V1/V2.** Attachment `v0/v1/v2` is key-wrapping only. Everything the seeder emits is Encryption-V1 type-2 `EncString` (AES-256-CBC-HMAC); no COSE/type-7 path exists. A future V2/COSE capability is a **separate** axis (a new enum), never a new attachment version.
166+ 
167+## Deterministic Data Generation
168+ 
169+Same domain = same seed = reproducible data:
170+ 
171+```csharp
172+var seed = options.Seed ?? DeriveStableSeed(options.Domain);
173+```
174+ 
175+## Scenarios
176+ 
177+Developer-facing documentation in `Seeds/docs/scenarios/`. Each file maps an engineering problem to a Seeder command.
178+ 
179+**Maintenance rules:**
180+ 
181+- When adding a new preset, check if an existing scenario should reference it as a variation
182+- When adding a new command or flag, check if it enables a new scenario or changes an existing one
183+- When CLI flags, commands, or preset names change, scan all `*.md` files under `Seeds/` and `SeederUtility/` for stale references
184+- Scenario files follow the template in `Seeds/docs/scenarios/README.md`
185+- Never duplicate CLI flag documentation — link to `SeederUtility/README.md`
186+- Never duplicate preset catalog details — link to `Seeds/docs/presets.md`
187+- Scenarios describe _why_ (the problem). READMEs describe _how_ (the tool). Keep the split clean.
188+ 
189+**File relationships:**
190+ 
191+- `SeederUtility/README.md` → CLI reference (commands, flags, examples) → links to scenarios
192+- `Seeds/docs/presets.md` → what exists (the catalog) → scenarios link back to it
193+- `Seeds/docs/scenarios/` → why you'd use it (problem → command)
194+ 
195+## Collection Management Settings
196+ 
197+**Collection management settings are not plan-gated.** `AllowAdminAccessToAllCollectionItems`, `LimitCollectionCreation`, `LimitCollectionDeletion`, and `LimitItemDeletion` apply identically across all plan types. They are org-level admin settings, not billing-plan features.
198+ 
199+**These settings alter access control behavior.** When seeding scenarios that test member vs. admin permissions, collection creation/deletion policies, or item-level access, set them explicitly in the preset rather than relying on defaults.
200+ 
201+**Configurable in presets and CLI.** Use the JSON preset `organization` block (e.g. `"limitCollectionCreation": true`) or the CLI flags: `--limit-collection-creation`, `--limit-collection-deletion`, `--limit-item-deletion`, `--allow-admin-collection-access`.
202+ 
203+## Security Reminders
204+ 
205+- Default test password: `asdfasdfasdf` (overridable via `--password` CLI flag or `SeederSettings`)
206+- Never commit database dumps with seeded data
207+- Seeded keys are for testing only
72208  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack