Files
chemenu/docs/how-to/back-up-to-a-synced-folder.md
T
torbenandClaude Code cceb9a7bfe
CI / verify (push) Successful in 8m41s
CI / pwsh (push) Successful in 2m44s
Release / release (push) Successful in 35s
Release / wiki-mirror (push) Skipped
intake: several configured intake channels (mcp, folder, command) all end in quarantine/ (was mcp-upload/), and upload collect pulls the synced-folder and command channels into it (#213); 10.0.0-beta.11
Files changed:
- .gitignore
- CHANGES.md
- VERSION
- docs/explanation/architecture.md
- docs/explanation/pipeline-rationale.md
- docs/how-to/README.md
- docs/how-to/back-up-to-a-synced-folder.md
- docs/how-to/collect-from-a-synced-folder.md
- docs/how-to/ingest-a-source.md
- docs/how-to/set-up-the-mcp-server.md
- docs/reference/commands/README.md
- docs/reference/commands/git.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/raw-material-and-uploads.md
- docs/reference/configuration.md
- instructions/gates.md
- instructions/ingest-queue.md
- instructions/mcp-read-server.md
- instructions/migrations/10.0.0-settings-tiers.md
- instructions/wiki-ingest/SKILL.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli_contract.py
- tools/chemenu/collect.py
- tools/chemenu/commands/backup_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/raw/pending.py
- tools/chemenu/commands/upload_cmd.py
- tools/chemenu/config.py
- tools/chemenu/config_shapes.py
- tools/chemenu/legacy_settings.py
- tools/chemenu/mcp/server.py
- tools/chemenu/reference_doc.py
- tools/chemenu/tests/test_backup.py
- tools/chemenu/tests/test_collect.py
- tools/chemenu/tests/test_config_shapes.py
- tools/chemenu/tests/test_doctor.py
- tools/chemenu/tests/test_legacy_settings.py
- tools/chemenu/tests/test_mcp_server.py
- tools/chemenu/tests/test_upload.py
- tools/chemenu/tests/test_upload_cmd.py
- tools/chemenu/upload.py

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
2026-10-12 22:04:18 +02:00

8.3 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.

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.