Files changed: - CHANGES.md - VERSION - docs/reference/commands/git.md - tools/CONTRACT.md - tools/chemenu/commands/git_publish.py - tools/chemenu/dist_templates/log.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
19 KiB
19 KiB
Git
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.
Contents
sync
Fetch <remote>/<branch> and bring the local branch up to date with it.
Synopsis
wikitool sync [--remote origin] [--branch main] [--confirm-rebase TOKEN]
Options
--remote <str> Git remote to reconcile against [default: origin]
--branch <str> Branch to reconcile [default: main]
--confirm-rebase TOKEN Clear the Rebase-Review Gate for the exact upstream
state and file overlap this token was issued for. The
token comes from the gate's own refusal output.
-h, --help Show this message and exit.
Examples
tools/wikitool sync
tools/wikitool sync --confirm-rebase <token> # re-run after exit 42, once the user approved
Behaviour
- Fetches
<remote>/<branch>, then: fast-forwards when only the remote moved; rebases the local commits on top when both sides moved but touched disjoint files; exits 42 (Rebase-Review Gate) when both sides touched the same file. - Files
wikitoolgenerates (kb/index.md,kb/log.md,kb/provenance.md, everykb/**/INDEX.md) never count as an overlap and never reach the gate. Where they are what stops git - uncommitted ones in the way of a fast-forward or rebase, or a rebase conflict in them - they are merged mechanically:kb/log.mdbecomes the incoming log plus the entries only this side appended, and the catalog andkb/provenance.mdare regenerated from the merged pages and left as an uncommitted change. When onlykb/log.mdstood in the way - an open log entry, nothing else generated - the catalog is not rebuilt: the incoming one stays, and just the local entries are appended again. A reconcile git can do on its own is unchanged and regenerates nothing. - Uncommitted changes that no incoming commit touches do not stop a rebase: they are carried through it (
git rebase --autostash) and come back unchanged. - Before anything is set aside, the working tree is stored as a commit under
refs/wikitool/reconcile-backup. A successful reconcile drops it; a failed one restores the working tree and names the ref. - A refused call performs no rebase attempt and leaves the branch where it was.
- The
--confirm-rebasetoken covers the exact upstream state and the set of files touched on both sides, generated files excluded; either one moving makes it stale. - Makes no commit, no push, and no forced operation of any kind.
- Three messages for a fetch that fails: no remote of that name, a remote that answers but has no such branch yet (a new, empty repository), and a remote that cannot be reached. All three exit 0 here;
publishstops on the first and the last. - Run it once at the start of a writing session.
Properties
- Changes files: yes
- Idempotent: yes
- Atomic: No - fetch, then at most one merge/rebase attempt, aborted cleanly on failure with the working tree restored; a success that merged generated files then rewrites the catalog, unless
kb/log.mdwas the only one - Counts toward the session call budget: yes
- Can reach the network: yes
- Gates: rebase-review - see exit codes and gates
Exit codes
0- success0- No remote configured - reported and skipped, not a failure0- The remote cannot be reached - reported and skipped, not a failure1- The automatic rebase hit a real conflict outside the generated files (git failed), orkb/log.mdwas edited rather than appended to; it is aborted cleanly and the working tree restored1- An uncommitted change - or an untracked file - sits on a path the incoming commits also change; nothing was changed42- Rebase-Review Gate:<remote>/<branch>moved and both sides changed the same file, generated files aside; the output lists the upstream commits, the overlapping files and their diff
See also
wikitool publish- runs the same reconcile before it commits and pushesinstructions/session-setup.md- where a session runssyncinstructions/gates.md- the gate procedure
publish
Reconcile with <remote>/<branch>, then stage all changes, commit, and push.
Synopsis
wikitool publish --message "<op>: <desc>" [--no-push] [--confirm TOKEN] [--confirm-rebase TOKEN] [--threshold N] [--remote origin] [--branch main] [--path P ...]
Options
--message <str> Commit message summary, e.g. 'ingest: docker-
cheatsheet' [required]
--push / --no-push [default: push]
--confirm TOKEN Clear the Mass-Update Gate for the exact changeset
this token was issued for. The token comes from the
gate's own refusal output - run without it first to
see the file list, show that output to the user, and
only pass this once they have approved it.
--confirm-rebase TOKEN Clear the Rebase-Review Gate raised by the pre-push
reconcile step. The token comes from that gate's own
refusal output - see `tools/wikitool sync`.
--threshold <int> Mass-Update Gate threshold: number of counted files
at/above which clearance is required. [default: 10]
--remote <str> Git remote to push to [default: origin]
--branch <str> Branch to push [default: main]
--path <str> Limit this publish to a path (repeatable). Lets a
large change be committed in reviewable batches
instead of one opaque commit - the Mass-Update Gate
then counts only the files in scope.
-h, --help Show this message and exit.
Examples
tools/wikitool publish --message "ingest: docker-cheatsheet"
tools/wikitool publish --confirm <token> --message "ingest: docker-cheatsheet" # re-run after a Mass-Update exit 42, once the user approved
tools/wikitool publish --confirm-rebase <token> --message "ingest: docker-cheatsheet" # re-run after a rebase-review exit 42, once the user approved
Behaviour
- Order: branch check and Publish-Remote Gate, then the reconcile with
<remote>/<branch>, then the Mass-Update Gate, thengit add -A, commit and push.--no-pushskips all but the Mass-Update Gate and the commit. - Without
--no-push, a remote that is not configured or cannot be reached ends the call with exit 1 at the reconcile - before the gate,git addand the commit, and also on a clean tree. Nothing is committed, the index and the working tree are unchanged, and the message names--no-pushas the way to a local commit. The nextpublishthat reaches the remote pushes that commit along with whatever is new. A remote that answers but has no<branch>yet (a new, empty repository) is not this case: the first publish of an instance commits and pushes as before. - Reconcile: fetches
<remote>/<branch>, fast-forwards when only the remote moved, rebases the local commits on top when both sides moved but touched disjoint files, and exits 42 (Rebase-Review Gate) when both sides touched the same file. A refused reconcile performs no rebase attempt. The--confirm-rebasetoken covers the exact upstream state and the set of files touched on both sides. - Generated files are never an overlap: where they are all that stops the reconcile, it merges them as
syncdoes (both sides' log entries kept, the catalog andkb/provenance.mdregenerated unless the log alone stood in the way) and carries uncommitted changes no incoming commit touches through the rebase. The proactive reconcile runs before staging, so this publish commits the regenerated files - with--pathtoo, see there; on the retry after a rejected push they get a commit of their own before the second push. - The push target must be the checked-out branch; this is checked before anything is staged. The unborn branch of a fresh
git init -b maincounts as checked out, so the first publish of a new instance works; a real detached HEAD is refused. - With nothing new to stage, a local commit the remote lacks is still pushed: one left behind by an earlier publish whose push failed, or every commit when the remote answers but does not have the branch yet (a new, empty remote repository).
- A rejected push that finds the remote unreachable on its one retry reports the original push error.
- A rejected push gets exactly one more reconcile-and-push; never more than one.
- Mass-Update Gate: counts the files that would be committed, refuses with exit 42 at
--threshold(default 10) or more, and prints a review report - a scale line (file count, total lines added/removed, status breakdown), attention notes where they apply (deletions by name, control-plane and harness-config touches, published pages, the largest single change, binaries), and every counted path grouped by area with its status and churn. The list is what the commit will hold: it is computed from a scratch copy of the index aftergit add -A, so a path that is staged as deleted and back in the working tree is not counted twice, and a rename counts as its old path deleted plus its new path added. The real index and the working tree are not touched, so a refused publish leaves both byte-identical. - Never counted and never shown for approval, but committed like everything else: anything under
work/, and the fileswikitoolgenerates itself (kb/index.md,kb/log.md,kb/provenance.md, everyINDEX.mdunderkb/). The refusal line accounts for both, by reason. - The
--confirmtoken covers each counted path, the blob id of its contents and the publish target: a different file list or edited contents need a new clearance. - Publish-Remote Gate: when
.wikitool-local.jsoncarriesremotes.allowed_push_urlsand the push URL of--remoteis not listed in it, exits 42 before the reconcile fetches anything. The URL is read withgit remote get-url --push, so a repointed remote does not pass on its name. An absent section means unrestricted; a malformed one is an error, not permission. - 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, everyINDEX.mdunderkb/) 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--confirmtoken and the re-run line cover the--pathgiven. Every other file outside--pathis left as it is.- Commit message:
--message, then aFiles changed:paragraph listing every committed path. When--messageends 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-trailersdecides 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.--messageis not part of any gate token. - Machine-data backup: with a
backupsection in.wikitool-local.jsonwhosemachine_datais true, a call that pushed then mirrors this machine's files that are not in git into<target>/<machine>/- the same step asbackup run. A failure there prints aWARNline 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 malformedbackupsection stops the call with exit 1 before anything is committed,--no-pushincluded. - Export after publish: every target of the
exportsection withafter_publish: trueis refreshed once a commit was made - the same step asexport run,--no-pushincluded, since the export reads the committedkb/. A failure there prints aWARNline with the reason and still exits 0, since the commit stands;export runrepeats it. A malformedexportsection stops the call with exit 1 before anything is committed, but only when some target setsafter_publish. - After a successful commit or push whose changed files include
tools/,types/,instructions/,AGENTS.mdor a path ending inCONTRACT.md, prints one reminder line: the phase past this point (an issue-body rewrite,docs/staleness, a changelog entry's accuracy) is not covered bydocs verify,instructions verifyorpytest. It is not a gate: no exit code change, nothing to clear, and silent for an ordinary content publish.
Properties
- Changes files: yes
- Idempotent: no
- Atomic: No - sequential git operations. Every gate runs before staging, except on the one retry of a rejected push, where the Rebase-Review Gate can exit 42 after the commit: nothing is pushed, and the re-run with
--confirm-rebasepushes that commit - Counts toward the session call budget: yes
- Can reach the network: yes
- Gates: mass-update, publish-remote, rebase-review - see exit codes and gates
Exit codes
0- success0- The machine-data backup after the push failed: aWARNline names the reason, and the commit and the push stand0- The export after the commit failed: aWARNline names the target and the reason, and the commit stands1- git failed -git add,git commit,git push, or the reconcile's automatic rebase (a conflict outside the generated files, an editedkb/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 freshgit initis not this case1- No--no-push, and the remote is not configured or cannot be reached; nothing was committed1---yes/-ywas passed - the flag does not exist and fails with an explicit error1- The settings files do not pass their check,remotes.allowed_push_urlsis not a list of strings, thebackupsection is malformed, or theexportsection is malformed while a target setsafter_publish; nothing was committed42- The remotes settings file of an earlier version is still there42- Mass-Update Gate:--threshold(default 10) or more counted files would be committed, or the--confirmtoken does not match this changeset42- Rebase-Review Gate:<remote>/<branch>moved and both sides changed the same file; the output lists the upstream commits, the overlapping files and their diff42- Publish-Remote Gate:remotes.allowed_push_urlsis set and the push URL of--remoteis not listed in it, or--remoteresolves to no push URL
See also
wikitool sync- the same reconcile on its own, without committing or pushinginstructions/gates.md- the gate procedureinstructions/setup-instance.md- the first publish of a new instancewikitool backup run- the machine-data backup on its ownwikitool export run- the page export 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
-h, --help Show this message and exit.
Examples
tools/wikitool backup init
Behaviour
- Reads the
backupsection of.wikitool-local.jsonand 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
originto<target>/gitwhen the checkout has noorigin. Anoriginthat already pushes there is left as it is; one that pushes anywhere else stops the command. - When
remotes.allowed_push_urlsexists and lacks the URLoriginpushes to, prints theremotessection 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
publishsends the history to the neworigin.
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- success1- Nobackupsection in.wikitool-local.json, or a malformed one - a target that is not absolute or lies inside the instance, amachine_namethat cleans to nothing or togit, anextrapath that resolves outside the instance or into.git/1-<target>/gitexists and is not a bare repository; nothing was changed1-originalready pushes to another URL; the message names both and nothing was changed
See also
wikitool backup run- the machine-data half of the backupwikitool publish- pushes to the bare repository and runs the machine-data backup after itdocs/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
-h, --help Show this message and exit.
Examples
tools/wikitool backup run
Behaviour
- Mirrors
.wikitool-local.json,ENVIRONMENT.mdif present, every file inincoming/but.gitkeep, and theextrapaths of thebackupsection into<target>/<machine>/, then writes the manifest.chemenu-backup.jsonthere: time, stack version, machine name, and per file its relative path, size and sha256. - Never mirrors
quarantine/,reports/,.wikitool-tools.json,tools/.venv/, the published skills or.git/- unless anextrapath 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.
publishruns the same step after every push whenmachine_datais 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- success1- Nobackupsection in.wikitool-local.json, or a malformed one - a target that is not absolute or lies inside the instance, amachine_namethat cleans to nothing or togit, anextrapath that resolves outside the instance or into.git/1-machine_datais false1-<target>/<machine>/is not empty and has no manifest, or its manifest cannot be read; nothing was written1- 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 repositorywikitool doctor- thebackupline reports the age of the last rundocs/how-to/back-up-to-a-synced-folder.md- the whole procedure, restoring included