> **WARNING:** This document describes only the change applied in this PR. > It may already be outdated once the next PR is merged. > Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation. ## The Problem `tools/remote repo-add` runs `werkator init --apply` with the instance fragment named by `WERKATOR_INIT_CONFIG`. Since PR#61, the fragment of mih09 also carries Werkator's own `builds.deploy`: `afterSuccessOf: default`, `branches: [main]`, `restartsInstance: true`, `werkdock.enabled: false`. On 2026-10-01, `repo-add` installed this block into the newly registered repository `werkcrappit`. Its `main@deploy` then ran on the host, outside the sandbox, with werkcrappit's inherited `buildCommand` (`./gradlew build`). It failed only because the host has no JDK 21. With a JDK, every green `main` build of werkcrappit would have restarted the instance. Werkator accepted the block, because nothing in a repository's own files can say whether the instance runs from that repository. The fragment mixed two things: the sandbox policy that every repository gets, and the deployment that belongs to one repository. ## Non-Goals - No detection of the repository the instance runs from; the operator says it in the instance file. - No change to an instance without a registry: it serves one repository, and that one may restart it. - No change to the pinning of `restartsInstance` against branch layers; it already holds. ## The Scenarios ### Feature: only the repository the instance deploys itself from may restart it #### Scenario#87.01: Several fragments are merged in order So that the self-deployment can travel in its own fragment, apart from the sandbox policy. - **Given** two fragments, the second one overriding a key of the first and adding a build - **When** `init --apply` gets both - **Then** the applied layer holds their merge, the later fragment winning - **And** a header names both files ##### Verified by - [ConfigLoaderTest](../../src/test/kotlin/de/hoennig/werkator/config/ConfigLoaderTest.kt) — "several fragments are merged in order" - [InitCommandTest](../../src/test/kotlin/de/hoennig/werkator/commands/InitCommandTest.kt) — the existing `--apply` tests with the option as a list #### Scenario#87.02: restartsInstance needs selfDeploys in the registry So that a deployment block copied into a foreign repository cannot restart the instance. - **Given** a registry with `werkator` marked `selfDeploys: true` and `werkcrappit` unmarked, both with a `restartsInstance` build - **When** their configurations are loaded - **Then** `werkator` loads with the restarting build - **And** `werkcrappit` is refused, naming the build, the instance file and `selfDeploys: true` - **And** a directory outside the registry is refused too, and so is a branch layer on a refused configuration ##### Verified by - [ConfigLoaderTest](../../src/test/kotlin/de/hoennig/werkator/config/ConfigLoaderTest.kt) — "only the registry entry marked selfDeploys may restart the instance" #### Scenario#87.03: A refused repository is not served So that the error shows at start, and the other repositories keep building. - **Given** an unmarked registry entry whose repository sets `restartsInstance` - **When** the registry opens - **Then** that repository is skipped with an error, and the others are served ##### Verified by - [RepoRegistryTest](../../src/test/kotlin/de/hoennig/werkator/repo/RepoRegistryTest.kt) — "a repository that would restart the instance without being marked selfDeploys is not served" #### Scenario#87.04: One repository at most deploys the instance So that "the repository the instance runs from" names one repository. - **Given** two registry entries with `selfDeploys: true` - **When** the registry opens - **Then** the start aborts, naming both entries ##### Verified by - [RepoRegistryTest](../../src/test/kotlin/de/hoennig/werkator/repo/RepoRegistryTest.kt) — "two entries marked selfDeploys abort the start" ## The Solution `RepositoryEntry` gets `selfDeploys`. `ConfigLoader.loadPrimary` refuses any `restartsInstance: true` in `builds` or the legacy `branches` when a registry exists and the repository's entry does not say `selfDeploys: true`. The paths are compared after resolving symlinks, so `~/werkator` and its real path match. The check sits in `loadPrimary`, so every load — the registry at start, the watcher per poll, the branch layer at build time — stands on it. `RepositoryEntry.directory` now resolves an entry's path for the registry and the check alike. `init --apply` repeats, and `ConfigLoader.applyInstanceFragments` merges the fragments in order. `tools/remote` gets `WERKATOR_SELF_DEPLOY_CONFIG`: `repo-init` and `instance-start` apply it on top of `WERKATOR_INIT_CONFIG`, `repo-add` never does. `repo-add` dies when `WERKATOR_INIT_CONFIG` sets `restartsInstance: true`, before it installs anything. A failed upload inside a command substitution now ends the script; `set -e` does not reach into one. Rollout on mih09: add `selfDeploys: true` to the `werkator` entry of `~/.werkator.yml` before the new version starts. An older Werkator ignores the key, so the order is safe; the other way round, the new version would not serve `werkator` and could not deploy itself again. Then split `.env.mih09.yml` locally into the sandbox policy and `.env.mih09.self-deploy.yml`. ## Additional Changes - `docs/configuration.md`, `docs/deployment.md`, `docs/llms.md`, `AGENTS.md` and the architecture skill describe `selfDeploys`, the repeated `--apply` and the second fragment. - Version 1.26.0 with its release note.