Skip to content

Configure everything from a single sakuya.config.json - #5

Merged
rene-roid merged 1 commit into
masterfrom
t3code/single-config-file
Sep 23, 2026
Merged

rene-roid merged 1 commit into
masterfrom
t3code/single-config-file

Conversation

@rene-roid

Copy link
Copy Markdown
Owner

Summary

  • One config file. sakuya.config.json at the repo root is read by the server, its launcher and the Vite dev server. It is created with the defaults on first run, and gitignored. sakuya.config.example.json is the committed reference with every setting, and a test keeps it identical to what a first run writes. A JSON schema gives editors autocomplete and a description of each setting on hover.
  • Fixes the old .env setup. The root .env was never loaded by the server, because Bun reads .env from the working directory and the server runs from apps/server. As a result, resource limits set there did nothing, and changing the port broke Vite's hardcoded proxy.
  • Migration. The first run seeds the new file from any old .env / apps/server/.env / environment, so the port, data dir and login carry over. An old AUTH_ENABLED=true that the file doesn't agree with refuses to start rather than come up without a password.
  • Env vars only override inside Docker (SAKUYA_*). The image pins host, port and data dir. Outside Docker they are ignored, and the boot log says so.
  • Resource limits are now limits.cpus and limits.memory, enforced as a hard ceiling by a launcher that wraps only the server:
    • Linux: a systemd scope, with each property probed separately.
    • Windows: a job object.
    • Docker: the app detects the container's CPU quota instead of it being restated.
    • The boot log reports what is actually enforced.
  • Compose. docker-compose.yml is generic; machine-specific mounts, ports and limits go in a gitignored docker-compose.override.yml.

Breaking changes

  • Environment variables and .env files are ignored outside Docker (they are migrated once on first run).
  • Removed SAKUYA_JOB_CONCURRENCY, SAKUYA_FFMPEG_THREADS, SAKUYA_ONNX_THREADS, SAKUYA_SHARP_CONCURRENCY and SAKUYA_HARD_LIMIT; limits.cpus derives all of them.
  • In Docker, PORT / AUTH_ENABLED / AUTH_SECRET are now SAKUYA_PORT / SAKUYA_AUTH_ENABLED / SAKUYA_AUTH_SECRET, and sakuya.config.json must exist before docker compose up.

Test plan

  • bun test --isolate: 107 pass. Includes new config-loader tests and the Windows job-object struct layout.
  • bun run typecheck, bun run lint (no new warnings)
  • bun dev on Linux with limits set: the server runs in a systemd scope with memory.max = 512 MiB and cpu.max = 1 CPU, Vite stays outside it, and /api proxies through the configured ports
  • Docker: both images build. The container reads the mounted file, pinned values win, a SAKUYA_AUTH_ENABLED override turns login on (401), and --cpus / --memory are detected
  • Migration from an existing apps/server/.env keeps login enabled with the same password
  • Windows: job-object limits have not been run on Windows yet

Configuration was spread across a root .env that the server never loaded
(Bun reads .env from the working directory, and the server runs from
apps/server), a second apps/server/.env, and constants hardcoded in
vite.config.ts. Changing the server port broke the web proxy, and resource
limits set in the root .env silently did nothing.

sakuya.config.json at the repo root is now the only source, read by the
server, its launcher and Vite alike. It is created with the defaults on first
run, migrating any old .env so the port, data dir and login carry over, and
is gitignored; sakuya.config.example.json is the committed reference, and a
test keeps it identical to what a first run writes. A JSON schema gives
editors autocomplete and per-setting docs. Bad values fail at startup naming
the key instead of reverting to a default.

Environment variables are no longer read outside Docker. Inside the image,
SAKUYA_* variables override the file, and the image pins host, port and data
dir. An old AUTH_ENABLED=true that the file doesn't agree with refuses to
start rather than come up without a password.

Resource limits collapse to limits.cpus and limits.memory, enforced as a hard
ceiling by a launcher that wraps only the server: a systemd scope on Linux
(each property probed separately, so an undelegated cpu controller doesn't
cost the memory cap) and a job object on Windows. In Docker the app detects
the container's CPU quota instead of it being restated. The boot log reports
what is actually enforced, read back from the cgroup or job object.

docker-compose.yml is now generic; machine-specific mounts, ports and limits
belong in a gitignored docker-compose.override.yml.
@rene-roid
rene-roid merged commit 6a2cd64 into master Sep 23, 2026
1 check passed
@rene-roid
rene-roid deleted the t3code/single-config-file branch September 23, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant