Skip to content

Maintenance & Backups

Day-to-day operation of a self-hosted instance: the maintenance scripts, how to update, and how to back up and restore your database. Run these operations from a shell. For the per-user export/import/delete flows in Discord, see Data Handling instead.

If you’re about to git pull a new version, read Safe Migration first: it covers backing up before the on-boot migration runner touches your schema.

CommandDescription
bun run setupOpen the setup wizard for base install and optional modules.
bun run updateBack up first, then pull latest code and install dependencies.
bun run backupCreate a bundle in backups/ with your DB dump and .env: contains all of your data.
bun run restore-backupRestore .env and database from a bundle (--latest or --from backups/<dir>).
bun run backup:personasExport ONLY personas (with server memories) across all servers; re-import via /persona import.
bun run nuke-dbDrop all tables (start the bot afterward to reinitialize).
bun run purge-commandsClear all registered Discord slash commands.
bun run rotate-keysRe-encrypt all encrypted fields to the current key version.
bun run env-doctorRead-only check of your configuration: lists .env entries that nothing reads (names only, never values) and where each variable is used.

Host bun run backup needs pg_dump, and host bun run restore-backup needs psql in your PATH. bun run update needs pg_dump for its backup. The --docker update path runs the backup in the container, so it needs host Bun, Git, and Docker but no host PostgreSQL tools.

Stop the running bot first, then use the backup-first updater:

Terminal window
bun run update

This runs bun run backup, then git pull --rebase --autostash, then bun install --frozen-lockfile. The backup bundle is written to backups/ and includes both the database dump and .env. Add --skip-backup to skip the pre-update backup. Manual fallback:

Terminal window
bun run backup
git pull --rebase --autostash
bun install --frozen-lockfile

Running from dist/? Use bun run update --build. Running Docker Compose? Use bun run update --docker; the updater first runs docker compose run --rm tomoribot bun run backup.

These variables tuned internal behavior: text and context heuristics, Discord component lifetimes, cache lifetimes, command cooldowns, schema limits, and provider sampling defaults. They are now fixed in code at their former defaults, so an old value in .env is ignored after upgrading. bun run env-doctor lists any that remain in your .env as unread, and you can delete them. Settings that depend on your host, network, credentials, or costs are still environment variables.

Command cooldowns are the exception to “fixed”: the per-category COOLDOWN_* names and DEFAULT_COMMAND_COOLDOWN are replaced by one multiplier, COMMAND_COOLDOWN_SCALE (default 1; 0 turns cooldowns off). To keep a tuned cooldown, divide your old value by its fixed value below: COOLDOWN_PERSONA=1000 becomes COMMAND_COOLDOWN_SCALE=0.1.

All 177 removed variables and their fixed values
VariableFixed value
ALLOW_PERSONAL_LOCAL_ENDPOINTSnone (it was never read)
BLOCK_USER_MAX_DURATION_HOURS168
BOT_GENERATE_IMAGE_AGENT_MAX_ITERATIONS5
BOT_GENERATE_IMAGE_HISTORY_LIMIT24
BOT_GENERATE_SCENE_MAX_CYCLES10
BOT_JSON_REPAIR_MAX_CHARS1048576
BOT_MAX_CONSECUTIVE_TOOL_ERRORS5
BOT_MAX_FUNCTION_CALL_ITERATIONS100
BOT_MAX_STOP_STRINGS_PER_SERVER40
BOT_MAX_STOP_STRING_LENGTH200
BRAVE_IMAGE_COMPRESSION_TARGET_MBone below BRAVE_IMAGE_DISCORD_LIMIT_MB (7 by default)
CHANNEL_WHITELIST_CACHE_TTL_MINUTES5
CONDITIONING_CONTEXT_MAX_GROUPS_PER_TYPE10
CONDITIONING_REASON_MAX_LENGTH250
COOLDOWN_CONDITIONING3000, scaled by COMMAND_COOLDOWN_SCALE
COOLDOWN_CONFIG3000, scaled by COMMAND_COOLDOWN_SCALE
COOLDOWN_FORGET3000, scaled by COMMAND_COOLDOWN_SCALE
COOLDOWN_MEMORY3000, scaled by COMMAND_COOLDOWN_SCALE
COOLDOWN_PERSONA10000, scaled by COMMAND_COOLDOWN_SCALE
COOLDOWN_PERSONAL3000, scaled by COMMAND_COOLDOWN_SCALE
COOLDOWN_SERVER3000, scaled by COMMAND_COOLDOWN_SCALE
COOLDOWN_TEACH3000, scaled by COMMAND_COOLDOWN_SCALE
DEEPSEEK_EXPRESSION_BATCH_SIZE20
DEFAULT_COMMAND_COOLDOWN1600, scaled by COMMAND_COOLDOWN_SCALE
DELIBERATE_TOOL_CONTEXT_TURNS4; a server can still change it in /config (Tool Context under Experimental Behavior)
DISCORD_TYPING_KEEPALIVE_INTERVAL_MS8000
DOCUMENT_CHUNK_OVERLAP200
DOCUMENT_CHUNK_SIZE1000
DOCUMENT_MAX_RESULTS6
DOCUMENT_MIN_SIMILARITY0.5
EMOJI_PENALTY_LOOKBACK3
EMOJI_PENALTY_THRESHOLD1
EMOJI_RUN_PREFIX_LENGTH3
EMOJI_STICKER_CACHE_TTL_MINUTES10
EMOJI_UNIQUE_LOOKBACK5
ENHANCED_CONTEXT_STASH_MAX_ENTRIES16
ENHANCED_CONTEXT_STASH_TTL_MS300000
EXPRESSION_DESC_MAX_LENGTH500
EXPRESSION_INIT_BATCH_DELAY_MS1000
EXPRESSION_INIT_MAX_CHUNK_RETRIES3
FALLBACK_NOTICE_BUTTON_TIMEOUT_MS86400000
FETCH_URL_HEALTHCHECK_CACHE_SEC60
FORWARD_CHAIN_MAX_DEPTH3
GENERATE_SCENE_MAX_CYCLES10
GIF_JPEG_QUALITY80
GIF_MAX_KEYFRAMES10
GUILD_MCP_CONFIG_CACHE_TTL_MINUTES5
HELP_COST_EST_OUTPUT_LONG500
HELP_COST_EST_OUTPUT_SHORT80
HELP_COST_EST_OUTPUT_TYPICAL220
HISTORY_EXTRACTION_WINDOW_SIZE40
HISTORY_INCHARACTER_RAG_MAX_RESULTS16
HUMANIZER_COMMA_FLUSH_PROBABILITY0.2
HUMANIZER_COMMA_REMOVE_PROBABILITY0.4
HUMANIZER_EMPHASIS_FLUSH_PROBABILITY0.5
IMAGE_CONTEXT_JPEG_QUALITY85
IMAGE_MIN_SIZE_BYTES5120
IMAGE_REFERENCE_TINY_MAX_BYTES950000
IMAGE_TAG_MAX_TAGS100
IMAGE_TAG_MAX_TAG_LENGTH200
KEY_ROTATION_ERROR_COOLDOWN_MS300000
KEY_ROTATION_RATE_LIMIT_COOLDOWN_MS60000
MARKDOWN_TABLE_BUTTON_TIMEOUT_MS7200000
MARKDOWN_TABLE_CACHE_TTL_MINUTES120
MARKDOWN_TABLE_RENDER_MAX_HEIGHT5000
MARKDOWN_TABLE_RENDER_MAX_WIDTH1400
MATRIX_EMBED_CHUNK_MAX_CHARS3500
MATRIX_LINK_CACHE_TTL_MINUTES5
MATRIX_MAX_TRACKED_SENT_EVENTS500
MATRIX_TYPING_TIMEOUT_MS60000
MAX_ATTRIBUTES10
MAX_ATTRIBUTE_LENGTH2000
MAX_FLUSH_COUNT40
MAX_SAMPLE_DIALOGUES15
MAX_SAMPLE_DIALOGUE_LENGTH2000
MAX_TRIGGER_WORDS10
MCP_STDIO_DIAGNOSTIC_MAX_CHARS8192
MCP_TOOL_SNAPSHOT_MAX_NAMES100
MCP_TOOL_SNAPSHOT_NAME_MAX_CHARS128
MEDIA_MAX_DIMENSION768
MEDIA_SIZE_LIMIT_BYTES1048576
MEMORY_EXPAND_BUTTON_TIMEOUT_MS86400000
MEMORY_NOTICE_PREVIEW_LIMIT600
NAI_CFG_RESCALE0.0; a server can still change it in /config (NovelAI image settings)
NAI_CHAR_REF_DESCRIPTIONcharacter&style
NAI_CHAR_REF_INFO_EXTRACTED1.0
NAI_CHAR_REF_SECONDARY_STRENGTH0.0
NAI_CHAR_REF_STRENGTH0.6
NAI_GLM_CHARS_PER_TOKEN2.5
NAI_GLM_CONTEXT_LIMIT12288
NAI_IMAGE_NEGATIVE_PROMPTbuilt-in text
NAI_IMAGE_NOISE_SCHEDULEkarras; a server can still change it in /config (NovelAI image settings)
NAI_IMAGE_SAMPLERk_euler_ancestral; a server can still change it in /config (NovelAI image settings)
NAI_IMAGE_SCALE5; a server can still change it in /config (NovelAI image settings)
NAI_IMAGE_STEPS23; a server can still change it in /config (NovelAI image settings)
NAI_INPAINT_PADDING0.15
NAI_INPAINT_STRENGTH1.0
NAI_KAYRA_CHARS_PER_TOKEN3.5
NAI_KAYRA_CONTEXT_LIMIT8192
NAI_TOOL_FAILURE_RETRY_THRESHOLD3
NVIDIA_IMAGE_CFG_SCALE3.5
NVIDIA_IMAGE_STEPS30
OPENROUTER_CATALOG_REFRESH_MIN_INTERVAL_MS60000
OPENROUTER_CATALOG_TTL_MS21600000
OPENROUTER_LENGTH_EMPTY_RETRY_DROP_PAIRS2
OPENROUTER_MIN_OUTPUT_TOKENS256
OPENROUTER_OUTPUT_SAFETY_FACTOR0.9
PARTICIPANT_ENRICHER_TIMEOUT_MS1500
PARTICIPANT_SOURCE_TIMEOUT_MS1500
PERSONAL_SPOTLIGHT_CACHE_MAX_ENTRIES2000
PERSONAL_SPOTLIGHT_CACHE_TTL_MINUTES5
PERSONA_IMPORT_NOW_BUTTON_TIMEOUT_MS840000
PERSONA_SPRITE_CACHE_TTL_MINUTES10
PERSONA_SPRITE_MAX_INSTRUCTIONS_LENGTH300
PERSONA_SPRITE_MESSAGE_CACHE_TTL_MINUTES120
PERSONA_SPRITE_PROMPT_MAX_COUNT20
PERSONA_USER_BLOCK_CACHE_TTL_SECONDS60
PERSONA_WORKFLOW_COMPONENT_TIMEOUT_MS120000
PRESET_GENERATION_MAX_OUTPUT_TOKENS16384
PRESET_MAX_ATTRIBUTES200
PRESET_MAX_IMAGE_TAGS200
PRESET_MAX_SAMPLE_DIALOGUES100
PRESET_MAX_STRING_LENGTH5000
PRESET_MAX_TRIGGER_WORDS100
RAG_AVAILABILITY_REPROBE_INTERVAL_MS300000
REACTION_CONTEXT_MAX_API_CALLS_PER_TURN20
REACTION_CONTEXT_MAX_REACTIONS_PER_MESSAGE4
REACTION_CONTEXT_MAX_USERS_PER_REACTION5
RELEASE_CARD_WEBP_QUALITY90
REMINDER_DELIVERY_MAX_RETRIES5
REMINDER_DELIVERY_RETRY_DELAY_MS60000
RESET_CONFIRMATION_TIMEOUT_MS60000
SCHEDULED_WORK_RECONCILE_INTERVAL_MS60000
SEND_FAILURE_RETRY_MINUTES15
SETUP_DRAFT_MAX_ENTRIES200
SHORT_TERM_MEMORY_DEFAULT_CRUDE_MESSAGE_COUNT6; a server can still change it in /config (short-term memory settings)
SHORT_TERM_MEMORY_MAX_MESSAGES_PER_CHANNEL10
SHORT_TERM_MEMORY_MAX_OTHER_CHANNELS3
SHORT_TERM_MEMORY_MAX_SUMMARY_LENGTH1500
SHORT_TERM_MEMORY_SUMMARY_TTL_HOURS24
SHORT_TERM_MEMORY_TTL_HOURS12
SPRITE_GROUP_CONTINUITY_TTL_MINUTES10
STARTUP_GRACE_PERIOD_MINUTES3
STATS_CARD_THEME_ACCENT#e7322a
STATS_CARD_THEME_BG#1d100e
STATS_CARD_THEME_SURFACE#2c1815
STATS_CARD_W1080
STATS_DASHBOARD_TIMEOUT_MSnone (it was never read)
STAT_FLUSH_INTERVAL_MS5000
STAT_FLUSH_MAX_BUFFER1000
STM_FRESH_INJECTION_DEPTH2
STM_FRESH_WINDOW_MINUTES60
STM_MAX_CATEGORIES5
STREAM_ABANDONED_SETTLE_TIMEOUT_MS5000
ST_PRESET_CACHE_TTL_MINUTES10
SYSPROMPT_SHOW_MAX_PREVIEW3800
TASK_EXPAND_BUTTON_TIMEOUT_MS86400000
TENOR_FETCH_TIMEOUT_MSnone (it was never read)
TEST_POSTGRES_DBnone (it was never read)
THINKING_LEVEL_BUDGET_HIGH_TOKENS8192
THINKING_LEVEL_BUDGET_LOW_TOKENS1024
THINKING_LEVEL_BUDGET_MEDIUM_TOKENS4096
TIME_AWARENESS_NOTE_DEPTH3
TIME_AWARENESS_REUNION_CLAIM_TTL_MS240000
TIME_AWARENESS_REUNION_DAYS7
TIP_BUTTON_TIMEOUT_MS86400000
TOMORI_STATE_CACHE_TTL_MINUTES10
TRANSFER_SNAPSHOT_MAX_ENTRIES200
TRANSFER_SNAPSHOT_TTL_MINUTES15
USER_CACHE_TTL_MINUTES30
VERBATIM_TOOL_CALL_MAX_BUFFER_CHARS8192
VISION_CAPTION_MAX_OUTPUT_TOKENS2048
VOICE_TRANSCRIPT_CACHE_TTL_MINUTES120
WEBHOOK_ERROR_COOLDOWN_MS600000
WEBHOOK_FAILURE_RETRY_MINUTES15
WEB_SEARCH_HEALTHCHECK_CACHE_SEC60
WELCOME_DELAY_MS60000

The TTS local servers under servers/tts/ lost their shared fallbacks, per-engine limits, and authentication settings. An old value in .env or your shell is ignored, so check the rows below that change behavior rather than only restating a default.

  • Ports: TOMORI_TTS_PORT is gone because one value in .env put every launched server on the same port. Each engine reads its own variable instead: CHATTERBOX_PORT (8011), QWEN3TTS_PORT (8012, or 8014 in voice-design mode), IRODORI_TTS_PORT (8013), FISH_S2_PORT (8015), VOXCPM2_PORT (8016), COSYVOICE3_PORT (8017), and MOSS_TTS_PORT (8018).
  • Authentication: the servers no longer check a bearer token or refuse a non-loopback bind. If you set FISH_S2_API_KEY, VOXCPM2_API_KEY, TOMORI_TTS_API_KEY, or COSYVOICE3_BEARER_TOKEN, the endpoint now accepts requests without it. Read Network access before binding off loopback.
  • Installer pins: the Fish Speech runtime commit and the CosyVoice runtime and model revisions are fixed in the installers. Updating them means editing the pin in the script.
All removed TTS local server variables
VariableNow
COSYVOICE3_ALLOW_REMOTE_BINDremoved; any TOMORI_TTS_HOST is accepted
COSYVOICE3_BEARER_TOKENremoved; no authentication
COSYVOICE3_MAX_REF_AUDIO_BYTES26214400
COSYVOICE3_MAX_REF_AUDIO_SECONDS30
COSYVOICE3_MODEL_IDFunAudioLLM/Fun-CosyVoice3-0.5B-2512
COSYVOICE3_MODEL_REVISIONpinned in the installer
COSYVOICE3_RUNTIME_COMMITpinned in the installer
COSYVOICE3_RUNTIME_DIRservers/tts/cosyvoice3/CosyVoice
COSYVOICE3_RUNTIME_REPOhttps://github.com/QwenAudio/CosyVoice.git
COSYVOICE3_UPDATEremoved; a rerun checks out the installer’s pins
FISH_S2_ALLOW_INSECURE_REMOTEremoved; any TOMORI_TTS_HOST is accepted
FISH_S2_API_KEYremoved; no authentication
FISH_S2_LAUNCH_TIMEOUT_MSTOMORI_TTS_STARTUP_TIMEOUT_MS applies (300000)
FISH_S2_MAX_REF_AUDIO_BYTES10485760
FISH_S2_RUNTIME_REFpinned in the installer
FISH_S2_RUNTIME_REPOSITORYhttps://github.com/Imagilux/fish-speech.git
FISH_S2_STARTUP_TIMEOUT_SECONDS180
FISH_S2_SYNTHESIS_TIMEOUT_SECONDS1800
FISH_S2_UPDATEremoved; a rerun checks out the installer’s pin and refreshes the model
FISH_S2_UPDATE_MODEL_REVISIONuse FISH_S2_MODEL_REVISION
FISH_S2_UPDATE_REFpinned in the installer
FISH_S2_UPSTREAM_HOST127.0.0.1
FISH_SPEECH_DIRservers/tts/fishs2/fish-speech
MOSS_TTS_MAX_REF_AUDIO_BYTES10485760
TOMORI_TTS_ALLOW_REMOTE_BINDremoved; any TOMORI_TTS_HOST is accepted
TOMORI_TTS_API_KEYremoved; no authentication
TOMORI_TTS_MAX_REF_AUDIO_BYTES10485760 (Fish)
TOMORI_TTS_MAX_TEXT_CHARS2000 (1000 for Irodori-TTS)
TOMORI_TTS_PORTthe engine’s own port variable
TTS_CLONE_TIMEOUT_MSuse TTS_SYNTHESIZE_TIMEOUT_MS
VOXCPM2_API_KEYremoved; no authentication
VOXCPM2_MAX_REF_AUDIO_BYTES10485760

bun run backup creates a timestamped bundle in backups/ (or your TOMORI_BACKUP_DIR if overridden in .env) containing your entire PostgreSQL database plus .env. Restore the latest bundle with:

Terminal window
bun run restore-backup --latest

Or restore a specific bundle:

Terminal window
bun run restore-backup --from backups/backup_2024-01-15_14-30-45

bun run backup:personas is a narrower export: persona presets and per-persona server memories only, across all servers. It must be re-imported manually via /persona import and cannot be used with restore-backup (that would cause primary-key conflicts).

TomoriBot also takes automatic startup backups in non-production environments, and a full restore requires the pgvector extension to be present on the target database. Both are covered in detail under Safe Migration, along with a manual pg_dump / pg_restore procedure if you prefer to drive the tooling directly.

Docker Compose supports automatic startup backups inside the app container. Bundles are written to the host backups/ directory because Compose mounts it into the container.

For a manual Docker backup:

Terminal window
docker compose stop tomoribot
docker compose run --rm tomoribot bun run backup
docker compose start tomoribot

For a Docker restore:

Terminal window
docker compose stop tomoribot
docker compose run --rm tomoribot bun run restore-backup --latest
docker compose up -d

Host-side scripts do not automatically run through Docker. To run them against the Compose database, set the following connection values on the host. Backup and restore also need the PostgreSQL client tools; nuke-db needs Bun only.

POSTGRES_HOST=localhost
POSTGRES_PORT=15432
POSTGRES_USER=tomori
POSTGRES_PASSWORD=your_password
POSTGRES_DB=tomodb

bun run nuke-db drops all tables; starting the bot afterward reinitializes the schema, seeds, and migrations from scratch. Use it together with a fresh bun run backup when you want a clean slate you can still roll back from: never run it without a current backup.