Files
chemenu/docs/reference/commands/pages.md
T
torbenandClaude Code e9f4759727
CI / verify (push) Successful in 6m17s
CI / pwsh (push) Successful in 1m59s
Release / release (push) Successful in 34s
AGENTS.md § Gates is the one gate list; cli_contract.GATES and docs verify hold it
The gate list contradicted itself across AGENTS.md, instructions/gates.md and the
command records' gate names. The Rebase-Review Gate is now listed, `new project`'s
exit 42 is no longer a pseudo-gate, gates.md and the explanation page link to the one
list instead of counting, and a register plus a docs verify check keep the three in step.

Files changed:
- AGENTS.md
- CHANGES.md
- VERSION
- docs/explanation/why-gates-are-code.md
- docs/reference/commands/pages.md
- docs/reference/commands/types-instructions-and-docs.md
- docs/reference/exit-codes.md
- instructions/gates.md
- tools/CONTRACT.md
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/new_page.py
- tools/chemenu/errors.py
- tools/chemenu/mcp/server.py
- tools/chemenu/tests/test_cli_contract.py
- tools/chemenu/tests/test_docs_verify.py
- tools/chemenu/tests/test_git_publish.py
- tools/chemenu/tests/test_reference_doc.py

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

27 KiB

Pages

Creating, updating, renaming, moving and removing wiki pages, and filing and closing items in the task tracker.

Contents

new

Scaffold a new wiki page of any type.

Synopsis

  • wikitool new <type-name> --name "<Name>" [--type <path>] [--set field=value ...] - Any type; its type-spec decides fields, directory, title prefix and template.
  • wikitool new entity --name "<Name>" --set entity_type=<t> [--set tags=a,b] [--set related=X,Y] [--set sources="Source - Z"] [--set provenance=sourced|general|mixed] - Writes kb/entities/<subdir>/<Name>.md - <subdir> from entity_type via the type-spec's layout:
  • wikitool new concept --name "<Name>" --set concept_type=<t> ... - Writes kb/concepts/<subdir>/<Name>.md - <subdir> from concept_type via the type-spec's layout:
  • wikitool new source --name "<Name>" --set source_type=<t> --set raw_files=raw/notes/x.md,raw/notes/y.md --set fidelity=<f> --set authority=<a> [--set source_url=<URL>] [--set entities=A,B] [--set concepts=C,D] - Writes kb/sources/<subdir>/Source - <Name>.md (prefix added automatically; <subdir> from source_type via the type-spec's layout:) with a raw_files: list; rejects paths that don't exist
  • wikitool new comparison --name "X vs Y" --set entities=X,Y - Writes kb/comparisons/X vs Y.md
  • wikitool new project --name "<Name>" --set responsibility=<bereich> [--resume] - Writes kb/gtd/<bereich>/<Name>.md and, with a task tracker configured, a same-named tracker project

Options

Arguments:
  type_name  Type name, e.g. entity|concept|source|comparison (see `wikitool
             types list`)  [required]

Options:
  --name <str>  Page title (a type's title_prefix is added automatically)
                [required]
  --type <str>  Override the type-spec path (defaults to the one named by
                TYPE_NAME)
  --set <str>   Frontmatter field, repeatable: --set entity_type=tool --set
                tags=a,b. Array values split on commas (escape a literal one as
                \,); repeating --set for an array field appends instead of
                replacing
  --resume      `project` only: confirm a human has completed the manual tracker
                step an earlier HumanInterventionRequired refusal asked for, so
                this run continues to page creation instead of refusing the now-
                existing tracker project as a collision.
  -h, --help    Show this message and exit.

Examples

tools/wikitool new entity --name "Docker" --set entity_type=tool --set tags=containers
tools/wikitool new source --name "Docker Cheatsheet" --set raw_files=raw/2026/09/docker-cheatsheet.md --set fidelity=verbatim --set authority=reporting
tools/wikitool new project --name "Homelab migration" --set responsibility=infrastruktur --resume    # re-run after exit 42, once the user created the tracker project

Behaviour

  • A title becomes a file name, so it must be valid and unique on Windows and macOS as well as Linux, whichever platform runs the command and whichever root the type writes to. The rule is kb/CONTRACT.md § Titles are identifiers; it is checked on the full title, after title_prefix.
  • The target's path below the instance root may be at most 160 characters, counted in UTF-16 code units the way Windows counts MAX_PATH, so a Windows checkout without long paths keeps working. A longer one is refused, for every root, naming the length and how much shorter it has to get.
  • new never overwrites: a file already at the target - or one a case-insensitive file system would treat as the same file - is refused for every root, instructions/ included.
  • The type-spec drives everything: fields, directory (base_dir/layout), title prefix, and template. types list/types describe show what a type requires.
  • The body skeleton is types/<type>.<value>.md when that file exists, <value> being the page's subtype field value (e.g. types/entity.person.md for entity_type=person) - it replaces the type-spec's ## Template block whole. Without such a file, and for a type with no subtype field, the ## Template block is used as before.
  • A schema default: is materialized only for a field the schema also lists in required:.
  • --set is repeatable, and comma-separated values fill array fields. An element that itself contains a comma is written \,, or passed as its own repeated --set for that field - repeating an array field appends.
  • A capture field the type-spec requires (a source's fidelity/authority) must be passed with --set; new never guesses it and refuses unknown for it.
  • Produces structurally correct frontmatter and a body skeleton only - the prose (Description, Summary, judgment calls about relationships) is written afterwards.
  • new project: with .wikitool-tasks.json configuring a task tracker, also makes sure a same-named tracker project exists - one name, one identity. No tracker configured is a legitimate, explicitly announced state: page only.
  • new project: tracker before page. The tracker side is settled first, so a failure past that point leaves a tracker project with no page - a state review's check 3 reports - never a page with no tracker project.
  • new project: a name already taken, case-insensitively, in kb/ or the tracker is refused outright, naming where it was found, and creates nothing. For caldav the tracker check covers every list in the account, not only the ones counted as projects.
  • new project: a provider whose configured access path has no write path (Super Productivity's access: "snapshot") refuses entirely with exit 1, naming the access: "api" instance to use instead - neither the tracker project nor the page is created, and --resume behaves the same.
  • new project: a provider that could write but has no project-creation call of its own (Super Productivity's access: "api" - GET /projects exists, POST /projects does not) prints instructions for a human and exits 42, creating nothing. That is not one of the named gates, but the same exit code and the same handling. caldav never does this: MKCALENDAR creates the list, so a valid, non-colliding name always creates it.
  • --resume is how a later run tells the command a human has done what that message asked: it re-verifies through the tracker's read path before continuing to page creation, rather than trusting the claim, and exits 42 again if the tracker still does not have the project. --resume on any other type is refused.

Properties

  • Changes files: yes
  • Idempotent: no
  • Atomic: new <type>: Yes - single file write. new project: No for the tracker-configured case - a tracker-project write (or its human-clearance request) happens before the kb/ page write, so a failure between the two leaves a tracker project with no page (a state review's check 3 already reports), never a page with no tracker project. Still a single file write when no tracker is configured
  • Counts toward the session call budget: yes
  • Can reach the network: no

Exit codes

  • 0 - success
  • 1 - A page with this title already exists, the type is unknown, or a --set value is invalid
  • 1 - The title is not a valid file name (forbidden character, control character, reserved name such as CON or Index, trailing dot or space, empty), collides with another page by case or Unicode normalization, the target file already exists, or the target path is over the 160-character path budget
  • 1 - A raw_files path does not exist
  • 1 - A capture field the type-spec requires is missing, or set to unknown
  • 1 - --resume with a type other than project
  • 1 - new project: The name is already taken in the tracker (case-insensitively; for caldav against every list in the account)
  • 1 - new project: The configured access path has no write path (Super Productivity's access: "snapshot")
  • 1 - new project: The page write failed after the tracker project was confirmed to exist
  • 42 - new project: The provider cannot create the project itself (Super Productivity's access: "api"); the output says what a human has to create

See also

  • wikitool types describe <type> - what a type requires and where it lands
  • wikitool touch - changes a page's own frontmatter afterwards
  • wikitool task new - a tracker item without a page
  • docs/explanation/knowledge-and-commitment.md - why a project is a page and a tracker project

task new

Create one open item in the configured task tracker - never a kb/ page.

Synopsis

  • wikitool task new --title "<Title>" (--project "<Name>" | --inbox) [--waiting [--follow-up-at YYYY-MM-DD]] [--notes "..."]

Options

  --title <str>         The item's title. Stored verbatim, never parsed.
                        [required]
  --project <str>       An existing tracker project's name (matched case-
                        insensitively). This command never searches or guesses
                        one and never creates one - use `wikitool new project`
                        first if it does not exist yet. Exactly one of
                        --project/--inbox is required.
  --inbox               File into the tracker's own inbox instead of a project -
                        the deliberately chosen exit when no project fits, never
                        a stand-in for an omitted --project. An item filed here
                        is invisible to `wikitool review`, since every check
                        there is reached through a project name and the inbox
                        has none.
  --waiting             Tag the item WAITING - the review's check 2 reads this.
  --follow-up-at <str>  YYYY-MM-DD. Only meaningful together with --waiting - it
                        is never a due date and is refused without --waiting.
  --notes <str>         A freetext backref, e.g. to the kb/ source page this
                        item came from. Stored verbatim, never parsed.
  -h, --help            Show this message and exit.

Examples

tools/wikitool task new --title "Renew the TLS certificate" --project "Homelab migration"
tools/wikitool task new --title "Quote from the electrician" --project "Homelab migration" --waiting --follow-up-at 2026-10-05
tools/wikitool task new --title "Read the qmd README" --inbox --notes "from [[Source - qmd - GitHub Repository]]"

Behaviour

  • Creates one open item in the configured task tracker; never touches kb/.
  • Exactly one of --project or --inbox is required; an omitted --project refuses rather than silently falling into the inbox.
  • --project names an existing tracker project, matched case-insensitively - never created, and never searched or guessed.
  • --inbox files into the tracker's own inbox. An item filed there never appears in review, since every one of its checks reaches items through a project name.
  • --waiting sets the WAITING status review's waiting-overdue check reads. --follow-up-at is refused without --waiting - it is never a due date on its own.
  • --notes carries a freetext backref (e.g. to the kb/ source page the item came from), stored verbatim, never parsed.
  • The tracker configuration is read from .wikitool-tasks.json, or from the file WIKITOOL_TASKS_CONFIG names when that variable is set (so one checkout can be run against several trackers in turn). A set variable that names no file is an error, never "no tracker configured".
  • No .wikitool-tasks.json fails immediately with a "no tracker configured" message.
  • A provider whose configured access path has no write path (Super Productivity's access: "snapshot") refuses entirely with exit 1, naming the access: "api" instance to use instead.
  • Never exits 42. A --project matching no tracker project, or --waiting against a provider that cannot represent it right now (Super Productivity: the waiting tag does not exist yet, and its API cannot create tags), are ordinary exit-1 refusals that create nothing.
  • Not idempotent: every successful run creates another item.

Properties

  • Changes files: yes
  • Idempotent: no
  • Atomic: Yes - a single API call, made only once every precondition (the project's own id, the WAITING tag's own id) is confirmed to exist, so a missing one never leaves a half-written item behind
  • Counts toward the session call budget: yes
  • Can reach the network: yes

Exit codes

  • 0 - success
  • 1 - No .wikitool-tasks.json - no tracker configured
  • 1 - WIKITOOL_TASKS_CONFIG names a file that does not exist or is broken
  • 1 - Neither or both of --project/--inbox, or a --follow-up-at without --waiting or not YYYY-MM-DD
  • 1 - A --project name matching no tracker project
  • 1 - --waiting against a provider with no way to represent it right now (Super Productivity: the waiting tag does not exist)
  • 1 - A read-only access path (Super Productivity's access: "snapshot")

See also

  • wikitool task list - a project's open items and their ids
  • wikitool task close - marks an item done
  • wikitool new project - a project page and its tracker project
  • docs/explanation/knowledge-and-commitment.md - why commitments live in the tracker, not in kb/

task list

List a project's open items - id, title, and whether each carries the WAITING status.

Synopsis

  • wikitool task list --project "<Name>"

Options

  --project <str>  An existing tracker project's name (matched case-
                   insensitively).  [required]
  -h, --help       Show this message and exit.

Examples

tools/wikitool task list --project "Homelab migration"

Behaviour

  • Lists one tracker project's open items: id, title, and whether each carries the WAITING status.
  • The id source task close and review's waiting_overdue/someday_stale findings need, without running review first.
  • Works on every access path a provider offers, read-only ones included.
  • A --project matching no tracker project prints "No open items": the tracker read does not distinguish an empty project from an unknown one.
  • Read-only.

Properties

  • Changes files: no
  • Idempotent: yes
  • Atomic: Yes - read-only, nothing to leave half-written
  • Counts toward the session call budget: yes
  • Can reach the network: yes

Exit codes

  • 0 - success
  • 0 - A --project matching no tracker project - prints "No open items", not an error
  • 1 - No .wikitool-tasks.json - no tracker configured
  • 1 - WIKITOOL_TASKS_CONFIG names a file that does not exist or is broken

See also

  • wikitool task close - closes an item by the id listed here
  • wikitool review - the findings that name items

task close

Mark one tracker item done - never delete it.

Synopsis

  • wikitool task close --id <item-id>

Options

  --id <str>  The tracker's own item id, e.g. from `task list` or `wikitool
              review`'s waiting_overdue/someday_stale findings - never a title.
              [required]
  -h, --help  Show this message and exit.

Examples

tools/wikitool task close --id <item-id>

Behaviour

  • Marks one tracker item done. It never deletes or moves an item - the only closing write this stack makes.
  • --id is the provider's own item id, from task list or a review finding - never a title.
  • The tracker configuration is read from .wikitool-tasks.json, or from the file WIKITOOL_TASKS_CONFIG names when that variable is set (so one checkout can be run against several trackers in turn). A set variable that names no file is an error, never "no tracker configured".
  • No .wikitool-tasks.json fails with a "no tracker configured" message.
  • A provider whose configured access path has no write path (Super Productivity's access: "snapshot") refuses entirely with exit 1, naming the access: "api" instance to use instead.
  • Never exits 42.

Properties

  • Changes files: yes
  • Idempotent: yes
  • Atomic: Yes - a single API call; an unknown id is rejected by the provider itself (Super Productivity: 404 TASK_NOT_FOUND) before anything is written
  • Counts toward the session call budget: yes
  • Can reach the network: yes

Exit codes

  • 0 - success
  • 1 - No .wikitool-tasks.json - no tracker configured
  • 1 - WIKITOOL_TASKS_CONFIG names a file that does not exist or is broken
  • 1 - An --id matching no tracker item right now
  • 1 - A read-only access path (Super Productivity's access: "snapshot")

See also

  • wikitool task list - where the id comes from
  • wikitool review - findings that carry item ids

touch

Bump a page's modified: date and optionally rewrite its other frontmatter fields.

Synopsis

  • wikitool touch --page "<Title>" [--summary "..."] [--provenance <v>] [--date YYYY-MM-DD] [--set field=value ...] [--add field=value ...] [--remove field=value ...] [--no-date] [--dry-run]

Options

  --page <str>        Exact page title, e.g. 'Docker Cheatsheet'  [required]
  --summary <str>     Replace the page's 1-line summary
  --provenance <str>  Replace the page's provenance marker
                      (sourced|general|mixed)
  --date <str>        Date to record (YYYY-MM-DD). `modified:` defaults to
                      today; a source's `date:` is its publication date and
                      changes only when given here.
  --set <str>         Replace a frontmatter field, repeatable: --set tags=a,b.
                      Array values split on commas (escape a literal one as \,);
                      repeating --set for one array field appends within this
                      call. Page-reference fields belong to `xref`, not here
  --add <str>         Append elements to an array field without naming the whole
                      list: --add tags=x. Elements already present are left
                      alone
  --remove <str>      Drop elements from an array field: --remove tags=x.
                      Removing an absent element succeeds and says so
  --no-date           Only change the given fields; leave the modified/date
                      field alone
  --dry-run           Preview the new frontmatter instead of writing
  -h, --help          Show this message and exit.

Examples

tools/wikitool touch --page "Docker" --summary "Container runtime and image format"
tools/wikitool touch --page "Docker" --add tags=containers --no-date
tools/wikitool touch --page "Source - Docker Cheatsheet" --date 2026-09-01 --dry-run

Behaviour

  • Bumps modified: to today and optionally rewrites any other field the page's type declares.
  • --summary/--provenance are shorthands; --set reaches every other field and replaces its value, while --add/--remove change single elements of an array field (removing an absent element succeeds and says so).
  • Repeating --set for one array field appends within the call, and \, is a literal comma.
  • Refused, naming the command that owns them instead: type: (the page-lifecycle procedure) and the page-ref arrays related:/sources:/entities:/concepts: (xref). Everything else the schema declares is settable, and an unknown field is refused with the list of fields the page actually has.
  • Schema-validates the fields it writes; raw_files: entries must exist on disk.
  • A source page declares date: instead of modified:: the publication date of the raw material. It is never bumped to today and changes only when --date names a value explicitly.
  • --no-date changes only the given fields and leaves the date alone; --dry-run previews the new frontmatter without writing.
  • Safe to re-run as-is: --set and --add are idempotent, and --remove of an already-absent element succeeds while reporting it.

Properties

  • Changes files: yes
  • Idempotent: yes
  • Atomic: Yes - single file write, and every refusal happens before it
  • Counts toward the session call budget: yes
  • Can reach the network: no

Exit codes

  • 0 - success
  • 1 - Page not found
  • 1 - An invalid value for a field it writes, or a raw_files: path that doesn't exist
  • 1 - A field owned by another command (type:, a page-ref array) or absent from the type's schema
  • 1 - --add/--remove on a non-array field

See also

  • wikitool xref add / wikitool xref remove - the page-ref arrays
  • instructions/page-lifecycle.md - changing a page's type:

rename

Rename a page, or repoint references that name a page that never existed.

Synopsis

  • wikitool rename --from "<Old>" --to "<New>" [--dry-run]

Options

  --from <str>  Current page title, exactly as it appears  [required]
  --to <str>    New page title  [required]
  --dry-run     List what would change instead of writing
  -h, --help    Show this message and exit.

Examples

tools/wikitool rename --from "act_runner" --to "Act Runner" --dry-run
tools/wikitool rename --from "Docker Engine" --to "Docker"

Behaviour

  • Renames a page and repoints every reference to it: body [[wikilinks]] (aliases and anchors preserved), a [^cite-id] whose id was derived from the old title (refreshed to match the new one, both in its Footnotes definition and every reference to it), the page's own H1, and every page-ref frontmatter array declared by the type's page_ref_fields:.
  • If --from is not a page but is referenced, it instead repoints those references onto the existing --to page and moves nothing - the fix for a reference spelled act_runner when the page is Act Runner.
  • Each page's rewrite is idempotent, so a re-run as-is is safe. If a write fails midway, nothing is renamed on disk and the error lists what was updated.
  • --dry-run lists every page it would change; run it first to see the blast radius.
  • Only --to is checked against the title rule and the path budget (160 UTF-16 code units for the whole path below the instance root). A page whose current title breaks either (lint's Unportable Titles and Long Paths) can always be renamed away from it, and a title that differs from the page's own only by case (Foo to FOO) is allowed.

Properties

  • Changes files: yes
  • Idempotent: yes
  • Atomic: No - one write per referencing page, then the file move
  • Counts toward the session call budget: yes
  • Can reach the network: no

Exit codes

  • 0 - success
  • 1 - --from equals --to
  • 1 - Neither --from nor --to is a page
  • 1 - The --to title is already taken - also by a page that differs only in case or Unicode normalization, or by a file in the page's directory - or is not a valid file name, or would put the page's path over the path budget (see kb/CONTRACT.md § Titles are identifiers)
  • 1 - A page write failed partway; nothing was renamed on disk

See also

  • instructions/page-lifecycle.md - renaming, moving and deleting a page
  • wikitool move - changes a page's directory, not its title
  • wikitool rm - deletes a page

rm

Delete a page and mechanically de-link it from the rest of the wiki.

Synopsis

  • wikitool rm --page "<Title>" [--yes] [--dry-run]

Options

  --page <str>  Exact title of the page to delete  [required]
  -y, --yes     Confirm deletion of a page that other pages still reference.
                Only pass this after a human has reviewed the inbound list -
                never set it automatically.
  --dry-run     List what would change instead of writing
  -h, --help    Show this message and exit.

Examples

tools/wikitool rm --page "Old Draft" --dry-run
tools/wikitool rm --page "Old Draft" --yes    # after the user approved the inbound list

Behaviour

  • Deletes a page and de-links it from the rest of the wiki: strips page-ref array entries and bare - [[Title]] / - **label:** [[Title]] bullets pointing at it.
  • Leaves prose references and inline citations in place and reports them afterwards; those are an editorial fix, not a reason to retry.
  • Refuses without --yes while other pages still reference it, listing them.
  • If a de-link write fails midway, the page is not deleted, so nothing is orphaned and a re-run is safe.
  • --dry-run lists what would change, without writing.
  • Not idempotent: once the page is gone, a second run finds nothing to delete.

Properties

  • Changes files: yes
  • Idempotent: no
  • Atomic: No - one write per referencing page, then the delete
  • Counts toward the session call budget: yes
  • Can reach the network: no

Exit codes

  • 0 - success
  • 1 - Page not found
  • 1 - Other pages still reference it and --yes was not passed
  • 1 - A de-link write failed partway; the page was not deleted

See also

  • instructions/page-lifecycle.md - when a page is deleted rather than renamed
  • wikitool rename - repoints references instead of removing them

move

Move a page (or every misplaced page) to the directory its type-spec computes.

Synopsis

  • wikitool move --page "<Title>"
  • wikitool move --reconcile [--dry-run]

Options

  --page <str>  Exact title of the page to move to its computed location
  --reconcile   Move every page under kb/ that is not at its computed location
  --dry-run     List what would move without writing
  -h, --help    Show this message and exit.

Examples

tools/wikitool move --page "Docker"
tools/wikitool move --reconcile --dry-run
tools/wikitool move --reconcile

Behaviour

  • Moves a page to the directory its type-spec computes for its current frontmatter (base_dir + layout, the same rule new places a page by) - never to a hand-chosen destination; there is no --to <dir>.
  • A destination whose path would be over the path budget (160 UTF-16 code units below the instance root) is refused, and --reconcile skips such a page and names it, as it does for an occupied destination - wikitool rename the page to a shorter title.
  • --reconcile applies it corpus-wide: every misplaced page moves in one call, and a second run reports nothing left to do. It fixes lint's Misplaced Pages (advisory) and Nested Pages (hard) findings.
  • Neither mode touches a body or a frontmatter field, and the page's title - its only identity in the wiki - never changes; only the file moves.
  • A directory a move empties is removed with it, so a page nested below its area leaves no leftover directory behind.
  • A page already at its computed location is reported and left alone, and --reconcile only re-moves what is still misplaced, so a re-run is safe.
  • --dry-run (with --reconcile) lists the moves; run it first to see the blast radius.
  • Run wikitool index rebuild afterwards.

Properties

  • Changes files: yes
  • Idempotent: yes
  • Atomic: --page: yes, a single file move. --reconcile: no - one file move per page, each idempotent
  • Counts toward the session call budget: yes
  • Can reach the network: no

Exit codes

  • 0 - success
  • 1 - Neither or both of --page/--reconcile given
  • 1 - The named page is not found, or has no type: to compute a placement from
  • 1 - The destination already holds an entry with the same name, or one that differs only in case or Unicode normalization (a pre-existing duplicate-stem collision), or its path would be over the path budget - refused rather than silently skipped
  • 1 - --reconcile failed partway

See also

  • wikitool lint - reports Misplaced and Nested Pages
  • wikitool index rebuild - run after moving
  • instructions/page-lifecycle.md - moving, renaming and deleting a page