Every settings field declares its tier; a value in the wrong file is an error naming
file, key and tier. A field naming a program or affecting a gate cannot be declared
instance. Secrets are references only: {"ref": "<name>"} via WIKITOOL_SECRET_<NAME> or
a user-only secrets file, {"ref": "op://..."} via op read (locked 1Password: exit 42).
The preflight records op as an optional tool. doctor gains one line per tier, docs
verify checks a committed wikitool.json for plaintext secrets, CI resolves a real
op:// value through 1password/load-secrets-action. No feature reads its settings
this way yet; without the two files every other command is unchanged.
Files changed:
- .gitea/workflows/ci.yml
- .gitignore
- AGENTS.md
- CHANGES.md
- INSTALL.md
- VERSION
- docs/explanation/README.md
- docs/explanation/configuration-tiers.md
- docs/how-to/README.md
- docs/how-to/use-1password-for-settings.md
- docs/reference/commands/README.md
- docs/reference/commands/configuration.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/types-instructions-and-docs.md
- docs/reference/configuration.md
- docs/reference/exit-codes.md
- instructions/dev/doc-pull-through.md
- instructions/dev/testing-conventions.md
- instructions/preflight.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/_util.py
- tools/chemenu/commands/config_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/config.py
- tools/chemenu/config_shapes.py
- tools/chemenu/prerequisites.py
- tools/chemenu/settings.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_preflight.py
- tools/chemenu/tests/test_preflight_pwsh.py
- tools/chemenu/tests/test_settings.py
- tools/chemenu/toolpaths.py
- tools/preflight.ps1
- tools/preflight.sh
- tools/prerequisites.txt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
396 lines
21 KiB
Markdown
396 lines
21 KiB
Markdown
# Configuration
|
|
|
|
The environment variables `wikitool` reads, the per-checkout files an operator may create at the
|
|
root of an instance, and the two tiered settings files. 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.
|
|
|
|
The shape of each file - its fields, what an absent or a malformed file means, an example - is
|
|
generated from the record `wikitool` itself reads the file with, so it cannot describe a field the
|
|
tool does not take. What a setting does around it is written by hand.
|
|
|
|
Three more files at the root are written by `wikitool` and never by hand: `.wikitool-release.json`,
|
|
`.wikitool-kb.json` and `.wikitool-tools.json` ([AGENTS.md invariant 1](../../AGENTS.md#invariants)).
|
|
The last one has its own section [below](#tool-paths), because the preflight that writes it is
|
|
something you run.
|
|
|
|
<!-- 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)
|
|
- [Tiered settings](#tiered-settings)
|
|
<!-- /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" |
|
|
| `WIKITOOL_SECRET_<NAME>` | The value behind a settings reference `{"ref": "<name>"}`, for CI and containers - `<NAME>` is the name upper-cased | The secrets file in the user's configuration directory ([below](#tiered-settings)) |
|
|
| `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`.
|
|
|
|
<!-- wikitool:reference-config-telemetry -->
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `schema` | any | no | - | Accepted and not read. Conventionally `1`; no version of this file is told apart by it yet. |
|
|
| `enabled` | boolean | no | the installation-form default | Telemetry on or off. `WIKI_TRACE` beats it in both directions. Any other value is read by its truthiness, so `"no"` means on. |
|
|
| `max_session_bytes` | positive integer | no | `5242880` | Byte cap per session trace. `WIKI_TRACE_MAX_SESSION_BYTES` beats it. A number written as a string is accepted. |
|
|
| `keep_sessions` | positive integer | no | `250` | How many session directories retention keeps. `WIKI_TRACE_KEEP_SESSIONS` beats it. A number written as a string is accepted. |
|
|
|
|
- **Absent:** The installation-form default applies: on in a clone of the origin repository, off in an instance.
|
|
- **Malformed:** Never an error. Unreadable JSON or a non-object counts as an absent file, and a cap that is not a positive integer as an absent cap. `doctor` reports each such deviation as a `WARN` under `telemetry`, naming the field.
|
|
- **Unknown keys:** Ignored; `doctor` reports them as a `WARN`.
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"max_session_bytes": 5242880,
|
|
"keep_sessions": 250
|
|
}
|
|
```
|
|
<!-- /wikitool:reference-config-telemetry -->
|
|
|
|
`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 - and of the
|
|
1Password CLI `op` when it is installed. `op` is optional: the preflight records it when it finds
|
|
it, reports `ABSENT` when it does not, and never asks for it. Only an `op://` reference in the
|
|
[tiered settings](#tiered-settings) needs it. `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.
|
|
|
|
<!-- wikitool:reference-config-remotes -->
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `schema` | any | no | - | Accepted and not read. Conventionally `1`; no version of this file is told apart by it yet. |
|
|
| `allowed_push_urls` | array of strings | yes | - | The push URLs `publish` may write to, compared with the URL the remote resolves to for a push - not with its name. An empty list allows no push at all. |
|
|
|
|
- **Absent:** Any remote is allowed; the Publish-Remote Gate does not apply.
|
|
- **Malformed:** `publish` stops with an error before committing anything. A broken file is never read as "no restriction".
|
|
- **Unknown keys:** Ignored.
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"schema": 1,
|
|
"allowed_push_urls": [
|
|
"<url>"
|
|
]
|
|
}
|
|
```
|
|
<!-- /wikitool:reference-config-remotes -->
|
|
|
|
With the file, `publish` refuses with exit 42 (the Publish-Remote Gate) before pushing to a URL not
|
|
on the list. 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**.
|
|
|
|
<!-- wikitool:reference-config-tasks -->
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `schema` | any | no | - | Accepted and not read. Conventionally `1`; no version of this file is told apart by it yet. |
|
|
| `provider` | string | yes | - | Which adapter the review goes through. The provider's own settings sit in a section of the same name. |
|
|
| `thresholds` | object | yes | - | The weekly review's three thresholds. |
|
|
| `thresholds.stalled_waiting_days` | positive integer | yes | - | A waiting-for item older than this many days counts as overdue. A number written as a string is accepted. |
|
|
| `thresholds.unpaged_project_weeks` | positive integer | yes | - | A tracker project with no `kb/` page is reported once it is older than this many weeks. A number written as a string is accepted. |
|
|
| `thresholds.someday_stale_months` | positive integer | yes | - | A someday/maybe item untouched for this many months counts as stale. A number written as a string is accepted. |
|
|
|
|
- **Absent:** No tracker is configured - a valid state. The weekly review has nothing to check against.
|
|
- **Malformed:** An error, and `doctor` reports `FAIL`. A broken file is never read as "no tracker configured".
|
|
- **Unknown keys:** Ignored, so the section of a provider not chosen right now can stay in the file.
|
|
|
|
**The `superproductivity` section.** Connection settings for the Super Productivity adapter.
|
|
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `access` | string | yes | - | Which way in: `api`, the local REST API (reads the current state and carries the write path), or `snapshot`, the newest backup snapshot (read-only). |
|
|
|
|
With `access: "api"`:
|
|
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `api_base_url` | string | no | `"http://127.0.0.1:3876"` | Where the app's REST API listens. An empty value means the default. |
|
|
| `api_token` | string | yes, not empty | - | The token from the app's settings. |
|
|
|
|
With `access: "snapshot"`:
|
|
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `backups_dir` | string | yes, not empty | - | The directory the app writes its backup snapshots to; `~` is expanded. |
|
|
|
|
- **Unknown keys:** Rejected: a section names only one access path's own fields, so a `backups_dir` beside `access: "api"` is an error, not ignored.
|
|
|
|
```json
|
|
{
|
|
"superproductivity": {
|
|
"access": "api",
|
|
"api_base_url": "http://127.0.0.1:3876",
|
|
"api_token": "..."
|
|
}
|
|
}
|
|
```
|
|
|
|
```json
|
|
{
|
|
"superproductivity": {
|
|
"access": "snapshot",
|
|
"backups_dir": "~/.config/superProductivity/backups"
|
|
}
|
|
}
|
|
```
|
|
|
|
**The `caldav` section.** Connection settings for the CalDAV adapter.
|
|
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `url` | string | yes, not empty | - | The account's CalDAV calendar home set. A trailing `/` is added when missing. |
|
|
| `username` | string | yes, not empty | - | The login name, which can differ from the user id in the URL. |
|
|
| `app_password` | string | yes, not empty | - | An app password is recommended over the account password. |
|
|
| `inbox_list` | string | yes, not empty | - | The name of the one inbox list. |
|
|
| `someday_list` | string | yes, not empty | - | The name of the one someday/maybe list. |
|
|
| `exclude_lists` | array of strings | no | `[]` | Existing plain task lists that are not projects. |
|
|
|
|
- **Unknown keys:** Rejected.
|
|
|
|
```json
|
|
{
|
|
"caldav": {
|
|
"url": "https://<host>/remote.php/dav/calendars/<user>/",
|
|
"username": "<login>",
|
|
"app_password": "...",
|
|
"inbox_list": "Inbox",
|
|
"someday_list": "Someday",
|
|
"exclude_lists": [
|
|
"..."
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
A complete example:
|
|
|
|
```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": "..."
|
|
}
|
|
}
|
|
```
|
|
<!-- /wikitool:reference-config-tasks -->
|
|
|
|
The `thresholds` block is configuration, not schema. 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`).
|
|
|
|
### 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.
|
|
|
|
- **`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>`.
|
|
|
|
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.
|
|
|
|
- `url` 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.
|
|
- `inbox_list` and `someday_list` name the two fixed lists, exactly one of each per instance.
|
|
- A list with a `VEVENT` component never counts as a project, so `exclude_lists` is needed only for
|
|
plain task lists.
|
|
|
|
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.
|
|
What the authentication in front of the server has to guarantee before you create it is in
|
|
[Set up the MCP read server](../how-to/set-up-the-mcp-server.md#optional-the-submit-path).
|
|
|
|
<!-- wikitool:reference-config-upload -->
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `schema` | any | no | - | Accepted and not read. Conventionally `1`; no version of this file is told apart by it yet. |
|
|
| `identity_header` | string | no | `"X-Forwarded-User"` | The request header the authenticating middleware sets to the submitter's identity on every request. An empty value means the default. |
|
|
| `max_bytes` | positive integer | yes | - | Largest single submission, in bytes. A number written as a string is accepted. |
|
|
| `allowed_extensions` | array of strings | yes | - | The file extensions `submit` accepts, each starting with `.`. Compared case-insensitively. Entries are read as strings and lower-cased; duplicates collapse. |
|
|
| `quota` | object | yes | - | Per-submitter limits over any rolling 24 hours. |
|
|
| `quota.submissions_per_day` | positive integer | yes | - | Submissions one submitter may make. A number written as a string is accepted. |
|
|
| `quota.bytes_per_day` | positive integer | yes | - | Bytes one submitter may submit. A number written as a string is accepted. |
|
|
|
|
- **Absent:** The `submit` tool is not registered: the write path does not exist.
|
|
- **Malformed:** An error. The MCP server does not start and `doctor` reports `FAIL`. A broken file is never read as "no limits".
|
|
- **Unknown keys:** Ignored.
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"schema": 1,
|
|
"identity_header": "X-Forwarded-User",
|
|
"max_bytes": 10485760,
|
|
"allowed_extensions": [
|
|
".md",
|
|
".pdf"
|
|
],
|
|
"quota": {
|
|
"submissions_per_day": 20,
|
|
"bytes_per_day": 52428800
|
|
}
|
|
}
|
|
```
|
|
<!-- /wikitool:reference-config-upload -->
|
|
|
|
Size and quota are your deployment's decision, not defaults worth copying blindly.
|
|
|
|
## Tiered settings
|
|
|
|
Two files at the root hold the settings of the features that read them this way, and every field
|
|
declares the tier it belongs to:
|
|
|
|
| Tier | File | Holds |
|
|
|------|------|-------|
|
|
| `instance` | `wikitool.json`, committed | What belongs to the corpus and is the same in every clone |
|
|
| `checkout` | `.wikitool-local.json`, gitignored | What is true only for this clone on this machine |
|
|
| `secret` | neither | Tokens and passwords - both files hold only a reference |
|
|
|
|
Each file is a JSON object of sections, one per feature, beside two keys of its own:
|
|
|
|
```json
|
|
{
|
|
"schema": 1,
|
|
"instance_id": "6f1c0e52-3d1b-4b8e-9a51-2f0e7d1c9b44",
|
|
"<section>": {"<field>": "<value>"}
|
|
}
|
|
```
|
|
|
|
`instance_id` sits in `wikitool.json` only. The first `wikitool config set` creates the file and
|
|
the id; the id names the directory of the secrets file below. No feature reads its settings this
|
|
way yet, so this version declares no section: `config set` names the sections it knows, and
|
|
`doctor` reports a section it does not read as a `WARN`.
|
|
|
|
**One place per value.** A value in the file its tier does not name is an error naming the file,
|
|
the key and the right tier - never an override. The same holds for a key set in both files.
|
|
|
|
**References.** A field of tier `secret` takes only a reference; a field marked private - a host
|
|
name, an internal URL - takes a plain value in `.wikitool-local.json` or a reference in either
|
|
file. No other field takes one.
|
|
|
|
| Reference | Resolves through |
|
|
|-----------|------------------|
|
|
| `{"ref": "<name>"}` - lower-case letters, digits and single `_` | `WIKITOOL_SECRET_<NAME>`, else the key `<name>` in the secrets file |
|
|
| `{"ref": "op://<vault>/<item>/<field>"}` | `op read`, the 1Password CLI the preflight recorded |
|
|
|
|
The secrets file is `~/.config/chemenu/<instance_id>/secrets.json` (`$XDG_CONFIG_HOME` instead of
|
|
`~/.config` when it is set; `%APPDATA%\chemenu\<instance_id>\secrets.json` on Windows), a JSON object of
|
|
names to strings. Outside Windows it must be readable by its owner only (`chmod 600`); a file
|
|
others can read is refused.
|
|
|
|
A reference is resolved when a command asks for that value, never when the files are read. A name
|
|
nobody provides, an `op` that is not installed, or an item 1Password does not have ends the command
|
|
with exit 1; a 1Password that is locked, signed out or waiting for an approval ends it with exit 42,
|
|
for a human to unlock. Setting 1Password up: [use-1password-for-settings.md](../how-to/use-1password-for-settings.md).
|
|
|
|
**Never in the committed file:** a field that names a program to run or affects a gate - not even
|
|
as a reference. `config set` does not write such a field either; the user edits
|
|
`.wikitool-local.json` by hand, and `doctor` checks it afterwards.
|
|
|
|
`wikitool doctor` reports one line per tier - `settings-instance`, `settings-checkout`,
|
|
`settings-secrets` - and for the references only whether they resolve. `docs verify` holds a
|
|
committed `wikitool.json` to the placement rules above, a plain secret or private value above
|
|
all. Neither file ships with `dist export`. Why the tiers exist, and what keeping secrets out of
|
|
the tree does not protect against: [configuration-tiers.md](../explanation/configuration-tiers.md).
|