Configuration File Guide
Explains Saba-chan's data folder, the config.json settings file, instance folders, and token files based on what the code actually does.
Configuration File Guide
Saba-chan's settings and state live under the data folder %APPDATA%\saba-chan (= C:\Users\<your-name>\AppData\Roaming\saba-chan). This document summarizes how the actual code uses the files inside it, and distinguishes between files you can safely edit by hand and files you should not touch.
The daemon (saba-core) does all the work; the GUI and CLI only call the daemon's local HTTP API. That's why it's safest to change settings from the GUI or CLI: the daemon checks the format when it saves them.
1. Folder Structure
%APPDATA%\saba-chan\
├── config.json ← All user settings (by namespace)
├── config.json.bak ← Last good copy (for automatic recovery)
├── .ipc_token ← Daemon ↔ GUI/CLI auth token (regenerated every time the daemon starts)
├── .node_token ← Discord (cloud relay) connection token. Saved by the daemon at pairing
├── instances\ ← Server instances
│ ├── order.json ← List order
│ └── <id>\
│ ├── instance.json ← Instance info
│ ├── settings.json ← Per-module game setting values
│ ├── logs\ ← Server console logs
│ ├── backups\ ← Backups
│ └── server\ ← Default install location (game server files)
├── modules\ ← Installed game modules
├── extensions\ ← Installed extensions
├── logs\ ← GUI logs (saba-chan-<timestamp>.log)
├── audit.log ← Record of server start/stop/commands (secrets masked)
├── updates\ ← Update staging area
└── installed-manifest.json ← Installed component versions
- The portable Python runtime (
python-standalone\,python-env\) is created in the install folder if it is writable, otherwise in this data folder. - There are also files the daemon manages on its own (
daemon.lock,scan-verdicts.json,sandbox-temp\, etc.). Don't touch them. - You can override the data root itself with the
SABA_DATA_DIRenvironment variable, but it is generally not recommended.
2. config.json — The File That Holds Every Setting
User settings go into one file, config.json, grouped by namespace (top-level key).
| Namespace | Contents | Where it's changed |
|---|---|---|
gui | GUI behavior, theme, language, daemon port | GUI settings |
relay | Discord integration (prefix, aliases, per-guild settings) | GUI Discord page |
updates | Update check interval, auto-download | GUI settings |
boot | Last chosen boot mode (GUI / CLI / daemon only) | Boot selector |
extensions | Enabled extension list enabled, per-extension settings settings | GUI settings → Extensions |
chatbot | AI chatbot settings | GUI Discord page |
sandbox | Consent to run unverified components without isolation | The launch-blocked prompt, Settings → Advanced |
cli, etc. | Each client's own settings | That client |
Saving and automatic recovery
- Saves are atomic (write to a temp file, then replace), and the last good copy right before the replacement is kept as
config.json.bak. - If
config.jsonis corrupted and can't be read, the daemon moves it aside asconfig.json.corrupt-<timestamp>and restores from.bak. - Unknown keys put into
guiorrelayare dropped when saving.
Migration of old settings files
Older versions stored settings in separate files (settings.json, bot-config.json, cli-settings.json, update-config.json, boot-config.json, extensions_state.json, extensionConfig.json). The current version moves them into config.json only once. The originals are left as they are, with a .migrated copy next to each. Once that copy exists the file is not migrated again, so editing an old file has no effect on the current settings.
3. gui — Shared GUI / Daemon Settings
When the daemon boots, if no SABA_IPC_PORT environment variable is set, it reads gui.ipcPort; if that's also missing, it falls back to the default 57474. The other keys are mostly read by the GUI.
| Key | Type | Default | Description |
|---|---|---|---|
ipcPort | number | 57474 | Daemon HTTP API port (always opened on 127.0.0.1 only) |
autoRefresh | boolean | true | Automatic GUI status refresh |
refreshInterval | number (ms) | 2000 | GUI status polling interval. Lowering it too far raises CPU usage |
consoleBufferSize | number | 2000 | Number of lines the GUI console keeps |
portConflictCheck | boolean | true | Check for port conflicts before starting a server |
language | string | inferred from OS | Language (ko, en, ja, de, es, fr, pt-BR, ru, zh-CN, zh-TW). Also used for module and Discord replies |
theme | string | none (GUI uses auto) | "dark" / "light" / "auto" |
There are also appearance keys such as colors, font scale, and window size; whatever you change in the GUI settings is saved as-is.
4. relay — Discord Integration
The Discord bot runs only on the cloud relay, so there is no bot process or bot token on your PC. This namespace stores the prefix, aliases, and per-guild settings you edit in the GUI; after pairing, the daemon syncs them to the relay through its heartbeat.
| Key | Type | Default | Description |
|---|---|---|---|
prefix | string | "!saba" | Chat command prefix. A space must follow the prefix for the message to count as a command |
moduleAliases | object | {} | Module aliases. Example: { "minecraft": "mc, 마크" } |
commandAliases | object | {} | Command aliases |
instanceAliases | object | {} | Instance ID → list of aliases. Used to pick one when you run several servers of the same game |
nodeSettings | object | {} | Per-guild settings (allowed instances, command permissions, Discord language and music settings, etc.) |
cloud | object | relayUrl, hostId. Filled in at pairing |
Permission and Discord settings inside
nodeSettingschange only through their dedicated screens (APIs); saving the whole bot config does not overwrite them. The oldmusicEnabled,musicChannelId, andtokenkeys are no longer used.
Command Syntax
!saba <server name or alias> <command> [arguments…]
!saba minecraft start!saba mc stop(alias)!saba palworld status!saba list— server list,!saba help— help
Every server has the default commands start, stop, and status; other commands are defined by the module. Extra features such as music are provided by the bot on the relay-server side.
5. instances\ — Server Instances
Each server you create in the GUI is stored as its own instances\<id>\ folder. <id> is a UUID.
instance.json— Name, module, executable/working folder, port, REST connection info, scheduled tasks, extension data (extension_data), etc.settings.json— Game setting values the module declares (e.g., max players, difficulty).order.json— Order of the GUI list.
// instances\<id>\instance.json (excerpt)
{
"id": "3f6c…",
"name": "My Minecraft Server",
"module_name": "minecraft",
"working_dir": null,
"port": 25565,
"extension_data": {}
}
- RCON is not used. Game commands are sent to the server console (stdin), and Palworld uses its REST API. Leftover RCON keys in old files are removed when they are loaded.
extension_datais reserved storage for extensions. For example, for modules installed through SteamCMD, the install method and app info go here.- When you save server settings (GUI server settings,
PATCH /api/instance/:id), keys that are neither common instance fields nor settings the module declares are rejected with anunknown_settingerror. - Deleting an instance deletes the whole
instances\<id>\folder, including the game server files in the default install location (server\) andbackups\.
Only hand-edit these files while the daemon is not running. Editing them while it runs diverges from the daemon's in-memory state, and the next save overwrites your edit.
6. Token Files (.ipc_token / .node_token)
| File | Format | When created | Used by |
|---|---|---|---|
.ipc_token | UUID v4 (single line) | Regenerated every time the daemon starts | GUI / CLI / modules and extensions (local API calls) |
.node_token | sbn_<hostId>.<secret> | Saved by the daemon when Discord pairing completes | The daemon's relay connection |
IPC token
The daemon API listens only on 127.0.0.1, and every request except /health needs the X-Saba-Token header.
GET /api/servers HTTP/1.1
Host: 127.0.0.1:57474
X-Saba-Token: <contents of the .ipc_token file>
- The token changes whenever the daemon restarts. The GUI and CLI re-read the token file when authentication fails, so you don't need to do anything.
- The token file location can be changed with
SABA_TOKEN_PATH.
Node token
.node_token is the secret that connects this PC to the Discord bot (cloud relay). The daemon sends it to the relay over HTTPS to authenticate. Never show it to anyone; if you suspect it leaked, pair again from the GUI. Re-pairing invalidates the old token.
7. Extension and Isolation Settings (extensions / sandbox)
extensions.enabled— List of enabled extension IDs.extensions.settings— Per-extension setting values{ "<id>": { "<key>": value } }. Changed through the daemon APIPUT /api/extensions/:id/config.sandbox.unisolated— Consent to run, without isolation, a component whose isolated environment couldn't be prepared. It is stored as a fingerprint of the component's files and is asked again if any file changes. You can withdraw it under Settings → Advanced → "Run without isolation" in the GUI, or withsaba-chan-cli sandbox revoke <component>.
8. Key Environment Variables
| Variable | Target | Description |
|---|---|---|
SABA_IPC_PORT | Daemon / CLI | Overrides gui.ipcPort |
SABA_DATA_DIR | Daemon | Re-points the data root itself (advanced) |
SABA_TOKEN_PATH | Daemon | IPC token file path |
SABA_MODULES_PATH / SABA_EXTENSIONS_DIR / SABA_INSTANCES_PATH | Daemon | Re-point the module, extension, and instance folders |
RUST_LOG | Daemon | Log filter (default info) |
SABA_IPC_URL | Module/extension subprocesses | Daemon API address. Injected by the daemon into child processes |
SABA_LANG | Module/extension subprocesses | Current language (gui.language) |
PYTHONPATH | Module/extension subprocesses | Module and extension paths combined and injected |
SABA_ENABLED_EXTENSIONS | Module/extension subprocesses | List of active extension IDs (,-separated) |
PYTHONIOENCODING | Module/extension subprocesses | Always utf-8 |
PYTHONUNBUFFERED | Module/extension subprocesses | 1 — flush stdout immediately |
If you suspect you've broken something, stop the daemon first, then delete the file in question and launch again; most files are regenerated with defaults. Deleting config.json resets every setting, including your Discord integration settings, so try restoring config.json.bak first. Don't delete the instances\ folder: your server list and any game files installed in the default location go with it.