# 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). ## 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) ## 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: ``` /git/ a bare repository - origin of the instance; publish pushes to it // 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\`, say - before you go on. ## Set it up 1. **Pick the target**: a folder inside the synced folder, for example `C:\Users\\OneDrive - \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\\\\OneDrive - \\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 `/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 "\git"`). 4. **Allow the push target**, if your `.wikitool-local.json` has a `remotes` section: `backup init` then prints that section with `\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 `/git` and, with `machine_data` on, copies the machine data into `//`. 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 `/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 | | `quarantine/` | no | material that arrived through an intake channel and 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\\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 `//` 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 "/git" "" cd "" 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 `//` except `.chemenu-backup.json`, into the new folder, keeping the paths. On Windows: `robocopy "\" "" /E /XF .chemenu-backup.json`; elsewhere: `rsync -a --exclude .chemenu-backup.json "//" "/"`. 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_` 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 `/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. A folder the sync client uploads can also hold a read-only version of selected pages, for readers outside the repository: [Export pages to a synced folder](export-to-a-synced-folder.md). It is a separate folder with its own settings, and never the backup target.