This is other text.
It has two sentences
" } ``` ### `outDir: string` The relative path from where the CLI is run to the directory the generated files should be created in. If the provided directory does not exist, it will be created automatically. **Required: false.** If omitted, the default location is `./ditto`. ### `iosLocales` An array that maps Ditto variant IDs to [iOS locale IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html). When used in conjunction with `ios-strings` or `ios-stringsdict` output formats, this configuration enables the CLI to generate a `Ditto.swift` driver file and organize locale files into the standard iOS `.lproj` localization bundles. **Required: false**. If omitted, iOS formats will be generated without locale-specific directory organization. Each entry in the array maps a variant ID to its corresponding locale code. The variant ID must match a variant defined in your `variants` configuration, or be included via variants `id: all`. The iOS locale code should be a valid iOS locale identifier (e.g., `en`, `es`, `fr`, `de`). **Behavior:** * When `iosLocales` is configured and used with `ios-strings` or `ios-stringsdict` formats, the CLI generates a `Ditto.swift` driver file * The `Ditto.swift` file and `.lproj` directories are placed at the root-level `outDir` (`./ditto` if not configured) and NOT at the `ios-strings` or `ios-stringsdict` output `outDir` — unless `iosLocalesOutDir` is configured, in which case they're placed there instead. See [`iosLocalesOutDir`](#ioslocalesoutdir) below. * Variants mapped in `iosLocales` are written to `[]` (workspace or component) | Same hierarchy as above, but only when writing copy for that locale |
Base style guide rules always apply. Locale-scoped rules apply only when writing copy for the matching locale — they never conflict because each locale is a separate scope.
## Developer-owned vs CLI-managed keys
| Keys | Owner | Edit by hand? |
| ------------------------------------ | ------------ | ------------------------------------- |
| `component`, `tags`, `surfaces` | Developer | Yes — add, remove, and modify freely. |
| `rules`, `locales`, workspace `tags` | CLI (`pull`) | No — overwritten on every pull. |
Never edit `rules` or `locales` by hand. Run `ditto-spec pull` to update them from the platform.
## Surface naming conventions
| Scenario | Key to use | Example |
| ------------------------- | --------------------- | ------------------------------------- |
| String prop | The prop name | `title`, `description` |
| Nested prop | Dot notation | `primaryAction.label` |
| Children prop | `$children` | `$children` |
| Hardcoded/internal string | Descriptive role name | `headline`, `bodyText`, `submitLabel` |
Check the `tags` key in `workspace.ditto.md` for tags available on the platform. Prefer reusing an existing tag over creating a new one — only tags that exist on the platform will match style guide rules.
## Tagging in a design system
Ditto specs support two levels of tagging that mirror how design systems organize components:
* **Component-level tags** describe the component itself — its role in the design system. A `DialogueModal` tagged `[dialog, confirmation]` pulls in style guide rules about how confirmation dialogs should read. These rules apply to every surface in the component.
* **Surface-level tags** describe each individual piece of text — its function within the component. An `actionText` surface tagged `[call-to-action]` pulls in rules specific to CTAs (e.g. "lead with a verb"). These rules apply only to that surface.
Both levels work together. For a `DialogueModal`:
```yaml theme={null}
tags: [dialog, confirmation] # rules about dialogs apply to ALL surfaces
surfaces:
headline:
tags: [heading, dialog-title] # + rules about headings apply here
actionText:
tags: [call-to-action] # + rules about CTAs apply here
cancelText:
tags: [button] # + rules about buttons apply here
```
The `headline` surface inherits style guide rules matched by `dialog`, `confirmation` (from the component), plus rules matched by `heading`, `dialog-title` (from the surface). If a rule matches both levels, it appears once at component level — broader scope wins.
This means you can create style guide rules on the Ditto platform scoped to design system concepts (`dialog`, `card`, `form`, `navigation`) and have them automatically cascade to every component tagged with that concept, while surface-level tags layer on more specific guidance.
## File discovery
The CLI searches directories listed in the `roots` config for any `*.ditto.md` files. `workspace.ditto.md` is identified by its `workspace: true` key; all other `.ditto.md` files are treated as component Ditto specs.
# Changelog
Source: https://developer.dittowords.com/feedback-support/changelog
## September 3, 2026
### API
Add [Publish component](https://developer.dittowords.com/api-reference/components/publish-component) (`POST /v2/components/publish`) endpoint for publishing an existing text item to the component library.
Add [Link components](https://developer.dittowords.com/api-reference/components/link-components) (`PATCH /v2/components/link`) endpoint for linking text items to a library component by developer ID.
Add [Unlink components](https://developer.dittowords.com/api-reference/components/unlink-components) endpoint, which unlinks every text item that currently shares a given developer ID with its sibling instances. Accepts an optional `projectId` to scope the unlink to a single project.
### MCP
Add the [`publish_library_component`](/mcp-reference/tools#publish_library_component) for publishing an existing text item to the component library.
Add the [`link_text_items_to_component`](/mcp-reference/tools#link_text_items_to_component) for linking text items to a library component by developer ID.
Add the [`unlink_text_items_from_component`](/mcp-reference/tools#unlink_text_items_from_component) tool, which unlinks every text item that currently shares a given developer ID with its sibling instances. Accepts an optional `projectId` to scope the unlink to a single project.
## August 27, 2026
### API
Add [ARB](https://github.com/google/app-resource-bundle/wiki/ApplicationResourceBundleSpecification) as an export format for [Export text items](https://developer.dittowords.com/api-reference/text-items/export-text-items) (`GET /v2/textItems/export`) and [Export components](https://developer.dittowords.com/api-reference/components/export-components) (`GET /v2/components/export`) — provide `?format=arb`. See [ARB JSON](/string-formats/json#arb-json) for the content shape.
### Ditto CLI - 5.9.0
Add `framework: arb` and `framework: icu` for `json`-format outputs, generating [ARB](/string-formats/json#arb-json) and [ICU](/string-formats/json#icu-json) JSON respectively. See [Frameworks](/cli-reference/files#framework-specific-files).
Add [`androidLocales`](/cli-reference/configuration#androidlocales), which maps Ditto variant IDs to Android locale-qualified resource directories (`values-/`) — the Android counterpart to `iosLocales`. Unlike `iosLocales`, there's no need to map `base`, since Android already has a default resource directory (`values/`) that the platform falls back to automatically.
Add [`androidLocalesOutDir`](/cli-reference/configuration#androidlocalesoutdir) and [`iosLocalesOutDir`](/cli-reference/configuration#ioslocalesoutdir), which let Android and iOS locale-organized output be written to separate root directories — useful since they typically need to live in different parts of a codebase.
## August 24, 2026
### Ditto CLI - 5.8.1
[`scan`](/cli-reference/commands#scan) now records which part of your repository it looked at, alongside the Git context added in 5.8.0. Scanning a repository root is recorded as covering the whole repository; scanning a single directory is recorded as covering only that directory.
This lets Ditto tell the difference between a string removed from your code and a string that simply was not part of the scan, so re-scanning one directory implies nothing about the rest of the repository.
## August 20, 2026
### Ditto CLI - 5.8.0
[`scan`](/cli-reference/commands#scan) now records the Git repository, commit, and branch of the code it scans. Ditto uses these to recognize a codebase it has already seen, so a later scan of the same repository can be matched against an earlier one instead of importing every string again.
This is read from your local Git checkout. Scan makes no additional network requests, does not send Git credentials, and records nothing about your remote beyond its host and path. Scanning outside a Git repository still works — the CLI notes that the scan can be imported but not re-synced, and continues.
## August 18, 2026
### Ditto CLI - 5.7.2
Move [`scan`](/cli-reference/commands#scan) text extraction into the shared `@dittowords/text-extract` library. Extraction behavior is unchanged.
## August 17, 2026
### API
Add `richText` parameter to [Create components](https://developer.dittowords.com/api-reference/components/create-components) (`POST /v2/components`) and [Patch components](https://developer.dittowords.com/api-reference/components/patch-components) (`PATCH /v2/components`).
When `richText` param is set to `html`, all text values in the update request — including plural and variant text — will be parsed as an HTML string and saved as rich text.
## August 13, 2026
### Ditto CLI - 5.7.1
Improve how [`scan`](/cli-reference/commands#scan) decodes the text it extracts. Escape sequences, XML entities, and inline markup are now handled per file format, so candidates arrive in Ditto as the text a user sees instead of as raw source.
### MCP
Add the [`list_statuses`](/mcp-reference/tools#list_statuses) tool, which lists the statuses text items and library components can be set to, in workflow order.
The MCP server now supports logging in with your Ditto account via OAuth, in addition to a static API token. See [Installation](/mcp-reference/installation) for setup instructions per client.
### API
Add [Delete components](https://developer.dittowords.com/api-reference/components/delete-components) (`DELETE /v2/components`) endpoint for deleting library components by developer ID.
Add [Fetch statuses](https://developer.dittowords.com/api-reference/statuses/get-statuses) (`GET /v2/statuses`) endpoint for listing the statuses available in a workspace, in workflow order.
## August 11, 2026
### API
Add `richText` parameter to [Update text items](https://developer.dittowords.com/api-reference/text-items/patch-text-items) (`PATCH /v2/textItems`) and [Create text items](https://developer.dittowords.com/api-reference/text-items/create-text-items) (`POST /v2/textItems`).
When `richText` param is set to `html`, all `text` values in the update request — including plural and variant text — will be parsed as an HTML string and saved as rich text.
For example, the following request would store formatted string "**Inspiration** for your next trip" as the Korean variant:
```json theme={null}
{
"richText": "html",
"variantId": "korean",
"updates": [
{ "developerId": "homepage.section.inspiration", "text": "Inspiration for your next trip" }
]
}
```
* Supported formatting: ``/``, ``/``, ``, ``, and `
` for line breaks.
* `` and `` are only supported for workspaces with superscript and subscript enabled.
* We drop unsupported markup such as links, lists, or headings but keep its text.
* `{{variable_name}}` placeholders still resolve, and keep any formatting applied around them.
* Without the parameter, text is saved as plaintext and any markup is stored literally, unchanged from previous behavior.
## August 10, 2026
### MCP
Add [`create_variables`](/mcp-reference/tools#create_variables), [`update_variables`](/mcp-reference/tools#update_variables), and [`delete_variables`](/mcp-reference/tools#delete_variables) tools for managing variables from your editor.
### API
Add [Create variables](https://developer.dittowords.com/api-reference/variables/create-variables) (`POST /v2/variables`), [Update variables](https://developer.dittowords.com/api-reference/variables/patch-variables) (`PATCH /v2/variables`), and [Delete variables](https://developer.dittowords.com/api-reference/variables/delete-variables) (`DELETE /v2/variables`) endpoints.
* Renaming a variable with `newName` rewrites every `{{variable_name}}` placeholder referencing it — across text items, library components, variants, and plurals — so existing text keeps resolving.
* A variable can't be deleted while any text item or library component still references it.
## August 6, 2026
### MCP
Add [`create_variants`](/mcp-reference/tools#create_variants), [`update_variants`](/mcp-reference/tools#update_variants), and [`delete_variants`](/mcp-reference/tools#delete_variants) tools for managing variants from your editor.
### API
Add [Create variants](https://developer.dittowords.com/api-reference/variants/create-variants) (`POST /v2/variants`), [Update variants](https://developer.dittowords.com/api-reference/variants/patch-variants) (`PATCH /v2/variants`), and [Delete variants](https://developer.dittowords.com/api-reference/variants/delete-variants) (`DELETE /v2/variants`) endpoints.
* At most one variant per workspace can hold a given locale code.
* A variant can't be deleted while any text item or library component still has text for it.
## August 5, 2026
### Ditto CLI - 5.7.0
Add the [`login`](/cli-reference/commands#login) and [`logout`](/cli-reference/commands#logout) commands. `login` signs you in through your browser, so the CLI no longer needs an API key.
```
npx @dittowords/cli login
```
* The session is saved to `$HOME/.config/ditto` and renews itself as you keep using the CLI. Commands act as you — your Ditto account and its permissions — instead of as whoever generated an API key.
* `logout` forgets the session on this machine and revokes it with Ditto.
* API keys still work. `DITTO_TOKEN` takes precedence over a saved session, so CI and other headless environments are unaffected. See [credential precedence](/cli-reference/authentication#credential-precedence).
## August 3, 2026
### MCP
Add [`create_styleguide`](/mcp-reference/tools#create_styleguide), [`list_styleguides`](/mcp-reference/tools#list_styleguides), and [`update_styleguide`](/mcp-reference/tools#update_styleguide) tools for managing style guides themselves — sections, the default-enabled setting, and metadata — as opposed to the rules inside them. Add [`create_styleguide_rules`](/mcp-reference/tools#create_styleguide_rules), [`update_styleguide_rules`](/mcp-reference/tools#update_styleguide_rules), and [`delete_styleguide_rules`](/mcp-reference/tools#delete_styleguide_rules) tools for managing the rules inside a style guide section.
Add [`list_component_folders`](/mcp-reference/tools#list_component_folders), [`create_component_folders`](/mcp-reference/tools#create_component_folders), [`update_component_folders`](/mcp-reference/tools#update_component_folders), and [`delete_component_folders`](/mcp-reference/tools#delete_component_folders) tools for managing component library folders from your editor.
### API
Add [Create a style guide](https://developer.dittowords.com/api-reference/styleguides/create-styleguides) (`POST /v2/styleguides`) and [Update a style guide](https://developer.dittowords.com/api-reference/styleguides/patch-styleguides) (`PATCH /v2/styleguides`) endpoints, along with [Create style guide rules](https://developer.dittowords.com/api-reference/styleguides/create-styleguide-rules) (`POST /v2/styleguides/rules`), [Update style guide rules](https://developer.dittowords.com/api-reference/styleguides/patch-styleguide-rules) (`PATCH /v2/styleguides/rules`), and [Delete style guide rules](https://developer.dittowords.com/api-reference/styleguides/delete-styleguide-rules) (`DELETE /v2/styleguides/rules`) endpoints for managing the rules inside a section.
Add [Fetch component folders](https://developer.dittowords.com/api-reference/component-folders/get-component-folders) (`GET /v2/componentFolders`), [Create component folders](https://developer.dittowords.com/api-reference/component-folders/create-component-folders) (`POST /v2/componentFolders`), [Update component folders](https://developer.dittowords.com/api-reference/component-folders/patch-component-folders) (`PATCH /v2/componentFolders`), and [Delete component folders](https://developer.dittowords.com/api-reference/component-folders/delete-component-folders) (`DELETE /v2/componentFolders`) endpoints.
## July 31, 2026
### MCP
Add the [`suggest_edit`](/mcp-reference/tools#suggest_edit) tool, which checks text against your workspace's style guide rules and returns suggested edits — the same rule-based suggestions shown in the Ditto app. Check an existing text item by developer ID, or freeform text that isn't saved as a text item yet.
## July 29, 2026
### MCP
Add [`list_project_blocks`](/mcp-reference/tools#list_project_blocks), [`create_project_blocks`](/mcp-reference/tools#create_project_blocks), [`update_project_blocks`](/mcp-reference/tools#update_project_blocks), and [`delete_project_blocks`](/mcp-reference/tools#delete_project_blocks) tools for managing the blocks that group text items within a project.
### API
Add [Fetch project blocks](https://developer.dittowords.com/api-reference/project-blocks/get-project-blocks) (`GET /v2/projectBlocks`), [Create project blocks](https://developer.dittowords.com/api-reference/project-blocks/create-project-blocks) (`POST /v2/projectBlocks`), [Update project blocks](https://developer.dittowords.com/api-reference/project-blocks/patch-project-blocks) (`PATCH /v2/projectBlocks`), and [Delete project blocks](https://developer.dittowords.com/api-reference/project-blocks/delete-project-blocks) (`DELETE /v2/projectBlocks`) endpoints.
## July 27, 2026
### Ditto CLI - 5.6.3
Improve how [`scan`](/cli-reference/commands#scan) handles codebases that are larger than a workspace's plan's scan limit.
Add the `--list-directories` flag. `scan --list-directories` prints the number of candidate strings found in each directory and exits without uploading anything, so you can choose a scope before running a real scan.
```
npx @dittowords/cli scan . --list-directories
```
* Counts are rolled up: each directory includes the strings found in its subdirectories.
* Directories are printed in tree order, indented by depth, with the whole scan total at the top.
When a scan exceeds your plan's limit, the error now suggests narrower paths to scan instead of just reporting the limit.
* The message lists the largest subdirectories that each fit within your remaining limit, with their string counts and a ready-to-run command for each.
* The limit is checked before candidates are uploaded, so an oversized scan fails right away instead of after the upload finishes.
### MCP
Add the [`create_ditto_project`](/mcp-reference/tools#create_ditto_project) and [`list_project_folders`](/mcp-reference/tools#list_project_folders) tools for creating projects and looking up project folders from your editor.
### API
Add [Create a project](https://developer.dittowords.com/api-reference/projects/create-projects) (`POST /v2/projects`) endpoint. Optionally provide a folder's developer ID to create the project inside that folder.
## July 24, 2026
### MCP
Add [`create_library_components`](/mcp-reference/tools#create_library_components) and [`update_library_components`](/mcp-reference/tools#update_library_components) tools for managing library components from your editor, and the [`list_component_folders`](/mcp-reference/tools#list_component_folders) tool for looking up their folders.
## July 22, 2026
### Documentation
Document the [agent setup package](https://github.com/dittowords/ditto-agent-setup) as the default way to integrate Ditto with Claude Code. See [Agent setup package](/agent-setup-package/overview).
Standardize the API token environment variable to `DITTO_TOKEN` across the CLI, Ditto Specs, and MCP setup docs (previously `DITTO_API_KEY` and `DITTO_API_TOKEN`).
### MCP
Add [`list_variants`](/mcp-reference/tools#list_variants) and [`list_variables`](/mcp-reference/tools#list_variables) tools, and expose variants and variables on the text item and library component tools — reference a variable with a `{{variable_name}}` placeholder, or set variant-specific text via a variant's developer ID.
## July 10, 2026
### MCP
Add [`create_text_items`](/mcp-reference/tools#create_text_items), [`update_text_items`](/mcp-reference/tools#update_text_items), and [`delete_text_items`](/mcp-reference/tools#delete_text_items) tools for managing text items in bulk from your editor, and the [`list_projects`](/mcp-reference/tools#list_projects) tool for looking up a project's developer ID.
## July 9, 2026
### API
Add [Fetch activity](https://developer.dittowords.com/api-reference/activity/get-activity) (`GET /v2/activity`) endpoint for retrieving a paginated list of change events in your workspace, optionally filtered by project, text item, library component, or entity type.
## July 1, 2026
### API
Add `blockName` field to [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`) response.
* Each text item now includes a `blockName` field: the name of the block the text item belongs to, or `null` if it is not in a block.
## June 25, 2026
### API
Add `sort` parameter to [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`).
* `id` (default) sorts the response alphabetically by developer ID (matching previous behavior)
* `project_order` groups items by project, returned alphabetically by project developer ID, then sorts within projects based on the custom sort order set up in the web app.
## June 16, 2026
### Ditto CLI - 5.6.0
Add the `scan` command. `scan ` analyzes a local directory for user-facing text and sends the candidates to Ditto, where you can review them and turn them into a content system tailored to your product. See the [Scan documentation](/cli-reference/commands#scan).
* This release includes packages that require **Node.js 20 or higher**.
## June 10, 2026
### API
Add new variant fields `variants[n].status`, `variants[n].assignee`, `variants[n].notes`, and `variants[n].characterLimit` to the [Create text items](https://developer.dittowords.com/api-reference/text-items/create-text-items) resource.
* `assignee` must be a valid email matching a user in your workspace
* variant `status` must be a valid status in your workspace
## June 4, 2026
### API
Add `folderId` to the [Update components](https://developer.dittowords.com/api-reference/components/patch-components) resource, allowing users to organize their components in bulk.
* If `folderId` of `null` or `"root"` is provided, will move component into "All Components".
* If `folderId` omitted, component folder will remain unchanged
Add [Get style guides](https://developer.dittowords.com/api-reference/styleguides/get-styleguides) (`GET /v2/styleguides`) endpoint for fetching the style guides created in your workspace, along with their sections and rules.
## May 28, 2026
### API
Add `assignee`, along with new variant fields `variants[n].status`, `variants[n].assignee`, `variants[n].notes`, and `variants[n].characterLimit` to the [Create components](https://developer.dittowords.com/api-reference/components/create-components) resource.
* `assignee` must be a valid email matching a user in your workspace
* variant `status` must be a valid status in your workspace
## May 18, 2026
### API
Add `characterLimit` field to [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`) and [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`) responses.
* Each text item and component in the response now includes a `characterLimit` field: a positive integer when a limit is set, or `null` when no limit is configured.
* For variant responses, `characterLimit` reflects the variant's own character limit rather than the base value.
## May 12, 2026
### API
Update Text Item and Component endpoints to support variant assignee, notes and character limit.
* [Fetch text items](https://developer.dittowords.com/api-reference/components/get-text-items) (`GET /v2/textItems`) and [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`) now return variant assignee and notes in variant response objects, not the base properties.
* Requests that include an assignee filter and a variantId return only items whose base and variant assignees both match the filter. This applies to [Fetch text items](https://developer.dittowords.com/api-reference/components/get-text-items) (`GET /v2/textItems`), [Export text items](https://developer.dittowords.com/api-reference/components/export-text-items) (`GET /v2/textItems/export`), [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`), and [Export components](https://developer.dittowords.com/api-reference/components/export-components) (`GET /v2/components/export`).
* Requests that include assignee, notes and/or character limit along with a variantId in the payload of [Update text items](https://developer.dittowords.com/api-reference/text-items/patch-text-items) (`PATCH /v2/textItems`) or [Update components](https://developer.dittowords.com/api-reference/components/patch-components) (`PATCH /v2/components`) will update that variant's properties, not the base values.
## April 30, 2026
### API
Add component name to the response of [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`) endpoint. Each component in the response will now include a `name` field matching the component name. The same component name will be returned across base text, variants and plural forms.
## April 6, 2026
### API
Add [Update components](https://developer.dittowords.com/api-reference/components/update-components) (`PATCH /v2/components`) endpoint.
Supports updating text, tags, status, and assignee on components identified by developer ID. Includes optional variant targeting with `variantId` and `forceVariantCreation` parameters.
Add `PATCH /v2/textItems` as the preferred method for updating text items. `PUT /v2/textItems` continues to work but is now deprecated.
## April 1, 2026
### Ditto CLI - 5.5.1
Dependency updates and internal improvements. See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.5.1).
## March 31, 2026
### Ditto CLI - 5.5.0
Add CLI support for filtering by tags. Add a `tags` configuration to your config file to scope text items and components by one or more tags, with support for `AND`/`OR` operators.
```yaml theme={null}
tags:
values:
- "tag-1"
- "tag-2"
operator: "AND"
```
The `tags` filter can be specified at the top level of your config or within individual outputs (output-level overrides top-level). When `operator` is `"AND"`, only items with all specified tags are returned. When `operator` is `"OR"` (or omitted), items with any of the specified tags are returned.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.5.0).
## March 27, 2026
### MCP
Add the [`get_workspace_tags`](/mcp-reference/tools#get_workspace_tags) tool, which lists the tags currently in use across the workspace — useful before adding tags to a style guide rule, since only existing tags are allowed. Add the first tools for creating, updating, and deleting style guide rules from your editor.
## March 26, 2026
### API
Add `assignee` and `tags` filters to [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`),
[Export components](https://developer.dittowords.com/api-reference/components/export-components) (`GET /v2/components/export`),
and [Export text items](https://developer.dittowords.com/api-reference/text-items/export-text-items) (`GET /v2/textItems/export`).
The `assignee` filter accepts an email address or `null` to match unassigned items. The `tags` filter accepts an array of tag values with an optional `operator` field (`AND` or `OR`, defaulting to `OR`).
## March 24, 2026
### Ditto CLI - 5.4.0
Add CLI support for filtering by integration status. Add `integrated: true` to your config file to fetch only text items and components that have been marked as integrated into development.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.4.0).
### API
Add the ability to update the `integrated` flag of a text item via [Update text items](https://developer.dittowords.com/api-reference/text-items/update-text-items) (`PUT /v2/textItems`).
## March 23, 2026
### API
Add `integrated` field to the response data of:
* [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`)
* [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`).
Add optional `integrated` boolean filter to:
* [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`)
* [Export text items](https://developer.dittowords.com/api-reference/text-items/export-text-items) (`GET /v2/textItems/export`)
* [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`)
* [Export components](https://developer.dittowords.com/api-reference/components/export-components) (`GET /v2/components/export`)
## March 20, 2026
### MCP
The Ditto MCP server can now run remotely over Streamable HTTP, instead of only as a local stdio server. See [Installation](/mcp-reference/installation) for how to connect Claude Code, Cursor, VS Code, Windsurf, Codex, and other MCP clients.
## March 19, 2026
### API
Add `plurals` field to [Update text items](https://developer.dittowords.com/api-reference/text-items/update-text-items) (`PUT /v2/textItems`) API endpoint.
The `plurals` field supports `upsert` and `remove` operations for managing plural forms (zero, one, two, few, many, other) on text items.
Existing plural forms not mentioned in either operation are preserved. Supports variant plurals via the `variantId` parameter.
## March 18, 2026
### API
Add `assignee` and `tags` filters to [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`).
The `assignee` filter accepts an email address or `null` to match unassigned text items. The `tags` filter accepts an array of tag values with an optional `operator` field (`AND` or `OR`, defaulting to `OR`).
[Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`)
and [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`)
now include the `assignee` field in the response payload, returned as the assignee's email address or `null` if unassigned.
## March 16, 2026
### API
Add `assignee` field to [Update text items](https://developer.dittowords.com/api-reference/text-items/update-text-items) (`PUT /v2/textItems`) API endpoint.
The `assignee` field accepts an optional email string of a user in the workspace to assign to the text item. Setting `assignee` to `null` will remove the current assignee.
## March 12, 2026
### MCP
Add the [`search_ditto_text`](/mcp-reference/tools#search_ditto_text) tool, which searches your workspace for existing text items and library components by content — so agents can find and reuse strings instead of generating new ones.
## March 5, 2026
### MCP
Ditto's MCP server is here! It connects AI coding agents to your team's content in Ditto, starting with the [`get_styleguide_rules`](/mcp-reference/tools#get_styleguide_rules) tool for fetching workspace and project-level style guide rules. See the [MCP overview](/mcp-reference/overview) to get started.
## February 10, 2026
### API
Add [Create components](https://developer.dittowords.com/api-reference/components/create-components) (`POST /v2/components`) endpoint for creating new library components.
## February 2, 2026
### API
[Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`),
[Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`),
[Export text items](https://developer.dittowords.com/api-reference/text-items/export-text-items) (`GET /v2/textItems/export`),
and [Export components](https://developer.dittowords.com/api-reference/components/export-components) (`GET /v2/components/export`)
now return a `400` error response when statuses that don't exist in your workspace are provided in the status filter.
## January 14, 2026
### API
[Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`)
and [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`)
now return separate records for each plural form. Plural forms follow the standard i18n plural forms outlined [here](https://www.i18next.com/translation-function/plurals).
Each record in the response includes a `pluralForm` value, and for each `pluralForm` on a text item or component, a separate record is returned with
that `pluralForm` and its respective value. If a record has a `pluralForm`, it will be appended to the end of the developer ID.
Example response:
```json theme={null}
[
{ "id": "some-items", "text": "Some items", "pluralForm": null, ... },
{ "id": "some-items_other", "text": "Some items", "pluralForm": "other", ...},
{ "id": "some-items_one", "text": "An item", "pluralForm": "one", ... }
]
```
### Ditto CLI - 5.3.1
Default [JSON file formats](https://developer.dittowords.com/cli-reference/files#json) now include plurals, where the standard
unicode plural rule (zero, one, two, few, many, other) is appended to the end of the developer ID key.
Example output:
```json theme={null}
{
"some-items": "Some items",
"some-items_one": "An item",
"some-items_other": "{{count}} items"
}
```
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.3.1).
## January 7, 2026
### API
Add [Export text items](https://developer.dittowords.com/api-reference/text-items/export-text-items) (`GET /v2/textItems/export`)
and [Export components](https://developer.dittowords.com/api-reference/components/export-components) (`GET /v2/components/export`)
endpoints for fetching text items and components in `.json` ICU, `.json` i18next, `.json` Vue i18n, `.strings`, `.stringsdict`, or `.xml` formats.
### Ditto CLI - 5.3.0
Add CLI support for Android `.xml`, iOS `.strings` and `.stringsdict`, and ICU `.json` formats. In conjunction with iOS format additions,
add iOS Locale directory generation for configured variant -> locale mappings in config. If iOS locales are configured, CLI will also auto-generate
a Ditto.swift file for reading locale values.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.3.0).
## December 11, 2025
### Ditto CLI - 5.2.0
Add CLI support for filtering [text items/components by status](/cli-reference/configuration#statuses) when pulling changes.
The filtering logic used for the cli is the same as the [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`) and the [Fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`) API endpoints.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.2.0).
## December 10, 2025
### API
Relax requirement in [Update text items](https://developer.dittowords.com/api-reference/text-items/update-text-items) (`PUT /v2/textItems`) API endpoint that requires text to be included in the request.
Add `tags` field which is an optional `string[]` that if set in the request will replace the existing tags with the specified tags on the textItem.
## December 9, 2025
### API
Clarified expected behavior with variant and status filtering for [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`) API endpoint.
Variants that match the variant filter should only be returned if they match the status filter and their base text also matches the status filter.
Added query param in [Fetch components](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/components`) API endpoint status filter that allows for filtering components by status.
Variants that match the variant filter should only be returned if they match the status filter and their base text also matches the status filter.
## December 5, 2025
### API
Added [Fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`) API endpoint status filter that allows for fetching textItems by status.
Relax requirement in [Update text items](https://developer.dittowords.com/api-reference/text-items/update-text-items) (`PUT /v2/textItems`) API endpoints that requires all textItems to be in the same project.
Now updates can include textItems that span multiple projects and all will be updated.
### Documentation
Fix env var naming used in the cli for setting the ditto api token to the correct value `DITTO_TOKEN`
## November 5, 2025
### API
Added [delete text items](https://developer.dittowords.com/api-reference/text-items/delete-text-items) (`DELETE /v2/textItems`) API endpoint for deleting text items.
## October 6, 2025
### Ditto Github Action - 1.0.2
Updates the Github Action to work with CLI `v5.x`, compatible with both new and legacy Ditto. After upgrading, the Github Action will fetch from new Ditto projects/components by default.
Legacy users will need to add `pull-from-legacy: "true"` to their workflow file to continue fetching legacy text.
If you wish to use this action for both new and legacy Ditto, simply create separate steps with different inputs. See the [README](https://github.com/marketplace/actions/ditto-github-action) for more details and examples.
Release notes:
* [1.0.2](https://github.com/dittowords/ditto-github-action/releases/tag/v1.0.2)
* [1.0.1](https://github.com/dittowords/ditto-github-action/releases/tag/v1.0.1)
* [1.0.0](https://github.com/dittowords/ditto-github-action/releases/tag/v1.0.0)
### Ditto CLI - 5.1.0
A small update to support the `-m` and `--meta` flags in commands. This is used internally for analytics and should not affect customer workflows.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.1.0).
## October 1, 2025
### Ditto CLI - 5.0.0
First official stable release that provides support for fetching project text and components from the new Ditto experience, including all features from the v5 Beta release (through 5.0.0-beta.8).
This version maintains full support for fetching from legacy projects and components. Simply include the `--legacy` flag along with any command from `v4.x`. Users with both new and legacy projects may pull data from both places into the same codebase by maintaining two separate config files and output directories, and including the path to the right config file in your pull command.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.0.0).
## September 29, 2025
### API
Added [fetch components](https://developer.dittowords.com/api-reference/components/get-components) (`GET /v2/components`) API endpoint for fetching components in the user's workspace.
### Ditto CLI - 5.0.0-beta.8
Added support for fetching components in addition to project text via the CLI. Include `components` in your config file to fetch components from the specified folders. Include `projects` in your config file to fetch text from the specified projects.
**Breaking change:** If `projects` or `components` are omitted from the config file, will not fetch text from that area. Previously, if `projects` was omitted, it would fetch text from all projects.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.8).
## September 11, 2025
### API
Added the ability to create variants from [update text items](https://developer.dittowords.com/api-reference/text-items/update-text-items#body-force-variant-creation) (`PUT /v2/textItems`) API endpoint with the `forceVariantCreation` parameter.
## August 18, 2025
### Ditto CLI - 5.0.0-beta.7
Added support for fetching and outputting rich text (HTML) content for Ditto text, by adding `richText: html` to the config file.
At this time, this version is still in Beta, accessible via `@dittowords/cli@beta`.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.7).
## July 24, 2025
### API
Added [create text items](https://developer.dittowords.com/api-reference/text-items/create-text-items) (`POST /v2/textItems`) API endpoint for creating new text items.
## July 8, 2025
### API
Added [update text items](https://developer.dittowords.com/api-reference/text-items/update-text-items) (`PUT /v2/textItems`) API endpoint for editing existing text items.
## April 30, 2025
### Ditto CLI - 5.0.0-beta.6
Beta release of CLI for Ditto 2.0. This version supports fetching text from new, non-legacy Ditto projects. It requires a new format for the config file and supports returning json files formatted for i18next. This version is still in beta, and can be accessed via `@dittowords/cli@beta`. Supports all legacy features via `--legacy` flag.
Release notes:
* [5.0.0-beta.6](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.6)
* [5.0.0-beta.5](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.5)
* [5.0.0-beta.4](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.4)
* [5.0.0-beta.3](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.3)
* [5.0.0-beta.2](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.2)
* [5.0.0-beta.1](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.1)
* [5.0.0-beta.0](https://github.com/dittowords/cli/releases/tag/v5.0.0-beta.0)
## March 28, 2025
### API
* Added [fetch project folders](https://developer.dittowords.com/legacy/api-reference-legacy/project-folders/fetch-project-folders) (`GET /v1/project-folders`) API endpoint for fetching project folders in the user's workspace.
* Added [fetch projects by project folder id](https://developer.dittowords.com/legacy/api-reference-legacy/project-folders/fetch-projects-by-project-folder-id) (`GET /v1/project-folders/:folder_id/projects`) API endpoint for fetching projects in the specified folder.
## March 24, 2025
### API
Added the first set of v2 endpoints to the API:
* Added [fetch projects](https://developer.dittowords.com/api-reference/projects/get-projects) (`GET /v2/projects`) API endpoint for fetching projects in the user's workspace.
* Added [fetch text items](https://developer.dittowords.com/api-reference/text-items/get-text-items) (`GET /v2/textItems`) API endpoint for fetching text items in the user's workspace.
* Added [fetch variables](https://developer.dittowords.com/api-reference/variables/get-variables) (`GET /v2/variables`) API endpoint for fetching variables in the user's workspace.
* Added [fetch variants](https://developer.dittowords.com/api-reference/variants/get-variants) (`GET /v2/variants`) API endpoint for fetching variants in the user's workspace.
## February 3, 2025
### API
The [fetch component text](https://developer.dittowords.com/legacy/api-reference-legacy/components/fetch-component-text) (`GET /v1/components`) API endpoint now supports the `includeTimeData` query parameter.
When `includeTimeData` is set to `true`, the response will include the `createdAt` and `updatedAt` fields for each component. This feature is only available when the `structured` format is used.
## November 11, 2024
### Ditto React - 1.6.3
* Dependency upgrades
See full release notes [here](https://github.com/dittowords/ditto-react/releases/tag/v1.6.3)
## May 21, 2024
### Ditto CLI - 4.5.2
* Fix to include header distinguishing Ditto CLI requests from direct API requests.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v4.5.2).
## May 7, 2024
### Ditto CLI - 4.5.1
* Fix issue with error logs not being flushed before exiting the CLI
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v4.5.1).
## May 3, 2024
### Ditto Github Action - 0.3.0
* add optional name input parameter pr-title-prefix to distinguish prs with multi config setups
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v0.3.0).
## May 2, 2024
### API / Web App
Pluralization is now supported for all JSON formats when importing components via the Ditto web app or the [Fetch component text](https://developer.dittowords.com/legacy/api-reference-legacy/components/fetch-component-text) API endpoint.
Example import data:
```json theme={null}
{
"fruit": "You have fruit in your cart.",
"fruit_one": "You have one fruit in your cart.",
"fruit_other": "You have some fruit in your cart."
}
```
## April 16, 2024
### CLI
v4.5.0 released to add support for a new option which disables the generation of `index.js` and `index.d.ts` files when working with JSON formats.
See the release notes [here](https://github.com/dittowords/cli/releases/tag/v4.5.0).
## March 22, 2024
### CLI
v4.4.1 released to fix periodic hanging from attempting to exit the CLI process using Ctrl + C.
See full release notes [here](https://github.com/dittowords/cli/releases/tag/v4.4.1).
## March 15, 2024
### Documentation
* Small fixes and wording clarifications on the [SDKs](https://developer.dittowords.com/additional-tools/sdks) page
## March 13, 2024
### Ditto React - 1.6.1
* Fix crash when rich text is enabled
See release notes: [https://github.com/dittowords/ditto-react/releases/tag/v1.6.1](https://github.com/dittowords/ditto-react/releases/tag/v1.6.1)
## February 29, 2024
### Ditto CLI - 4.4.0
* Add `pull` --sample-data flag for variants
See release notes: [https://github.com/dittowords/cli/releases/tag/v4.4.0](https://github.com/dittowords/cli/releases/tag/v4.4.0)
## February 27, 2024
### Ditto API
* `/v1/variants` now supports the `showSampleData` query parameter
* Fix `/v1/variants` for `projectIds` query parameter
## February 19, 2024
### Ditto CLI - 4.3.0
* `nested` format is now supported
See release notes: [https://github.com/dittowords/cli/releases/tag/v4.3.0](https://github.com/dittowords/cli/releases/tag/v4.3.0)
### Ditto CLI - 4.2.3
* Upgrades to several dependencies
See release notes: [https://github.com/dittowords/cli/releases/tag/v4.2.3](https://github.com/dittowords/cli/releases/tag/v4.2.3)
## January 22, 2024
### Ditto CLI - 4.2.2
* Stop component folders with emojis from creating a leading separator
See release notes: [https://github.com/dittowords/cli/releases/tag/v4.2.2](https://github.com/dittowords/cli/releases/tag/v4.2.2)
## December 12, 2023
### Ditto API
The `/components/file` [endpoint](https://developer.dittowords.com/legacy/api-reference-legacy/components/import-components-via-a-file)
now supports a `folderId` query parameter. You can supply the Developer ID of one of
your component folders, and all the components will be imported to that folder.
## December 7, 2023
### Ditto React
v1.3.2 released to fix a bug that incorrectly tracked the "Searching" location.
## November 28, 2023
### Ditto CLI - 4.2.1
* Only run init() on commands that need it in [https://github.com/dittowords/cli/pull/89](https://github.com/dittowords/cli/pull/89)
This change prevents the `ditto` directory from being created on commands that don't need it (e.g. `generate-suggestions`)
See release notes: [https://github.com/dittowords/cli/releases/tag/v4.2.1](https://github.com/dittowords/cli/releases/tag/v4.2.1)
## November 16, 2023
### Ditto CLI - 4.2.0
Add `--sample-data` flag to the `components-folders` command in [https://github.com/dittowords/cli/pull/88](https://github.com/dittowords/cli/pull/88)
See release notes: [https://github.com/dittowords/cli/releases/tag/v4.2.0](https://github.com/dittowords/cli/releases/tag/v4.2.0)
## November 2, 2023
### Ditto React
Ditto text items with rich text can now be rendered natively by passing the `richText` property on either `Ditto` or `DittoText`.
This expands rich text support from v1.5.0 which introduced support for rich text on components.
Example:
```
```
## October 30, 2023
### Ditto CLI — 4.1.0
This release includes features designed to tighten integration for a variety of environments, including iOS, TypeScript, and more.
See the release notes [here](https://github.com/dittowords/cli/releases/tag/v4.1.0).
### New example apps
We've released new versions of our example applications, which have been updated to include the latest in recommended practices for integrating Ditto into development.
See the full list [here](/example-apps#examples).
## September 29, 2023
[Ditto Webhooks](/additional-tools/webhooks) have been released!
## August 29, 2023
### Ditto React
* Ditto components with rich text can now be rendered natively by passing the richText property on either Ditto or DittoComponent.
* Example: ` `
## August 18, 2023
### Ditto API
* Endpoints for fetching project text now support an `exclude_components` query parameter.
* When `exclude_components=true`, only text items not associated with Ditto components will be returned from a given endpoint.
### Ditto CLI
* We've released a new major version (v4) of the CLI. See the release notes [here](https://github.com/dittowords/cli/releases/tag/v4.0.0).
## August 15, 2023
### Ditto API
The behavior of variables when exporting to mobile formats (`.strings`, `.stringsdict`, and `.xml`) has changed.
Variables will now maintain a consistent ordering across base text, variant text, and plural forms; they're assigned an index according to the order of usage (starting with base text, and then variants), and that index is maintained through variant exports.
For example, consider the following text:
```json theme={null}
// Base Text
{{username}}, your role is {{role}}.
// Variant Text
Tú papel es {{role}}, {{username}}.
Previously, exports for the base text and variant text would cause format specifier indices to be reversed for the variables:
/* base-example.strings */
"text" = "%1$@, your role is %2$@.";
/* spanish-example.strings */
"text" = "Tú papel es %1$@, %2$@.";
To facilitate ease of integration into development, exports for variant text will now ensure that the format specifier indices match those in the base text:
/* base-example.strings */
"text" = "%1$@, your role is %2$@.";
/* spanish-example.strings */
"text" = "Tú papel es %2$@, %1$@.";
```
## August 7, 2023
### Ditto API
* Support has been added for an `exclude_components` query parameter to the endpoint.
* When set to `true`, only text items not associated with components will be returned from the endpoint.
### Ditto CLI
* Small bug fix to ensure files aren't written to disk for empty API responses.
* For more information, please refer to the release [here](https://github.com/dittowords/cli/releases/tag/v3.10.1).
## July 26, 2023
### Ditto API
* When exporting data for variants, variant metadata (name and description) is now included.
* In the JSON formats, two new meta keys are added at the top level: `variant_name` and `variant-description`
* In the Android `.xml`, iOS `.strings`, and iOS `.stringsdict` formats, a comment is added for each field at the top of the file
## July 17, 2023
### Ditto API
* The `flat` format now supports rich text.
## June 27, 2023
### Ditto CLI
* Added support for specifying a list of formats in the format configuration property.
* For more information, please refer to the release [here](https://github.com/dittowords/cli/releases).
## June 26, 2023
### Ditto React
* `v1.4.1` fixes a bug introduced in `v1.4.0` which caused variables to ignore passed values.
## June 14, 2023
### Ditto CLI
* Added the `import-components` command which enables component imports via a file through the CLI. For information about the command please refer to the [documentation](https://github.com/dittowords/cli#import-components) in the README.
## June 12, 2023
### Ditto API
* We've added the new `POST /components/file` endpoint to enable uploading components through the API.
## June 8, 2023
### VSCode Extension
* Add the ability to only match on components from a component folder. Must be used with `v3.8.0` of the Ditto CLI.
### Ditto CLI
* Add `component-folders` command which lists component folders in your workspace. See the release [here](https://github.com/dittowords/cli/releases/tag/v3.8.0).
## June 5, 2023
### Ditto CLI
* Add the `-cf` (`--component-folder`) flag for `generate-suggestions`. See the release [here](https://github.com/dittowords/cli/releases/tag/v3.7.0).
## June 2, 2023
### Ditto CLI
* Performance improvements. See the release [here](https://github.com/dittowords/cli/releases/tag/v3.6.1).
## May 30, 2023
### Ditto CLI
* We've added support for specifying the new `ios-stringsdict` format in the CLI configuration. See the release [here](https://github.com/dittowords/cli/releases/tag/v3.6.0).
### Ditto API
We clarified a small point of confusion with the documentation around the request payload expected for the endpoint.
The JSON payload should include a top-level data property:
```json theme={null}
{
"data": {
"[API ID]": {
"text": "[TEXT OF TEXT ITEM (CAN INCLUDE VARIABLES)]",
"notes": "[NOTES OF TEXT ITEM]", // optional
"tags": [ ... ], // optional: array of strings
"plurals": [ // optional: array of plural objects
{
"text": "[TEXT OF PLURAL FORM]",
"form": "[one|two|zero|few|many|other]"
}
]
}
}
}
```
## May 12, 2023
### Ditto API
We've added support for the iOS `.stringsdict` format to our API. Read more [here](https://developer.dittowords.com/legacy/api-reference-legacy/text-formats#ios-.stringsdict-format-ios-stringsdict).
## May 3, 2023
### Ditto CLI
* Adds ICU support
* Fixes a bug where pulling would fail on new initializations
* [Full Changelog](https://github.com/dittowords/cli/compare/v3.3.0...v3.5.0)
## May 1, 2023
### VS Code Extension
We've create a VS Code extension! Check it out [here](https://marketplace.visualstudio.com/items?itemName=dittotech.vscode-ditto).
## April 28, 2023
### Ditto API
We've added support for an ICU JSON export format to our API. Read more [here](https://developer.dittowords.com/api-reference/text-formats#icu-json-format-icu).
## April 26, 2023
### Ditto CLI
`v3.4.0` of the CLI has been published, which adds a `-v`, `--version` flag to output what version of the CLI is being run.
## March 23, 2023
### Ditto React
We've published `v1.4.0`, which includes explicit support for map and list variables, in addition to miscellaneous cleanup.
Read about the release [here](https://github.com/dittowords/ditto-react/releases/tag/v1.4.0).
## March 22, 2023
### Ditto API, Ditto CLI, Ditto React
We've added a `__type` property to variable output in our structured export format; this enables simple discrimination between different types of variables:
```json theme={null}
{
"some-variable-1": {
"example": "Hello world!",
"__type": "string"
},
"some-variable-2": {
"example": 100,
"__type": "number"
},
"some-variable-3": {
"text:" "Foo",
"url": "https://bar.com",
"__type": "hyperlink"
}
}
```
## March 21, 2023
### Ditto API
We've added support for a `nested` JSON export format to our API. Read more [here](https://developer.dittowords.com/api-reference/text-formats#nested-json-format-nested).
## March 9, 2023
### Ditto CLI
We've published `v3.0.0` of the CLI, which focuses around a number breaking changes intended to better align default CLI behavior with Ditto best practices.
Read the release notes [here](https://github.com/dittowords/cli/releases/tag/v3.0.0).
## February 15, 2023
### Ditto API
We've released two bug fixes specific to the Android XML export format:
* index values for format specifiers will now be relative to a text item's base value AND its plurals, instead of resetting for each plural form ([issue](https://github.com/dittowords/cli/issues/48))
* extra whitespace is no longer added between text and variables in the final output ([issue](https://github.com/dittowords/cli/issues/49))
## February 14, 2023
### Ditto API
We've released a new version of our API that includes some breaking changes. The old API endpoints are deprecated, and existing users should migrate to the new endpoints at their earliest convenience.
## February 6, 2023
### Ditto Web App
* Removed the deprecated the full format from the export modals on the project page and in the component library
* Set the flat format to be the default export format in the web app
## February 3, 2023
### Ditto API
Minor documentation update to add and emphasize a deprecation notice for the full format.
## February 1, 2023
### Ditto React — 1.3.0
Added support for using variables in conjunction with the flat format. See the release [here](https://github.com/dittowords/ditto-react/releases/tag/v1.3.0).
## January 25, 2023
We added support to the web app for importing components from two new file formats:
* Android localization files (.xml)
* iOS localization files (.strings)
Read more [here](https://dittov3.notion.site/Importing-JSON-iOS-Android-Files-256cc8865c7a80fe94cdf135631bf8c6).
## January 19, 2023
### Ditto React — 1.2.1
* Updated README to clarify that the flat format does not currently support variables.
* Fixed a bug preventing falsy values (namely 0 and "") from being properly interpolated.
See the release [here](https://github.com/dittowords/ditto-react/releases/tag/v1.2.1).
## December 15, 2022
### Ditto CLI
Added rich text support. See more info [here](https://github.com/dittowords/cli#richtext)
## December 13, 2022
### Ditto API
Added the `includeRichText` flag to the following endpoints (format must be full or structured):
* `/projects`
* `/projects/:id`
* `/projects/:id/components`
* `/components`
* `/component-folders/:api*id/components`
## November 30, 2022
### Ditto CLI
Added the `status` filter as a configuration variable. To filter the fetched text by its status, you can now use the `status` parameter in your `config.yml`.
## November 29, 2022
### Ditto CLI
Added `android` and `ios-strings` as available formats. To use these formats, specify them under the format paramter in your `config.yml`.
## November 10, 2022
### Ditto API
Fixed a typo in an example in the documentation containing an incorrect usage of the curl command.
### Ditto CLI
Added information to the README about two supported environment variables:
* `DITTO_CONFIG_FILE:` used to specify an alternate file location for the CLI to read authentication information from. The default path is `$HOME/.config/ditto`.
* `DITTO_TEXT_DIR`: used to specify an alternate folder location for the CLI to write its output files to. The default path is `./ditto`.
## Oct 11, 2022
### Ditto API
* Added new endpoint: Fetch component folders
* Added new endpoint: Fetch components by component folder
* Added sub-headings to divide the endpoints by the entity they're associated with, and implemented minor miscellaneous cleanup across the endpoint documentation
## Sep 23, 2022
### Ditto API
Text items with plural values will have those plural values included in flat exports as individual key/value pairs; pluralized keys are structured like `[TEXT ID]_[PLURAL FORM]`. See the [flat format documentation](/string-formats/json#flat-json) for more details.
Fixed a bug where the status field failed to properly filter returned data when specified in conjunction with the `android` or `ios-strings` formats.
## Sep 19, 2022
### Ditto React — 1.2.0
* We exported two hooks that can be used for accessing synced data: `useDittoSingleText` and `useDittoComponent`. These hooks are experimental and will likely undergo API changes in the future.
* See the release [here](https://github.com/dittowords/ditto-react/releases/tag/v1.2.0).
### Ditto API
* Added the `status` field to data returned from the `/components` and `/projects/:id/components` endpoints.
## Jun 30, 2022
### Ditto API
* Added support for including variables in payloads sent to the `PUT /components` endpoint.
* Fixed an issue with Android & iOS export formats not escaping special characters: `\n`, `\t`, `@`, `?`, `'`, and `"` characters are now properly escaped.
* Added missing `xliff` namespace to exported Android `.xml` files.
\= Fixed a bug with Android `.xml` exports that occurred with text items with API IDs that include the `-` character. Now, all `-` characters are replaced with `\_` characters in the name property of `` and `` tags, and a `ditto_api_id` property has been added to string and plural tags to serve as a reference to the original API ID.
### Ditto CLI — 2.5.1
* Fixed a bug when using the `project add` / `project remove` commands and selecting the component library caused incorrect modifications to be made to the CLI's configuration file.
* See the release [here](https://github.com/dittowords/cli/releases/tag/v2.5.1).
### Ditto Example Projects
* Added new iOS Example Project showcasing how to use exported .strings files.
* Added new Android Example Project showcasing how to use exported .xml string files.
See [Example Projects](/example-apps) for more details.
## Jun 13, 2022
### Ditto GitHub Action — 0.2.0
Added an optional `ditto-dir` input parameter for projects that do not have the ditto directory in the root of the repository
## June 7, 2022
### Ditto API
Added support for upserting plurals via the `PUT /components`.
See our [API documentation](/api-reference) for more details.
## June 1, 2022
### Ditto API
* Added early support for exporting text data to Android and iOS Strings formats. All endpoints that support a `format` query parameter can now accept values of `android` or `ios-strings`.
* Added `GET /variables` endpoint that returns the variables in the workspace of the requesting user.
* Added the ability to filter by text item status by passing a status query parameter in API requests. Supported by the following endpoints:
* `GET /projects`
* `GET /projects/:id`
* `GET /projects/:id/components`
* `GET /components`
See our [API documentation](/api-reference) for more details.
## May 23, 2022
### Ditto CLI — 2.5.0
* Added meta option flag in support of the Ditto GitHub Action release. See the release [here](https://github.com/dittowords/cli/releases/tag/v2.5.0).
### Ditto GitHub Action — 0.1.0
* v0.1.0 released! Check it out [here](https://github.com/dittowords/ditto-github-action).
## May 16, 2022
### Ditto CLI — 2.4.0
* Update some user-facing CLI messages to accurately reflect our new subdomain: app.dittowords.com (instead of the old beta.dittowords.com). See the release [here](https://github.com/dittowords/cli/releases/tag/v2.4.0).
## May 10, 2022
### Ditto CLI — 2.3.0
* Allows users to override the output directory via a new environment variable `DITTO_TEXT_DIR`
* When no projects are found in the `config.yml` file an additional help message displays about verifying that the projects have developer mode enabled
* See the release [here](https://github.com/dittowords/cli/releases/tag/v2.3.0).
## February 28, 2022
### Ditto API
Added better error handling for the niche edge case where an API request is made using the token of a user that has been removed from their workspace.
## January 20, 2022
### Ditto React — 1.1.1
* Our React SDK now supports variable interpolation by passing in values through the variables prop.
* Our React SDK now supports displaying plural forms through the count prop.
For more information about using variable interpolations and pluralization through our React SDK, check out our [SDK documentation](/additional-tools/sdks).
### Ditto CLI — 2.2.0
* The CLI now supports reading API keys from an environment variable (`DITTO_API_KEY`).
* See the release [here](https://github.com/dittowords/cli/releases/tag/v2.2.0).
## January 11, 2022
### Ditto CLI
We deployed a bugfix release to fix issues introduced in the latest minor version of the package:
* the pull command no longer crashes when projects other than the component library are specified in `config.yml`
* resolves a casing issue in the project add command that was causing it to crash
See the release [here](https://github.com/dittowords/cli/releases/v2.1.2).
## January 6, 2022
### Ditto CLI
We've added a new supported property to `ditto/config.yml` to allow explicitly specifying that the component library should be fetched and included in the CLI's output:
`components: true`
This is now the preferred alternative to the old way of specifying the component library:
```yml theme={null}
projects:
name: Ditto Component Library
id: ditto_component_library
```
Our goal with this change is to make the CLI easier to use and understand by aligning it with the way things work in the Ditto web app, where the component library is fundamentally different from the projects in a workspace.
See the release [here](https://github.com/dittowords/cli/releases/tag/v2.1.1).
## December 8, 2021
### Ditto API
* `GET /projects/:id/components` can now be used to fetch the components used in a project
* Return format matches the `GET /components` endpoint
* Supports `format` and `variant` parameters (the same as the `/projects`, `/project/:id`, and `/components` endpoints)
## November 29, 2021
### Ditto API
* `GET /components` can now be used to fetch the components in a workspace
* Supports format and variant parameters (the same as the `/projects` and `/project/:id` endpoints)
* `GET /projects/ditto_component_library` has been deprecated; the endpoint is still available, but references to it have been removed from the documentation.
* `PUT /components` can now be used to update the text of components in a workspace
* Currently only supports updating variant text via the variant query parameter (an error will be thrown if not specified)
* Currently only available to teams on Team or Enterprise plans
* Data is specified on data key in request body and must be in one of our [three supported import formats](https://dittov3.notion.site/Importing-JSON-iOS-Android-Files-256cc8865c7a80fe94cdf135631bf8c6)
## November 11, 2021
### Ditto CLI — 2.0.0
* Output files are now written to disk in several different ways according to how the CLI is configured; most notably, if the variants option is set and a format of structured or flat is specified, output files will be written on a per-project per-variant basis
* Data for `structured` and `flat` formats is saved without arbitrary top-level nesting
* Files are only written for variants that contain values for the configured projects (no more empty files)
For a more in-depth description (with examples) of these changes and others in the release, see the full release notes [here](https://github.com/dittowords/cli/releases/tag/v2.0.0).
### Ditto React — 1.0.0
* `ditto-react` now only works with CLI version `2.x.x` — leaning into new CLI improvements allowed us to drastically reduce many areas of complex logical overhead
* We made some stabilization improvements to the way that missing/invalid `frameId`, `blockId`, `textId`, or `componentId` values are handled
* We implemented significant refactoring in several areas of the project
For a more in-depth description of these changes, see the full release notes [here](https://github.com/dittowords/ditto-react/releases/tag/v1.0.0)
### Ditto Demo
* We added a [new branch](https://github.com/dittowords/ditto-demo/tree/react-i18next) that showcases how Ditto can be integrated into a project with react-i18next
* We updated dependencies to the latest versions of the Ditto CLI (v2.0.0) and Ditto React (v1.0.0)
## October 22, 2021
### Ditto API — 2.4.1
* We fixed a bug with the API (and in-app exports) that included hidden text in `flat` and `structured` JSON exports. Now, hidden text will correctly not be included in these export formats!
### Ditto Demo
* We included the files to import into the component library separately from where they'd be synced via the CLI
* We included more instructions on linking the demo app with its corresponding design file
## October 7, 2021
### General
* Refactored API documentation to be easier to navigate and communicate critical concepts more clearly
### Ditto CLI — 1.1.1
* When the `pull` command is executed, all `.json` and `.js` files are now removed from the `ditto` folder prior to new data being written
\= Support added for new options in `ditto/config.yml`:
* `variants`: `true` or `false`
* If set to true, data will be fetched for both base and variant text and stored in separate JSON files
* `format`: `flat` or `structured` - If specified, data will be fetched and stored in the specified format
\= Refactored `README`
* `GET /variants` will now return names and API IDs for variants in the workspace associated with the requesting user.
### Ditto React — 0.0.5
* Support added for `flat` and structured formats
* Support added for passing a `variant` value to `DittoProvider`
* Bug fixes around support for integrating with workspace component libraries (as opposed to individual projects)
* Refactored `README`
### Ditto Demo
* Refactored `ditto-sdk` usage to integrate with a component library instead of an individual project
* Added a language picker to showcase `ditto-react` and `ditto-cli` support for variants
* Refactored `README`, including adding instructions for connecting the repo to a component library
## September 27, 2021
### General
Fixed incorrect example of `/projects` usage in API Reference. The `projectIds` query parameter should be specified as follows:
* Correct: `?projectIds[]=&projectIds[]=`
* Incorrect: `?projectIds[]=,`
### API — 2.4.0
`GET /variants` will now return names and API IDs for variants in the workspace associated with the requesting user.
## September 8, 2021
### API — 2.3.0
* `GET /projects` and `GET /projects/:id` now accept an optional query parameter of `variant`; when provided, the data exported will be specific to the variant with an API ID that matches the parameter's value. For `default` and `structured` formats, the variants key will not be included when the variant parameter is provided.
Example: `/projects/?variant=xxx-xxx-xxx`
* `GET /projects/:id` will not include top-level projects and project\_xyz keys
Example request: `GET /projects/123`
Example response before change:
```json theme={null}
{ projects: { project_123: { text_item: "Hello World", ... }}}
```
Example response after change:
```json theme={null}
{ text_item: "Hello World", ... }
```
## August 11, 2021
### API — 2.2.0
`GET /projects` and `GET /projects/:id` now accepts an optional query parameter of `format`, which can be either `flat` or `structured`. If no format is provided, the `full` JSON of the project will be returned with blocks and frames.
Example: `/projects/?format=flat`
## July 28, 2021
With the recent release of [Variants for Components](https://dittov3.notion.site/Variants-for-Components-256cc8865c7a80bb8c44da73209fb0cc), we've included them in both exports from our web-app and the JSON response from the API.
### API — 2.1.0
* `GET /projects/:id` will now return component variants. This applies both for when fetching projects or when fetching the component library (i.e. id = ditto\_component\_library)
* `GET /projects/:id` will now match the project JSON export from the web-app to include component information (`is_comp` and `component_api_id`) in the text object
## June 21, 2021
We've updated our React library and our demo project to work with the multi-project JSON structure that the CLI now saves in `text.json`.
### Ditto React — 0.0.4
TypeScript bindings are now exported 🎉
A new `projectId` prop can be passed to `DittoProvider` or `Ditto`
* If passed to `DittoProvider`, all descendant `Ditto` components will default to pulling text from the associated project
* If passed to `Ditto`, the component will pull text from the associated project
* If passed to both `DittoProvider` and `Ditto`, the value passed to `Ditto` will take precedence
* Breaking change: If a `Ditto` component is rendered that is not provided a `projectId` via direct prop or `DittoContext` ancestor, an error will be thrown
See more details in the [updated documentation](https://www.npmjs.com/package/ditto-react).
### Ditto Demo
* Upgraded `ditto-react` to `v0.0.4`
* Updated source to work with new `ditto-react` version by passing `projectId` props to all instances of `DittoContext`
## June 7, 2021
We've updated both our CLI and API to handle multiple projects.
Heads up! This results in some breaking changes to the CLI in order for it to list projects, and will change the format of the `text.json` fetched by the CLI. Please upgrade your Ditto CLI via either `npm` or `yarn`.
### API — 2.0.0
* `GET /project-names` is the new name of the previous `GET /projects` endpoint. Just as before, this will return the names and IDs of projects in your Ditto workspace with Developer Mode turned on
* `GET /projects/:id` will now return the structured JSON in a format compatible with multiple projects
* `GET /projects` is a new endpoint that will return the content of multiple projects (specified via the query parameter projectIds) as a single JSON object
### CLI — 1.0.0
* We've updated the CLI to handle syncing multiple projects in a single directory! This means several things:
`/ditto/config.yml` now supports multiple projects. `ditto-cli` pull will pull all projects in the current directory's /`ditto/config.yml`
* We've added two new commands to add and remove projects from `/ditto/config.yml`
* `ditto-cli project add`
* `ditto-cli project remove`
* The regular `ditto-cli project` command will now function as `ditto-cli project add`
## April 1, 2021
### API — 1.1.0
* `GET /projects` now includes the Component Library if Developer Mode is enabled for the Component Library
* `GET /projects/:id` will return the Component Library as a structured JSON if the ID provided is `ditto_component_library`
## February 25, 2021
### API — 1.0.0
* `GET /projects` endpoint for fetching Ditto projects from workspace
* `GET /projects/:id` endpoint for fetching content in Ditto project as structured JSON
# Feedback & Support
Source: https://developer.dittowords.com/feedback-support/feedback-support
Have questions, feedback, or requests for our developer tools? Please **open an issue** in the respective repo on Github and an engineer from our team will get back to you with a resolution as quickly as possible.
### API or CLI Support
* Open an issue at [dittowords/cli](https://github.com/dittowords/cli/issues)
### React SDK Support
* Open an issue at [dittowords/ditto-react](https://github.com/dittowords/ditto-react/issues)
### Github Action Support
* Open an issue at [dittowords/ditto-github-action](https://github.com/dittowords/ditto-github-action/issues)
### Contact Support
For any other questions or urgent issues, please contact our customer success team via [support@dittowords.com](mailto:support@dittowords.com).
# Introduction
Source: https://developer.dittowords.com/introduction
## What is Ditto?
**Ditto manages your team’s product text — from draft to design to development — with a single source of truth.**
For developers, Ditto functions as infrastructure for product text, keeping strings up to date and managing everything from string keys, variable interpolation, and plurals, to file formats, localization, and variations.
## Why use Ditto’s developer integrations?
Shipping product **quickly**, **safely**, and **with consistency** are the core elements of **operational scale**. Here’s how Ditto can help:
* **Save work for developers:** Say goodbye to the stray Slack message or bug ticket to update text (“Hey, can you update the text to actually say \[XYZ]?”). Whether it’s in prod or in QA, Ditto reduces the time spent hunting down strings and gives time back to developers for real engineering work.
* **A single source of truth, accessible via API:** Rather than multiple overlapping, disjointed sources for product text (Figma, a spreadsheet, a document, a localization tool, directly in development, etc.), Ditto connects sources so that everyone is on the same page. The latest version of text is always accessible directly via our API.
* **Building automated workflows:** Use our CLI in a CI pipeline, build automation with our webhooks, or use our API to bring text to other destinations; Ditto’s developer integrations serve as building blocks.
* **Safety and formatting:** With Ditto, developers get ready-to-use string files. Ditto handles all of the variable interpolation, pluralization, ID-naming, platform-specific formatting (JSON/ICU/iOS/Android), and localization-readiness.
## How is Ditto different from a headless CMS?
You can think of Ditto’s developer tooling as a headless CMS for your team’s product text. Because Ditto manages **product text**, it’s built for how teams work on product:
* **Built for microcopy** — Think everything from CTAs to error messages to disclosures, as opposed to structured, long-form content like a blog post.
* **Focused on componentization** — Ditto treats text as reusable components, rather than individual one-offs — like your design systems and frontend code do with UI elements.
* **Integrates with your existing stack** — Ditto fits into your existing product development workflows, with tools like our our Figma plugin, VS Code extension, GitHub Action, localization/TMS integrations, SDKs, and framework- and platform-specific formats.
* **Manage the distribution of your strings** — Ditto's developer integrations include everything you need to keep strings up to date locally, and you can manage how it gets distributed, just like the rest of your code (i.e. deployed to a staging/QA environment, to production, to a CDN).
## How does Ditto work?
Ditto functions at both the **application layer** and the **API layer** to keep text in sync across sources.
**At the application layer**, teams use our web app and Figma plugin to edit, review, and translate text. Core to this usage are **components** in Ditto (see [Key Concepts](/concepts)). In Ditto, text is treated as reusable components instead of one-off, isolated elements to help enforce consistency at scale.
**At the API layer**, Ditto automates the updating and formatting of strings in development using our 6 core tools:
Fetches formatted, up-to-date text (and metadata) from Ditto
Wraps our API to directly update strings in local development
Connects Ditto to AI-powered development tools (Claude Code, Cursor, Codex, Figma Make, etc.) via the Model Context Protocol
Manages Ditto spec files that declare text surfaces and style guide rules for components
Sends updated information based on events in Ditto (i.e. edits, status changes, ID changes, etc.)
Reviews pull requests for style guide violations and text re-use suggestions
# Authentication
Source: https://developer.dittowords.com/legacy/api-reference-legacy/authentication
Ditto's developer integrations require an API key to authenticate requests. You can manage your API keys from the [Developer Integrations](https://app.dittowords.com/developers) page.
API keys enable programmatic access to all data in your workspace, so be sure to keep them secure. Don't share your API keys in publicly accessible places such as GitHub or client-side code.
## Generate an API key
1. Navigate to the [Developer Integrations](https://app.dittowords.com/developers) page.
2. Enable developer integrations for your workspace if they haven't been enabled already (see [this help guide](https://dittov3.notion.site/Developer-Mode-256cc8865c7a801ea9bdca5aa4303fca) for more information).
3. Under the **API Keys** section, click **+ Create API key**.
4. Enter a name for the API key and click the **Create** button.
5. Copy the value of the API key to your clipboard and store it somewhere safe; you won't be able to access it again after closing the modal.
## Authenticate API requests
Authorize requests to the Ditto API by passing an API key in an `Authorization` header:
```
"Authorization": ""
```
Here is an example request to the `/components` endpoint:
```sh theme={null}
curl -X GET \
--header "Authorization: " \
"https://api.dittowords.com/v1/components"
```
## Authenticate the Ditto CLI
The first time you run the CLI, you’ll be asked to provide an API key.
See the [CLI documentation](/cli-reference) for more information.
# Fetch component folders
Source: https://developer.dittowords.com/legacy/api-reference-legacy/components-folders/fetch-component-folders
openapi-legacy.json get /component-folders
Returns an object of component folders in the requesting user's workspace.
# Fetch component text by component folder
Source: https://developer.dittowords.com/legacy/api-reference-legacy/components-folders/fetch-component-text-by-component-folder
openapi-legacy.json get /component-folders/{api_id}/components
Returns the components in the specified folder. Format is identical to the format used by the Fetch components endpoint.
# Fetch component text
Source: https://developer.dittowords.com/legacy/api-reference-legacy/components/fetch-component-text
openapi-legacy.json get /components
Returns the components in the workspace of the requesting user. Only component libraries with Developer Mode enabled can be fetched.
# Import components via a file
Source: https://developer.dittowords.com/legacy/api-reference-legacy/components/import-components-via-a-file
openapi-legacy.json post /components/file
For more information about importing components via a file please see: https://dittov3.notion.site/Importing-JSON-iOS-Android-Files-256cc8865c7a80fe94cdf135631bf8c6. The request body must be of type multipart/form-data.
# Update component text variant
Source: https://developer.dittowords.com/legacy/api-reference-legacy/components/update-component-text-variant
openapi-legacy.json put /components
Used for updating the text and status fields for components in the workspace of the requesting user.
-> Currently only supports updating variant text or status on components via the variant query parameter (an error will be thrown if the variant param is not specified)
-> Currently only available for teams on team or enterprise plans
# Fetch project folders
Source: https://developer.dittowords.com/legacy/api-reference-legacy/project-folders/fetch-project-folders
openapi-legacy.json get /project-folders
Returns a list of project folders in the workspace of the requesting user.
# Fetch projects by project folder id
Source: https://developer.dittowords.com/legacy/api-reference-legacy/project-folders/fetch-projects-by-project-folder-id
openapi-legacy.json get /project-folders/{folder_id}/projects
Returns a list of projects in the specified project folder.
# Fetch component text by project id
Source: https://developer.dittowords.com/legacy/api-reference-legacy/projects/fetch-component-text-by-project-id
openapi-legacy.json get /projects/{id}/components
Returns the components used in the specified project. Format is identical to the format used by the Fetch components endpoint.
# Fetch projects
Source: https://developer.dittowords.com/legacy/api-reference-legacy/projects/fetch-projects
openapi-legacy.json get /projects
Returns a list of Ditto projects. Only projects with Developer Mode enabled can be fetched.
# Fetch text by project id
Source: https://developer.dittowords.com/legacy/api-reference-legacy/projects/fetch-text-by-project-id
openapi-legacy.json get /projects/{id}
Returns the contents of the Ditto project referred to by :id. You can find the id of a Ditto project from its URL: https://app.dittowords.com/doc/:id. Only projects with Developer Mode enabled can be fetched.
# Fetch variables
Source: https://developer.dittowords.com/legacy/api-reference-legacy/variables/fetch-variables
openapi-legacy.json get /variables
Returns the variables in the workspace of the requesting user.
# Fetch variants
Source: https://developer.dittowords.com/legacy/api-reference-legacy/variants/fetch-variants
openapi-legacy.json get /variants
Returns a list of variants in the workspace of the requesting user.
# Installation
Source: https://developer.dittowords.com/legacy/cli-reference-legacy/authentication
Installation and authentication of the Ditto CLI
## Overview
The following documentation relates to `v4.x` of the Ditto CLI. To use legacy features with `v5.x`, add the `--legacy`
flag to your commands.
The Ditto CLI allows developers to access the [Ditto API](/api-reference) directly from the command line. The Ditto CLI updates text directly in local development. Teams can also build workflows with the CLI, including utilizing it in CI/CD.
## Installation
To install the CLI as a development dependency:
```bash npm theme={null}
npm i --save-dev @dittowords/cli
```
```bash yarn theme={null}
yarn add --dev @dittowords/cli
```
After installation, you can get a list of the available commands by running the help command:
```bash theme={null}
npx @dittowords/cli --help
```
**Note:** [npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) comes with `npm` 5.2
or higher
## Authentication
The first time you run the CLI, you'll be asked to provide an API key. You can generate an API key in your [developer integrations settings](https://app.dittowords.com/developers/api-keys).
By default, your API key is saved to `$HOME/.config/ditto`; the default path can be overwritten by specifying a custom one via the environment variable `DITTO_CONFIG_FILE`.
The Ditto API key is read from the file at the path stored at `DITTO_CONFIG_FILE` unless it's explicitly provided by the env var `DITTO_API_KEY`.
We don't recommend editing the authentication file by hand; if you need to remove a saved API key or swap one key with another, it's better to fully delete the file and then re-run the CLI.
To change your API key, delete the `$HOME/.config/ditto` file and you'll be prompted for a new key the next time that the CLI executes.
## Fetching text
Once you've installed, authenticated, and [configured](/cli-reference/configuration) the CLI, you'll be able to pull down up-to-date text by running the CLI:
```
npx @dittowords/cli pull
```
This will update the string files you have locally in the `/ditto` directory from where you're running the CLI. (For more information on the structure of files pulled by Ditto, see [files](/cli-reference/files))
Because the Ditto CLI updates your string files locally, you can continue to manage it as you would with any other product update (push it to staging, commit changes to a branch, etc.).
# Configuration
Source: https://developer.dittowords.com/legacy/cli-reference-legacy/configuration
Setting what text and formats the CLI pulls down
## Overview
The `config.yml` file is the source of truth for a given directory about how the CLI should fetch and store data from Ditto based on the specified properties. It includes information about which Ditto components the CLI should pull text from, the string file formats, and more.
This is the default configuration file that is generated the first time that the CLI is run in a given directory:
```yml theme={null}
sources:
components:
enabled: true
format: flat
variants: true
```
## Supported Properties
Listed below are each of the properties that you can specify in your CLI config.
### `sources`
A list of places the CLI should pull text data from. For the CLI to function, at least one source type (`components` or `projects`) is required.
#### `sources.components`
A boolean or configuration object indicating how component data should be pulled from your component library.
The simplest configuration is a boolean, which indicates that all components in your component library should be fetched:
```yml theme={null}
sources:
components: true
```
You can also pass an object that supports two complementary properties: `root` and `folders`.
* `root` controls behavior for components that are NOT in folders (i.e. that are at the *root* of the component library)
* `folders` controls behavior for components that are ARE in folders
Further examples on how to use the two properties to specify the components fetched:
If `root` is `true` and `folders` is unspecified, **only components not in folders** will be fetched:
```yml theme={null}
sources:
components:
root: true
```
If `root` is `false` and `folders` is unspecified, **only components in any folder** will be fetched:
```yml theme={null}
sources:
components:
root: false
```
If `root` is unspecified and `folders` contains a list of component folders, **only components in the specified folders** will be fetched:
```yml theme={null}
sources:
components:
folders:
- id: folder-api-id-1
name: Folder 1
- id: folder-api-id-2
name: Folder 2
```
If `root` is `true` and `folders` contains a list of component folders, **non-folder components and components in the specified folders** will be fetched:
```yml theme={null}
sources:
components:
root: true
folders:
- id: folder-api-id-1
name: Folder 1
- id: folder-api-id-2
name: Folder 2
```
`root` can also be specified as a configuration object with a `status` property to indicate that non-folder components should be fetched that have the indicated status:
```yml theme={null}
sources:
components:
root:
status: WIP
```
#### `sources.projects`
A list of projects to pull text from.
```yml theme={null}
sources:
projects:
- id: 61b8d26105f8f400e97fdd14
name: Landing Page Copy
- id: 606cb89ac55041013d552f8b
name: User Settings
```
* The `name` property is used for display purposes when referencing a project in the CLI, but does not have to be an exact match with the project name in Ditto.
An `exclude_components` property can be added on a per-project basis to indicate that text items should only be pulled which are not associated with a component:
```yml theme={null}
sources:
projects:
- id: 61b8d26105f8f400e97fdd14
name: Landing Page Copy
exclude_components: true
```
### `variants`
Enables including variant information when pulling text data for configured sources.
Defaults to `false` if not specified.
```yml theme={null}
variants: true
```
### `format`
The format that text data should be generated in. For examples of each format, see [JSON](/string-formats/json), [iOS Strings](/string-formats/ios), and [Android XML](/string-formats/android) in the String Formats documentation.
Accepted values:
* `structured`
* `flat`
* `nested`
* `android`
* `ios-strings`
* `ios-stringsdict`
Defaults to `flat` if not specified.
```yml theme={null}
format: flat
```
Also accepts a list of values:
```yml theme={null}
format:
- ios-strings
- ios-stringsdict
```
You should not specify multiple JSON formats in the same configuration, as they will overwrite one another when writing to disk.
### `status`
If specified, only source data with the indicated status will be fetched. Accepted values:
* `NONE`
* `WIP`
* `REVIEW`
* `FINAL`
If `status` is specified at the top level of the configuration, it will apply to all sources:
```yml theme={null}
status: FINAL
sources:
components: true
projects:
- id: project-1
name: Project 1
```
`status` can also be specified at the level of individual sources:
```yml theme={null}
sources:
components:
root:
status: REVIEW
folders:
- id: folder-api-id-1
name: Folder 1
status: NONE
projects:
- id: project-1
name: Project 1
status: WIP
```
If both are specified, a source-level `status` overrides a top-level `status`.
More information about Ditto statuses can be found [here](https://dittov3.notion.site/Tips-for-cross-team-collaboration-256cc8865c7a8041a922f2d3838c61ec).
### `richText`
If defined with the `flat` format, output values will be HTML strings (rich text) for each piece of source data.
If defined with the `structured` format, output data will include a `rich_text` property that is an HTML string (rich text) for each piece of source data.
You can read more about Ditto's rich text feature [here](https://dittov3.notion.site/Rich-Text-Formatting-in-Ditto-256cc8865c7a808b9837c1bfb7728dba).
```yml theme={null}
richText: true
```
### `iosLocales`
A property that maps [variant](https://dittov3.notion.site/Variants-256cc8865c7a80e38671e6f9206001af) IDs in Ditto to [iOS locale IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html), intended to simplify the process of integrating Ditto with an iOS project.
This property should only be defined in conjunction with one or both of the `ios-strings` or `ios-stringsdict` formats.
When this property is defined, iOS string files written to disk by the CLI are grouped into `lproj` localization bundles, and a `Ditto.swift` driver file is generated.
```yml theme={null}
iosLocales:
- base: en
- spanish: es
```
The `base` property is required, and should map to the locale ID corresponding to the default language of your iOS project.
See [iOS format-specific files](/cli-reference/files#ios) for more information.
### `disableJsDriver`
A boolean property that disables the generation of the `index.js` and `index.d.ts` driver files when working with JSON formats.
```yml theme={null}
disableJsDriver: true
```
## Full Configuration Example
```yml theme={null}
sources:
components:
root: true
folders:
- id: onboarding
name: Onboarding
- id: onboarding-2
name: Onboarding 2
status: WIP
projects:
- name: Landing Page Copy
id: 61b8d26105f8f400e97fdd14
- name: User Settings
id: 606cb89ac55041013d552f8b
status: WIP
variants: true
format: structured
status: FINAL
richText: false
disableJsDriver: false
```
# Files
Source: https://developer.dittowords.com/legacy/cli-reference-legacy/files
The file structure of text pulled down via the CLI
## Output Directory
The CLI outputs data from Ditto by writing files to disk. By default, these files are written to a `./ditto` folder relative to the current working directory, but the location of the output files can be customized by setting the environment variable `DITTO_TEXT_DIR`.
If a `DITTO_TEXT_DIR` environment variable is specified, the config will still be read from a `./ditto` folder relative to the current working directory that the CLI is executing in.
## `./ditto` Directory
This directory houses the configuration file (`./ditto/config.yml`) used by the CLI and is also the default write destination for any output files the CLI writes to disk.
If you run the CLI in a directory that does not contain a `ditto/` folder, the folder and a default `config.yml` file will be automatically created.
## String File Naming Conventions
All string files created will adhere to the following template:
```
{source_name}__{variant_name}.{extension}
```
* `source_name`: the name of the source a given file holds data for
* for components, this is `components__{folder_name}`
* for projects, this is `{project-name}`
* `variant_name`: the API ID of a variant or `base` for files generated for non-variant text
* `extension`: the file extension that corresponds to the configured format(s)
To keep cross-platform behavior consistent, file names will be fully lowercase, have whitespace replaced with hyphens, and have non-word characters (with the exception of `-` and `_`) removed.
See the section on [iOS format-specific files](#iOS) for the only exception to these conventions.
## Format-specific Files
### JSON
If one or more JSON string formats are configured, an `index.js` driver file is generated to simplify the process of integrating Ditto into JavaScript apps.
If a `package.json` file is detected with `"type": "module"`, the driver file will be generated as an ESM module. Otherwise, it will be generated as a CommonJS module.
```js theme={null}
// CommonJS
const componentsRootBase = require("./components__root__base.json");
const componentsRootSpanish = require("./components__root__spanish.json");
const exampleProjectBase = require("./example-project__base.json");
const exampleProjectSpanish = require("./example-project__spanish.json");
module.exports = {
ditto_component_library: {
base: { ...componentsRootBase },
spanish: { ...componentsRootSpanish },
},
project_xxx: {
base: { ...exampleProjectBase },
spanish: { ...exampleProjectSpanish },
},
};
// ESM
import componentsRootBase from "./components__root__base.json";
import componentsRootSpanish from "./components__root__spanish.json";
import exampleProjectBase from "./example-project__base.json";
import exampleProjectSpanish from "./example-project__spanish.json";
export default {
ditto_component_library: {
base: { ...componentsRootBase },
spanish: { ...componentsRootSpanish },
},
project_xxx: {
base: { ...exampleProjectBase },
spanish: { ...exampleProjectSpanish },
},
};
```
To enable easy Typescript compatibility, an `index.d.ts` file is also generated with type definitions for the driver file.
The generation of both the `index.js` and `index.d.ts` files can be disabled by specifying `disableJsDriver: true` in your `config.yml` file.
### iOS
If one or more iOS string formats (`ios-strings`, `ios-stringsdict`) are configured alongside the [iosLocales](/cli-reference/configuration#ioslocales) property, iOS string files are grouped into localization bundles and a `Ditto.swift` driver file is generated.
The string files will be structured as follows:
```sh theme={null}
ditto/
├── en.lproj/
│ ├── components.strings
│ ├── project1.strings
├── es.lproj/
│ ├── components.strings
│ ├── project1.strings
```
The `Ditto.swift` driver file will look like this:
```swift theme={null}
//
// Ditto.swift
//
// Created by the Ditto CLI on 10/6/2023, 1:16:52 PM
//
import SwiftUI
struct Ditto {
public static func component1(_ localeOverride: String? = nil) -> String {
String.localizedStringWithFormat(NSLocalizedString("component-1", tableName: "components", /* ... */))
}
public struct project1 {
public static func textItem1(_ localeOverride: String? = nil, variable1: String) -> String {
String.localizedStringWithFormat(NSLocalizedString("text-item-1", tableName: "project1", /* ... */), variable1)
}
}
```
These files are designed to be imported into Xcode **by reference**. This enables using the CLI to pull the latest strings from Ditto and have the text in your project automatically updated.
To add these files to your Xcode project:
1. Open Finder and select all `.strings` and `.stringsdict` files inside of the respective `lproj` folders.
2. Drag the selected files into your Xcode project.
3. When prompted, select **Create folder references** and deselect **Copy if needed**.
4. Click **Finish**.
Once all your localization bundles and `Ditto.swift` driver are imported into Xcode, you can call methods from the `Ditto` struct directly to get localized strings:
```swift theme={null}
struct ContentView: View {
var body: some View {
Text(Ditto.component1())
Text(Ditto.textItem1(variable1: "Hello world!"))
}
}
```
# Example use cases
Source: https://developer.dittowords.com/mcp-reference/examples
Example prompts and instructions for using the Ditto MCP server with AI coding agents
The Ditto MCP server works best when you give your AI agent instructions about when and how to use its tools. You can include these instructions directly in a prompt, or add them to a project-level configuration file like `CLAUDE.md` (Claude Code), `.cursorrules` (Cursor), or similar.
Below are example instructions organized by tool.
## Style guide rules
The `get_styleguide_rules` tool lets your agent fetch your team's content rules and apply them when writing UI text.
### Generate UI with compliant text
Add this to your agent instructions to apply style guide rules whenever the agent creates new UI:
```
Use the style guides in Ditto to generate UI with compliant text.
```
The agent will call `get_styleguide_rules` before writing any user-facing strings, and apply those rules to the text it generates.
### Audit existing strings
You can also use the tool to check and fix text that already exists in your codebase:
```
Check my existing user-facing strings and update them so they comply
with style guide rules in Ditto.
```
The agent will fetch your rules, scan your code for user-facing strings, and suggest updates where the text doesn't match your guidelines.
## Text search and reuse
The `search_ditto_text` tool lets your agent find and reuse strings that already exist in your Ditto projects.
### Reuse text when generating UI
Add this instruction so your agent checks Ditto for existing text before writing new copy:
```
Try to reuse text in Ditto when generating UI.
```
When the agent needs to add a button label, heading, or other UI string, it will search Ditto first and reference existing text when a match is found.
### Replace hardcoded strings
You can ask the agent to scan your codebase and swap hardcoded strings for existing Ditto text:
```
Look at my existing user-facing strings in my codebase and see if you
can replace any with text that exists in Ditto.
```
The agent will search Ditto for matches against your current strings and suggest replacements where equivalent text already exists.
## Combining tools
For the best results, combine both tools in your agent instructions:
```
When working on UI:
- Use the style guides in Ditto to ensure all user-facing text follows
our content guidelines.
- Try to reuse existing text from Ditto instead of writing new copy.
```
This way, the agent will both check for existing text to reuse and validate any new text it writes against your style guide rules.
## Managing style guide rules
The `create_styleguide_rules`, `update_styleguide_rules`, and `delete_styleguide_rules` tools let your agent manage the rules inside your style guide. The `get_workspace_tags` tool lists the tags available to attach to a rule.
### Turn a code review comment into a rule
When you notice a recurring content issue, ask the agent to capture it as a rule so future text follows it automatically:
```
We keep shipping error messages that blame the user. Add a Ditto style
guide rule that error messages should be neutral and solution-oriented,
with an example like "You entered an invalid email" → "Enter a valid
email address."
```
The agent calls `get_styleguide_rules` to find the target style guide and section, calls `get_workspace_tags` if it wants to tag the rule, then calls `create_styleguide_rules`.
### Refine an existing rule
```
Our "date formatting" rule in Ditto only covers full dates. Update it to
also specify that relative times like "2 hours ago" are lowercase.
```
The agent calls `get_styleguide_rules` to find the rule ID, then calls `update_styleguide_rules` with the changed fields.
### Remove an outdated rule
```
We no longer use title case anywhere. Delete the "title case headings"
rule from our Ditto style guide.
```
The agent calls `get_styleguide_rules` to find the rule ID, then calls `delete_styleguide_rules`.
# Installation
Source: https://developer.dittowords.com/mcp-reference/installation
Connect the Ditto MCP server to Claude Code, Codex, Cursor, VS Code, Windsurf, Figma Make, and other MCP clients
## Before you start
The Ditto MCP server lives at:
```text theme={null}
https://api.dittowords.com/v2/mcp
```
It uses Streamable HTTP transport and supports OAuth, so most clients ask you to log in to Ditto the first time they connect. There's no token to create, and no credentials to store in your configuration.
Need a static credential instead — for continuous integration, a headless agent, or a client without OAuth support? See [Authenticating with an API token](#authenticating-with-an-api-token).
Using Claude Code, Claude Desktop, or Cursor? [Installing the agent setup package](/agent-setup-package/overview) is the recommended way to get started — you get the MCP server, along with always-on instructions and skills, in one step. If you only want to install the MCP server without any of the built-in skills, follow the setup instructions for the agent that you use.
## Claude Code
Claude Code supports remote MCP servers natively.
### Local scope (default)
Adds the Ditto MCP server for your own use in the current project. This is private to you and won't be visible to other team members.
```bash theme={null}
claude mcp add --transport http ditto https://api.dittowords.com/v2/mcp
```
### Project scope
Shares the Ditto MCP configuration with your entire team via version control. This creates a `.mcp.json` file at your project root that can be checked into source control.
```bash theme={null}
claude mcp add --scope project --transport http ditto https://api.dittowords.com/v2/mcp
```
Or manually add a `.mcp.json` file to your project root:
```json theme={null}
{
"mcpServers": {
"ditto": {
"type": "http",
"url": "https://api.dittowords.com/v2/mcp"
}
}
}
```
The file holds no credentials, so it's safe to commit. Each team member logs in with their own Ditto account the first time they use the server. Claude Code also prompts for approval the first time a project-scoped server is used.
### User scope
Adds the Ditto MCP server across all of your projects. This is private to you but available everywhere.
```bash theme={null}
claude mcp add --scope user --transport http ditto https://api.dittowords.com/v2/mcp
```
### Log in
After adding the server with any scope, restart any active instances of Claude Code. Then run `/mcp`, select **ditto**, and choose **Authenticate**. A browser tab opens for you to log in to Ditto and approve access.
Approve the connection to see Ditto MCP tools in your tool list.
## Cursor, VS Code, Windsurf
These clients support remote MCP servers with Streamable HTTP natively.
* **Cursor**: Go to **Cursor Settings > Tools & MCP** and click **+ Add new MCP server**.
* **VS Code**: Open your user or workspace `mcp.json` and add to `servers`.
* **Windsurf**: Open your MCP configuration file.
**Cursor** (`~/.cursor/mcp.json` or workspace `.cursor/mcp.json`):
```json theme={null}
{
"mcpServers": {
"ditto": {
"url": "https://api.dittowords.com/v2/mcp"
}
}
}
```
**VS Code** (`~/.vscode/mcp.json` or workspace `.vscode/mcp.json`):
```json theme={null}
{
"servers": {
"ditto": {
"type": "http",
"url": "https://api.dittowords.com/v2/mcp"
}
}
}
```
**Windsurf** (MCP configuration file):
```json theme={null}
{
"mcpServers": {
"ditto": {
"serverUrl": "https://api.dittowords.com/v2/mcp"
}
}
}
```
After saving, your client prompts you to log in to Ditto and approve access. Complete the login in the browser tab that opens, then check your MCP settings — a green status indicator next to the Ditto server means you're connected.
## Codex
Codex supports remote MCP servers over Streamable HTTP, with OAuth as the default authentication method.
### Add the server
```bash theme={null}
codex mcp add ditto --url https://api.dittowords.com/v2/mcp
```
Or add it to `~/.codex/config.toml` yourself:
```toml theme={null}
[mcp_servers.ditto]
url = "https://api.dittowords.com/v2/mcp"
```
To scope the server to a single project instead, use `.codex/config.toml` in the project root. Codex reads project-level configuration for trusted projects only.
### Log in
```bash theme={null}
codex mcp login ditto
```
A browser tab opens for you to log in to Ditto and approve access. Confirm the result with `codex mcp list`.
## Figma Make
From the chat box, select **Add context**, hover over **Connectors**, then choose **Manage**.
Navigate to the **Created by you** tab and click **Create**. Enter "Ditto" as the connector name.
Enter the following URL and click **Create**:
```text theme={null}
https://api.dittowords.com/v2/mcp
```
Click **Connect** on the connector. Figma Make picks up Ditto's OAuth flow and opens a browser tab where you log in to Ditto and approve access.
Review the available tools and enable the ones you'd like to use.
Figma Make reaches MCP servers over HTTPS only. It doesn't support localhost or stdio servers.
## Other clients
If your MCP client doesn't support Streamable HTTP or SSE natively, use the [`mcp-remote`](https://github.com/geelen/mcp-remote) package as a bridge. It runs the OAuth flow for you and opens a browser tab for login on first use.
This also applies if you're on **Cursor 2.6.x**, which has a [known bug](https://forum.cursor.com/t/cursor-fails-to-fall-back-from-streamable-http-to-sse-transport-for-remote-mcp-servers/154390) where the V2 MCP handler doesn't fall back from Streamable HTTP to SSE — it retries indefinitely instead of connecting. Use the `mcp-remote` config below as a workaround until the bug is fixed.
```json theme={null}
{
"mcpServers": {
"ditto": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.dittowords.com/v2/mcp"
]
}
}
}
```
## Authenticating with an API token
OAuth is the recommended way to connect, but the MCP server also accepts a Ditto API token. Use a token when there's no browser to log in with or no OAuth support to rely on:
* Continuous integration and other automated pipelines
* Headless agents running on a server
* Machine-to-machine access, where the credential belongs to a system rather than a person
* MCP clients that don't support OAuth
With OAuth, the agent acts as **you** — the Ditto account you logged in with, and its permissions. With an API token, the agent acts as the user who generated that token, so if an API token is ever shared, the Ditto activity history will attribute certain actions to the wrong person.
Generate a token from your [developer integrations settings](https://app.dittowords.com/developers/api-keys), then pass it in an `Authorization` header as `token `.
Follow the [Figma Make](#figma-make) steps, but before clicking **Connect**, open **Advanced settings** and add a custom request header:
* **Header name**: `Authorization`
* **Header value**: `token `
Add `--header` to any of the scoped commands:
```bash theme={null}
claude mcp add --transport http ditto https://api.dittowords.com/v2/mcp --header "Authorization: token "
```
For project scope, reference an environment variable so the file stays free of secrets:
```bash theme={null}
claude mcp add --scope project --transport http ditto https://api.dittowords.com/v2/mcp --header 'Authorization: token ${DITTO_API_TOKEN}'
```
Or manually, in `.mcp.json`:
```json theme={null}
{
"mcpServers": {
"ditto": {
"type": "http",
"url": "https://api.dittowords.com/v2/mcp",
"headers": {
"Authorization": "token ${DITTO_API_TOKEN}"
}
}
}
}
```
Each team member then sets the `DITTO_API_TOKEN` environment variable with their own API token.
Add an `Authorization` header to the server entry in `~/.codex/config.toml`:
```toml theme={null}
[mcp_servers.ditto]
url = "https://api.dittowords.com/v2/mcp"
http_headers = { Authorization = "token " }
```
To keep the token out of the file, use `env_http_headers` to pull the header value from an environment variable instead:
```toml theme={null}
[mcp_servers.ditto]
url = "https://api.dittowords.com/v2/mcp"
env_http_headers = { Authorization = "DITTO_MCP_AUTH" }
```
Codex sends the environment variable's value as the header verbatim, so include the `token ` prefix when you set it:
```bash theme={null}
export DITTO_MCP_AUTH="token "
```
Skip `bearer_token_env_var` — it sends the credential as `Authorization: Bearer `, which Ditto reads as an OAuth access token and rejects.
Add a `headers` object to the server configuration.
**Cursor** (`~/.cursor/mcp.json` or workspace `.cursor/mcp.json`):
```json theme={null}
{
"mcpServers": {
"ditto": {
"url": "https://api.dittowords.com/v2/mcp",
"headers": {
"Authorization": "token "
}
}
}
}
```
**VS Code** (`~/.vscode/mcp.json` or workspace `.vscode/mcp.json`):
```json theme={null}
{
"servers": {
"ditto": {
"type": "http",
"url": "https://api.dittowords.com/v2/mcp",
"headers": {
"Authorization": "token "
}
}
}
}
```
**Windsurf** (MCP configuration file):
```json theme={null}
{
"mcpServers": {
"ditto": {
"serverUrl": "https://api.dittowords.com/v2/mcp",
"headers": {
"Authorization": "token "
}
}
}
}
```
```json theme={null}
{
"mcpServers": {
"ditto": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.dittowords.com/v2/mcp",
"--header",
"Authorization: token "
]
}
}
}
```
# Overview
Source: https://developer.dittowords.com/mcp-reference/overview
Overview of Ditto's MCP server for AI coding agents
## What is the Ditto MCP server?
The Ditto MCP (Model Context Protocol) server connects AI coding agents to your team's content in Ditto. It gives agents access to your style guide rules and existing text so they can write on-brand text, reuse existing strings, and manage your style guide when generating code.
With the MCP server, your AI coding agent can:
* **Follow your style guide rules** when writing UI text, so generated copy is consistent with your team's guidelines.
* **Search and reuse existing text** from Ditto projects and library components, so agents reference approved text instead of generating new ones.
* **Create and edit content** — projects, project blocks, text items, library components, component folders, variables, and variants — directly from your editor.
* **Manage style guides** — create and update style guides and their rules, and inspect workspace tags and statuses, directly from your editor.
## How it works
The Ditto MCP server runs remotely and exposes tools your AI agent can call, organized around a few areas:
* **Style guides**: fetch, create, and update style guides and their rules (`get_styleguide_rules`, `create_styleguide`, `list_styleguides`, `update_styleguide`, `create_styleguide_rules`, `update_styleguide_rules`, `delete_styleguide_rules`), check text against them (`suggest_edit`), and look up available tags (`get_workspace_tags`).
* **Text search**: find existing text items and library components by content (`search_ditto_text`).
* **Projects and blocks**: list, create, and organize projects and the blocks within them (`list_projects`, `create_ditto_project`, `list_project_folders`, `list_project_blocks`, `create_project_blocks`, `update_project_blocks`, `delete_project_blocks`).
* **Text items and library components**: create, update, and delete project text and reusable library components (`create_text_items`, `update_text_items`, `delete_text_items`, `create_library_components`, `update_library_components`, `list_component_folders`, `create_component_folders`, `update_component_folders`, `delete_component_folders`), and publish or link project text into the library (`publish_library_component`, `link_text_items_to_component`, `unlink_text_items_from_component`).
* **Variables and variants**: manage placeholders and locale/tone alternatives (`list_variables`, `create_variables`, `update_variables`, `delete_variables`, `list_variants`, `create_variants`, `update_variants`, `delete_variants`).
* **Statuses**: look up the statuses text items and library components can be set to (`list_statuses`).
See the [full tool reference](/mcp-reference/tools) for what each tool does and how they fit together.
Your AI agent calls these tools automatically based on the instructions you provide. For example, you can add a line to your `CLAUDE.md` or `.cursorrules` file telling the agent to check Ditto's style guides before writing any user-facing text. See [Example use cases](/mcp-reference/examples) for more.
## Project configuration
Add a `ditto/config.yml` or `ditto/config.yaml` file in your project root to scope MCP tool calls to specific Ditto projects:
```yaml theme={null}
projects:
- id: "your-project-developer-id"
```
When present, the MCP server will automatically include these project IDs in tool calls, so results are scoped to the projects relevant to your codebase.
# Tools
Source: https://developer.dittowords.com/mcp-reference/tools
Available tools in the Ditto MCP server
The Ditto MCP server provides the following tools that your AI coding agent can call.
## get\_styleguide\_rules
Fetches style guide rules from your Ditto workspace, including both workspace-level and project-specific rules. Use this to ensure AI-generated UI text follows your team's content guidelines.
To create and manage style guide rules in Ditto, see [How to use Ditto's AI content systems](https://help.dittowords.com/en/articles/11956299-how-to-use-ditto-s-ai-content-systems).
## search\_ditto\_text
Searches your Ditto workspace for existing text items and/or library components by content. Use this to find and reuse strings that already exist in your team's content, rather than generating new text.
## list\_projects
Lists all projects in your workspace with their names and developer IDs. Use this to find a project's developer ID when you only know its name — for example, before creating, updating, or searching text items.
## list\_project\_folders
Lists all project folders in the workspace with their developer IDs, names, and parent folder (by developer ID; no parent means the folder sits directly under the workspace root). Use this to find a folder's developer ID before `create_ditto_project`, which takes a folderId to create the project inside a folder. Folders are a separate namespace from projects — `list_projects` will not surface them.
## create\_ditto\_project
Creates a new project in the workspace. Projects hold project-scoped text items, as opposed to library components which are reusable across projects. Use the returned developer ID (or `list_projects`) to reference it afterward, for example with `create_text_items`.
## list\_component\_folders
Lists all folders in your component library with their names, developer IDs, and parent folder (by developer ID; no parent means the folder sits directly under the library root). Use this to find a folder's developer ID before filing a component into it with `create_library_components` or `update_library_components`, or before managing the folders themselves with `create_component_folders`, `update_component_folders`, and `delete_component_folders`. Folders are a separate namespace from projects — `list_projects` will not surface them.
## create\_component\_folders
Creates new folders in the component library. Each folder can optionally specify a developer ID (must be unique in the workspace) and a parent folder to nest inside — omit the parent to create the folder at the library root.
Batch calls are all-or-nothing: if any folder in the call fails (e.g. a duplicate developer ID), none of the folders are created.
## update\_component\_folders
Updates existing folders by their developer IDs. Only the fields you provide are changed. Set `parentId` to move a folder — provide `null` or `"root"` to move it to the library root, or omit to leave it in place. To rename a folder's developer ID, set `newDeveloperId`.
Batch calls are all-or-nothing: if any update in the call fails (e.g. a duplicate developer ID, or a move that would create a circular hierarchy), none of the updates are applied.
## delete\_component\_folders
Permanently deletes folders from the component library by their developer IDs. This cannot be undone. Components and subfolders inside a deleted folder are not deleted — they're moved up into the deleted folder's parent folder (or the library root).
## list\_project\_blocks
Lists the blocks in a Ditto project with their developer IDs and names, in display order. Blocks group text items within a project. Use this to find a block's developer ID before `update_project_blocks` or `delete_project_blocks`. If you only know the project's name, call `list_projects` to look up its developer ID.
## create\_project\_blocks
Creates new blocks in a Ditto project. Blocks group text items within a project. New blocks are appended to the end of the project. Use the returned developer IDs (or `list_project_blocks`) to reference them afterward.
## update\_project\_blocks
Updates existing blocks in a Ditto project by their developer IDs (find them with `list_project_blocks`). Only the fields you provide are changed. To rename a block's developer ID, set `newDeveloperId` — it can be combined with a name change in the same update object.
Batch calls are all-or-nothing: if any update fails (e.g. a duplicate developer ID within the project), none of the updates in the call are applied.
## delete\_project\_blocks
Permanently deletes blocks from a Ditto project by their developer IDs (find them with `list_project_blocks`). This cannot be undone. Text items in a deleted block are not deleted — they're unassigned and moved to the end of the project's root level.
## list\_variables
Lists all variables in the workspace with their developer IDs, types, and data. Use this to find a variable's developer ID (its name) before referencing it in `create_text_items` or `update_text_items` — list the id in the `variables` field and reference it as a `{{variable_name}}` placeholder in the text.
## create\_variables
Creates variables in the workspace. A variable is a reusable placeholder that resolves to a different value at runtime. Each has a type that determines what it holds: a `string` or `number` variable holds an example and an optional fallback, a `hyperlink` holds link text and a url, a `list` holds the set of values the variable can take, and a `map` holds key-value pairs. A variable's name doubles as its developer ID: letters, numbers, and underscores only, and unique in the workspace. Creating a variable adds it to no text on its own — reference it from `create_text_items` or `update_text_items` by listing it in the `variables` field and writing it as a `{{variable_name}}` placeholder in the text.
Batch calls are all-or-nothing: if any variable in the call fails (for example, a name already in use), none of them are created.
## update\_variables
Renames variables or changes their type or value. Because a variable's name is its developer ID, renaming one with `newName` changes how it is referenced — but nothing inside Ditto is orphaned, because every `{{placeholder}}` using it is rewritten to match, across text items, library components, variant text, and plurals. What breaks is outside Ditto: anything naming the old id, such as code, an integration config, or CLI output, along with later API and MCP calls. Use `list_variables` to find a variable's current developer ID.
Only the fields you provide are changed, and each update must change at least one of `newName`, `type`, or `data`. Changing a type requires sending `data` alongside it, even when the value itself stays the same. How `data` is applied depends on the type: string, number, and hyperlink variables have fixed fields, so sending only some of them leaves the rest alone — send an empty string to clear one. A list's value is an array and a map's is an object, and each is the variable's entire content, so what you send replaces it outright.
Batch calls are all-or-nothing: if any update in the call is invalid, none of the updates are applied.
## delete\_variables
Permanently deletes variables from the workspace by their developer IDs (their names). This cannot be undone. A variable cannot be deleted while any text item or library component still references it, and one such variable rejects the whole batch — remove the `{{placeholder}}` from that text first, then retry. Confirm the developer IDs with the user before calling.
## list\_variants
Lists all variants in the workspace with their developer IDs, names, descriptions, and locale codes. Use this to find a variant's developer ID when you only know its name — for example, before `create_text_items` or `update_text_items`, which take variant developer IDs to set variant-specific text. When translating text for a variant, treat its localeCode (e.g. `es`, `fr-ca`) as the authoritative target locale — do not infer the locale from the variant's name or description. If a variant's localeCode is null, it is not locale-scoped; confirm the intended locale with the user rather than guessing.
## create\_variants
Creates variants in the workspace. A variant is a named alternative that text items and library components can each have their own text for — most often a locale to translate into, but also a tone or brand variation. Creating a variant adds no text on its own: use `create_text_items` or `update_text_items` with the variant's developer ID to set a text item's text for that variant. Set localeCode whenever the variant represents a language, because translation tools treat it as the authoritative target locale rather than inferring one from the name; at most one variant per workspace can hold a given locale code. A developer ID is generated from the name unless you pass one explicitly, so read the developer IDs off the response rather than assuming them.
## update\_variants
Renames variants or changes their description, locale code, or developer ID. A variant's name and its developer ID are independent. The name is the human-readable label shown in Ditto; the developer ID is the stable key that code, integrations, and CLI output use to refer to the variant. Renaming a variant leaves its developer ID untouched, so anything already referencing it keeps resolving — set newDeveloperId only when you want that key itself to change. Nothing inside Ditto is orphaned or rewritten by either change: text items and library components reference a variant by an internal id rather than its developer ID, so each keeps its text for the variant, and variant-scoped style guides stay attached. What breaks is outside Ditto — anything naming the old developer ID, such as CLI output, an integration config, or code, along with later API and MCP calls, which have to use the new one. Use `list_variants` to find a variant's current developer ID. At most one variant per workspace can hold a given locale code. Changing a locale code reaches past the variant itself: variant-scoped style guides and AI translation targeting both resolve a locale to a variant, so moving a locale onto a different variant changes which style guide governs that locale's text and where translated text is suggested. The whole batch is rejected if any update is invalid.
## delete\_variants
Permanently deletes variants from the workspace by their developer IDs. This cannot be undone. A variant cannot be deleted while any text item or library component still has text for it, and one such variant rejects the whole batch — remove that text first, then retry. Style guides scoped to a deleted variant survive but stop being variant-scoped.
## create\_text\_items
Creates new text items in a project. Provide the project's developer ID and the items to add. Each item supports text, an optional developer ID, status, tags, assignee (by email), notes, a character limit, a development-integration flag, and plural forms. Use `search_ditto_text` first to check whether equivalent text already exists to reuse.
Batch calls are all-or-nothing: if any item in the call fails (e.g. a duplicate developer ID), none of the items are created.
## update\_text\_items
Updates existing text items by their developer IDs. Only the fields you provide are changed; the rest are left as-is. Supports text, status, tags, assignee, notes, character limit, the development-integration flag, and plural updates. Tags are replaced wholesale — pass the full desired set.
Batch calls are all-or-nothing: if any update in the call fails, none of the updates are applied.
## delete\_text\_items
Permanently deletes text items by their developer IDs. This cannot be undone, and text items that are library instances cannot be deleted.
## create\_library\_components
Creates new components in the Ditto component library. Library components are reusable text shared across projects, as opposed to project-scoped text items. Each component supports a name, text, an optional developer ID, folder, status, tags, assignee (by email), notes, a character limit, a development-integration flag, and plural forms. Use `search_ditto_text` first to check whether equivalent text already exists to reuse.
Batch calls are all-or-nothing: if any component in the call fails (e.g. a duplicate developer ID), none of the components are created.
## update\_library\_components
Updates existing library components by their developer IDs. Only the fields you provide are changed; the rest are left as-is. Supports text, folder, status, tags, assignee, notes, character limit, the development-integration flag, and plural updates. Tags are replaced wholesale — pass the full desired set.
Batch calls are all-or-nothing: if any update in the call fails, none of the updates are applied.
## publish\_library\_component
Publishes an existing project text item to the Ditto component library, turning it into a reusable library component. The text item's current text, variables, variants, and other fields are carried over to the new component, and the text item becomes its first linked instance. The new component keeps the text item's existing developer ID.
The text item must not already be a library instance — use `link_text_items_to_component` to attach additional items to an existing component instead.
## link\_text\_items\_to\_component
Links one or more existing project text items to an existing library component by developer ID, so they share the component's text going forward. Each linked text item takes on the component's current text, variables, variants, and other fields. Text items already linked to a different component are skipped — the result reports how many text items were actually linked and lists the developer IDs of any that were skipped.
## unlink\_text\_items\_from\_component
Unlinks one or more text items from their library component by developer ID, turning them back into standalone project text items with a freshly generated developer ID each. The text items keep their current text; future edits to the library component no longer affect them.
Every text item linked to the same component shares that component's developer ID with its sibling instances, so a given developer ID unlinks every text item that currently carries it, not just one. Pass `projectId` to scope the unlink to only the instances in one project, leaving instances elsewhere untouched.
## create\_styleguide
Create a new style guide (name, description, sections, whether it's enabled by default). Sections organize rules and word list entries; if omitted, a default set of sections is used. If you provide sections, each section ID must be unique and the list must include at least one rules section and one word list section. Returns the new style guide's developer ID.
Pass `variantId` to scope the style guide to a single variant — because a locale in Ditto is a variant's locale code, this is how a style guide is associated with a locale. The variant must have a locale code — for now, style guides can only be scoped to variants that have one.
## list\_styleguides
Lists all style guides in the workspace with their developer IDs, descriptions, sections, and rules. Use this to find a style guide's developer ID and section IDs before calling `create_styleguide_rules` or `update_styleguide`.
## update\_styleguide
Update an existing style guide by developer ID (any field: name, description, enabled by default, variant, sections). Only the fields you provide are changed. Pass developer ID `default` to toggle the built-in Ditto Style Guide's enabled-by-default setting.
Pass `variantId` to scope the style guide to a single variant — because a locale in Ditto is a variant's locale code, this is how a style guide is associated with a locale — or `null` to unscope it so it applies to all text. The variant must have a locale code — for now, style guides can only be scoped to variants that have one.
Updating sections replaces the full list — each section ID must be unique, and the list must include at least one rules section and one word list section — rules in a removed section move automatically to the first remaining rules section.
## create\_styleguide\_rules
Create one or more rules in a style guide section. Use the `{name, description, examples, tags}` shape for a 'rules' section, or the `{term, disallowed, description, tags}` shape for a 'wordlist' section — the shape must match the target section's kind. Batch calls are all-or-nothing: if any rule fails, none are created.
## update\_styleguide\_rules
Update one or more existing rules by ID (from `get_styleguide_rules` or `create_styleguide_rules`). Only the fields you provide are changed. Use `name`/`examples` for a rule in a 'rules' section, or `term`/`disallowed` for a rule in a 'wordlist' section — the shape must match that rule's own section. Batch calls are all-or-nothing: if any update fails, none are applied.
## delete\_styleguide\_rules
Permanently delete one or more rules by ID. This cannot be undone. Batch calls are all-or-nothing: if any rule ID doesn't exist, none are deleted.
## suggest\_edit
Checks text against your Ditto workspace's style guide rules and returns suggested edits — the same rule-based suggestions shown in the Ditto app. Check an existing text item by its developer ID, or check freeform text that isn't saved as a text item yet. Results are cached per exact input; pass `forceNewGeneration` to force a fresh check.
An empty result means the text already complies with the style guide, or that this exact suggestion was already reviewed and dismissed in the app.
## get\_workspace\_tags
Returns all tags currently in use across the workspace. Useful before adding tags to a rule — only existing tags are allowed.
## list\_statuses
Lists the statuses which text items and library components can be set to in your workspace, in workflow order — the order your workspace moves text through, from earliest (a first draft) to latest (ready to ship). A workspace can rename the default statuses or replace the set entirely, so none of the defaults are guaranteed to exist. Call this before setting or filtering by a status rather than assuming a particular key is valid. Statuses are set by key, not by the display name shown in the app.