Persistence and logging
Where Kumo keeps state on disk — Application Support layout, state files, preferences, backups, the update cache, and every log channel.
Application Support Directory
Kumo stores local state under:
~/Library/Application Support/Kumo/KumoPaths centralizes all paths so GUI, CLI, tests, and future service code use the same layout.
Directory Layout
Kumo/
profiles/
default.yaml
profiles-metadata.json
current.txt
overrides/
overrides.json
files/
work/
config.yaml
logs/
core.log
substore.log
cores/
mihomo
substore/
status.json
backend/
frontend/
state.json
preferences.jsonBackup Format
Kumo can export a directory backup containing:
manifest.jsonprofiles/overrides/substore/state.json
The first backup format is directory-based rather than zip-based so it remains transparent, testable, and easy for agents to inspect. A future UI can wrap the same manifest in a compressed archive or sync it to WebDAV without changing the CoreKit import/export contract.
State File
state.json stores CoreStatus:
- core run state
- process identifier
- outbound mode
- controller endpoint
- mixed proxy port
- system proxy state (including PAC
modeandpacScript) - controlled runtime settings, including TUN stack, routing, DNS, route exclusions, MTU, and ICMP forwarding preferences
- last status message
This allows the CLI and GUI to share state without requiring a service in v1.
Runtime setting models must decode missing fields with defaults so app updates
can add new TUN controls without invalidating an existing state.json.
User Preferences
preferences.json stores UserPreferences (UI lifecycle preferences that do
not affect Mihomo runtime):
launchAtLogin— synced withSMAppService.mainAppbyKumoAppDelegate.hideMenuBarIcon— persisted for the menu bar visibility preference; Kumo now uses an AppKitNSStatusItem, so runtime visibility can be wired through the status item controller when the Settings toggle is re-exposed.quitOnLastWindowClose— read byapplicationShouldTerminateAfterLastWindowClosed.updateChannel(stable/beta) andupdateManifestURL— feedAppUpdateManager.checkForUpdate(...). A blankupdateManifestURLuses Kumo's default GitHub Releases feed; a value overrides it for local testing or private distribution.
Decoding falls back to defaults so a missing or corrupted file never blocks launch.
App Updates
App update downloads are cached under:
updates/downloads/The detached DMG installer writes its log to:
logs/app-update-installer.logThe cache is disposable. Release metadata and artifact rules are documented in Release Management.
Sub-Store
substore/status.json (SubStoreStatus) stores enable flag, custom backend
URL, host/LAN mode, proxy mode, cron settings, resource version, copied bundle
paths, and configured ports.
Bundled Sub-Store resources are copied from KumoCoreKit into:
substore/resources/
manifest.json
node/bin/node
backend/sub-store.bundle.jsSub-Store runtime data is kept under substore/data/, matching
SUB_STORE_DATA_BASE_PATH. Temporary staging work belongs under
substore/temp/. There is no bundled web frontend: Kumo's SwiftUI Sub-Store
surface talks to the local backend over HTTP directly.
SubStoreSupervisor launches the bundled Node sidecar with
sub-store.bundle.js and Sparkle-compatible environment variables. Stopping
Sub-Store terminates the backend process and closes the log handle.
Runtime Configuration
The generated Mihomo runtime configuration is written to:
work/config.yamlMihomo is launched with the work directory so it reads the generated config.
Logs
Core stdout and stderr are appended to:
logs/core.logSub-Store backend stdout and stderr are appended to:
logs/substore.logEach Sub-Store launch writes a header line ([ISO timestamp] starting <executable> <args>) so log readers can split sessions easily.
The main UI intentionally does not expose full logs on the Overview screen. Full log inspection belongs in the Logs destination under Inspect. The Sub-Store settings page surfaces a "View Logs" button that opens logs/substore.log in the user's text editor.
Live Mihomo logs should be treated as an event stream with a bounded in-memory cache. The local core.log file remains a fallback and diagnostic artifact.
The CLI has a separate debug-log channel under:
logs/cli/Each kumo invocation may create a *-kumo-debug-0.log file with command-level
diagnostics. --logs-max <count> controls retention, and --logs-max=0
disables CLI debug log files for sensitive environments. --logs-dir <path>
can redirect these files for temporary diagnostics.
kumo --timing writes a process-specific *-kumo-timing.json file in the same
directory. Timing files are for performance diagnostics and should not be mixed
with runtime event streams.
CLI terminal output follows npm-style log levels:
silent < error < warn < notice < http < info < verbose < sillyNormal command results go to stdout. Logs, warnings, progress, timing summaries,
and debug-log paths go to stderr. --json keeps stdout as plain JSON only.
Before writing terminal or file logs, CLI diagnostics redact controller secrets, authorization headers, basic auth passwords, subscription tokens, and token-like query parameters. Redaction is a safety net, not a reason to paste logs into public places without review.
Overrides
Overrides are planned under:
overrides/
overrides.json
files/
<id>.yaml
<id>.js
<id>.logYAML overrides are applied before Kumo-controlled runtime settings. JavaScript overrides require a reviewed sandbox before they are enabled.
Future Work
- Rotate logs.
- Add separate app and service logs.
- Add structured JSONL event logs for agents.
- Add privacy review for logs before sharing diagnostics.
- Add log rotation and Sub-Store log retention controls.
System integration and permissions
App bundle metadata, entitlements, system proxy commands, Spotlight, Services, App Intents, the CLI symlink, and the permission boundaries Kumo lives within.
Release management
Release channels, the latest.yml manifest, DMG packaging, and the make targets that build a signed Kumo.app for distribution.