Files
chemenu/docs/how-to/back-up-to-a-synced-folder.md
T
torbenandClaude Sonnet 5.5 02bf3b0403
CI / verify (push) Successful in 8m17s
CI / pwsh (push) Successful in 2m52s
Release / converters (push) Successful in 26s
Release / release (push) Successful in 37s
Release / wiki-mirror (push) Skipped
tools: Export- und Eingangsordner im Backup-Ziel - Überschneidungsregel nur noch auf <ziel>/git und den eigenen Maschinenordner, Laufzeitprüfung auf Vorfahren in upload collect und export run (#216); 10.1.0-beta.16
Files changed:
- CHANGES.md
- VERSION
- docs/how-to/back-up-to-a-synced-folder.md
- docs/how-to/collect-from-a-synced-folder.md
- docs/how-to/export-to-a-synced-folder.md
- docs/reference/commands/exports.md
- docs/reference/commands/raw-material-and-uploads.md
- docs/reference/configuration.md
- tools/CONTRACT.md
- tools/chemenu/backup.py
- tools/chemenu/collect.py
- tools/chemenu/commands/export_cmd.py
- tools/chemenu/commands/upload_cmd.py
- tools/chemenu/config_shapes.py
- tools/chemenu/page_export.py
- tools/chemenu/tests/test_collect.py
- tools/chemenu/tests/test_export_run.py
- tools/chemenu/upload.py

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
2026-10-16 11:19:12 +02:00

10 KiB

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.

Contents

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:

    {
      "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.

One folder for the backup, the intake and the export

The target may be the one folder your whole setup shares. The backup writes only into git and into the folder of its own machine; everything else in the target belongs to the sync folder, so an intake folder and an export folder can sit beside them:

<OneDrive - company>\Chemenu\          backup.target
    git\                               the bare repository (backup init, publish)
    <MACHINE>\                         this machine's data (backup run, publish)
    Inbox\                             intake channel, handler folder
    Export\                            export target

The rule behind it: no export and no intake folder may be, or lie in, <target>\git or a machine folder. For the export that holds from above as well (its path must not contain them either); an intake folder may sit above them, since upload collect reads only the top level of its folder. doctor checks the part that the settings can show. What they cannot show - the folder of another machine, or one that a machine starts to fill later - is checked when the command runs: upload collect and export run refuse a folder that holds or lies in a .chemenu-backup.json, a bare repository or (for upload collect) a .wikitool-export.json, and touch nothing in it.

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
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\<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:

    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: 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) - 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.

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. It is a separate folder with its own settings, and never the backup target.