Refinement decided 2026-09-01: each side gets its native format — the wrapper keeps a bash-sourceable transport env file, Werkator takes a YAML fragment in its own config schema via 'init --apply FILE', deep-merged idempotently. The env-to-config mapping table disappears entirely: the fragment IS configuration in the one schema, validated by the existing binding, documented by the existing reference. The env file names the fragment (WERKATOR_INIT_CONFIG), keeping one entry point per instance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5.0 KiB
Step 23: Init Owns the Files, tools/remote Wraps
Prerequisites: step 21 session D (the role-named tools/remote).
Read README.md first.
The Problem
werkator init and tools/remote overlap: both write the machine config — init as a commented template, the script by appending heredoc blocks (bwrap, server) and patching values with sed.
The script re-implements configuration knowledge Werkator owns (YAML shape, indentation, key names), outside the three-places sync invariant — the indentation-mismatch of one append guard produced nine duplicate bwrap blocks on mih34 before it was found.
Smaller duplications of the same kind: the script re-implements control-token generation in bash (ControlTokenService owns it), and check-prerequisites still pipes the bash script whose generic half exists as werkdock doctor.
The Decision (2026-09-01)
Werkator becomes the executing app wherever possible; tools/remote shrinks to a wrapper: build artifacts locally, transport them, execute Werkator/werkdock remotely, switch services.
Parameters travel as files, not as many CLI options — and each side gets the format that is native to it (refined 2026-09-01):
- The wrapper keeps a small, bash-sourceable env file with the transport values only:
tools/remote --env .env.mih34 werkator repo-initselects the target (default:.env), so several instances (.env.mih34,.env.vm4006, later a Werkbaum instance) are files, not edits. - Werkator takes a YAML fragment in its own config schema:
werkator init --apply mih34.ymldeep-merges the fragment into the machine config, idempotently — creating sections that are missing, updating the given values, never duplicating. No mapping table exists: the fragment saysserver: {port: …}andbuilds: {default: {bwrap: …}}directly, is validated by the existing schema binding, and is documented by the existingdocs/configuration.md. - The wrapper uploads the fragment alongside the artifacts and calls
werkator init --apply …remotely — the heredocs andsedcalls intools/remotedisappear. - The env file names the fragment (
WERKATOR_INIT_CONFIG=mih34.yml), keeping one entry point per instance.
The removed legacy env-to-YAML conversion stays removed — there is no conversion at all anymore: the fragment already is configuration in the one schema, applied once at setup time; the server reads nothing but its YAML at runtime.
The Files per Instance
.env.mih34(wrapper):WERKATOR_REMOTE,WERKATOR_PATH,WERKATOR_LOCAL_PORT,WERKATOR_REPO_URL,WERKATOR_ROOTFS(the local archive to upload),WERKATOR_INIT_CONFIG.mih34.yml(init fragment):server.*(port, publicBaseUrl, systemd limits) andbuilds.default.bwrap.*(enabled, the remote rootfs path, werkdock path) — exactly the blocks the script used to append.- Secrets (
git.token,giteakeys) stay out of both files on purpose — they are entered in the machine config on the host, as today.
The Sessions
A — Werkator side
init --apply FILE: deep-merge the YAML fragment into the machine config — reusing the loader's merge, creating missing sections, updating given values, never duplicating (the duplication class dies here); a fragment that fails the schema binding or carries unknown keys is refused loudly.init --systemdkeeps generating the units; decide in the session whether the Apache.htaccessbecomes part of the host-integration output when the applied config carriesserver.portand a public domain (proposal: yes, underinit --systemd, since it is generated host integration exactly like the units).- New subcommand
werkator control-token: print the token, creating it exactly likeControlTokenServicedoes — the bash duplication in the wrapper dies. - Tests per the writing-tests conventions;
docs/bootstrapping.mddocuments--apply(the fragment keys need no new reference — they are ordinarydocs/configuration.mdkeys).
B — Wrapper side
tools/remote --env FILE(default.env); the init fragment named byWERKATOR_INIT_CONFIGis uploaded, and the remote init runs with--apply.repo-initandinstance-startlose their heredoc/sedconfig writing;control-tokendelegates to the new subcommand.check-prerequisitesuploads the werkdock binary first and runswerkdock doctor;tools/werkator-build-prerequisites.shretires (its werkdock port is the survivor).
C — Live verification and docs
- Run the full wrapper flow against mih34 (
instance-update,repo-init,instance-startas no-op re-runs);docs/deployment.md's webspace section switches to the--envinvocations.
Acceptance Criteria
- Session A:
werkator init --apply …merges and re-merges a fragment idempotently;werkator control-tokenexists; full suite green. - Session B:
tools/remotecontains no YAML heredocs and nosedinto the machine config; the prerequisites bash script is gone. - Session C: the mih34 re-runs change nothing on a configured host and the deployment docs show only
--env-style calls.