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
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
- Set it up
- One folder for the backup, the intake and the export
- What is backed up, and what is not
- Restore
- 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 gcandgit repackthen 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
-
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. -
Write the
backupsection into.wikitool-local.jsonat the root of the instance - by hand, since its fields decide what leaves this machine andconfig setrefuses 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_namedefaults to the computer's host name;extralists further paths inside the instance to copy, and can be left out. -
Tell the agent:
Set up the backup target from the
backupsection.The agent runs
tools/wikitool backup init. It creates<target>/gitas a bare repository and makes itorigin- unless the instance already has anoriginthat points elsewhere: then it changes nothing and shows you both URLs, and whetheroriginmoves is yours to decide (git remote set-url origin "<target>\git"). -
Allow the push target, if your
.wikitool-local.jsonhas aremotessection:backup initthen prints that section with<target>\gitadded. Copy it into the file yourself - the list is the Publish-Remote Gate, and no agent edits it. Without aremotessection there is nothing to do. -
Publish. The next
tools/wikitool publishpushes the whole history to<target>/gitand, withmachine_dataon, copies the machine data into<target>/<machine>/. From then on every publish that pushes does both.tools/wikitool backup runcopies the machine data on its own, whenever you want it current without publishing - after dropping a file intoincoming/, for instance, which is otherwise only copied by the next publish. -
Check it:
tools/wikitool doctor. Thebackupline names the target and how old the last copy of the machine data is; aWARNthere 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:
-
Clone the repository and check it:
git clone "<target>/git" "<new folder>" cd "<new folder>" git fsck --fullThe clone is outside the synced folder, like the original; its
originis the bare repository already. -
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>/". -
Bootstrap the checkout - tell the agent:
Bootstrap this checkout.
It follows instructions/bootstrap.md: the preflight, the published skills,
doctor. -
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 withraw loginfor each host that needs it.doctor'ssettings-secretsline 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.