export: export run writes selected kb/ pages as a derived, read-only version into configured target folders (markdown and command handlers, manifest, after_publish), raw accept also refuses manifest-listed files, doctor checks the section (#214); 10.0.0-beta.13
CI / verify (push) Successful in 9m2s
CI / pwsh (push) Successful in 2m48s
Release / release (push) Successful in 34s
Release / wiki-mirror (push) Skipped

Files changed:
- CHANGES.md
- VERSION
- 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/export-guidelines.md
- docs/how-to/export-to-a-synced-folder.md
- docs/reference/commands/README.md
- docs/reference/commands/exports.md
- docs/reference/commands/git.md
- docs/reference/commands/guideline-export.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/raw-material-and-uploads.md
- docs/reference/configuration.md
- docs/reference/exit-codes.md
- instructions/setup-instance.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/backup.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/export_cmd.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/raw/_common.py
- tools/chemenu/commands/raw/accept.py
- tools/chemenu/commands/raw/capture.py
- tools/chemenu/config_shapes.py
- tools/chemenu/guideline_export.py
- tools/chemenu/page_export.py
- tools/chemenu/reference_doc.py
- tools/chemenu/repo_capture.py
- tools/chemenu/tests/test_config_shapes.py
- tools/chemenu/tests/test_export_run.py

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Code committed 2026-10-13 05:53:48 +02:00
1 parent ecefe0a033
commit 99945c4841
33 files changed
+2316 -96

No files matched your search

+155
View File
@@ -0,0 +1,155 @@
# Export to a synced folder
Give a reader outside the repository a read-only version of part of `kb/`: the selected pages,
written as files into a folder - typically one a sync client such as OneDrive uploads, so that a
Microsoft 365 tenant can index them. The export is derived. It is regenerated from the committed
pages on every run, nobody edits it, and nothing in it flows back into the wiki. What the settings
look like: [configuration reference](../reference/configuration.md#export-to-a-folder).
<!-- wikitool:toc -->
## Contents
- [Pick the pages and the format](#pick-the-pages-and-the-format)
- [Set it up](#set-it-up)
- [What a run does to the folder](#what-a-run-does-to-the-folder)
- [Export after every publish](#export-after-every-publish)
- [Convert the pages with a program of your own](#convert-the-pages-with-a-program-of-your-own)
- [What does not come back in](#what-does-not-come-back-in)
- [Related](#related)
<!-- /wikitool:toc -->
## Pick the pages and the format
- **Which pages.** Only what a target's `include` selects is written; there is no "everything". A
selection is a list of `search` predicates that must all hold - `tags=shared`, `kind=system`,
`!draft` - and a page that fits any selection of the target is exported. Try a selection with
`tools/wikitool search --field tags=shared` first.
- **Which format.** Two ways, equally valid:
- `markdown` writes the pages as `.md` files. It needs nothing but the folder.
- `command` hands those files to a converter of your own and exports what it produces - Word
documents with `pandoc`, say.
Whether a Microsoft 365 tenant indexes `.md` files for Copilot is not settled for every tenant.
Try a small `markdown` target first; if the tenant does not pick the files up, the same pages go
through a `command` target as a format it does.
## Set it up
1. **Pick the folder**: a folder inside the synced folder, for example
`C:\Users\<you>\OneDrive - <company>\Chemenu-Lesefassung`. It must be empty or not exist yet,
and it must lie outside the instance, outside every other export target, outside every `intake`
folder and outside `backup.target`.
2. **Write the `export` section** into `.wikitool-local.json` at the root of the instance - by hand,
since its fields decide what leaves this machine and which program runs, and `config set`
refuses them:
```json
{
"export": {
"targets": {
"shared": {
"handler": "markdown",
"path": "C:\\Users\\<you>\\OneDrive - <company>\\Chemenu-Lesefassung",
"include": [["tags=shared"]],
"frontmatter": "summary",
"links": "relative",
"after_publish": false
}
}
}
}
```
`frontmatter` decides what follows the export marker in each file: `minimal` nothing, `summary`
(the default) the title, type, summary and modified date, `full` the page's whole frontmatter.
`links: relative` (the default) turns a link to an exported page into a relative Markdown link;
`links: text` leaves the page's name. A link to a page that is not exported is always plain text.
3. **Tell the agent:**
> Export the pages.
The agent runs `tools/wikitool export run`. It reports per target which pages are new, which
changed and which were removed, and how many stayed as they were. Name a target to run only that
one: `tools/wikitool export run shared`.
4. **Check it:** `tools/wikitool doctor`. The `export` line lists the targets; a `FAIL` there names
what is wrong with the section.
The export reads the committed pages. A `kb/` or `types/` with uncommitted changes is refused, so
every file names the commit its pages come from. Publish first.
## What a run does to the folder
The folder holds the pages and one file of the stack's own, `.wikitool-export.json`, which lists
what the last run wrote.
- **Only its own files.** A run removes a file only when it is listed and no longer exported, and a
folder only when the run created it. Anything else in the folder stays as it is.
- **Nobody edits an export.** A listed file that someone changed stops the target before anything is
written, and the message names the file. Move or delete it and run again. A listed file that is
missing is written again.
- **A folder that is not an export is refused.** A folder that holds files and no manifest is
somebody's folder; the run writes nothing into it.
- **An empty selection is an error.** A run that finds no page does not delete the earlier export.
- **An unchanged export stays untouched.** A run that has nothing to change writes nothing, not even
a modification time - the sync client has nothing to upload.
- **A growing selection needs no confirmation.** New pages are reported as new; read the list
before the sync client uploads them.
Targets are independent: one that fails is reported with its reason and the others still run; the
command then exits 1.
## Export after every publish
With `"after_publish": true` on a target, every `tools/wikitool publish` that committed refreshes
it afterwards - with `--no-push` too, since the export reads the commit, not the remote. If that
export fails, `publish` prints a `WARN` with the reason and still exits 0: the commit and the push
stand. Fix what the line names and run `tools/wikitool export run`; another `publish` does not
repeat it. A malformed `export` section stops `publish` before it commits, but only when some target
sets `after_publish`.
## Convert the pages with a program of your own
A target with `"handler": "command"` names an entry of `commands`:
```json
{
"export": {
"targets": {
"as-word": {
"handler": "command",
"command": "pandoc-docx",
"path": "C:\\Users\\<you>\\OneDrive - <company>\\Chemenu-Word",
"include": [["tags=shared"]]
}
},
"commands": {
"pandoc-docx": ["pwsh", "-NoProfile", "-File", "C:\\tools\\pandoc-docx.ps1"]
}
}
}
```
The pages are rendered into a staging directory first. The program runs without a shell, with stdin
closed and a limit of 300 seconds, and gets two more arguments: the directory with the Markdown
files and an empty directory for its output. On exit 0 the regular files it left there (below any
subdirectory, symlinks left out and reported) become the content of the target; the manifest and
all the rules above apply to them as to Markdown. Any other end - a non-zero exit, a timeout, a
program that does not start - leaves the target exactly as it was and prints the end of the
program's stderr. The staging directory is always removed.
## What does not come back in
An export is never a source. Every Markdown file starts with a frontmatter block whose first key is
`wikitool_export`, and `tools/wikitool raw accept` and `raw capture` refuse a file that carries it.
A converter may lose that key, so `raw accept` also refuses any file in `incoming/` that is byte
for byte one of the files in the manifest of a configured target - and warns, without refusing,
when a target has no manifest yet or the `export` section is broken.
## Related
- [Configuration reference](../reference/configuration.md#export-to-a-folder)
- [Export commands](../reference/commands/exports.md)
- [Export guidelines to captured repositories](export-guidelines.md) - the other export, one file
pushed into a repository
- [Back up to a synced folder](back-up-to-a-synced-folder.md) - the same kind of folder, for the
backup instead