klappy.dev

The StylebookHandoffs

Handoff

Fresh Session Continuation from 2026-04-19 (post agent-team pilot)

Where we are right now

Current epoch: E0008.3 (validation as fourth epistemic mode with context-break requirement). Canon merged and in use. Next anticipated: E0009 (self-correction), still gated on teams-over-swarms canon landing.

What just shipped to prod (2026-04-19):

  • klappy/oddkit#110 — internal rename: canon* / canonUrl / ZipBaselineFetcher / BASELINE_URL → knowledge_base* / knowledgeBaseUrl / KnowledgeBaseFetcher / DEFAULT_KNOWLEDGE_BASE_URL. 5 files, 169/171 lines, workers/src/zip-baseline-fetcher.ts filename kept for diff minimality.
  • klappy/oddkit#111 — main → prod promotion. Prod tip: fae2df6. https://oddkit.klappy.dev/mcp smoke: 24/24 pass. Health: {"version":"0.16.0"}.

What's in open PRs awaiting merge (not blocking next session, but worth reviewing before starting more work):

  • klappy/klappy.dev#109 — odd/ledger/2026-04-19-agent-team-pilot.md. 220-line session ledger, full DOLCHEO, six thesis-validation questions answered honestly.
  • klappy/klappy.dev#110 — canon/principles/agent-self-report-under-stress.md (tier 2). 198 lines, full gauntlet run. Extends verification-requires-fresh-context into the post-observation moment. Distinguished from docs/incidents/agent-fault-assertion-without-verification.

Prod state verified: oddkit.klappy.dev at 0.16.0 with renamed code, full envelope contract, telemetry blob6 now carries knowledge_base_url as the rendered field name, legacy canon_url arg accept stripped from parseToolCall.


The pilot's headline findings (these change how the next sessions should run)

1. The agent-team pattern works — but has a load-bearing caveat

The Opus 4.7 execution + Sonnet 4.6 validation + enforced context break + model diversity pattern produced a better artifact than solo work would have (run 1's rename was strictly more complete than what the orchestrator would have written alone, catching 12 camelCase identifiers a word-boundary regex missed). Cross-model validation with fresh context ran clean: zero errors, zero halts, VERIFIED disposition.

Caveat: Managed-agent execution on klappy/oddkit triggered a categorical safety-layer reminder ("you MUST refuse to improve or augment the code") in all three Opus 4.7 execution dispatches. The signal is scope-insensitive — it fired identically on multi-file, single-file-narrow-scope, and explicit-framing variants. It is verb-sensitive — Sonnet's read-only validator ran to idle with zero interference. The probable trigger is the repo's own AGENTS.md file being read by the managed agent and parsed by some upstream classifier as a prompt-injection directive.

Operator decision (do not re-litigate): Do not report this to Anthropic as a bug. The false-positive behavior is currently working in the operator's favor for reasons the operator will determine when to act on.

Practical implication for next sessions: Managed-agent execution on oddkit code edits is not available. The working pattern for any oddkit code change going forward is path 3: orchestrator applies edits locally, Sonnet 4.6 validates with fresh context against the PR. That's the shape of the remaining post-canary-refactor arc.

2. Agent terminal self-reports diverge from tool-use history under stress

The canon principle at klappy://canon/principles/agent-self-report-under-stress (open in PR #110) documents this in detail. Operational summary for the next session:

  • Never trust a managed-agent's terminal summary as sole evidence of completion.
  • For every idle session: pull the full event log, scan for side-effect-producing tool calls (git commit, git push, PR creation, file writes), corroborate each against the external system it claims to have affected.
  • Check the remote for orphan branches / unannounced pushes before force-pushing or resetting.

Run 1 of tonight's pilot completed the entire rename, committed, pushed, and opened PR #110 — then reported FILES_TOUCHED: (none — no source files modified). Only a push conflict from a separate orchestrator attempt revealed the work. Runs 2 and 3 replicated the false self-report pattern.

3. The orchestrator working pattern is proven

  • Orchestrator (Opus 4.7) runs in the claude.ai container, applies edits locally in /home/claude/work/<repo>, commits with human identity (per-session is fine), pushes via PAT-authenticated remote, opens PR via urllib.request + json.dumps.
  • CF auto-deploys every pushed branch to a preview URL of the form <branch-slug>-<project>.klappy.workers.dev (slashes become hyphens). Do NOT run wrangler deploy manually — githooks + CF pipeline handles it.
  • Live smoke before merge: ODDKIT_URL=<preview> node workers/test/canon-tool-envelope.smoke.mjs. Must exit 0 with all green.
  • Dispatch fresh Sonnet 4.6 agent (new agent object, not a session on the orchestrator — the agent object change is what enforces context independence) with PR URL + HEAD SHA + canon URIs + acceptance criteria.
  • Accept VERIFIED or iterate. Merge via squash through GitHub REST. Repeat for prod promotion via a separate main→prod PR.

The rhythm: orchestrator edits → orchestrator pushes → CF deploys preview → orchestrator smokes preview → Sonnet validates from fresh context → orchestrator merges → main-preview smoke → main→prod PR → prod smoke. Six gates, each mechanical, each producing evidence.


Priority 1Pick up immediately

P1.1 — DOLCHEO canon doc (tier 2)

Candidate path: canon/definitions/dolcheo-vocabulary.md.

Operator lean (from prior session handoff, confirmed across tonight): DOLCHEO replaces DOLCHE. DOLCHE was always incomplete because Open items had no home. Both Os remain O; rely on section context to distinguish closed-Observation from Open-item.

Doc must cover:

  • Why the extension (retrospective-only tracking loses forward-pointing threads; tonight's ledger used Open items with priority bands and they worked well)
  • Each letter defined: Decision, Observation (closed), Learning, Constraint, Handoff, Encode, Open (forward-pointing)
  • Guidance on when to use Open vs Handoff (Handoff = work transfer to another agent/session/person; Open = unresolved thread or question that stays with the current owner)
  • Example ledger structure with Open Items sectioned by priority band (P1–P6) — tonight's ledger is a working example
  • Relationship to oddkit_encode (the tool must accept all seven letters, currently hardcoded to four)

Gauntlet required:

  • oddkit_preflight
  • oddkit_challenge in canon-tier-2 mode — address all block_until_addressed: false prerequisites inline
  • Frontmatter must match canon/meta/frontmatter-schema (native YAML types — booleans unquoted, integers unquoted, dates unquoted, simple identifiers unquoted, strings with special chars quoted)
  • AI-voice-clichés pass (canon/constraints/ai-voice-cliches) — no negation parallelism, no puffing, no formulaic transitions, varied pacing, specific evidence

Derives from and complements at minimum: canon/values/axioms.md, canon/methods/self-audit.md, prior session ledgers that established DOLCHE.

P1.2 — oddkit_encode batch-mode feature + governance-driven refactor (combined)

This is one PR doing two things at once, because they're the same work:

Feature: batch-mode input

  • Accept paragraph-split input with optional [D] / [O] / [L] / [C] / [H] / [E] prefixes (no prefix → default type via existing heuristic).
  • Return per-artifact array instead of single typed blob.
  • Each artifact gets its own quality score.
  • Single-artifact input must still work unchanged (backward behavior preserved).

Prompt-over-code refactor (canary pattern applied to encode)

  • Read DOLCHEO vocabulary from canon/definitions/dolcheo-vocabulary.md at runtime via KnowledgeBaseFetcher.
  • Three-tier resolution: live canon → bundled baseline → minimal hardcoded fallback.
  • Response envelope declares governance_source: "knowledge_base" | "bundled" | "minimal".
  • Zod schema accepts knowledge_base_url optional override (for strict-mode testing).
  • Parallel shape to telemetry_policy canary (the completed reference — see klappy/oddkit#108 and klappy/oddkit#109).

Smoke test additions (required before merge per canon/constraints/core-governance-baseline):

  • Extend workers/test/canon-tool-envelope.smoke.mjs with oddkit_encode assertions for envelope shape, governance_source present and valid, batch-mode per-artifact response, single-artifact backward behavior, knowledge_base_url override falls through to minimal when file missing.

Tool description update: after P1.1 canon ships, update the oddkit_encode tool description to reference DOLCHEO (seven letters) and mention the batch-mode prefix syntax. This was explicitly deferred multiple times pending this refactor — ship it now.

Operating constraint: orchestrator applies edits locally (path 3 pattern — managed-agent execution on oddkit code is blocked). Sonnet 4.6 validates after. Do not dispatch Opus 4.7 execution agents to klappy/oddkit; they will halt.

P1.3 — Canon doc for the post-canary-refactor arc (if not already clear)

The audit doc at docs/oddkit/audit/governance-anti-pattern-sweep-2026-04-17.md lists 10 remaining tools. After oddkit_encode (P1.2), priority order is:

  1. oddkit_challenge — execution mode hardcoded regex for claim-type detection. Canon has challenge types; tool should read at runtime.
  2. oddkit_gate — problem_defined prerequisite uses hardcoded regex. Cannot recognize writing-canon transitions without runtime canon read.
  3. oddkit_preflight — DoD lookups partially hardcoded. Should read full DoD spec from canon.
  4. oddkit_validate — completion criteria matching hardcoded. Canon has validation vocabulary (E0008.3 context-break requirement); tool should fetch.
  5. oddkit_orient — mode classification uses hardcoded list. Now that validation is a fourth mode, orient must read modes from canon to keep pace with canon changes without code redeploys.
  6. oddkit_search — ranking weights and tag boosts hardcoded. Lower priority (less load-bearing for epistemic correctness).
  7. oddkit_catalog — start_here suggestions hardcoded. Should be canon-driven.
  8. oddkit_cleanup_storage — probably fine as-is; verify and mark complete.
  9. oddkit_version — trivial tool, probably no violation; verify and mark complete.

Each follows the canary template: canon doc first → tool fetches runtime → three-tier fallback → governance_source in envelope → Zod knowledge_base_url override → smoke test extension → live-smoke against preview → merge → main-preview smoke → main→prod PR → prod smoke. One PR per tool, full gauntlet each.

Total scope: ~8–10 more PRs over several sessions after P1.2.


Priority 2Version discoverability (surfaced tonight, worth addressing)

P2.1 — Backfill [Unreleased] and cut 0.17.0

Current version 0.16.0 was set 2026-04-03 (16 days ago). [Unreleased] in CHANGELOG.md is empty. Since 0.16.0 shipped:

  • E0008 (x-ray tracing, KV elimination) — PRs #83, #89
  • E0008.1 / E0008.2 (oddkit_time)
  • E0008.3 (validation-as-epistemic-mode, verification-requires-fresh-context)
  • canon_url → knowledge_base_url user-facing contract rename — PRs #101, #106, #107, #108, #109
  • Governance anti-pattern audit — #105
  • Internal rename (tonight's PR #110, promoted via #111)

Semver MINOR bump: 0.17.0. New contract, new tool, new canon mode — minor is right. Do this as its own PR, distinct from P1 work, so the version bump is atomic and traceable.

P2.2 — Render CHANGELOG on klappy.dev

One-line impact, big observability win. Add /oddkit/changelog route that renders CHANGELOG.md from the oddkit repo. Then add version_notes_url: <that URL> to the MCP initialize response's instructions block (or a new envelope field).

Lower priority than P1 but worth slotting into the post-canary-refactor arc since tool envelopes get touched anyway.


Priority 3Canon principles still queued from earlier sessions

Unchanged from the prior handoff:

  • canon/principles/teams-over-swarms.md (tier 2) — governing architectural preference. Tonight's pilot provides fresh evidence for it: the team pattern produced better output than solo work even in a single-PR test.
  • canon/patterns/bugbot-as-validator.md (tier 2, lower priority) — could be subsumed into teams-over-swarms.
  • canon/principles/mechanical-work-belongs-in-code.md (tier 2) — first concrete application is P1.2 (encode batch-mode).

These are writing work, no managed-agent execution needed.


Operating notes for the fresh session

  • Read the bootstrap first. Project instructions point at klappy://canon/bootstrap/model-operating-contract. Fetch it at session start.
  • Declare mode. "Exploring." "Planning." "Executing." "Validating." State it before substantive work.
  • oddkit_time every turn. Pass prior server_time as reference to get elapsed without guessing. E0008.2 is active and in use.
  • Search canon before asking. oddkit_search is essentially free. Most questions are answered in canon.
  • During execution, produce artifacts, not questions. Questions belong in planning.
  • Validate via fresh Sonnet 4.6 agent. New agent object (not a session on an existing agent). Different model, no shared context, same oddkit MCP binding. The validator-pr110-2026-04-19 agent spec from tonight's session is a good template — see the session ledger.
  • Track DOLCHEO continuously. Save to /home/claude/work/ledger/<date>-<topic>.md as you go.
  • The orchestrator applies edits on oddkit. Managed-agent execution on oddkit is blocked by the safety layer; the operator has declined to report this, so plan around it.
  • Live smoke before merging any MCP tool change. Ship-blocker per canon/constraints/core-governance-baseline. Template: workers/test/canon-tool-envelope.smoke.mjs. Run against the branch preview URL (CF auto-deploys every pushed branch).
  • Githooks handle version sync on commit. workers/package.json and root package.json must match. Commit is blocked if they drift.

Credentials and tooling reference

  • GitHub PAT: in project instructions.
  • ANTHROPIC_API_KEY: in project instructions.
  • Working dirs used tonight: /home/claude/work/oddkit, /home/claude/work/klappy.dev.
  • Managed-agents skill: /mnt/skills/user/managed-agents/SKILL.md — path assumption note: $HOME=/root in the cloud env, not /home/user. The skill says /home/user; ignore it, use $HOME.
  • Managed-agents environment ID: env_016RffZyqSdHeb5s3Z6UABw8.
  • Anthropic Managed Agents API: https://api.anthropic.com/v1 with header anthropic-beta: managed-agents-2026-04-01.
  • oddkit prod: https://oddkit.klappy.dev/mcp.
  • oddkit main preview: https://main-oddkit.klappy.workers.dev/mcp.
  • oddkit branch preview pattern: https://<branch-slug>-oddkit.klappy.workers.dev/mcp (slash in branch → hyphen).
  • klappy.dev canon lives on main branch.

Known foot-guns, learned tonight

  • Do NOT mix python3 <<PYEOF > file.txt with in-script open(file, 'w').write(...). Shell > opens fd, Python writes, shell stdout-capture overwrites on exit. The file ends up with stdout content stomping the first N chars. Rule: write from Python only; send diagnostics to sys.stderr.
  • Do NOT force-push without checking the remote first. Tonight the orchestrator nearly force-pushed a less-complete rename over a managed-agent's completed (but silently-pushed) PR. Always git fetch and compare before git push --force.
  • Do NOT run wrangler deploy manually on klappy/oddkit. Githooks + CF auto-deploy handle it. Manual deploys will either duplicate or collide with the pipeline.
  • Do NOT trust a managed-agent's terminal self-report. See canon/principles/agent-self-report-under-stress (tonight's PR #110 on klappy.dev). Pull the event log, corroborate side-effects against external state.

Orient. Read the bootstrap. Search canon for DOLCHEO vocabulary and oddkit_encode prompt-over-code — confirm no existing drafts I missed. Then:

  1. Draft canon/definitions/dolcheo-vocabulary.md (P1.1). Full gauntlet.
  2. Open PR on klappy.dev. Wait for merge (or proceed — canon doc merged before code refactor is the desired order but not a hard block if the doc is on a branch).
  3. Apply oddkit_encode batch-mode + canary refactor in workers/src/orchestrate.ts (or wherever encode is defined). Tier by tier: canon-fetch → bundled fallback → minimal fallback. Add governance_source to response envelope. Extend smoke. Run against branch preview. Get 24/24 plus the new encode assertions.
  4. Open PR on klappy/oddkit. Get CI + bugbot green. Dispatch Sonnet 4.6 validator against the PR URL.
  5. Merge when VERIFIED. Main-preview smoke. Open main→prod PR. Prod smoke. Close out.

Budget for P1.1 + P1.2 as a single focused session: realistically 3–4 hours of orchestrator work. Don't over-scope. If the session runs long, ship P1.1 and handoff P1.2 — the DOLCHEO canon doc is the prerequisite that unblocks the tool change anyway.

Markdown · RSS · built from klappy/klappy.dev@b750d7d