Files
chemenu/instructions/session-setup.md
T
torben e4e2332e01
CI / verify (push) Successful in 52s
Release / release (push) Successful in 36s
session: Harness-Session-Variable schliesst die Luecke im Session-Id-Fallback (Telemetrie-Join, Iteration-Budget-Gate); SIGPIPE-Nebenbefund im Emitter behoben
Files changed:
- CHANGES.md
- EVALS.md
- INSTALL.md
- VERSION
- instructions/session-setup.md
- tools/CONTRACT.md
- tools/chemenu/cli.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/run_budget.py
- tools/chemenu/session.py
- tools/chemenu/telemetry/writer.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_cli.py
- tools/chemenu/tests/test_run_budget.py
- tools/chemenu/tests/test_telemetry_emit.py
2026-09-16 19:18:00 +02:00

5.2 KiB

type, name, description
type name description
types/instruction.md session-setup Scope the wikitool iteration budget to the task by exporting a stable session id 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.

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):

export WIKITOOL_SESSION_ID="wiki-$(date +%s)"
tools/wikitool sync

An export 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, pass the id inline on every call instead of export, keeping the same value for the whole task:

WIKITOOL_SESSION_ID="wiki-1234" tools/wikitool sync
WIKITOOL_SESSION_ID="wiki-1234" tools/wikitool new entity --name "..."

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. 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.

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:

export WIKITOOL_SESSION_ID="ingest-documents-handbook/u3"

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.

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, migrate and upstream verify) - 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.