npx skills add ...
npx skills add bitwarden/clients --skill cipher-type-planner
npx skills add bitwarden/clients --skill cipher-type-planner
Plans the creation or modification of a cipher type (vault item type) across the Bitwarden clients monorepo. Use this skill when a user wants to add a new cipher type, modify an existing cipher type, or asks about what is needed to implement a cipher type. DO NOT invoke for general vault or cipher questions unrelated to adding or changing a cipher type.
Ask the user the following questions (use AskUserQuestion). Adapt questions based on what
the user has already provided.
Required questions:
CipherType enum definition.$0) - Which client should this plan focus on? (web, desktop, browser, cli, or all). Shared library changes (libs/common, libs/vault) are always included; $0 controls which apps/* files appear. Skip if already provided as an argument. Default: all.$0 is browser or all.Additional questions:
Ask each of the following. If the engineer does not have an answer, accept "N/A" or "not yet decided" and note it as a gap in the plan.
subTitle getter on the view model return? This appears in vault list items.bwi- icon classes.After gathering requirements, enter plan mode using EnterPlanMode. Explore the codebase to
verify current patterns and file locations. Use the SshKey cipher type (value 5) as the canonical
reference for implementation patterns.
Key files to inspect for patterns:
libs/common/src/vault/enums/cipher-type.ts - Enum definitionlibs/common/src/vault/models/api/ssh-key.api.ts - API model patternlibs/common/src/vault/models/data/ssh-key.data.ts - Data model patternlibs/common/src/vault/models/domain/ssh-key.ts - Domain model patternlibs/common/src/vault/models/view/ssh-key.view.ts - View model patternlibs/common/src/models/export/ssh-key.export.ts - Export model patternlibs/common/src/vault/models/domain/cipher.ts - Container switch patternslibs/vault/src/cipher-form/components/sshkey-section/ - Form component patternlibs/vault/src/cipher-view/sshkey-sections/ - View component patternWrite a comprehensive plan to the plan file. The plan MUST include all sections below.
List every file that needs to be created, with the full path and a brief description. Organize by layer:
Model stack:
libs/common/src/vault/models/api/<type>.api.ts - API response shapelibs/common/src/vault/models/data/<type>.data.ts - Serializable storage formatlibs/common/src/vault/models/domain/<type>.ts - Encrypted business objectlibs/common/src/vault/models/domain/<type>.spec.ts - Domain model testslibs/common/src/vault/models/view/<type>.view.ts - Decrypted view for UIExport (if import/export is included):
libs/common/src/models/export/<type>.export.ts - Export modelUI components:
libs/vault/src/cipher-form/components/<type>-section/ - Form section component (TS, HTML, spec)libs/vault/src/cipher-view/<type>-sections/ - View section component (TS, HTML)List every file that needs modification, organized by concern. For each file, describe the specific change needed.
Core enum:
libs/common/src/vault/enums/cipher-type.ts - Add <Type>: <N> to CipherTypelibs/common/src/vault/enums/cipher-type.spec.ts - Update testsContainer switches (add case for new type):
libs/common/src/vault/models/data/cipher.data.ts - Constructorlibs/common/src/vault/models/domain/cipher.ts - Constructor, decrypt(),
toCipherData(), fromJSON(), toSdkCipher(), fromSdkCipher()libs/common/src/vault/models/view/cipher.view.ts - item getter, fromJSON(),
fromSdkCipherView(), getSdkCipherViewType(), toSdkCipherView()libs/common/src/vault/models/request/cipher.request.ts - Constructorlibs/common/src/vault/models/response/cipher.response.ts - Constructorlibs/common/src/vault/services/cipher.service.ts - encryptCipherData()Export (if import/export is included):
libs/common/src/models/export/cipher.export.ts - toView(), toDomain(), build()SDK integration:
libs/common/src/vault/models/domain/cipher-sdk-mapper.ts - Record mappertoSdk*/fromSdk*)UI wiring:
libs/vault/src/cipher-form/components/cipher-form.component.ts - Import and wire sectionlibs/vault/src/cipher-form/components/cipher-form.component.html - Add section templatelibs/vault/src/cipher-view/cipher-view.component.ts - Import and wire sectionlibs/vault/src/cipher-view/cipher-view.component.html - Add section templatelibs/common/src/vault/icon/build-cipher-icon.ts - Add icon caseVault filters (CRITICAL — without these, ciphers won't appear in the vault list):
All vault filter files must be feature-flag-gated so the new type only appears when the flag is
enabled. Use ConfigService.getFeatureFlag$() with combineLatest to filter the type out of
arrays when the flag is off.
Always included (shared):
libs/vault/src/services/vault-filter.service.ts - CRITICAL: Add type to buildCipherTypeTree() allTypeFilters array. Without this, ciphers of the new type will not appear in the vault sidebar or list.libs/vault/src/models/filter-function.ts - Add filter case for the new typelibs/angular/src/vault/components/vault-items.component.ts - Feature-flag-gate empty state type buttonsInclude if $0 is web or all:
apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts - Add to allTypeFilters, searchPlaceholder, and feature-flag-gate in buildAllFilters()apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.component.ts - Feature-flag-gate in buildAllFilters()Include if $0 is desktop or all:
apps/desktop/src/vault/app/vault-v3/vault-filter/filters/type-filter.component.ts - Add ConfigService, combineLatest with feature flagInclude if $0 is browser or all:
apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts - Add ConfigService, feature-flag-gate cipherTypesNew item menus (feature-flag-gated):
Always included (shared):
libs/common/src/vault/types/cipher-menu-items.ts - Add menu item entry for new typelibs/vault/src/components/new-cipher-menu/new-cipher-menu.component.ts - Add canCreate<Type> = input(false) signal, gate in cipherMenuItems observableInclude if $0 is web or all:
apps/web/src/app/vault/individual-vault/vault-header/vault-header.component.ts - Add canCreate<Type>$ observable from feature flagapps/web/src/app/vault/individual-vault/vault-header/vault-header.component.html - Bind [canCreate<Type>] to <vault-new-cipher-menu>Include if $0 is browser or all:
apps/browser/src/vault/popup/components/vault/new-item-dropdown/new-item-dropdown.component.ts - Add ConfigService, combineLatest with feature flagLocalization (add i18n keys):
Include only locale files for $0. If $0 is all, include all three:
apps/web/src/locales/en/messages.json (web)apps/desktop/src/locales/en/messages.json (desktop)apps/browser/src/_locales/en/messages.json (browser)Linked fields (if applicable):
libs/common/src/vault/enums/linked-id-type.enum.tsAutofill (if applicable — only if $0 is browser or all):
apps/browser/src/autofill/ only if the type supports
autofillRestricted item types (if applicable):
Restricted item type enforcement is used across all clients. Include files for $0:
Always included (shared):
libs/common/src/vault/services/vault-settings/vault-settings.service.ts - Restricted types serviceInclude if $0 is web or all:
apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/restricted-item-types.component.ts - Policy configuration UIapps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/restricted-item-types.component.htmlInclude if $0 is browser or all:
apps/browser/src/vault/popup/components/vault/item-more-options/item-more-options.component.ts - Restricted type checksInclude if $0 is cli or all:
apps/cli/src/vault/create.command.ts - Restricted type checksapps/cli/src/commands/list.command.ts - Restricted type checksapps/cli/src/commands/get.command.ts - Restricted type checksList all i18n keys that need to be added. At minimum:
List all test files that need to be created or updated:
libs/common/src/vault/enums/cipher-type.spec.tslibs/common/src/vault/models/domain/cipher.spec.tslibs/common/src/vault/models/domain/<type>.spec.ts (new)libs/common/src/vault/models/view/cipher.view.spec.tslibs/common/src/vault/services/cipher.service.spec.tslibs/common/src/vault/services/cipher-sdk.service.spec.tslibs/common/src/vault/icon/build-cipher-icon.spec.tslibs/common/src/models/export/cipher.export.spec.tslibs/vault/src/cipher-form/components/cipher-form.component.spec.tslibs/vault/src/cipher-view/cipher-view.component.spec.tsRecommended implementation order, customized for this specific type. Only include steps relevant
to $0 (shared steps are always included):
toSdk*/fromSdk*) (shared)$0)$0)$0)$0)$0 is cli or all)$0 is browser or all)$0)Each cipher type can expose copiable fields in the vault list item context menus (right-click / more
menu). Include only the sections relevant to $0.
| File | What to add |
|---|---|
libs/vault/src/services/copy-cipher-field.service.ts | Add field names to the CopyAction type union. Add entries to the CopyActions record with typeI18nKey (i18n key for the toast message), protected (whether it requires password re-prompt), and optional event (for event collection). |
libs/common/src/vault/utils/cipher-view-like-utils.ts | Add cases to hasCopyableValue() that check whether the cipher has a non-empty value for each copiable field. |
$0 is browser or all)| File | What to add |
|---|---|
apps/browser/src/vault/popup/components/vault/item-copy-action/item-copy-actions.component.ts | Add a singleCopyable<Type> getter (for single-field quick copy button), a has<Type>Values getter, and a getNumberOf<Type>Values() method. Follow the Card pattern. |
apps/browser/src/vault/popup/components/vault/item-copy-action/item-copy-actions.component.html | Add a section using @if syntax (NOT *ngIf) with the single/multi field pattern. |
$0 is web or all)| File | What to add |
|---|---|
apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.ts | Add is<Type>Cipher and hasVisible<Type>Options getters. Add hasVisible<Type>Options to the showMenuDivider check. |
apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html | Add copy buttons using @if syntax with appCopyField directive. |
$0 is desktop or all)| File | What to add |
|---|---|
apps/desktop/src/vault/app/vault-v3/vault-items/vault-cipher-row.component.ts | Add a CipherType.<Type> case to the copyFields computed signal, returning CopyFieldConfig[] entries. This is the most modern pattern — uses a computed signal rather than getters. |