Skip to content

Release 0.9.0 — runtime-claim corrections, two defect fixes, compaction-budget guard - #1

Merged
yaniv-golan merged 18 commits into
mainfrom
release/0.9.0
Aug 6, 2026
Merged

Release 0.9.0 — runtime-claim corrections, two defect fixes, compaction-budget guard#1
yaniv-golan merged 18 commits into
mainfrom
release/0.9.0

Conversation

@yaniv-golan

Copy link
Copy Markdown
Owner

Every Claude-runtime claim in this repo was re-verified against the shipping Claude Code 2.1.222 binary. Four were wrong. Two real defects were found and fixed along the way, one of them a data-loss bug.

Highlights

Two defects, not just documentation

  • The generated skill was written where the user cannot see it — and on remote Cowork, destroyed. The working directory was placed beside the skill directory, which is a read-only cache on plugin and marketplace installs; the agent fell back to a session scratchpad that a remote session discards on exit, taking the new skill, its scripts and every eval result with it. Found by running the full create → test → eval → review loop under the harness, and reproduced with both a full and a truncated skill, which is what ruled out compaction as the cause.
  • The eval viewer was never shut down. VIEWER_PID=$! and kill $VIEWER_PID sat in separate shell invocations, so the variable was unset by the time it was read.

Four corrected claims

  • Listing overflow degrades per skill, not all at once — there is no ~20-character collapse threshold.
  • The listing budget is contextWindow × 4 × skillListingBudgetFraction, not a fixed ~8 KB.
  • allowed-tools grants permission rather than requesting it; the real gate is workspace trust.
  • Cowork's image ships a large Python stack and can install from PyPI, so thirdparty-import was a false positive on import pandas.

New

  • compaction-truncation-risk lint rule — flags a SKILL.md over the 19,900-character post-compaction limit. Exact rather than heuristic, because the cap is a fixed character count in the runtime.
  • Documentation of the compaction budget, including two ways a skill silently loses content permanently.

Breaking changes

  • Lint rule renamed: listing-collapse-risklisting-desc-drop-risk. Update any tooling that keys on the old name.
  • Advisory findings no longer gate check_portability.py --strict. Warnings and errors gate as before; --strict-advisories restores the old behaviour.

Verification

Tests (95), quick_validate, check_portability, package_skill --dry-run, and the full cowork-harness static lane (lint-skill --strict, analyze-skill --strict, gated scenario lint, record --dry-run) all pass. The negative-control scenario was additionally run live to confirm it survives cowork-harness 1.18.0 flipping proactive skill-suggest on.

Full detail in CHANGELOG.md.

After merge

Tag the merge commit to cut the release — release.yml triggers on push: tags: 'v*', so the tag alone is what publishes:

git tag v0.9.0 && git push origin v0.9.0

yaniv-golan and others added 18 commits August 6, 2026 12:59
…ordered degradation

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 0bc0f831ea2f64cce5c08333f1d054f647cee166)
…isk and correct its premise

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 525ec56a6f750b9361e9d15f84a838a1f12d0546)
…es no longer gate --strict

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 8ce8799c1e0c7a7c0f9256f4acace9d9f2bf278d)
…st it

Also adds the skill content lifecycle section (Task 8 Step 3 of the plan, folded
in here because it shares the same anchor).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 80f9aff6110f296ce2606b4b5a6640e8bf0b3713)
…l source

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit ae28263d5a5ff9eadc38d1a27dd4e7dd3d523a30)
…commit delivery, drop the link advice

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 4748e1c2e475f8c8d844264c673b81fc999e6c26)
… to claude-opus-5

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit a66fcce68577af10b736325b769ad9f986ec9094)
…ound:false

SKILL.md measures 490 lines / 39,525 chars / ~9,881 tokens against the 5,000-token
per-skill re-attach cap this commit documents; the cut falls at line 255. Recorded,
not addressed — deferred to a separate restructuring pass with its own eval run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit a75fd30c51ff9310ed4b31716731edc7a486ed9e)
Re-verified every Claude-runtime claim against Claude Code 2.1.222, the Desktop
archive, 712 real skill listings, and two live Cowork probes. Four claims were
wrong; each correction states its evidence in the CHANGELOG entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 7db800cb9df2bc1fdea4936e96d3942a2a4680e5)
…arratives

The 0.9.0 corrections left behind archaeology in forward-facing docs — what the doc
used to claim, when it was disproved, and why. That is changelog material; the docs
should just state the current rule. Trimmed from harness/README.md, environments.md
(three places), create-skill.yaml, and frontmatter.py; the CHANGELOG keeps the full
history. environments.md drops 874 chars, which matters because it is agent-loaded
reference text.

Two forward-facing notes are kept deliberately: frontmatter.py still warns against
re-introducing PyYAML, and create-skill.yaml still explains why its assertion stays
now that the premise behind it changed. Both state a rule, not a correction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 1caaa1c7ce0b94713389ab3b258423590075b133)
Records the full rule list, the exit-code contract, and that --strict gates on
warnings and errors only while advisories report without gating
(--strict-advisories opts in). Also notes this repo's own linter baseline, so a
non-empty finding list is not mistaken for a regression - a new rule id is the
signal.

Kept in sync with the CLAUDE.md mirror.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
…name

main is protected but enforce_admins is off, so a maintainer push succeeds and only
prints 'Bypassed rule violations' — the protection cannot stop an accidental release,
which makes the approval the real gate. Says so, and calls out automated agents
explicitly: committing locally is not approval to push.

Also corrects the recipe: release.yml triggers on 'push: tags: v*', so pushing the
tag by name is sufficient and a release never needs a direct push to main. The old
'git push origin main --tags' both bypassed the PR flow and pushed more than needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 53f910d5015dfb4f5cede8b03fba78af21f0c659)
After auto-compaction Claude re-attaches each invoked skill truncated to 19,900
characters. The cap is documented as "5,000 tokens" but the runtime sizes skill
content by character count rather than tokenizing it, so characters are the unit
that matters and wc -m is the way to measure. A tokenizer reading answers a
different question and, on technical markdown, overstates the overage.

Also records two behaviours that are easy to lose content to: truncation is
written back, so a second compaction cannot recover the tail, and combined-cap
overflow drops a skill's stored content entirely for the rest of the session.

Verified against the shipping Claude Code 2.1.222 binary; the per-skill and
combined caps are fixed literals with no context-window scaling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
SKILL.md told the agent to put <skill-name>-workspace/ "as a sibling to the
skill directory". On a plugin or marketplace install the skill lives in a
read-only cache, so that path is unwritable — and the agent silently falls back
to the session scratchpad, which no user can see. On a remote Cowork session the
scratchpad is reclaimed when the session ends, so the generated skill, its
scripts, evals.json, the fixtures and every eval output are DESTROYED.

Measured with cowork-harness at container fidelity, 2026-08-06, on the full
create -> test -> eval -> review loop. Reproduced in both arms, so it is not a
compaction artifact:

  full SKILL.md        41 files undelivered (scratchpad/skills/...)
  truncated SKILL.md   26 files undelivered (scratchpad/...)

Both runs otherwise succeeded (68 and 62 tools, 6 sub-agents each) and both
correctly paused for human review before packaging — the loss is purely the
workspace location.

The instruction now requires a user-visible, writable location and explains the
failure mode, phrased by outcome rather than naming a lane-specific path.
references/environments.md carries the Cowork-specific detail with the measured
figures.

Note this lands at SKILL.md:234, inside the 19,900-char surviving window, so it
is present after compaction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 9987b8e9e5039e8a67f83758e7966d9c2c080412)
… size guard

Nothing measured the post-compaction budget, which is why this repo's own
SKILL.md sat at ~2x it for nine releases without anyone noticing.

The check is exact rather than heuristic. The runtime's documented '5,000 token'
per-skill cap is computed as Math.round(chars / 4) against a hardcoded literal
and sliced to 5000*4 minus a 98-char marker, so the real limit is 19,900
CHARACTERS and the check is a length comparison — no tokenizer, no estimate, no
divisor to tune, no false-positive rate to argue about. The finding names the
approximate line where the cut falls and states the unit explicitly, because
both common proxies are wrong here: wc -c counts bytes and a tokenizer reads
~26% low on technical markdown.

Advisory severity, so it reports without gating --strict. Scoped to
claude-code + cowork: the mechanic lives in the Claude Code binary, and
Claude.ai's behaviour is unverified.

Adds 3 tests including the exact boundary. This skill's documented linter
baseline goes 3 findings -> 4; DEVELOPMENT.md and its CLAUDE.md mirror updated
and re-verified against real output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit c117824a34262f4f89f5411a41f6cb1369951cf2)
Bumps the pin from 1.16.0 across CI, harness/README.md, docs/DEVELOPMENT.md,
the scenario headers and the shipped references/environments.md install floor.

Two behavioural changes in the 1.17-1.19 range apply here:

  - The CI lint step now runs --strict --min-severity WARN. Without both flags
    it cannot fail on a WARN-class rule, so the gate was inert.
  - verify-cassettes takes --allow-empty, replacing a hand-rolled ls guard. A
    missing path still exits 2, so it cannot green a typo.

1.18.0's host-inventory finding class and its refusal to record into a
repo-visible path are tier-gated to protocol/hostloop and do not affect this
suite, where every scenario is fidelity: container. Both are documented in
harness/README.md for anyone adding such a scenario later, since
harness/cassettes/ is repo-visible here.

The scenarios pin no baseline, so the agent moved 2.1.219 -> 2.1.221 with this
upgrade. That also flipped proactiveSkillSuggestEnabled on, changing the surface
the no-trigger negative control asserts against; recorded in that scenario.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
…gest flip

cowork-harness 1.18.0's baseline flipped proactiveSkillSuggestEnabled from
{on:false,defaultValue} to {on:true,force}, changing the surface no-trigger.yaml
asserts against. The previous commit documented that as an open question.

Ran it live at container fidelity (2026-08-06, $0.2036, 1 turn):

  no_skill_triggered: "skill-creator-plus"   PASS
  result: success                            PASS
  mcp__skills__suggest_skills                served
  skillActivity                              []
  toolCounts                                 {} (agent just answered "Paris")

The served-tool line is the one that matters — it shows the run exercised the
post-flip surface rather than passing because the surface was absent. The
control holds, so the gate stays unpinned: production is ON and the harness now
models ON, making the unpinned run the faithful test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit 85eee1a6e78040c25272818872607d4e3ce00670)
The entry had grown to 1,909 words across 15 bullets — three times the largest
prior release (0.8.0 at 641) and roughly fifteen times typical, with one bullet
at 240 words, longer than three earlier releases combined. It read as an
investigation log rather than release notes.

Rewritten to 762 words. Removed: internal runtime symbol names, the
measurement narratives behind each finding (probe counts, arm-by-arm figures,
fidelity tiers), and self-critical asides about how long defects went unnoticed.
Kept every change and every user-visible consequence.

Section order corrected to Added / Changed / Fixed, matching 0.8.0; the entry
had been Fixed / Changed / Added.

Both breaking changes remain explicit: the listing-collapse-risk ->
listing-desc-drop-risk rule rename, and advisories no longer gating --strict.
Coverage re-checked against the full origin/main..HEAD diff rather than the
commit log; the CI-only changes (lint severity flags, verify-cassettes
--allow-empty) are folded into the harness-pin bullet where a contributor
copying the recipe will see them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhZZyCWnhiNQfwRkX6CNWL
(cherry picked from commit b868f608660e39edb7f1339db221343431fb868c)
@yaniv-golan
yaniv-golan merged commit 6887ca9 into main Aug 6, 2026
2 checks passed
@yaniv-golan
yaniv-golan deleted the release/0.9.0 branch August 6, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant