Files
chemenu/instructions/session-setup.md
T
torbenandClaude Opus 5.5 d4638bacde
CI / verify (push) Successful in 5m51s
CI / pwsh (push) Successful in 1m58s
Release / release (push) Successful in 35s
fix: publish/sync merge generated files mechanically and carry non-overlapping uncommitted work through a rebase (#180)
Overlap only in kb/index.md, kb/log.md, kb/provenance.md and kb/**/INDEX.md no longer
fails a reconcile or reaches the rebase-review gate: the log keeps both sides' entries,
the catalog and provenance are regenerated. Uncommitted work no incoming commit touches
rides through the rebase via --autostash; the working tree is backed up under
refs/wikitool/reconcile-backup first. is_generated is narrowed to kb/.

Files changed:
- CHANGES.md
- VERSION
- instructions/gates.md
- instructions/session-setup.md
- tools/CONTRACT.md
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/index_build.py
- tools/chemenu/commands/provenance_cmd.py
- tools/chemenu/tests/test_git_publish.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
2026-10-06 08:41:29 +02:00

125 lines
6.5 KiB
Markdown

---
type: types/instruction.md
name: session-setup
description: Scope the wikitool iteration budget to the task by setting a stable session id - one line for bash, one for PowerShell - before the first tool call.
---
# Scope the session budget
Every `wikitool` call is counted against a per-session iteration budget. A "session" is keyed
by a fallback chain (`chemenu.session`): `WIKITOOL_SESSION_ID` first, then a harness's own
session variable where one is registered (`CLAUDE_CODE_SESSION_ID` today), then the parent
process id.
Without an explicit id, and on a harness with no registered variable, the budget is scoped to
whichever shell happened to run the command, so a task spanning several terminals is counted as
several sessions - and one that reuses a shell inherits an unrelated count.
<!-- wikitool:toc -->
## Contents
- [Steps](#steps)
- [Multi-unit runs](#multi-unit-runs)
- [Scope](#scope)
<!-- /wikitool:toc -->
## Steps
Run this **once per working session**, before the first `wikitool` call that is not exempt from
the budget (see § Scope for what that means). Pick the id yourself - a short name for the task and
the current date and time, such as `wiki-20261001-1430` - and set it with the line for the shell
you run in. In a POSIX shell (Linux, macOS, Git Bash on Windows):
```bash
export WIKITOOL_SESSION_ID="wiki-20261001-1430"
```
In PowerShell 7:
```powershell
$env:WIKITOOL_SESSION_ID = 'wiki-20261001-1430'
```
These two lines are the only shell-specific syntax in the stack's instructions; everything else is
a `tools/wikitool` or `git` call that reads the same in both shells. Then:
```bash
tools/wikitool sync
```
**The variable only carries if the shell carries.** Several agent harnesses run every tool call in
a freshly initialised shell: the working directory survives, shell state - environment variables,
functions - does not, so the variable is gone by the next call and each call falls back to whatever
the chain's next step resolves to.
On a harness with a registered variable in that chain (Claude Code, via `CLAUDE_CODE_SESSION_ID`),
the fallback already keeps every call in one bucket without this step - but it scopes to the
*whole* harness session, not to this one task, so a long-running session can carry unrelated prior
work into the same count. Setting `WIKITOOL_SESSION_ID` explicitly still narrows the bucket to the
task at hand, and remains the only way to scope it at all on a harness with no registered
variable - each call falls back to its own parent pid there, and neither the 60-call ceiling nor
the loop-breaker can ever trip (measured directly on a real upgrade run: 33 `wikitool` calls in
one task split into 21 telemetry buckets under the pid fallback alone). On such a harness, put the
line **in front of every `tools/wikitool` call, in the same command**, joined with `;` - which
both shells read the same way - and keep the same value for the whole task.
**GitHub Copilot registers no variable.** Neither Copilot CLI nor Copilot's agent mode in VS Code
sets a session variable in the shell it runs commands in (checked against their documentation,
October 2026), so the chain has no second step there. Under Copilot the line above is what scopes
the budget at all, and what `tools/wikitool doctor` reads: without it, `doctor` reports
`session-id: WARN` and names the parent-pid fallback.
Which of the three applies is answerable in one call: run `tools/wikitool budget status` twice in
separate calls, and see whether it names the same id both times, and where that id came from -
`budget status` prints both.
Check the current state at any time with `tools/wikitool budget status`, which is never
counted against the budget itself and prints the id it is counting under, and its origin
(`WIKITOOL_SESSION_ID`, a named harness variable, or the parent-pid fallback).
**Why `sync` here, not just at publish time.** `publish` already pulls before it pushes, but a
session that runs many `wikitool` calls before its first `publish` (an ingest, a multi-page
update) would otherwise build all of that work against whatever the local clone happened to
hold when the session started - stale by however long the previous sync was, on a repo more
than one machine or session writes to. Running `sync` first shrinks that window to the start of
the session instead of discovering the drift only at the very end.
`sync` fetches the remote and fast-forwards or rebases automatically when that is safe; it
never commits and never pushes. Files `wikitool` generates are never a reason to stop: when the
catalog or `kb/log.md` changed on both sides, `sync` keeps both sides' log entries and
regenerates the catalog and `kb/provenance.md`, which it leaves as an uncommitted change for the
next `publish`. Uncommitted work that the incoming commits do not touch stays where it is.
**Exit 42 (rebase-review)?** Same as any exit 42 - read the
diff it prints, judge whether it conflicts with what you are about to do, summarize that to the
user, then `tools/wikitool sync --confirm-rebase <token>` before continuing. See
[gates.md](gates.md).
## Multi-unit runs
A task planned as several units - a tree ingest, where each unit produces its own source page
and its own `publish` - takes one id per unit, derived from the workshop's run key:
`<runkey>/u<N>`, for instance `ingest-documents-handbook/u3`, set with the same line as above.
The run key, the workshop directory name and the session id are then the same string, so the
checklist in `work/<runkey>/README.md` and the budget state cannot disagree about where the
run stands.
A new id may only be taken at a unit boundary recorded in `plan.md` - never after a gate
refusal. See [gates.md](gates.md).
## Scope
**The exemption is an allowlist, not "read-only" or "does not change the wiki."** A command
needs this setup unless it is one of the dozen `tools/CONTRACT.md` marks exempt in its command
table (`search`, `doctor`, `links show`, `cite id`, `budget status`, the read-only forms of
`eval`, `version` and `migrate`) - that table, not a rule of thumb here, is
the single list. One entry on it, `version regrade`, is exempt only in its bare listing form and
counted when it is given positions to regrade; every other entry is exempt however it is called.
`lint` is the case that breaks the "changes the wiki" reading: it only writes to `reports/`,
which is gitignored, so it looks side-effect-free - but it is not on the allowlist and is counted
like any mutating command. A skill that calls only exempt commands needs no session id; a skill
that calls `lint` alone still does.
The limits themselves, and what to do when one trips, are in [gates.md](gates.md).