Skip to content

Configuration Reference

Kunuleco has two configuration files. The node reads config.json, which the installer writes. The Urchin client keeps its own settings in urchin_settings.cfg. A handful of environment variables override the node's file.

Rewritten 2026-09-30. The earlier version of this page described core, transport, identity, persistence and logging keys. No code reads them (Config.load() in core/config.py is a stub), so they are gone.


The node's config.json

Where it is

Platform Path
Windows %LOCALAPPDATA%\Kunuleco\config.json
Linux, and any other non-Windows system ~/.local/share/kunuleco/config.json

The node resolves this path in two places that agree (scripts/kunuleco.py at import, and installer_config_path() in core/config.py). Neither has a macOS branch, so on macOS the node looks under ~/.local/share/kunuleco/. The client keeps its settings under ~/Library/Application Support/Kunuleco/ on macOS (see below), so on that platform the two files are not side by side.

A node started without an installer runs without this file and uses the defaults and environment variables below.

What the installer writes

The installer writes it once, at install (installer/.../install/orchestrator.py). A typical file:

{
  "version": "1.0",
  "base_dir": "/home/alice/.local/share/kunuleco",
  "data_dir": "/home/alice/.local/share/kunuleco/data",
  "logs_dir": "/home/alice/.local/share/kunuleco/logs",
  "config_dir": "/home/alice/.local/share/kunuleco/config",
  "venv_dir": "/home/alice/.local/share/kunuleco/venv",
  "ipfs": {
    "binary": "/home/alice/.local/share/kunuleco/bin/ipfs",
    "repo": "/home/alice/.local/share/kunuleco/data/ipfs",
    "api_port": 15001,
    "swarm_port": 14001,
    "gateway_port": 18080
  },
  "tor": {
    "binary": "/home/alice/.local/share/kunuleco/bin/tor",
    "data_dir": "/home/alice/.local/share/kunuleco/data/tor",
    "config": "/home/alice/.local/share/kunuleco/data/tor/torrc",
    "socks_port": 19050,
    "control_port": 19051
  },
  "veilid": {
    "binary": "/home/alice/.local/share/kunuleco/bin/veilid-server",
    "data_dir": "/home/alice/.local/share/kunuleco/data/veilid"
  }
}

The paths depend on the platform and the install location. The ports are the installer's fixed values (platform/paths.py), chosen so an installed node does not collide with a system IPFS or Tor.

What the node reads from it

Key Used for Default without the file
data_dir The node's data directory. Accounts, the database and keystores live here. KUNULECO_DATA_DIR overrides it. KUNULECO_DATA_DIR, else ./data if it exists, else ~/.kunuleco
ipfs.api_port The kubo API the node talks to (http://localhost:<port>). IPFS_API_URL overrides it. 5001
ipfs.binary, ipfs.repo Which kubo to start and its repository. The node sets IPFS_PATH for kubo from repo. none
tor.binary Which Tor to start. It must be a file. a Tor on the PATH
tor.config, tor.socks_port, tor.control_port Tor's torrc and ports. The node exports the ports as TOR_SOCKS_PORT and TOR_CONTROL_PORT for the modules that read them. 9050, 9051
veilid.binary, veilid.data_dir Which veilid-server to start and its data. VEILID_BINARY overrides the binary. none
media_retention_days How many days a received media note stays pinned before it is unpinned. The one key the node itself writes, through media retention <days> (1 to 365). Absent until that command is used. 3

The node reads the veilid API port from veilid.api_port when present, which the installer does not write, so an installed node uses 15959 (and 5959 without the file). The other keys the installer writes (version, base_dir, logs_dir, config_dir, venv_dir, ipfs.swarm_port, ipfs.gateway_port, tor.data_dir) are the installer's own record. The node does not read them.

Changing it

Edit the file and restart the node. There is no command that edits it, apart from media retention, which writes its one key and keeps every other key as it was (write_node_setting in core/config.py).


Environment variables

Variable Effect Default
KUNULECO_DATA_DIR The data directory. Takes precedence over config.json's data_dir. see data_dir above
KUNULECO_CLIENT_PORT The TLS port clients connect to. 8123
KUNULECO_CAPTP_PORT The CapTP port other nodes dial, on every transport, and the port mDNS advertises. A value that is not a port refuses to start rather than falling back. 4243
IPFS_API_URL The kubo API URL. Takes precedence over ipfs.api_port. from ipfs.api_port
VEILID_BINARY The veilid-server to start. Takes precedence over veilid.binary. from config.json
TOR_CONTROL_PASSWORD Password for Tor's control port, when Tor is set up to ask for one. (none)
KUNULECO_KDF_PROFILE argon2id tier for NEW account records (DOS-12): moderate = username key INTERACTIVE / password key MODERATE; interactive = both INTERACTIVE; sensitive = both SENSITIVE (1 GiB per derivation — the pre-0.2.198 behaviour, which froze a 1 GB node for 15 minutes per login). Recorded per account and read back at login. Changing it later re-wraps every existing record that sits ABOVE the new tier at that account's next successful login (DOS-12 half 3: the login already holds both keys, so the re-wrap costs the two policy derivations and one row rewrite; the log line is [DOS-12] re-wrapped legacy record); a record already cheaper than the policy is never made dearer. Pre-0.2.198 accounts therefore pay SENSITIVE exactly once more, at the first login on this build. Unknown values refuse to start the derivation rather than defaulting. moderate

TOR_SOCKS_PORT, TOR_CONTROL_PORT and VEILID_API_PORT are set by the node from config.json for its own modules. Setting them in the shell has no lasting effect, so change config.json instead. The SSH endpoint listens on 8122, which is fixed in scripts/ssh_server.py.

Precedence, for the node: an environment variable, then config.json, then the built-in default.


The client's urchin_settings.cfg

Where it is

Platform Path
Windows %LOCALAPPDATA%\Kunuleco\config\urchin_settings.cfg
Linux ~/.local/share/kunuleco/config/urchin_settings.cfg
macOS ~/Library/Application Support/Kunuleco/config/urchin_settings.cfg
Android and anything else the app's own data directory (OS.get_user_data_dir()), under config/

It is a Godot ConfigFile (an INI-like text file with [section] headers). The client writes it as you change settings, so there is rarely a reason to edit it by hand. Close the client first if you do.

What it holds

Section Keys What they are
server host, port The node the client connects to.
appearance avatar_id, skin, hair, eye, face_sharing Your avatar, and whether you said yes to sharing your face.
audio microphone_enabled Whether the client may use the microphone.
accessibility glow, motion, scanlines Visual effects you can turn down or off.
display profile The display profile (comfortable unless changed).
input default_mode The input mode the client starts in (cmd unless changed).
friends archipelagos, home_group How your friends are grouped in the world view.
world actions_collapsed Whether the world's action panel is collapsed.
onboarding show_tutorial Whether to show the tutorial.
tutorial completed_identities Which identities have finished the tutorial.
debug logging Whether the client writes a debug log.

The client owns this file and its sections change with the client. The list above is from client source on 2026-09-30 (scripts/core/urchin_singleton.gd and the scenes that call set_value).