feat: docs/ carries the operator's how-to guides, a configuration reference and the architecture and telemetry explanations carved out of README.md, INSTALL.md, INSTALL-MCP.md and EVALS.md; the last two retired (#190)
CI / verify (push) Successful in 6m17s
CI / pwsh (push) Successful in 1m59s
Release / release (push) Successful in 35s

Files changed:
- .gitea/workflows/ci.yml
- .gitignore
- .vibe/hooks.toml
- AGENTS.md
- CHANGES.md
- EVALS.md
- INSTALL-MCP.md
- INSTALL.md
- README.md
- VERSION
- docs/dev/development.md
- docs/explanation/README.md
- docs/explanation/architecture.md
- docs/explanation/language-boundaries.md
- docs/explanation/telemetry-and-evaluation.md
- docs/how-to/README.md
- docs/how-to/browse-with-obsidian.md
- docs/how-to/capture-repository-docs.md
- docs/how-to/export-guidelines.md
- docs/how-to/ingest-a-source.md
- docs/how-to/maintain-the-wiki.md
- docs/how-to/query-the-wiki.md
- docs/how-to/run-the-weekly-review.md
- docs/how-to/set-up-the-mcp-server.md
- docs/how-to/trace-and-score-sessions.md
- docs/how-to/troubleshoot.md
- docs/how-to/update-an-instance.md
- docs/reference/README.md
- docs/reference/commands/distribution-and-versioning.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/raw-material-and-uploads.md
- docs/reference/commands/telemetry.md
- docs/reference/commands/types-instructions-and-docs.md
- docs/reference/configuration.md
- instructions/dev/dev-setup.md
- instructions/dev/doc-pull-through.md
- instructions/dev/stack-build/SKILL.md
- instructions/dev/testing-conventions.md
- instructions/dev/version-parts.md
- instructions/setup-instance.md
- instructions/upgrade-instance.md
- reports/CONTRACT.md
- tools/.coveragerc
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/commands/dist_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/eval_cmd.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/upload_cmd.py
- tools/chemenu/commands/version_cmd.py
- tools/chemenu/evals/__init__.py
- tools/chemenu/evals/scorecard.py
- tools/chemenu/evals/trajectory.py
- tools/chemenu/telemetry/policy.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_git_publish.py
- tools/chemenu/tests/test_instructions_shell.py
- tools/chemenu/tests/test_pipeline_l0.py
- tools/chemenu/toc.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Opus 5.5 committed 2026-10-07 05:13:56 +02:00
1 parent cff7df4ffa
commit f9056c04f7
61 files changed
+2169 -1772

No files matched your search

+3
View File
@@ -13,6 +13,9 @@ written by hand.
start it, generated from their `SKILL.md`.
- [Page types](page-types.md) - every page type the stack ships for `kb/`, its subtypes, where
its pages are written and its required fields, generated from the type-specs.
- [Configuration](configuration.md) - the environment variables `wikitool` reads and the
per-checkout files an operator may create. Written by hand: it has no source to be generated
from yet.
The last two describe the stack's shipped defaults, which an instance may change or extend;
`tools/wikitool instructions list` and `tools/wikitool types describe <type>` show what one
@@ -55,7 +55,7 @@ tools/wikitool dist export ../my-wiki
**Behaviour**
- Writes a contentless, distributable copy of this repo's machinery into an empty or new `<target>` directory.
- Ships `AGENTS.md`/`README.md`/`EVALS.md` with any `dist:strip-start`...`dist:strip-end` marker region removed, `instructions/` (minus `instructions/dev/`), `types/` (the `root: kb` page type-specs, their schemas and their subtype templates `types/<type>.<value>.md` re-keyed as `.template`, the stack's own verbatim), `docs/` verbatim (minus `docs/dev/`), `tools/` (no venv/caches, and not the dev-only test suite `tools/chemenu/tests/` with its `pytest.ini`/`.coveragerc`), the `.github/hooks/`+`.vibe/` session-tracing config plus `.claude/settings.json`, `kb/CONTRACT.md` (no pages, no areas) and `VERSION`.
- Ships `AGENTS.md`/`README.md`/`INSTALL.md` with any `dist:strip-start`...`dist:strip-end` marker region removed, `instructions/` (minus `instructions/dev/`), `types/` (the `root: kb` page type-specs, their schemas and their subtype templates `types/<type>.<value>.md` re-keyed as `.template`, the stack's own verbatim), `docs/` verbatim (minus `docs/dev/`), `tools/` (no venv/caches, and not the dev-only test suite `tools/chemenu/tests/` with its `pytest.ini`/`.coveragerc`), the `.github/hooks/`+`.vibe/` session-tracing config plus `.claude/settings.json`, `kb/CONTRACT.md` (no pages, no areas) and `VERSION`.
- Ships `raw/` and `incoming/` as flat roots, each with a `.gitkeep` and no subdirectories. `incoming/.gitkeep` is trackable and survives becoming a git repository, so a plain clone gets the directory without any bootstrap step.
- Ships templates, never the filled files: `USER.md.template`/`SOUL.md.template`, `kb/CONVENTIONS.md.template`, and each collection's contract re-keyed as `kb/<name>/COLLECTION.md.template`. The filled `USER.md`/`SOUL.md`/`kb/CONVENTIONS.md`/`kb/<name>/COLLECTION.md`/`types/<page-type>.md`/`types/<page-type>.<value>.md` bind their instance; `find_leaks` refuses a plan carrying one.
- Writes a generated `.wikitool-release.json` stamp: version, export date, origin, and a sha256 per exported file - the base a later upgrade compares against.
@@ -242,7 +242,7 @@ tools/wikitool dist upgrade --latest --expect 8.0.0 --dry-run
- `wikitool version check` - finds out whether an update exists
- `wikitool version notes` - the notes of the release `--expect` should name
- `instructions/upgrade-instance.md` - the order after the swap
- `INSTALL.md` § "Version und Updates" - which release, whether to take it, where the tarball comes from
- `docs/how-to/update-an-instance.md` - which release, whether to take it, where the tarball comes from
- `wikitool migrate status` - the migrations the report names
## `version show`
@@ -323,7 +323,7 @@ tools/wikitool version check --json
- The only command whose whole job is the network call - `version notes` reaches the same feed too, but only as a fallback on a distributed instance, and `dist upgrade --latest` asks it which release to download.
- Never reached implicitly from another command (`dist upgrade` asks only when passed `--latest`), needs no key, and times out after `--timeout` seconds (default 10).
- The feed is `--url`, else `$WIKITOOL_UPDATE_URL`, else the release stamp's, else the built-in origin. `$WIKITOOL_UPDATE_TOKEN` is only needed if that feed is not readable anonymously.
- For `update` or `migration` it prints that applying the release is a separate, manual step (`INSTALL.md` § "Eine Instanz aktualisieren").
- For `update` or `migration` it prints that applying the release is a separate, manual step (`docs/how-to/update-an-instance.md`).
- Read-only; exempt from the Iteration Budget Gate.
**Properties**
@@ -344,7 +344,7 @@ tools/wikitool version check --json
- `wikitool dist upgrade` - applies the update this reports
- `wikitool version notes` - prints the release notes
- `INSTALL.md` § "Version und Updates" - what the operator decides before an update
- `docs/how-to/update-an-instance.md` - what the operator decides before an update
## `version notes`
+2 -2
View File
@@ -60,7 +60,7 @@ tools/wikitool doctor --json
- `instructions/setup-instance.md` - the setup steps most findings point back to
- `instructions/preflight.md` - what `tool-paths` and `install-dir` point back to
- `INSTALL.md` § "Konfiguration" - the per-checkout configuration files
- `EVALS.md` - telemetry state and caps
- `docs/reference/configuration.md` - the per-checkout configuration files
- `docs/explanation/telemetry-and-evaluation.md` - telemetry state and caps
- `instructions/session-setup.md` - setting `WIKITOOL_SESSION_ID`
<!-- /wikitool:reference-commands -->
@@ -401,7 +401,7 @@ tools/wikitool upload list --json
**See also**
- `wikitool upload show` - one submission's manifest
- `INSTALL-MCP.md` § "Schritt 7: Optional - den `submit`-Pfad freischalten"
- `docs/how-to/set-up-the-mcp-server.md` § "Optional: the submit path"
## `upload show`
+2 -2
View File
@@ -53,7 +53,7 @@ tools/wikitool eval sessions --json
**See also**
- `wikitool eval score` - scores one of them
- `EVALS.md` - how telemetry and evaluation work
- `docs/explanation/telemetry-and-evaluation.md` - how telemetry and evaluation work
## `eval score`
@@ -110,5 +110,5 @@ tools/wikitool eval score --session wiki-1727330000 --save
**See also**
- `wikitool eval sessions` - which session ids exist
- `EVALS.md` - the scoring levels
- `docs/explanation/telemetry-and-evaluation.md` - the scoring levels
<!-- /wikitool:reference-commands -->
@@ -355,7 +355,7 @@ tools/wikitool docs toc --apply
- Creates, refreshes or removes the generated table-of-contents region on every reference file over 100 lines: `AGENTS.md`, every stage contract, `kb/CONVENTIONS.md`, every `kb/*/COLLECTION.md`, every flat `instructions/**.md` file, every `types/*.md` type-spec, and every `docs/` page - each together with the `<name>.template` it ships as, where one exists.
- The scope is computed from those categories rather than listed, so a file added later is in scope without a code change.
- Out of scope: every `SKILL.md`, the human docs (`README.md`, `CHANGES.md`, `EVALS.md`, `INSTALL.md`, `tools/README.md`), and every subtype template `types/<type>.<value>.md` - `new` copies it into a page, so it never carries a region whatever its length.
- Out of scope: every `SKILL.md`, the human docs at the root and beside the code (`README.md`, `CHANGES.md`, `INSTALL.md`, `tools/README.md`), and every subtype template `types/<type>.<value>.md` - `new` copies it into a page, so it never carries a region whatever its length.
- Dry-run by default (prints which files would change); `--apply` writes. Idempotent: a re-run after an interruption converges rather than doubling a region.
- If `docs verify` still reports a stale region after `--apply`, the file's `##` headings changed in between; run it again.
+203
View File
@@ -0,0 +1,203 @@
# Configuration
The environment variables `wikitool` reads, and the per-checkout files an operator may create at the
root of an instance. None of them is needed for an instance to work: an instance installed from a
release runs against the origin's public release feed with no configuration at all.
This page is written by hand. Unlike the command reference, it has no single source in the code it
could be generated from yet, so a change to one of these files' shape has to be carried here
by whoever makes it.
<!-- wikitool:toc -->
## Contents
- [Environment variables](#environment-variables)
- [Telemetry](#telemetry)
- [Tool paths](#tool-paths)
- [Allowed push URLs](#allowed-push-urls)
- [Task tracker](#task-tracker)
- [Super Productivity](#super-productivity)
- [CalDAV](#caldav)
- [MCP submissions](#mcp-submissions)
<!-- /wikitool:toc -->
## Environment variables
| Variable | Purpose | Fallback |
|----------|---------|----------|
| `WIKI_AUTHOR` | Overrides the author name of new source pages | `git config user.name`. Without either, `new` stops with an `ERROR` |
| `WIKITOOL_SESSION_ID` | Scopes the Iteration Budget Gate to a task rather than a terminal, and names the directory a trace lands in | A session variable the harness sets itself, where one is known (for example `CLAUDE_CODE_SESSION_ID`), else the parent process id ([instructions/session-setup.md](../../instructions/session-setup.md)) |
| `WIKITOOL_UPDATE_URL` | The release feed `version check`, `version notes` and `dist upgrade --latest` ask | The value in `.wikitool-release.json`, else the origin's feed |
| `WIKITOOL_UPDATE_TOKEN` | A Gitea token for the release feed, sent only to downloads on the feed's own host | None. Not needed against the origin, only against a feed in a private repository |
| `WIKITOOL_TASKS_CONFIG` | Path to a tracker configuration that `task`, `review` and `doctor` read instead of `.wikitool-tasks.json`, for running one checkout against several trackers in turn | `.wikitool-tasks.json` at the root. A path to a file that does not exist is an error, never "no tracker configured" |
| `CHEMENU_ROOT` | Which corpus the package works on, for a caller outside the checkout itself | The checkout the package sits in. `tools/wikitool` behaves the same without it |
| `WIKI_TRACE` | `0`/`1` turns telemetry off or on, beating both the default and `.wikitool-telemetry.json` | The installation-form default ([below](#telemetry)) |
| `WIKI_TRACE_DIR` | Writes traces somewhere other than `reports/telemetry/` | `reports/telemetry/` |
| `WIKI_TRACE_CONTENT` | `0` keeps only lengths and digests of prompts and replies instead of their text | Text is kept |
| `WIKI_TRACE_MAX_CONTENT` | Per-attribute content cap in characters | 60 KiB |
| `WIKI_TRACE_MAX_SESSION_BYTES` | Byte cap per session trace; beats the file's `max_session_bytes` | 5 MiB |
| `WIKI_TRACE_KEEP_SESSIONS` | How many session directories retention keeps; beats the file's `keep_sessions` | 250 |
## Telemetry
**Telemetry is off in an instance.** Every instance carries the `.wikitool-release.json` of its
release, and that is how `chemenu.telemetry.policy` recognises that nobody asked for telemetry. The
same holds for every further clone of the instance, because the file is committed with the first
publish. Only a clone of the origin repository, used to develop the stack, has no stamp. There the
traces are the instrument the stack measures itself with, and they are **on**.
To turn the default around, create `.wikitool-telemetry.json` at the root. It is per checkout and
gitignored, with no `.template`, like `.wikitool-remotes.json`:
```json
{ "enabled": true, "max_session_bytes": 5242880, "keep_sessions": 250 }
```
All three keys are optional. `WIKI_TRACE` still overrides `enabled` in both directions and beats
this file. `wikitool doctor` reports the current state: on or off, why, and how much has been
recorded against both caps. What the caps do and what never reaches a trace:
[telemetry-and-evaluation.md](../explanation/telemetry-and-evaluation.md).
## Tool paths
**The preflight writes this file, not you.** `.wikitool-tools.json` at the root holds the absolute
paths of Python, git and ripgrep, as the preflight found them on this machine. `wikitool` starts git
and rg from there instead of from `PATH`. It is per checkout and gitignored, because a path on one
machine says nothing about the next.
If the file is missing or incomplete, `tools/wikitool` does not start (exit 42) and names the
preflight. If a tool sits somewhere the preflight does not look, name it:
`tools/preflight.sh --set rg=<path>`, or in PowerShell
`pwsh -NoProfile -ExecutionPolicy Bypass -File tools/preflight.ps1 --set rg=<path>`. Never edit the
file by hand. `doctor` reports under `tool-paths` whether every path still works.
## Allowed push URLs
`.wikitool-remotes.json` at the root restricts where `publish` may push, per checkout and
gitignored:
```json
{ "allowed_push_urls": ["git@example.org:me/my-wiki.git"] }
```
Without the file, any remote is allowed. With it, `publish` refuses with exit 42 (the Publish-Remote
Gate) before pushing to a URL not on the list. A malformed file is an error, not permission. Only you
edit this file. The gate has no token and no flag, and an agent that edits the list to get past a
refusal is opening a gate on its own initiative.
## Task tracker
**Optional.** The weekly review (`tools/wikitool review`, skill `gtd-weekly-review`) checks the
project pages under `kb/gtd/` against a task tracker. Which tracker that is goes in
`.wikitool-tasks.json` at the root. Like the telemetry and remotes files, it is per checkout and has
no `.template`, and it is **gitignored as soon as a token is in it**. Without the file, no tracker is
configured, which is a valid state, not an error. A broken file, on the other hand, is a `FAIL`: an
unreadable configuration must never pass as "no tracker".
```json
{
"schema": 1,
"provider": "superproductivity",
"thresholds": {
"stalled_waiting_days": 14,
"unpaged_project_weeks": 3,
"someday_stale_months": 5
},
"superproductivity": {
"access": "api",
"api_base_url": "http://127.0.0.1:3876",
"api_token": "<token from the SP settings>"
}
}
```
`provider` picks the adapter. The stack ships `superproductivity` and `caldav`.
The `thresholds` block holds the review's three thresholds (configuration, not schema): when a
waiting-for counts as overdue, how old a tracker project without a `kb/` page has to be before it is
reported, and when a someday item counts as stale. A value the provider cannot supply at all - a
waiting item with no follow-up date, a tracker project with no creation date - is not skipped silently
but reported as its own finding (`waiting_no_follow_up`/`project_age_unknown`).
The provider block of the same name holds the connection details.
### Super Productivity
`access` is **mandatory and has no fallback**. It chooses between two mutually exclusive ways in:
- **`access: "snapshot"`** for an instance run headless: it reads only the newest backup snapshot
under `backups_dir`. That works without the app running, but only reads. The tracker cannot be
written from there.
```json
"superproductivity": {
"access": "snapshot",
"backups_dir": "~/.config/superProductivity/backups"
}
```
- **`access: "api"`** for a desktop instance: it talks only to the local REST API. That answers only
while the app runs, but it gives the current state and carries the write path. `api_token` is
required, because every endpoint except `GET /health` demands `Authorization: Bearer <token>`.
The block names only the fields of its own way in. A `backups_dir` beside `access: "api"`, or an
`api_token` beside `access: "snapshot"`, is refused when the configuration is read, not ignored.
What can write:
- `tools/wikitool new project` creates a tracker project of the same name only with `access: "api"`,
and even there not automatically. The command stops (exit 42) and asks a human to create it, then
continues with `--resume`.
- `tools/wikitool task new` creates a single item without a `kb/` page.
- `tools/wikitool task close --id` marks an item done. It never deletes one.
With `access: "snapshot"`, all three refuse completely with exit 1, because the tracker is read-only
from there. `tools/wikitool task list --project` only reads, so it answers with either `access`.
### CalDAV
`caldav` is the standards-based second adapter (RFC 4791/5545). It is verified against Nextcloud
Tasks, with iOS *Reminders* as the mobile client, and built for that split: tick items off on the
phone, maintain them at the desk. Unlike Super Productivity, there is only one way in. CalDAV is
always a network access, so no `access` field is needed:
```json
"caldav": {
"url": "https://<host>/remote.php/dav/calendars/<user>/",
"username": "<login>",
"app_password": "<Nextcloud app password>",
"inbox_list": "Inbox",
"someday_list": "Someday",
"exclude_lists": ["<an existing list that is not a project>"]
}
```
- `url` points at the account's CalDAV calendar home set. It may be an alias - Nextcloud accepts a
short name there - because every later address comes only from the `href`s the server returns,
never from this URL joined with a name.
- `username` is the login name, which can differ from the user id in the URL. A Nextcloud app
password is recommended, not the account password.
- `inbox_list` and `someday_list` name the two fixed lists, exactly one of each per instance.
- `exclude_lists` leaves out existing plain task lists that are not projects. A list with a
`VEVENT` component never counts as a project anyway.
A project is a list whose only supported component is `VTODO`. `tools/wikitool new project` creates
it automatically with `MKCALENDAR` - without asking, unlike Super Productivity, because CalDAV has a
real create command for lists. The uniqueness check runs against **every** list in the account,
including excluded lists, the inbox, someday and mixed calendars. If a new name collides with any of
them, nothing is created and the collision is named. Renaming the existing list in Nextcloud stays a
manual step.
`task new` and `task close` work without restriction on `caldav`, which has no read-only mode like
`access: "snapshot"`. When ticking an item off, `task close` changes only `STATUS`, `COMPLETED`,
`PERCENT-COMPLETE`, `LAST-MODIFIED` and `DTSTAMP` on the existing `.ics` resource. Every other
property, including an unknown `X-` property or an alarm, is kept unchanged. A resource that changed
since it was read (an ETag conflict) is not written, and the command stops with exit 1. Nothing is
ever deleted. The lists of finished projects stay after archiving, because the adapter never deletes
a list. Remove them by hand in Nextcloud when you want to.
## MCP submissions
`.wikitool-upload.json` in the served corpus turns on the MCP read server's optional `submit` tool.
Its shape, and what the authentication in front of the server has to guarantee before you create
it, are in [Set up the MCP read server](../how-to/set-up-the-mcp-server.md#optional-the-submit-path).