backup: an instance backs up into a synced folder - backup init makes a bare repository under <target>/git its origin, backup run and publish mirror the machine data into <target>/<machine>/, doctor warns about .git in a synced folder (#186); 10.0.0-beta.10
CI / verify (push) Successful in 8m24s
CI / pwsh (push) Successful in 2m45s
Release / release (push) Successful in 34s
Release / wiki-mirror (push) Skipped

Files changed:
- CHANGES.md
- INSTALL.md
- VERSION
- docs/explanation/configuration-tiers.md
- docs/how-to/README.md
- docs/how-to/back-up-to-a-synced-folder.md
- docs/reference/commands/README.md
- docs/reference/commands/git.md
- docs/reference/commands/instance-health.md
- docs/reference/configuration.md
- instructions/publish-cycle.md
- instructions/setup-instance.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/backup.py
- tools/chemenu/cli.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/backup_cmd.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/config_shapes.py
- tools/chemenu/reference_doc.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_backup.py
- tools/chemenu/tests/test_config_shapes.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Opus 5.5 committed 2026-10-12 19:39:49 +02:00
1 parent e789146116
commit 9736472f48
25 files changed
+2024 -15

No files matched your search

+17
View File
@@ -7,6 +7,16 @@ command that writes them are in [the configuration reference](../reference/confi
the rules an agent follows are in [AGENTS.md § Settings](../../AGENTS.md#settings). This page is
about why it is built this way, and what it does not do.
<!-- wikitool:toc -->
## Contents
- [Three kinds of data that used to share files](#three-kinds-of-data-that-used-to-share-files)
- [One place per value, not an override](#one-place-per-value-not-an-override)
- [What runs, and where it pushes, never travels with a pull](#what-runs-and-where-it-pushes-never-travels-with-a-pull)
- [References instead of values](#references-instead-of-values)
- [What this does not protect against](#what-this-does-not-protect-against)
<!-- /wikitool:toc -->
## Three kinds of data that used to share files
Before the tiers, every feature kept its settings in a gitignored file of its own. Three kinds of
@@ -57,6 +67,13 @@ same value. In CI, `op` runs with a service-account token and resolves the same
references. Alternatively, 1Password's own action resolves values into variables before
`wikitool` starts, which serves references by name. This repository's CI does the second.
A plain private value in `.wikitool-local.json` stays on this machine only as long as that file
does. A backup into a synced folder (the `backup` section) copies the file as it is, because it is
the one record of how this checkout is set up, and a restore without it starts from nothing. That
trade is the operator's, made by writing the section by hand. A reference keeps the value out of
that copy as well, and the secrets file is never in it: it lies outside the instance, and a backup
reads nothing outside it.
A reference is resolved only when a command asks for that one value, never when the files are
read, and the value stays in that process's memory. `doctor` reports whether each reference
resolves, never what it resolves to.
+2
View File
@@ -30,5 +30,7 @@ Running the instance:
- [Trace and score agent sessions](trace-and-score-sessions.md)
- [Use 1Password for settings](use-1password-for-settings.md) - secrets and private values out
of the tree, on the desktop and in CI
- [Back up to a synced folder](back-up-to-a-synced-folder.md) - OneDrive and the like as the
backup of an instance without a git server, and restoring from it
Installing a new instance is [INSTALL.md](../../INSTALL.md) at the repository root.
+158
View File
@@ -0,0 +1,158 @@
# Back up to a synced folder
Back an instance up into a folder a sync client uploads - OneDrive, or any other client that keeps a
local folder in step with a server - when there is no git server to push to. The instance itself
stays in a folder the sync client does not touch; the synced folder receives a git repository to
push to and a copy of the files on this machine that are not in git. What the settings look like:
[configuration reference](../reference/configuration.md#backup-to-a-synced-folder).
<!-- wikitool:toc -->
## Contents
- [Why the instance does not live in the synced folder](#why-the-instance-does-not-live-in-the-synced-folder)
- [Set it up](#set-it-up)
- [What is backed up, and what is not](#what-is-backed-up-and-what-is-not)
- [Restore](#restore)
- [One device writes](#one-device-writes)
<!-- /wikitool:toc -->
## Why the instance does not live in the synced folder
Putting the whole instance - `.git` included - into the synced folder looks like the simplest
backup, and fails in three ways:
- **Locks.** On Windows, OneDrive holds a file it is uploading open for a moment. `git gc` and
`git repack` then fail to delete or replace a file under `.git` ("unlink failed").
- **Placeholders.** With Files On-Demand, the client offloads files it considers unused and leaves a
placeholder behind; git then reads objects that first have to be downloaded, or are not there
when the machine is offline.
- **Conflict copies.** As soon as a second device syncs the same folder, two writers meet inside
`.git`, and the client resolves that by making copies of the files both changed - a repository
git can no longer read.
So the instance lives outside the synced folder, and the synced folder gets a layout git writes to
in a way a sync client handles well:
```
<target>/git/ a bare repository - origin of the instance; publish pushes to it
<target>/<machine>/ a copy of this machine's files that are not in git, plus .chemenu-backup.json
```
Git writes into the bare repository only on a push, and then mostly adds new files that never
change again.
`tools/wikitool doctor` reports `sync-folder` as a `WARN` when the instance's git directory lies in
a synced folder. On Windows, check that line even if you never chose such a folder: when Documents
or Desktop is redirected into OneDrive (Known Folder Move), an instance under Documents lies in
OneDrive without looking like it. Move the instance to a folder outside it - `C:\Wiki\<name>`, say -
before you go on.
## Set it up
1. **Pick the target**: a folder inside the synced folder, for example
`C:\Users\<you>\OneDrive - <company>\Chemenu-Backup`. It must not lie inside the instance.
2. **Write the `backup` section** into `.wikitool-local.json` at the root of the instance - by hand,
since its fields decide what leaves this machine and `config set` refuses them:
```json
{
"backup": {
"target": "C:\\Users\\<you>\\OneDrive - <company>\\Chemenu-Backup",
"machine_data": true,
"machine_name": "WORK-LAPTOP",
"extra": [".claude/settings.local.json"]
}
}
```
Backslashes in a JSON string are doubled. `machine_name` defaults to the computer's host name;
`extra` lists further paths inside the instance to copy, and can be left out.
3. **Tell the agent:**
> Set up the backup target from the `backup` section.
The agent runs `tools/wikitool backup init`. It creates `<target>/git` as a bare repository and
makes it `origin` - unless the instance already has an `origin` that points elsewhere: then it
changes nothing and shows you both URLs, and whether `origin` moves is yours to decide
(`git remote set-url origin "<target>\git"`).
4. **Allow the push target**, if your `.wikitool-local.json` has a `remotes` section: `backup init`
then prints that section with `<target>\git` added. Copy it into the file yourself - the list is
the Publish-Remote Gate, and no agent edits it. Without a `remotes` section there is nothing to do.
5. **Publish.** The next `tools/wikitool publish` pushes the whole history to `<target>/git` and,
with `machine_data` on, copies the machine data into `<target>/<machine>/`. From then on every
publish that pushes does both. `tools/wikitool backup run` copies the machine data on its own,
whenever you want it current without publishing - after dropping a file into `incoming/`, for
instance, which is otherwise only copied by the next publish.
6. **Check it:** `tools/wikitool doctor`. The `backup` line names the target and how old the last
copy of the machine data is; a `WARN` there names what is missing.
If a publish reports a `WARN` that the machine-data backup failed, the commit and the push have
still happened. Fix what the line names - a synced folder that is not there, a folder that is not
writable - and run `tools/wikitool backup run`. Another publish does not help: it has nothing new to
push.
## What is backed up, and what is not
| Path | Backed up | Why |
|------|-----------|-----|
| Everything committed (`kb/`, `raw/`, `wikitool.json`, ...) | yes, in `<target>/git` | that is what `publish` pushes |
| `.wikitool-local.json` | yes | the settings of this checkout |
| `ENVIRONMENT.md` | yes, if present | written by hand |
| Everything in `incoming/` but `.gitkeep` | yes | sources waiting there are backed up nowhere else |
| The `extra` paths | yes | what you named |
| `mcp-upload/` | no | material submitted from outside that nobody has reviewed yet |
| `reports/` | no | regenerated by `lint`; telemetry holds prompts |
| `.wikitool-tools.json`, `tools/.venv/`, the published skills | no | the preflight and `instructions sync` rebuild them |
| The secrets file | **never** | it lies outside the instance, and a backup reads nothing outside it |
**Private values reach the synced folder.** `.wikitool-local.json` is copied as it is, so a plain
private value in it - an internal host name, an internal URL - ends up in OneDrive. A secret does
not: a secret is never in that file, only a reference to it, and the secrets file it resolves
through (`%APPDATA%\chemenu\<instance_id>\secrets.json`, with the sessions `raw login` stored)
lies outside the instance. An `extra` path that leads outside the instance - through `..` or a
link - is refused, so no setting can copy it either.
In `<target>/<machine>/` a run writes and deletes only what is its own: it removes a file only when
its previous run copied it and the instance no longer has it (a source `raw accept` moved out of
`incoming/`, say), and refuses a folder that is not empty and has no `.chemenu-backup.json`, rather
than copying into somebody else's folder. A link inside a copied directory is skipped and named,
never followed.
## Restore
On the same machine or a new one:
1. **Clone the repository and check it:**
```bash
git clone "<target>/git" "<new folder>"
cd "<new folder>"
git fsck --full
```
The clone is outside the synced folder, like the original; its `origin` is the bare repository
already.
2. **Copy the machine data back**: everything in `<target>/<machine>/` except
`.chemenu-backup.json`, into the new folder, keeping the paths. On Windows:
`robocopy "<target>\<machine>" "<new folder>" /E /XF .chemenu-backup.json`; elsewhere:
`rsync -a --exclude .chemenu-backup.json "<target>/<machine>/" "<new folder>/"`.
3. **Bootstrap the checkout** - tell the agent:
> Bootstrap this checkout.
It follows [instructions/bootstrap.md](../../instructions/bootstrap.md): the preflight, the
published skills, `doctor`.
4. **Provide the secrets again.** They were never in the backup. Put each value back where its
reference reads it - 1Password, the secrets file, or a `WIKITOOL_SECRET_<NAME>` variable
([use-1password-for-settings.md](use-1password-for-settings.md)) - and sign in again with
`raw login` for each host that needs it. `doctor`'s `settings-secrets` line names every reference
that does not resolve yet.
`doctor` must then run through without a `FAIL`.
## One device writes
Only one device publishes to `<target>/git`. Two devices pushing into the same synced folder are two
writers again, only one step removed - and the sync client resolves that with conflict copies, not
with a merge. An instance on a second device gets a target of its own. The sync client is a backup
here, not a way to work on one instance from two devices.
+2
View File
@@ -97,6 +97,8 @@ Full records: [git.md](git.md)
- [`sync`](git.md#sync) - Fetch `<remote>/<branch>` and bring the local branch up to date with it.
- [`publish`](git.md#publish) - Reconcile with `<remote>/<branch>`, then stage all changes, commit, and push.
- [`backup init`](git.md#backup-init) - Create the backup target's bare repository and make it `origin` when there is none.
- [`backup run`](git.md#backup-run) - Mirror this machine's files that are not in git into `<target>/<machine>/`.
## Guideline export
+106 -2
View File
@@ -1,12 +1,15 @@
# Git
Pulling in the remote and publishing a change - the only way a change leaves this checkout.
Pulling in the remote and publishing a change - the only way a change leaves this checkout - and
backing the checkout up into a synced folder.
<!-- wikitool:toc -->
## Contents
- [`sync`](#sync)
- [`publish`](#publish)
- [`backup init`](#backup-init)
- [`backup run`](#backup-run)
<!-- /wikitool:toc -->
<!-- wikitool:reference-commands -->
@@ -130,6 +133,7 @@ tools/wikitool publish --confirm-rebase <token> --message "ingest: docker-cheats
- The remotes settings file of an earlier version is not read: while it exists this exits 42 and names `tools/wikitool config migrate`, so a restriction is never lost silently.
- `--path` (repeatable) scopes the whole operation - gate count, staging and commit - to that subtree, with one exception: uncommitted generated files outside `--path` (`kb/index.md`, `kb/log.md`, `kb/provenance.md`, every `INDEX.md` under `kb/`) are staged and committed too, and a line names them - whether a reconcile or the change itself wrote them. They stay out of the gate count, and the `--confirm` token and the re-run line cover the `--path` given. Every other file outside `--path` is left as it is.
- Commit message: `--message`, then a `Files changed:` paragraph listing every committed path. When `--message` ends in a paragraph git reads as a trailer block (`Co-Authored-By:` and the like), that block stays the last paragraph and the list goes in front of it, since git reads trailers from the last paragraph only. `git interpret-trailers` decides whether there is such a block, and the list moves only when git reads the same trailers from the result; otherwise it is appended at the end. `--message` is not part of any gate token.
- Machine-data backup: with a `backup` section in `.wikitool-local.json` whose `machine_data` is true, a call that pushed then mirrors this machine's files that are not in git into `<target>/<machine>/` - the same step as `backup run`. A failure there prints a `WARN` line with the reason and still exits 0, since the commit and the push stand. No backup with `--no-push`, after a failed push, or when there was nothing to push. A malformed `backup` section stops the call with exit 1 before anything is committed, `--no-push` included.
- After a successful commit or push whose changed files include `tools/`, `types/`, `instructions/`, `AGENTS.md` or a path ending in `CONTRACT.md`, prints one reminder line: the phase past this point (an issue-body rewrite, `docs/` staleness, a changelog entry's accuracy) is not covered by `docs verify`, `instructions verify` or `pytest`. It is not a gate: no exit code change, nothing to clear, and silent for an ordinary content publish.
**Properties**
@@ -144,11 +148,12 @@ tools/wikitool publish --confirm-rebase <token> --message "ingest: docker-cheats
**Exit codes**
- `0` - success
- `0` - The machine-data backup after the push failed: a `WARN` line names the reason, and the commit and the push stand
- `1` - git failed - `git add`, `git commit`, `git push`, or the reconcile's automatic rebase (a conflict outside the generated files, an edited `kb/log.md`, or an uncommitted change on a path the incoming commits change)
- `1` - The push target (`--branch`) is not the checked-out branch, or HEAD is detached; the unborn branch of a fresh `git init` is not this case
- `1` - No `--no-push`, and the remote is not configured or cannot be reached; nothing was committed
- `1` - `--yes`/`-y` was passed - the flag does not exist and fails with an explicit error
- `1` - The settings files do not pass their check, or `remotes.allowed_push_urls` is not a list of strings
- `1` - The settings files do not pass their check, `remotes.allowed_push_urls` is not a list of strings, or the `backup` section is malformed; nothing was committed
- `42` - The remotes settings file of an earlier version is still there
- `42` - Mass-Update Gate: `--threshold` (default 10) or more counted files would be committed, or the `--confirm` token does not match this changeset
- `42` - Rebase-Review Gate: `<remote>/<branch>` moved and both sides changed the same file; the output lists the upstream commits, the overlapping files and their diff
@@ -159,4 +164,103 @@ tools/wikitool publish --confirm-rebase <token> --message "ingest: docker-cheats
- `wikitool sync` - the same reconcile on its own, without committing or pushing
- `instructions/gates.md` - the gate procedure
- `instructions/setup-instance.md` - the first publish of a new instance
- `wikitool backup run` - the machine-data backup on its own
## `backup init`
Create the backup target's bare repository and make it `origin` when there is none.
**Synopsis**
- `wikitool backup init`
**Options**
```text
-h, --help Show this message and exit.
```
**Examples**
```bash
tools/wikitool backup init
```
**Behaviour**
- Reads the `backup` section of `.wikitool-local.json` and creates `<target>/` and `<target>/git`, the latter as a bare repository (`git init --bare -b main`). An existing bare repository there, or an empty directory, is used as it is.
- Sets `origin` to `<target>/git` when the checkout has no `origin`. An `origin` that already pushes there is left as it is; one that pushes anywhere else stops the command.
- When `remotes.allowed_push_urls` exists and lacks the URL `origin` pushes to, prints the `remotes` section with that URL added, for the user to copy into `.wikitool-local.json`. It never writes that file: the field is a gate.
- Pushes nothing: the next `publish` sends the history to the new `origin`.
**Properties**
- Changes files: yes
- Idempotent: yes
- Atomic: Every precondition is checked first; a refusal changes nothing
- Counts toward the session call budget: yes
- Can reach the network: no
**Exit codes**
- `0` - success
- `1` - No `backup` section in `.wikitool-local.json`, or a malformed one - a target that is not absolute or lies inside the instance, a `machine_name` that cleans to nothing or to `git`, an `extra` path that resolves outside the instance or into `.git/`
- `1` - `<target>/git` exists and is not a bare repository; nothing was changed
- `1` - `origin` already pushes to another URL; the message names both and nothing was changed
**See also**
- `wikitool backup run` - the machine-data half of the backup
- `wikitool publish` - pushes to the bare repository and runs the machine-data backup after it
- `docs/how-to/back-up-to-a-synced-folder.md` - the whole procedure, restoring included
## `backup run`
Mirror this machine's files that are not in git into `<target>/<machine>/`.
**Synopsis**
- `wikitool backup run`
**Options**
```text
-h, --help Show this message and exit.
```
**Examples**
```bash
tools/wikitool backup run
```
**Behaviour**
- Mirrors `.wikitool-local.json`, `ENVIRONMENT.md` if present, every file in `incoming/` but `.gitkeep`, and the `extra` paths of the `backup` section into `<target>/<machine>/`, then writes the manifest `.chemenu-backup.json` there: time, stack version, machine name, and per file its relative path, size and sha256.
- Never mirrors `mcp-upload/`, `reports/`, `.wikitool-tools.json`, `tools/.venv/`, the published skills or `.git/` - unless an `extra` path names one of the first ones. The secrets file lies outside the instance and is never read.
- Writes and deletes only under `<target>/<machine>/`. Deletes only a file the previous manifest lists and the instance no longer has; a file there the manifest does not list stays as it is. A file whose size and sha256 match the previous manifest is not rewritten.
- A symbolic link or junction inside a mirrored directory is skipped and named in the output, never followed.
- `publish` runs the same step after every push when `machine_data` is true.
**Properties**
- Changes files: yes
- Idempotent: yes
- Atomic: Per file - each is written to a temporary file and renamed, the manifest last; an interrupted run leaves whole files and the previous manifest
- Counts toward the session call budget: yes
- Can reach the network: no
**Exit codes**
- `0` - success
- `1` - No `backup` section in `.wikitool-local.json`, or a malformed one - a target that is not absolute or lies inside the instance, a `machine_name` that cleans to nothing or to `git`, an `extra` path that resolves outside the instance or into `.git/`
- `1` - `machine_data` is false
- `1` - `<target>/<machine>/` is not empty and has no manifest, or its manifest cannot be read; nothing was written
- `1` - The target is not a directory (the synced folder is missing or not mounted), or a write failed
**See also**
- `wikitool backup init` - sets up the target's bare repository
- `wikitool doctor` - the `backup` line reports the age of the last run
- `docs/how-to/back-up-to-a-synced-folder.md` - the whole procedure, restoring included
<!-- /wikitool:reference-commands -->
@@ -36,6 +36,8 @@ tools/wikitool doctor --json
- KB conventions: `kb/CONVENTIONS.md` present, unsentinelled, and naming all three tool-owned section headings - a `FAIL` on any of the three.
- Environment note: `ENVIRONMENT.md` is optional, so absent is `OK`; a still-templated one is a `WARN`.
- Legacy settings (`legacy-settings`): one `FAIL` for each per-feature settings file of an earlier version (telemetry, remotes, upload, task tracker) that is still there. Nothing reads them any more, so the settings they hold are not in effect; the fix is `tools/wikitool config migrate`.
- Synced folder (`sync-folder`): a `WARN` when the git directory, links and junctions resolved, lies under a folder named by `OneDrive`, `OneDriveCommercial` or `OneDriveConsumer` (compared without regard to case on Windows) or under `~/Library/CloudStorage/` (macOS); `OK` otherwise, never a `FAIL`.
- Backup (`backup`): the `backup` section absent is `OK`, malformed is a `FAIL`. Configured, a `WARN` when `<target>/git` is not a bare repository, `origin` does not push there, or - with `machine_data` true - no machine-data backup exists yet; otherwise `OK` with the age of the last machine-data backup.
- MCP `submit` tool: whether the `upload` section of the settings is present, absent or malformed, its limits, and how many submissions wait in `mcp-upload/`. Absent is `OK` and means the write path does not exist at all; malformed is a `FAIL`.
- Task tracker: the `tasks` section present, absent or malformed - absent is `OK` (no tracker configured), malformed is a `FAIL`. When `WIKITOOL_TASKS_CONFIG` is set, the profile it names is read instead of the `tasks`, `superproductivity` and `caldav` sections and the finding names it; a set variable that names no file is a `FAIL`, never `OK`.
- For a configured `superproductivity` provider, the configured `access` path's own state: `access: "api"` reports whether its local REST API answers `GET /health` with a ready renderer right now, `access: "snapshot"` whether a backup file is ready. The other access path is never attempted, and neither state is ever a `FAIL`.
@@ -67,5 +69,6 @@ tools/wikitool doctor --json
- `instructions/preflight.md` - what `tool-paths` and `install-dir` point back to
- `docs/reference/configuration.md` - the per-checkout configuration files and the tiered settings
- `docs/explanation/telemetry-and-evaluation.md` - telemetry state and caps
- `docs/how-to/back-up-to-a-synced-folder.md` - what `sync-folder` and `backup` point to
- `instructions/session-setup.md` - setting `WIKITOOL_SESSION_ID`
<!-- /wikitool:reference-commands -->
+52 -1
View File
@@ -30,6 +30,7 @@ something you run.
- [MCP submissions](#mcp-submissions)
- [Site handlers](#site-handlers)
- [Fetch routes](#fetch-routes)
- [Backup to a synced folder](#backup-to-a-synced-folder)
- [Files of earlier versions](#files-of-earlier-versions)
<!-- /wikitool:toc -->
@@ -91,7 +92,8 @@ Each file is a JSON object of sections, one per feature, beside two keys of its
`instance_id` sits in `wikitool.json` only. The first `wikitool config set` creates the file and
the id; the id names the directory of the secrets file below. The sections are [telemetry](#telemetry),
[remotes](#allowed-push-urls), [tasks, superproductivity and caldav](#task-tracker) and
[upload](#mcp-submissions), [sites](#site-handlers) and [fetch](#fetch-routes). `config set` names the sections it knows, and `doctor` reports a
[upload](#mcp-submissions), [sites](#site-handlers), [fetch](#fetch-routes) and
[backup](#backup-to-a-synced-folder). `config set` names the sections it knows, and `doctor` reports a
section it does not read as a `WARN`.
**One place per value.** A value in the file its tier does not name is an error naming the file,
@@ -533,6 +535,55 @@ Example:
```
<!-- /wikitool:reference-config-fetch -->
## Backup to a synced folder
The `backup` section of `.wikitool-local.json` backs this checkout up into a folder a sync client
uploads - OneDrive and the like - while the working tree itself stays outside it. The target gets
two kinds of content:
```
<target>/git/ bare repository, the checkout's origin; publish pushes here
<target>/<machine>/ mirror of this machine's files that are not in git, plus .chemenu-backup.json
```
`tools/wikitool backup init` creates `<target>/git` and makes it `origin` when the checkout has none.
With `machine_data` on, every `publish` that pushed mirrors `.wikitool-local.json`, `ENVIRONMENT.md`,
what waits in `incoming/` and the `extra` paths into `<target>/<machine>/`; `tools/wikitool backup
run` does the same on its own. The secrets file is never among them - it lies outside the instance,
and a backup reads nothing outside it. Plain private values in `.wikitool-local.json`, an internal
host name for one, do reach the synced folder.
<!-- wikitool:reference-config-backup -->
| Field | Tier | Type | Required | Default | Description |
|-------|------|------|----------|---------|-------------|
| `target` | checkout, gate | string | yes | - | The backup folder: an absolute path outside the instance. `backup init` creates `<target>/git` in it, `backup run` writes only to `<target>/<machine>/`. |
| `machine_data` | checkout, gate | boolean | no | `false` | Mirror this machine's files after every `publish` that pushed, and with `backup run`: `.wikitool-local.json`, `ENVIRONMENT.md`, what waits in `incoming/`, and `extra`. |
| `machine_name` | checkout | string | no | the host name | The name of this machine's folder under the target. Every character outside letters, digits, `-` and `_` becomes `-`, and leading and trailing `-` are dropped; a name that is empty afterwards, or `git` in any case, is an error. |
| `extra` | checkout, gate | array of strings | no | `[]` | Further files or directories to mirror, relative to the instance. One that resolves outside the instance, or into `.git/`, is an error. |
- **Absent:** No backup: `publish` behaves as without it, and `backup init` and `backup run` stop with exit 1 naming the section.
- **Malformed:** An error. `publish` stops with exit 1 before it commits anything, `backup init` and `backup run` stop with exit 1, and `doctor` reports `FAIL`. A broken section is never read as "no backup".
Example:
```json
{
"backup": {
"target": "C:\\Users\\<user>\\OneDrive - <company>\\Chemenu-Backup",
"machine_data": true,
"machine_name": "WORK-LAPTOP",
"extra": [
".claude/settings.local.json"
]
}
}
```
<!-- /wikitool:reference-config-backup -->
`target`, `machine_data` and `extra` decide what leaves this machine, so they are marked `gate`:
`config set` exits 42 for them, and only you write them. The procedure, restoring included:
[back-up-to-a-synced-folder.md](../how-to/back-up-to-a-synced-folder.md).
## Files of earlier versions
Until version 10 every feature above had a file of its own at the root: `.wikitool-telemetry.json`,