For administrators deploying ThunderAI across an organization. It covers pre-configuring settings, enforcing them so users cannot change them, distributing a shared set of prompts, replacing the prompts of the special features and choosing their connection, limiting the automatic features to some accounts, and restricting what users can do with prompts and the setup wizard.

No add-on setting needs to be touched on each machine: everything here is driven by Thunderbird's own enterprise policy file.

Enterprise configuration is available from ThunderAI 5.1.0.

Before you start

⚠️ Policies are read only at Thunderbird startup

There is no live reload. Any change to policies.json — including rotating an API key or token — takes effect only after Thunderbird is fully restarted. Users who leave Thunderbird running for days will not pick up a change until they restart.

If you rotate a credential, plan for the window in which running clients still hold the old one.

⚠️ Policy files are world-readable

policies.json must be readable by every user account on the machine, so any local user can read any API key you put in it. It is not a secret store.

Prefer pointing ThunderAI at an internal gateway (via openai_comp_host) that holds the real provider credentials server-side, and put a revocable per-organization token in the policy — not a raw provider key. If you must deploy a provider key directly, use one scoped and rate-limited to this purpose, and rotate it on the assumption it is exposed.

Where policies.json goes

OSPath
Linux/etc/thunderbird/policies/policies.json (recommended)
or <install dir>/distribution/policies.json
WindowsC:\Program Files\Mozilla Thunderbird\distribution\policies.json
macOS/Applications/Thunderbird.app/Contents/Resources/distribution/policies.json

On Linux, use /etc/thunderbird/policies/. It lives outside the application directory, so it survives application updates. The distribution directory — the only option on Windows and macOS — sits inside the installation and may be removed or replaced when Thunderbird updates, silently dropping your configuration.

On Windows you can avoid that by using Group Policy / the registry instead of the file, under HKLM\SOFTWARE\Policies\Mozilla\Thunderbird. On macOS, a configuration profile (.mobileconfig) is the equivalent durable option. Both express the same 3rdparty structure shown below.

To verify a policy has loaded, open about:policies in Thunderbird.

Structure

Every ThunderAI setting lives under 3rdparty → Extensions → thunderai@micz.it:

{
  "policies": {
    "3rdparty": {
      "Extensions": {
        "thunderai@micz.it": {
          "connection_type": "openai_comp_api"
        }
      }
    }
  }
}

Policy key names are exactly ThunderAI's own setting names. There is no mapping table and no renaming — see the key reference.

Enforced vs. initial values

Every key you set is enforced by default. The user sees it in the settings, greyed out with a padlock badge reading Managed by <_org_name> (or just Managed), and cannot change it. A banner at the top of the page explains that some settings are managed by the organization.

To supply a starting value the user may then change, add a sibling "<key>:locked": false:

"reply_type": "reply_all",
"reply_type:locked": false
Enforced (default)"<key>:locked": false
User can change itnoyes
Control in settingsdisabled, marked "Managed" with a padlocknormal
If the user already set itpolicy value winsuser's value wins
Written to the user's profileneveryes, once they change it

That third row matters. An unlocked value is only an initial suggestion: a user who already configured that setting keeps their own value and never sees yours. Use an enforced value if you need it to actually apply everywhere.

Nothing enforced is ever written into the user's profile, so removing a key from the policy cleanly restores whatever the user had before, or the ThunderAI default.

Both kinds of value are shown where the user looks for them. Enforced and initial values appear in the options page and in every feature settings page — including the list fields and the spam filter's address book option, which are locked on their pages like any other control — and they also apply in the API chat window and in the popup.

Policy connection values are not copied into prompts. When a user turns on a specific integration for a single feature (Add Tags, Summarize, Spam Filter…), or sets a connection on a custom prompt, those fields start from the ThunderAI defaults, not from the host, model or key in your policy. A copied value would outlive the policy.

API keys set by policy

An API key supplied by the policy is never displayed in the settings. The field shows a masked placeholder, and from the settings pages the user cannot reveal the key, run the connection test with it, or fetch the model list with it. ThunderAI itself still uses the key normally, in the API chat window and in every feature. Because the model list cannot be fetched with your key, set the model explicitly in the policy (for example openai_comp_model).

An unlocked key ("<key>:locked": false) stays masked until the user types a key of their own, which is then stored and wins, like any other unlocked value.

This keeps the key out of the add-on's pages. It does not make it secret: it is still readable in policies.json — see Before you start.

Strict mode: _lock_unlisted and _user_editable

By default a policy controls only the settings it names. Everything else stays the user's choice, including settings added by future ThunderAI versions.

Strict mode reverses that. With "_lock_unlisted": true, every setting your policy does not set is locked at ThunderAI's built-in default. In the settings pages it looks and behaves exactly like a setting you lock explicitly: disabled, and marked as managed with the padlock. Settings added by a future version are locked at their default from the first start after the update.

KeyTypeMeaning
_lock_unlistedboolean (default false)true turns strict mode on.
_user_editablearray of setting names (default [])The settings that stay user-editable in strict mode. Only used when _lock_unlisted is true.

How each setting is resolved

In strict mode, in order of precedence:

  1. Per-machine settings are never affected. They stay user-editable: the API chat window size and position, the chat font zoom, the layout of the custom prompts page, and the per-profile account selection of the spam filter and Add Tags (see Keys that cannot be set by policy).
  2. A setting your policy sets keeps its usual behaviour: enforced, or only an initial value with "<key>:locked": false, exactly as without strict mode. The settings implied by _special_prompts_connection (the feature's Use a specific integration switch and its connection type) count as set by the policy. If such a setting also appears in _user_editable, the policy value wins and a warning is logged.
  3. A setting listed in _user_editable stays the user's: their own value, or the default if they never changed it.
  4. Every other setting is locked at its default.

Without _lock_unlisted, or with it set to false, nothing changes compared to earlier versions.

The account lists are never locked by strict mode: spamfilter_enabled_accounts_match and add_tags_enabled_accounts_match. Their default means "not managed", and locking them would stop those automatic features on every account. The features themselves (spamfilter, add_tags) are locked at their default, which is off.

Users' own values are never deleted. If you turn strict mode off, they come back at the next start.

Example

{
  "policies": {
    "3rdparty": {
      "Extensions": {
        "thunderai@micz.it": {
          "_org_name": "ACME Corp",
          "_lock_unlisted": true,
          "_user_editable": ["default_sign_name", "default_chatgpt_lang", "do_debug"],
          "connection_type": "openai_comp_api",
          "openai_comp_host": "https://ai-gateway.acme.example",
          "openai_comp_api_key": "sk-acme-...",
          "openai_comp_model": "gpt-4o-mini",
          "translate": true,
          "summarize": true
        }
      }
    }
  }
}

The connection, Translate and Summarize are enforced as written. Users can still change their signature name, default language and debug logging. Every other setting, including any added by future versions, is locked at its default.

Before you turn it on

⚠️ Set a connection

The default is "no connection". A strict policy must set connection_type and the matching provider settings, or list them in _user_editable. Otherwise ThunderAI stays unconfigured, and the setup wizard cannot save a connection.

  • Some defaults are on. Translate (translate), Create calendar event (get_calendar_event), Create task (get_task), showing token usage in the chat (chat_show_usage_data) and hiding the model's thinking (hide_thinking) are on by default. If you don't want them, set them to false explicitly.
  • Prompts are not settings. Strict mode does not lock custom prompts, menu order, custom placeholders, per-feature connections or special prompt texts. To control those, use _disable_prompt_management, _special_prompts_text and _special_prompts_connection.
  • Debug logging is locked off (do_debug) unless you list it in _user_editable. List it if your support team needs logs from users.
  • Restart required. As for every policy change, strict mode takes effect at the next Thunderbird start.

Validation

Problems are reported as warnings in the Thunderbird Error Console, even with debug logging off (see Troubleshooting):

  • _lock_unlisted must be true or false. Any other value is ignored with a warning, and strict mode stays off.
  • _user_editable must be an array. Otherwise it is ignored with a warning, and strict mode is off.
  • An entry of _user_editable that is not a string, or that names an unknown setting, is skipped with a warning.
  • An entry naming a per-machine setting is skipped with a warning: those settings are always editable.
  • _user_editable without "_lock_unlisted": true is ignored with a warning.

Worked example

An organization routing all AI traffic through an internal gateway, enforcing the connection and the privacy-relevant settings, suggesting a couple of defaults, and shipping two shared prompts.

Example policies.json
{
  "policies": {
    "3rdparty": {
      "Extensions": {
        "thunderai@micz.it": {

          "_schema_version": 1,
          "_org_name": "ACME Corporation",
          "_org_id": "acme",

          "connection_type": "openai_comp_api",
          "openai_comp_host": "https://ai-gateway.acme.example/v1",
          "openai_comp_api_key": "acme-gateway-token-REPLACE-ME",
          "openai_comp_model": "gpt-4o",
          "openai_comp_chat_name": "ACME AI",

          "spamfilter": false,
          "add_tags_auto": false,

          "_disable_setup_wizard": true,

          "default_chatgpt_lang": "English",
          "default_chatgpt_lang:locked": false,
          "reply_type": "reply_all",
          "reply_type:locked": false,

          "_org_prompts": [
            {
              "id": "support_reply",
              "name": "Draft support reply",
              "text": "Draft a reply to this customer email. Follow ACME tone of voice: concise, factual, no promises about delivery dates.\n\n{%mail_text_body_or_selected%}",
              "type": "1",
              "action": "1",
              "need_signature": "1"
            },
            {
              "id": "legal_review",
              "name": "Flag legal risk",
              "text": "Review the following text and list any statement that could create a contractual obligation.\n\n{%mail_text_body_or_selected%}",
              "type": "0",
              "action": "0",
              "api_type": "anthropic_api"
            }
          ]

        }
      }
    }
  }
}

What the user sees: the connection is pre-configured and locked, so they are never asked to run the setup wizard — and cannot open it either. The spam filter and auto-tagging are off and cannot be turned on. Language and reply style start at the organization's preference but can be changed. The two ACME prompts appear on the Manage Prompts page with an Organization badge, read-only, and can be Duplicated to make an editable personal version.

Organization prompts

_org_prompts is an array of prompt objects that becomes a shared, read-only prompt set alongside the user's own.

Requires _org_id — lowercase letters, digits and hyphens only, no underscore. It namespaces your prompt ids so they can never clash with ThunderAI's built-ins or with another organization's. Choose it once and never change it: it is part of every prompt id, and changing it makes users lose the menu positions they set.

The final id becomes org_<_org_id>_<id> — so "id": "support_reply" with "_org_id": "acme" is stored as org_acme_support_reply.

Fields

FieldRequiredNotes
idyesunique within the array, no whitespace; prefixed automatically
nameyesshown in menus
textyesthe prompt; may contain {%placeholder%} tokens
typeno"0" always, "1" reading, "2" composing
actionno"0" close, "1" reply, "2" substitute text
need_selectedno"1" requires a text selection
need_signatureno"1" includes the signature
need_custom_textno"1" prompts for extra input
define_response_langno"1" appends a response-language instruction
use_diff_viewerno"1" offers a diff of the result
api_typenoroute this prompt to a specific provider

api_type accepts chatgpt_web, chatgpt_api, google_gemini_api, anthropic_api, ollama_api, openai_comp_api. Empty or absent means "use the configured connection".

Behaviour

  • Fully declarative. The policy is the only source of truth. Add, change or remove a prompt and it is reflected at the next Thunderbird start. Users' own prompts are never touched.
  • Read-only, but duplicable. Users cannot edit or delete them, but Duplicate (or Duplicate and edit) makes an ordinary editable personal prompt — unless _disable_prompt_management is on.
  • Users control placement. Menu position and visibility are per-user, set in Menu Order like any other prompt.
  • If a user already has a prompt with the same id, yours takes precedence and theirs is disabled, with an explanation shown on the Manage Prompts page. Their prompt is not deleted and works again if you remove yours.
  • Ship only your prompts. Combine _org_prompts with _disable_default_prompts to take the built-in prompts out of the menus, so users see only the organization set.

If a prompt is rejected

Each prompt is validated independently — one bad entry is skipped, the rest still load. A prompt is skipped if id, name or text is missing or empty, if id is duplicated, or if api_type is not a valid connection type. If _org_id is missing or malformed the whole set is skipped.

Rejections are reported in the Thunderbird Error Console (Tools → Developer Tools → Error Console), prefixed [ThunderAI Logger | mzta-managed]. Check it after changing a policy — these warnings appear whether or not debug logging is on.

Special prompt texts

The special features (Add Tags, Spam Filter, Summarize, Translate, Calendar Event, Task) each run a prompt whose text users can edit on the feature's settings page. _special_prompts_text replaces that text with yours, for every user. For example, you can make the spam filter apply your organization's own criteria:

"_special_prompts_text": {
  "prompt_spamfilter": "Decide whether this email is spam for ACME. Treat any request to change bank details as spam. Answer only with a JSON object: {\"spamValue\": <0-100>, \"explanation\": \"<one sentence>\"}.\n\n{%mail_html_body%}"
}

Neither of the other mechanisms can do this. These texts are stored with the feature's prompt, not in a preference, and _org_prompts only adds new prompts.

Prompt ids

KeyText
prompt_add_tagsAdd Tags
prompt_spamfilterSpam Filter
prompt_summarizeSummarize, the instruction
prompt_summarize_email_templateSummarize, how each message is presented when several are summarized together
prompt_summarize_email_separatorSummarize, the separator between those messages. Whitespace only is allowed here.
prompt_translate_thisTranslate
prompt_get_calendar_eventCalendar Event
prompt_get_calendar_event_from_clipboardCalendar Event from the clipboard
prompt_get_taskTask

The Calendar Event settings page edits both calendar texts in one field. So a text you set for prompt_get_calendar_event applies to the clipboard variant too, unless the policy also names prompt_get_calendar_event_from_clipboard.

Behaviour

  • Always enforced. There is no initial-value form: "_special_prompts_text:locked" is ignored with a warning.
  • Only the text. Everything else about the feature (its icon, its menu visibility, its connection) stays the user's. To set the connection, use _special_prompts_connection.
  • Read-only on the settings page. The text is shown, marked as managed, and can be selected and copied, but not edited. Save and Reset are disabled.
  • Never written to the user's profile. Removing an entry, or the whole key, restores each user's own text exactly as they had it, or the ThunderAI default.

The response format

Most of these features read the AI's answer as JSON, and the text of the prompt is what asks for that format. A text without it would break the feature for everyone. So a text is rejected if it never names the response fields its feature reads:

KeyMust nameMust contain
prompt_spamfilterspamValue, explanationa body placeholder, or no placeholder at all
prompt_add_tagstags
prompt_get_calendar_event, …_from_clipboardstartDate, endDate, summary{%selected_text%}, {%selected_html%}, a body placeholder, or no placeholder at all
prompt_get_tasksummary
prompt_translate_thissubject, body, status{%mail_html_body%} or {%mail_text_body%}, and {%thunderai_translate_lang%}
prompt_summarize_email_template—a body placeholder, or no placeholder at all
prompt_summarize, prompt_summarize_email_separator——

Body placeholders: {%mail_text_body%}, {%mail_html_body%}, {%mail_text_body_or_selected%}, {%mail_html_body_or_selected%}. A text with no placeholder at all gets the message appended automatically.

A field name is matched as a whole word, case-sensitive, anywhere in the text. This catches a text rewritten without its output format; it does not check that the format itself is well formed. Start from the ThunderAI default text, shown on each feature's settings page, and keep its format part.

If the value of _special_prompts_text is not an object, the whole key is ignored. Otherwise each entry is checked on its own. An entry is skipped, with a warning, if its key is not one of the ids above, if its value is not a non-empty string, or if it misses a response field: the user's own text then stays in effect. A missing placeholder (the third column) is only a warning, logged at every startup: the text is still enforced, but the message may not reach the AI.

Per-feature connections

Some features can use a connection of their own instead of the main one. In each feature's settings page, users switch on Use a specific integration and pick a provider. _special_prompts_connection lets you set that connection from the policy, feature by feature. For example, you can send spam filtering to a small, cheap model and leave everything else on the main connection.

This connection is stored with the feature's prompt, not in a preference. That is why the ordinary keys cannot set it and this separate key exists.

"_special_prompts_connection": {
  "spamfilter": {
    "api_type": "openai_comp_api",
    "openai_comp_host": "https://ai-gateway.acme.example/v1",
    "openai_comp_api_key": "acme-gateway-token-REPLACE-ME",
    "openai_comp_model": "gpt-4o-mini",
    "openai_comp_model:locked": false
  }
}

Shape

The value is an object. Each key names a feature, and each value is that feature's connection:

KeyFeature
add_tagsAdd Tags
spamfilterSpam Filter
summarizeSummarize
translateTranslate
get_calendar_eventCalendar Event, including the "from clipboard" variant
get_taskTask

Inside each entry, api_type selects the provider. The other field names are exactly the connection property names ThunderAI stores on the feature's prompt for that api_type. There is no renaming, and they match the provider's global key names:

api_typeFields
openai_comp_apiopenai_comp_host, openai_comp_model, openai_comp_api_key, openai_comp_use_v1 (boolean), openai_comp_chat_name, openai_comp_temperature, openai_comp_extra_body
chatgpt_apichatgpt_api_key, chatgpt_model, chatgpt_developer_messages, chatgpt_temperature, chatgpt_store (boolean), chatgpt_reasoning_summary, chatgpt_reasoning_effort, chatgpt_extra_body, chatgpt_max_output_tokens (number), chatgpt_verbosity, chatgpt_text_format, chatgpt_text_format_schema_name, chatgpt_text_format_schema, chatgpt_top_p, chatgpt_truncation, chatgpt_prompt_cache_key, chatgpt_service_tier, chatgpt_safety_identifier, chatgpt_include_encrypted_reasoning (boolean)
anthropic_apianthropic_api_key, anthropic_model, anthropic_version, anthropic_max_tokens (number), anthropic_system_prompt, anthropic_temperature, anthropic_top_p, anthropic_top_k, anthropic_stop_sequences, anthropic_extended_thinking_budget (number), anthropic_effort
google_gemini_apigoogle_gemini_api_key, google_gemini_model, google_gemini_system_instruction, google_gemini_thinking_budget, google_gemini_temperature, google_gemini_max_output_tokens (number), google_gemini_top_p, google_gemini_top_k, google_gemini_extra_body
ollama_apiollama_host, ollama_api_key, ollama_model, ollama_num_ctx (number), ollama_temperature, ollama_think, ollama_format_json (boolean), ollama_keep_alive, ollama_system_prompt, ollama_extra_options

Fields not marked otherwise are strings. That includes the temperatures, *_top_p, *_top_k, google_gemini_thinking_budget and ollama_think: write "0.7", not 0.7. You can leave out any field except api_type. For a field the policy does not set, the feature uses the user's own value if they have one, and otherwise the main connection's value, just as it does without a policy.

Enforced and initial fields

  • api_type is always enforced. "api_type:locked": false is ignored with a warning. Leaving the provider open to change would make no sense while its provider-specific fields are enforced.
  • Every other field is enforced unless you add a sibling "<field>:locked": false, as everywhere else in the policy. An unlocked field works like other initial values, with one difference: it applies only while the user has no value of their own for that field. It is never written to their profile. If the user sets a value of their own, it is kept, and it stays after the policy is removed.
  • A top-level "_special_prompts_connection:locked" is ignored with a warning.

Implied switch and connection type

Each accepted entry also switches the feature to its own connection and sets the connection type, both locked. It is as if the policy also contained:

"spamfilter_use_specific_integration": true,
"spamfilter_connection_type": "openai_comp_api"

On the feature's settings page, the Use a specific integration switch is on and locked, and the provider select shows your api_type, locked. Enforced fields are locked with the padlock. Unlocked fields stay editable.

If the same policy also sets those two keys explicitly:

Explicit key in the same policyResult
<feature>_use_specific_integration: false, locked or notThe connection entry is skipped, with a warning. The explicit switch wins, and the feature uses the main connection.
<feature>_use_specific_integration: true with :locked: falseEnforced anyway, with a warning.
<feature>_connection_type that differs from api_type, or is unlockedReplaced by api_type and locked, with a warning.

Allowed types and validation

Every feature accepts the same five api_type values: chatgpt_api, google_gemini_api, anthropic_api, ollama_api and openai_comp_api. chatgpt_web is rejected for every feature. The features cannot run on ChatGPT Web, and their settings pages don't offer it.

Each entry is checked on its own, and one bad entry never stops the rest of the policy:

  • If the value of _special_prompts_connection is not an object, the whole key is ignored.
  • An entry is skipped as a whole if its key is not one of the six features, if it is not an object, or if api_type is missing or not one of the five types above.
  • Every other problem skips only that field, and the rest of the entry applies:
    • a field that belongs to a different provider, for example ollama_host under "api_type": "openai_comp_api";
    • a value of the wrong type. It is not converted: "4096" is not 4096;
    • a value that fails its content rule:
FieldMust be
*_hostan http:// or https:// URL
*_modelnot empty
ollama_num_ctx, anthropic_extended_thinking_budgetan integer, 0 or more
anthropic_max_tokensan integer, 1 or more
google_gemini_max_output_tokensan integer, 0 or more (0 means not set)
chatgpt_max_output_tokens0 (not set), or an integer of 16 or more
*_temperature"", or a string holding a number of 0 or more
*_top_p"", or a string holding a number from 0 to 1
*_top_k"", or a string holding an integer, 0 or more
google_gemini_thinking_budget"", or a string holding an integer ("-1" is Gemini's "dynamic")
ollama_think"", "false", "true", or a level in lowercase letters such as "low", "medium", "high", "max". The boolean true/false used before 5.1.0 is still read, with a warning.
ollama_keep_alive"", a whole number of seconds, or a duration such as "5m" or "1h30m"
*_extra_body, ollama_extra_options, chatgpt_text_format_schema"", or a string holding a JSON object
chatgpt_verbosity"", "low", "medium" or "high"
chatgpt_text_format"", "json_object" or "json_schema"
chatgpt_truncation"", "auto" or "disabled"
chatgpt_service_tier"", "auto", "default", "flex" or "priority"

"<field>:locked" must be a boolean. Any other value is ignored with a warning, and the field stays enforced. A ":locked" whose field is absent or was rejected is also reported.

The settings pages don't apply these rules to what users type. The policy does, because a typo there breaks the feature for everyone, and users cannot fix it themselves. Every skip is reported in the Error Console and names the feature and the field (see Troubleshooting).

The organization's key

An API key field works like any API key set by policy. The feature uses it normally, but the settings page shows only a masked placeholder. The user cannot reveal the key, fetch the model list with it, or test the connection with it. So set the model in the entry too, for example openai_comp_model. The key is never saved in the user's profile and never included in an export.

Changing and removing it

A change takes effect at the next Thunderbird restart, like every other policy change (see Before you start).

Nothing the policy supplies is written into the user's profile. Removing an entry, or the whole key, restores each user's own per-feature connection exactly as they had it, field by field, including their switch and connection type. A user who had none goes back to the main connection. When the policy replaces a value a user had stored, a warning is logged at startup. It names the feature and the field, never the value.

Limiting features to some accounts

The automatic spam filter and automatic Add Tags can be limited to some accounts. Users choose them with checkboxes on the feature's settings page, stored in spamfilter_enabled_accounts and add_tags_enabled_accounts. Those two keys cannot be set by policy: they hold account identifiers that Thunderbird assigns separately in each profile, so no single value would be right on every machine.

Use spamfilter_enabled_accounts_match and add_tags_enabled_accounts_match instead. They name accounts by what is the same everywhere, and ThunderAI finds the matching accounts in each profile:

"spamfilter_enabled_accounts_match": [
  "support@acme.example",
  "@sales.acme.example",
  "local"
],
"add_tags_enabled_accounts_match": ["@acme.example"]
EntryMatches
user@acme.examplean account with an identity of that address
@acme.example or *@acme.examplean account with an identity in that domain
localLocal Folders
  • Entries are case-insensitive. An account matches when any of its identities does.
  • RSS feed accounts are never matched.
  • An address with a + tag (user+tag@acme.example) is not accepted. Use the domain form to cover it.
  • Only the automatic runs are limited. Running the feature from the menu on a message works as without a policy.
  • Always enforced. ":locked": false is ignored with a warning: there is no control the user could change the value with.
  • A list that matches nothing means no account, not every account. A warning is logged when it happens. An empty array ([]) in the policy is different: it is the same as leaving the key out.
  • Accounts are matched again each time new mail is processed, so an account added after startup is picked up without a restart.

On the feature's settings page the account checkboxes show the matched accounts, disabled and marked as managed, with a note explaining it. The user's own selection is never changed: removing the key restores it.

Each entry is checked on its own: an entry that is not one of the forms above (including one that is not a string) is skipped with a warning naming its position, and the others still apply. Unlike the other list keys, one bad entry does not discard the whole list. That would fall back to the user's selection, perhaps every account, for a key whose job is to limit where mail is sent. For the same reason, a list whose entries are all invalid is kept as an empty list: no account.

Restrictions

Restrictions are policy-only switches that take something away instead of setting a value. They have no counterpart in the settings, so the :locked convention does not apply to them.

"_disable_prompt_management": true,
"_disable_default_prompts": true,
"_disable_setup_wizard": true

A restriction is either on (true) or off (false, the same as leaving it out). Any other value — including the string "true" — is ignored with a warning and the restriction stays off. A policy that sets only restrictions still counts as active: users see the managed banner and an explanation next to every disabled control.

KeyWhat the user losesWhat keeps working
_disable_prompt_managementCreating, duplicating, importing and exporting prompts. Their own existing prompts become read-only and disappear from the menus.Built-in and organization prompts, fully usable. The user's prompts are never deleted: they stay listed (read-only, with an explanation) and come back exactly as they were when the restriction is lifted.
_disable_default_promptsThe ThunderAI built-in prompts, in every menu and in the popup. They stay listed, dimmed and explained, on the prompt pages.The special features — Add Tags, Summarize, Translate, Spam Filter, Calendar Event, Task — plus the user's own prompts and the organization's. Menu positions and custom icons of the built-ins are kept.
_disable_setup_wizardThe setup wizard: its buttons in the options page are disabled, the welcome-page banner is hidden, and opening the wizard by its URL shows Setup wizard unavailable.Everything else. In the popup, the "run the setup wizard" link is replaced by a note that the connection is configured centrally.

The first two are independent and can be combined: they cover different prompts (the user's own and the built-in ones), and each shows its own explanation.

Export is disabled on purpose under _disable_prompt_management: an exported file carries the prompt texts and, with include API settings, can carry provider credentials too.

_disable_setup_wizard only makes sense together with an enforced connection (connection_type and its provider settings). On its own it just leaves users with no guided way to configure ThunderAI. Custom data placeholders are not covered by any restriction.

Settings that require a browser permission

⚠️ A policy can switch these features on, but cannot grant their permission

Two ThunderAI features need an optional permission that the add-on can only request interactively, when the user turns the feature on in its settings page. A policy value does not go through that path: setting the key to true switches the feature on but does not grant the permission. The feature then appears enabled and does nothing until the permission has been granted.

KeyPermissionSettings pageWithout the permission
get_calendar_event_from_clipboardclipboardReadCalendar EventThe "calendar event from clipboard" menu item is shown, but cannot read the clipboard: using it only shows the error Could not read clipboard. Please check permissions.
spamfilter_skip_addressbookaddressBooksSpam FilterThe spam filter cannot check whether a sender is in the user's address books, so those senders are not skipped and are analyzed like any other. Nothing is reported to the user. Note that this key defaults to true, so this applies even if you leave it out of the policy.

What you can do

  1. Grant the permission in advance, if your deployment method allows it. Thunderbird's ExtensionSettings policy, as documented in the Thunderbird policy templates, controls how an add-on is installed and updated, but lists no setting to pre-grant an add-on's optional permissions. This has not been verified for every Thunderbird version: check the templates for the version you deploy. If your tooling can grant the permission some other way, the feature works as soon as it is granted.
  2. Otherwise, ask users to grant it once. Each user opens the ThunderAI settings page listed above and turns the option on, then accepts the permission prompt. The prompt appears only when the option is switched on: if it already shows as on, the user switches it off and on again. This needs a control the user can change. If the key is locked by the policy, the control is disabled and the prompt cannot be triggered from there. In that case either set the key with "<key>:locked": false, so the user can grant the permission, or leave the key out of the policy.
  3. Check the result. Keys that ThunderAI rejects are reported in the Thunderbird Error Console (Tools → Developer Tools → Error Console, filter on ThunderAI), even with debug logging off — look there first. A missing permission, though, is not reported: the key is valid, it is the permission that is absent. Confirm it on a test machine using the symptom in the table above.

For example, both features on, as initial values the user can change to grant the permission:

"get_calendar_event_from_clipboard": true,
"get_calendar_event_from_clipboard:locked": false,
"spamfilter_skip_addressbook": true,
"spamfilter_skip_addressbook:locked": false

Keep in mind that an unlocked value is only a starting point: a user who already set the option keeps their own value, and can turn the feature off again (see Enforced vs. initial values).

As with every policy change, this takes effect only at the next Thunderbird restart — see Before you start.

Key reference

Every key below is a ThunderAI setting name, used verbatim as the policy key. Values must match the type shown: a wrong type is ignored with a warning and is not coerced — "true" is not true, and "70" is not 70.

Array keys (add_tags_exclusions, spamfilter_skip_addresses, spamfilter_block_addresses, summarize_auto_senders_list) must contain only strings. A single element of another type makes ThunderAI ignore the whole value, with a warning — it is not filtered out. The account lists (*_enabled_accounts_match) are the exception: they are checked entry by entry, see Limiting features to some accounts.

Values the add-on cannot use

A value of the right type is also checked against what the setting accepts, and rejected the same way — ignored with a warning naming the key, never adjusted:

KeysMust be
connection_typeone of the connection types listed in the key reference. Not "", which means "not configured".
<feature>_connection_typeone of the five API types. Not chatgpt_web: the features cannot run on it.
reply_type, diff_granularity, summarize_display_mode, summarize_auto, translate_autoone of the values listed for the key: the choices its settings page offers
every numberan integer, 0 or more. spamfilter_threshold: 0 to 100. add_tags_maxnum, summarize_max_messages, max_prompt_length, batch_max_concurrency: 1 or more.
calendar_timezone"", or a time zone name as the Calendar Event settings list it, such as "Europe/Rome" (case-sensitive)
the provider keys (openai_comp_host, ollama_num_ctx, chatgpt_temperature…)the same rules as the fields of a per-feature connection: hosts are http(s):// URLs, models are not empty, temperatures are strings holding a number… See the rules table.

Free-text keys (languages, signature name, system prompts…) accept any string. Provider-specific choices such as chatgpt_reasoning_effort or anthropic_effort are not checked: the values each provider accepts change with its models. The exceptions are the ChatGPT choices the settings page offers as a fixed list (chatgpt_verbosity, chatgpt_text_format, chatgpt_truncation, chatgpt_service_tier): those must be one of its values, see the rules table.

One rule spans two keys. An automatic summary is always shown inline. So when the policy sets summarize_auto to 2 or 3 and also sets summarize_display_mode, the display mode becomes "inline", with a warning, and takes the lock of summarize_auto: enforced if that is enforced, an initial value if it has ":locked": false.

All keys

137 of ThunderAI's 146 settings can be set by policy; the other nine are listed at the end. Two settable keys need a permission the policy cannot grant — see Settings that require a browser permission.

In strict mode, every key not set by the policy is locked at the default shown in this reference, except the per-machine keys, which the reference marks as not settable by policy at the end of the list, and the two *_enabled_accounts_match keys.

Group by Section to browse by area, or A–Z when you already have a key name and need its type. The search box matches key names and descriptions; click a key to copy it.

Structure and organization 7

  • Structure and organization

    Values: true

    true turns strict mode on: every setting the policy does not set is locked at its default. See Strict mode.

    Typeboolean
    Defaultfalse
  • Structure and organization

    since v5.1.0

    Required for _org_prompts. Lowercase letters, digits and hyphens only, no underscore. Choose it once and never change it.

    Typestring
    Default""
  • Structure and organization

    since v5.1.0

    Organization name shown beside the managed settings.

    Typestring
    Default""
  • Structure and organization

    since v5.1.0

    The shared, read-only prompt set. See the Organization prompts section.

    Typearray
    Default[]
  • Structure and organization

    since v5.1.0

    Policy schema version of this block.

    Typenumber
    Default1
  • Structure and organization

    since v5.1.0

    Values: prompt_add_tags | prompt_spamfilter | prompt_summarize | prompt_summarize_email_template | prompt_summarize_email_separator | prompt_translate_this | prompt_get_calendar_event | prompt_get_calendar_event_from_clipboard | prompt_get_task

    The enforced text of the special prompts. Always enforced. See Special prompt texts.

    Typeobject
    Default{}
  • Structure and organization

    Setting names that stay user-editable in strict mode. Only used when _lock_unlisted is true. See Strict mode.

    Typearray
    Default[]

Restrictions 3

  • Restrictions

    since v5.1.0

    Values: true

    Removes the ThunderAI built-in prompts from the menus, typically leaving only the organization ones. Special features (tags, summarize, translate, spam filter, calendar, task) are not affected. See Restrictions.

    Typeboolean
    Defaultfalse
  • Restrictions

    since v5.1.0

    Values: true

    No prompt can be created, duplicated, imported or exported. The user's own prompts become read-only and are removed from the menus, but are never deleted. Built-in and organization prompts keep working. See Restrictions.

    Typeboolean
    Defaultfalse
  • Restrictions

    since v5.1.0

    Values: true

    The setup wizard cannot be opened from anywhere, not even by its direct URL. Use it together with a locked connection. See Restrictions.

    Typeboolean
    Defaultfalse

Connection 2

  • Connection

    since v5.1.0

    Values: chatgpt_web | chatgpt_api | google_gemini_api | anthropic_api | ollama_api | openai_comp_api

    Empty means "not configured" and triggers the setup wizard - set it to skip onboarding entirely.

    Typestring
    Default""
  • Connection

    since v5.1.0

    Typeboolean
    Defaultfalse

OpenAI-compatible 7

  • OpenAI-compatible

    since v5.1.0

    Typestring
    Default""
  • OpenAI-compatible

    since v5.1.0

    Typestring
    Default"OpenAI Comp"
  • OpenAI-compatible

    since v5.1.0

    Typestring
    Default""
  • OpenAI-compatible

    since v5.1.0

    Point this at your internal gateway.

    Typestring
    Default""
  • OpenAI-compatible

    since v5.1.0

    Typestring
    Default""
  • OpenAI-compatible

    since v5.1.0

    Typestring
    Default""
  • OpenAI-compatible

    since v5.1.0

    Typeboolean
    Defaulttrue

OpenAI / ChatGPT API 19

  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typeboolean
    Defaultfalse
  • OpenAI / ChatGPT API

    since v5.1.0

    0 means not set. Otherwise at least 16.

    Typenumber
    Default0
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Values: "" | auto | default | flex | priority

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Typeboolean
    Defaultfalse
  • OpenAI / ChatGPT API

    since v5.1.0

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Values: "" | json_object | json_schema

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Empty, or a string holding a JSON object.

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Name of the schema used with json_schema.

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Empty, or a string holding a number from 0 to 1.

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Values: "" | auto | disabled

    Typestring
    Default""
  • OpenAI / ChatGPT API

    since v5.1.0

    Values: "" | low | medium | high

    Typestring
    Default""

Anthropic / Claude 11

  • Anthropic / Claude

    since v5.1.0

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    Typenumber
    Default0
  • Anthropic / Claude

    since v5.1.0

    Typenumber
    Default4096
  • Anthropic / Claude

    since v5.1.0

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    One stop sequence per line.

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    Empty, or a string holding an integer, 0 or more.

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    Empty, or a string holding a number from 0 to 1.

    Typestring
    Default""
  • Anthropic / Claude

    since v5.1.0

    Typestring
    Default"2023-06-01"

Google Gemini 9

  • Google Gemini

    since v5.1.0

    Typestring
    Default""
  • Google Gemini

    since v5.1.0

    Empty, or a string holding a JSON object.

    Typestring
    Default""
  • Google Gemini

    since v5.1.0

    0 means not set.

    Typenumber
    Default0
  • Google Gemini

    since v5.1.0

    Typestring
    Default""
  • Google Gemini

    since v5.1.0

    Typestring
    Default""
  • Google Gemini

    since v5.1.0

    Typestring
    Default""
  • Google Gemini

    since v5.1.0

    Typestring
    Default""
  • Google Gemini

    since v5.1.0

    Empty, or a string holding an integer, 0 or more.

    Typestring
    Default""
  • Google Gemini

    since v5.1.0

    Empty, or a string holding a number from 0 to 1.

    Typestring
    Default""

Ollama 10

  • Ollama

    since v5.1.0

    For an Ollama server behind authentication.

    Typestring
    Default""
  • Ollama

    since v5.1.0

    Empty, or a string holding a JSON object.

    Typestring
    Default""
  • Ollama

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Ollama

    since v5.1.0

    Typestring
    Default""
  • Ollama

    since v5.1.0

    Empty, a whole number of seconds (-1 keeps the model loaded) or a duration such as "5m" or "1h30m".

    Typestring
    Default""
  • Ollama

    since v5.1.0

    Typestring
    Default""
  • Ollama

    since v5.1.0

    Typenumber
    Default0
  • Ollama

    since v5.1.0

    Typestring
    Default""
  • Ollama

    since v5.1.0

    Typestring
    Default""
  • Ollama

    since v5.1.0

    Values: "" | false | true | low | medium | high | max

    A level, not a flag: "" (server default), "false", "true", or a level such as "low", "medium", "high", "max". Any lowercase word is accepted, because a model may report its own levels. The boolean true/false of policies written before 5.1.0 is still read, as "true"/"false", with a warning.

    Typestring
    Default""

ChatGPT Web 5

  • ChatGPT Web

    since v5.1.0

    Typestring
    Default""
  • ChatGPT Web

    since v5.1.0

    Typenumber
    Default1000
  • ChatGPT Web

    since v5.1.0

    Typestring
    Default""
  • ChatGPT Web

    since v5.1.0

    Typestring
    Default""
  • ChatGPT Web

    since v5.1.0

    Typeboolean
    Defaultfalse

Features 6

  • Features

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Features

    since v5.1.0

    Typeboolean
    Defaulttrue
  • Features

    since v5.1.0

    Typeboolean
    Defaulttrue
  • Features

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Features

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Features

    since v5.1.0

    Typeboolean
    Defaulttrue

Tagging 14

  • Tagging

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Tagging

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Tagging

    since v5.1.0

    Auto tagging normally skips the sent folder; this re-enables it.

    Typeboolean
    Defaultfalse
  • Tagging

    since v5.1.0

    Typeboolean
    Defaulttrue
  • Tagging

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Tagging

    since v5.1.0

    Typestring
    Default""
  • Tagging

    since v5.1.0

    Accounts automatic Add Tags runs on, as an array of addresses, domains (@acme.example) or local. Always enforced. See Limiting features to some accounts.

    Typearray
    Default[]
  • Tagging

    since v5.1.0

    Tags that are never assigned, as an array of strings. Matched as a substring, case-insensitive, unless add_tags_exclusions_exact_match is on. When locked, the tag dialog no longer offers to exclude a tag.

    Typearray
    Default[]
  • Tagging

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Tagging

    since v5.1.0

    Typeboolean
    Defaulttrue
  • Tagging

    since v5.1.0

    Typeboolean
    Defaulttrue
  • Tagging

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Tagging

    since v5.1.0

    Max messages tagged at once from the context menu (0 = no limit). Above it the user is warned and the operation is blocked. Automatic tagging is not capped.

    Typenumber
    Default0
  • Tagging

    since v5.1.0

    At least 1.

    Typenumber
    Default3

Spam filter 7

  • Spam filter

    since v5.1.0

    Senders always reported as spam (score 100), without asking the AI.

    Typearray
    Default[]
  • Spam filter

    since v5.1.0

    Accounts the automatic spam filter runs on, as an array of addresses, domains (@acme.example) or local. Always enforced. See Limiting features to some accounts.

    Typearray
    Default[]
  • Spam filter

    since v5.1.0

    If true, the automatic spam filter runs only on inbox folders.

    Typeboolean
    Defaultfalse
  • Spam filter

    since v5.1.0

    Typeboolean
    Defaulttrue
  • Spam filter

    since v5.1.0

    Needs the addressBooks permission, which a policy cannot grant. See Settings that require a browser permission.

    Typeboolean
    Defaulttrue
  • Spam filter

    since v5.1.0

    Typearray
    Default[]
  • Spam filter

    since v5.1.0

    From 0 to 100.

    Typenumber
    Default70

Summarize 9

  • Summarize

    since v5.1.0

    0 disabled, 1 manual button, 2 on message open, 3 on receive. With 2 or 3 a summarize_display_mode set in the same policy becomes "inline" and takes the lock of this key.

    Typenumber
    Default1
  • Summarize

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Summarize

    since v5.1.0

    Sender addresses or domain patterns ("@domain.com", "*@domain.com").

    Typearray
    Default[]
  • Summarize

    since v5.1.0

    Values: inline | webchat

    inline or webchat. Forced to "inline" when the policy sets summarize_auto to 2 or 3.

    Typestring
    Default"inline"
  • Summarize

    since v5.1.0

    Always write the summary in summarize_lang (or default_chatgpt_lang).

    Typeboolean
    Defaultfalse
  • Summarize

    since v5.1.0

    Summary language when summarize_force_lang is on; falls back on default_chatgpt_lang.

    Typestring
    Default""
  • Summarize

    since v5.1.0

    0 = no limit, otherwise max characters shown inline.

    Typenumber
    Default0
  • Summarize

    since v5.1.0

    Max messages summarized at once in webchat mode. At least 1.

    Typenumber
    Default20
  • Summarize

    since v5.1.0

    Typeboolean
    Defaultfalse

Translate 4

  • Translate

    since v5.1.0

    0 disabled, 1 manual button, 2 on message open, 3 on receive.

    Typenumber
    Default0
  • Translate

    since v5.1.0

    Languages not to translate.

    Typestring
    Default""
  • Translate

    since v5.1.0

    Target language; falls back on default_chatgpt_lang.

    Typestring
    Default""
  • Translate

    since v5.1.0

    0 = no limit, otherwise max characters shown inline.

    Typenumber
    Default0

Calendar and tasks 10

  • Calendar and tasks

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Calendar and tasks

    since v5.1.0

    If true, do not ask for a selection but use the full prompt. The Calendar Event prompt must then contain {%mail_text_body_or_selected%} or {%mail_html_body_or_selected%}, otherwise the message body is not sent to the AI: ThunderAI warns in the Error Console at startup and, when the key is locked, shows a note on the Calendar Event settings page.

    Typeboolean
    Defaultfalse
  • Calendar and tasks

    since v5.1.0

    Ask the AI for a reminder. If off, Thunderbird's default reminder is used.

    Typeboolean
    Defaultfalse
  • Calendar and tasks

    since v5.1.0

    Natural-language reminder rules added to the prompt when calendar_reminder_enabled is on.

    Typestring
    Default""
  • Calendar and tasks

    since v5.1.0

    Empty, or a time zone name such as "Europe/Rome", written exactly as the time zone list in the Calendar Event settings shows it.

    Typestring
    Default""
  • Calendar and tasks

    since v5.1.0

    Needs the clipboardRead permission, which a policy cannot grant. See Settings that require a browser permission.

    Typeboolean
    Defaultfalse
  • Calendar and tasks

    since v5.1.0

    Same as calendar_reminder_enabled, for tasks.

    Typeboolean
    Defaultfalse
  • Calendar and tasks

    since v5.1.0

    Same as calendar_reminder_rules, for tasks.

    Typestring
    Default""

Per-feature connection overrides 13

  • Per-feature connection overrides

    since v5.1.0

    Values: add_tags | spamfilter | summarize | translate | get_calendar_event | get_task

    The connection of each feature, enforced by the policy. See Per-feature connections.

    Typeobject
    Default{}
  • Per-feature connection overrides

    since v5.1.0

    Values: chatgpt_api | google_gemini_api | anthropic_api | ollama_api | openai_comp_api

    chatgpt_web is not accepted: the features cannot run on ChatGPT Web.

    Typestring
    Default"chatgpt_api"
  • Per-feature connection overrides

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Per-feature connection overrides

    since v5.1.0

    Values: chatgpt_api | google_gemini_api | anthropic_api | ollama_api | openai_comp_api

    chatgpt_web is not accepted: the features cannot run on ChatGPT Web.

    Typestring
    Default"chatgpt_api"
  • Per-feature connection overrides

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Per-feature connection overrides

    since v5.1.0

    Values: chatgpt_api | google_gemini_api | anthropic_api | ollama_api | openai_comp_api

    chatgpt_web is not accepted: the features cannot run on ChatGPT Web.

    Typestring
    Default"chatgpt_api"
  • Per-feature connection overrides

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Per-feature connection overrides

    since v5.1.0

    Values: chatgpt_api | google_gemini_api | anthropic_api | ollama_api | openai_comp_api

    chatgpt_web is not accepted: the features cannot run on ChatGPT Web.

    Typestring
    Default"chatgpt_api"
  • Per-feature connection overrides

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Per-feature connection overrides

    since v5.1.0

    Values: chatgpt_api | google_gemini_api | anthropic_api | ollama_api | openai_comp_api

    chatgpt_web is not accepted: the features cannot run on ChatGPT Web.

    Typestring
    Default"chatgpt_api"
  • Per-feature connection overrides

    since v5.1.0

    Typeboolean
    Defaultfalse
  • Per-feature connection overrides

    since v5.1.0

    Values: chatgpt_api | google_gemini_api | anthropic_api | ollama_api | openai_comp_api

    chatgpt_web is not accepted: the features cannot run on ChatGPT Web.

    Typestring
    Default"chatgpt_api"
  • Per-feature connection overrides

    since v5.1.0

    Typeboolean
    Defaultfalse

General 12

  • General

    since v5.1.0

    Max messages processed at once by a batch (automatic Add Tags, Spam Filter, Summarize and Translate, on receive or from the context menu). At least 1.

    Typenumber
    Default1
  • General

    since v5.1.0

    Show the token counts reported by the API under each answer in the chat, and a session total.

    Typeboolean
    Defaulttrue
  • General

    since v5.1.0

    Typestring
    Default""
  • General

    since v5.1.0

    Typestring
    Default""
  • General

    since v5.1.0

    Values: words | sentences

    words or sentences.

    Typestring
    Default"words"
  • General

    since v5.1.0

    Typeboolean
    Defaultfalse
  • General

    since v5.1.0

    Typeboolean
    Defaultfalse
  • General

    since v5.1.0

    Typeboolean
    Defaulttrue
  • General

    since v5.1.0

    In characters, at least 1.

    Typenumber
    Default30000
  • General

    since v5.1.0

    Typeboolean
    Defaultfalse
  • General

    since v5.1.0

    Values: reply_all | reply_sender

    reply_all or reply_sender.

    Typestring
    Default"reply_all"
  • General

    since v5.1.0

    In milliseconds, before a hung special command is aborted.

    Typenumber
    Default120000

Keys that cannot be set by policy

These are per-machine or per-profile state, not configuration. Setting them is ignored with a warning.

KeyWhy
add_tags_enabled_accountsAccount identifiers, specific to a profile. Use add_tags_enabled_accounts_match instead.
api_webchat_font_scaleLocal UI zoom.
chatgpt_win_heightWindow geometry and position, specific to a machine display.
chatgpt_win_leftWindow geometry and position, specific to a machine display.
chatgpt_win_save_positionWindow geometry and position, specific to a machine display.
chatgpt_win_topWindow geometry and position, specific to a machine display.
chatgpt_win_widthWindow geometry and position, specific to a machine display.
custom_prompts_viewLayout of the Manage Prompts page.
spamfilter_enabled_accountsAccount identifiers, specific to a profile. Use spamfilter_enabled_accounts_match instead.

Troubleshooting

Open about:policies to confirm Thunderbird loaded the file at all. If ThunderAI's settings are not listed there, the problem is the file's location or its JSON syntax, not ThunderAI.

Open the Error Console (Tools → Developer Tools → Error Console) and filter on ThunderAI. Rejected keys and prompts are reported there, each naming what was wrong. These warnings are not gated on debug logging.

SymptomLikely cause
Nothing applied at allFile in the wrong place, or invalid JSON. Check about:policies.
One key ignored, warning about its typeValue type does not match — "true" is not true, "70" is not 70.
One key ignored, warning that it "must be" somethingThe type is right but the value is not usable: not one of the listed values, out of range, a host that is not a URL, an unknown time zone. See Values the add-on cannot use.
A list key ignored as a wholeOne of its elements is not a string. Array keys must contain only strings.
One key ignored, "cannot be set by policy"It is in the excluded list above.
Settings still editableThe key has "<key>:locked": false, or you are looking at a key you did not set.
A change did nothingThunderbird was not restarted. Policies are read only at startup.
Organization prompts missing_org_id missing or contains an underscore/uppercase — the whole set is then skipped.
One prompt missingMissing id, name or text, a duplicate id, or an invalid api_type.
A special prompt text not appliedUnknown prompt id, an empty text, or a text that does not name the response fields its feature reads (for example spamValue). The user's own text stays in effect. See Special prompt texts.
A special prompt text applied, but the feature ignores the messageThe text has placeholders but none that brings in the message (or, for Translate, no {%thunderai_translate_lang%}). A warning is logged at every startup.
Automatic spam filter or Add Tags runs on no account*_enabled_accounts_match matches no account in that profile, or all its entries were rejected. See Limiting features to some accounts.
Summaries shown inline although the policy sets webchatExpected: summarize_auto is 2 or 3, and automatic summaries are always inline.
A per-feature connection ignored as a wholeUnknown feature key, a missing api_type, chatgpt_web, or the same policy sets <feature>_use_specific_integration to false. See Per-feature connections.
One field of a per-feature connection ignoredIt belongs to a different provider, has the wrong type (temperatures are strings), or fails its content rule, such as a host that is not an http(s):// URL.
A restriction has no effectThe value is not the boolean true — "true" or 1 is ignored and the restriction stays off.
Users' own prompts vanished from the menus_disable_prompt_management is on. The prompts are not deleted: they are still listed read-only and return when the restriction is removed.
Built-in prompts vanished from the menus_disable_default_prompts is on. Special features such as Summarize or Add Tags are not affected.
An unlocked value did not applyThe user had already set that preference; their value wins. Enforce it instead.
Calendar from clipboard or address book skipping enabled, but not workingThe feature's permission was never granted. See Settings that require a browser permission.
Calendar Event ignores the message body, warning about calendar_no_selectionThe option is on but the Calendar Event prompt has neither {%mail_text_body_or_selected%} nor {%mail_html_body_or_selected%}.
Users cannot test the connection or fetch modelsExpected when the API key comes from the policy. Set the model in the policy. See API keys set by policy.

Notes

  • ThunderAI requests no additional permissions for any of this. Two features have a permission of their own that a policy cannot grant — see Settings that require a browser permission.
  • With no policy installed, ThunderAI behaves exactly as it does for any individual user.

Back to guides