Skip to content

fix(skill): description overran the listing cap; add a real cctab alias - #16

Draft
motin wants to merge 3 commits into
mainfrom
fix/skill-discoverability
Draft

fix(skill): description overran the listing cap; add a real cctab alias#16
motin wants to merge 3 commits into
mainfrom
fix/skill-discoverability

Conversation

@motin

@motin motin commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

What prompted this

A session in ~/Dev/horizon was told "open a new cctab to improve the /render-doc skill …". It ran which cctab / type cctab, grepped ~/.zshrc for an alias, found nothing, called ListAgents, concluded "there is no cctab command and I can't open an interactive tab from inside a session", and handed the work to an Agent-tool worktree subagent — the exact substitution this skill's description forbids in bold.

Root cause: not the description, and not packaging

The working theory going in was that the skill was never enumerated. It was. ~/.claude/projects/…-dropoff-ux/<id>.jsonl line 8 holds a skill_listing attachment with isInitial: true, skillCount: 82 containing cctabs:cctabs with the full TRIGGER list, "open a new cctab" (singular alias) included.

What actually happened:

  • The full listing is injected once per session. After that, Claude Code injects only single-skill recall deltas (isInitial: false, skillCount: 1) — in that transcript, repeatedly horizon-analytics, horizon-next-steps, b2b-triage.
  • A compaction occurred at line 2120. The initial 30 KB listing lives in the pre-compaction context and is not carried into the summary, and no second isInitial: true listing is ever emitted.
  • The request landed at line 3918 — ~1800 lines and one compaction after the only full listing.

So the handful of skills that session reported as "all I ever saw" (horizon-analytics, render-doc, b2b-triage, precompact-handoff, conductor-auth-refresh) was an accurate description of its post-compaction context, and the conclusion drawn from it ("it was never in my listing") was wrong.

This is harness behavior and cannot be fixed from this repo. Hypotheses ruled out along the way: a skills-only plugin needing its own manifest (the 0.5.0 cache dir has .claude-plugin/plugin.json, identical in layout to browser-automation, which lists fine); two cached versions confusing enumeration (0.4.10 is .orphaned_at-marked and inert); user-scope suppression by project skills — disproved by experiment, see below.

What this PR changes

1. The description was being silently truncated

Claude Code caps a skill description at 1535 chars in the listing and appends . Ours ran 1760, so every listing it appeared in was cut at "do this in parallel without a new tab", or w… — losing the tail of the anti-substitution rule and the entire NOT for: line. Nothing warns about it; the skill still loads and works when invoked by name.

  • Now 1432 chars (~100 headroom).
  • The decisive sentence (a subagent is NOT a tab) moved above the TRIGGER list so it can't be what gets dropped.
  • Every trigger phrase preserved verbatim — asserted in the verification script; the list was already well-tuned.
  • Opening clause leads with the literal tokens cctab / cctabs / terminal tabs.
  • CLAUDE.md now records the budget + ordering rule so the next edit doesn't quietly overrun it.

2. cctab is now a real command

The skill has always advertised "cctab" as a singular alias while only cctabs was installed. Added as a second bin on the same entry point.

I was asked to weigh this honestly as a possible hack. It is not a fix for the root cause — nothing here is. But it is the only change in this PR that touches the actual failure path: post-compaction there is no listing, so probing the shell is the one discovery route left, and it dead-ended on a name our own docs promise. A stub that merely printed a pointer to the skill would be a hack; a real alias just makes the documented name true.

3. Incidental: @types/bun missing from bun.lock

Declared in package.json but absent from the lockfile, so a fresh clone fails npm run typecheck with TS2307 across all 12 test files. Separate commit.

How this was verified

Not by reasoning that it should work — by running fresh sessions with --plugin-dir pointed at this branch.

Check Result
Baseline, empty project dir cctabs:cctabs listed
63 dummy project skills (matching horizon's count) cctabs:cctabs still listed — crowding hypothesis disproved
New description, tail intact ends …tmux panes, or screen sessions.; ellipsis present? NO; NOT for: present? YES
End-to-end trigger, 63 competing skills, --allowedTools Skill --disallowedTools "Bash Agent …" TOOL_USE: Skill {"skill": "cctabs:cctabs", "args": "new render-doc-toc --prompt …"} — skill invoked, not the Agent tool
No side effects no tab created (cctabs sessions clean; the render-doc-styles tab predates this work)
npm run check typecheck clean, 157 pass / 0 fail, build OK

Control worth stating plainly: the old description also triggers correctly under the same crowded conditions. So change 1 is truncation hygiene and listing-position robustness, not demonstrated behavioral repair. I could not reproduce the original failure, because reproducing it requires a compacted long session with no listing — and in that state no description wording is in play at all.

Deliberately left alone

  • ~/Dev/horizon — untouched (read-only inspection of its config and transcript).
  • The TRIGGER list — unchanged, verbatim.
  • origin/fix/skill-trigger-open-a-tab — a June attempt at this same symptom, pre-0.5.0 (still contains wave.ts). Its substance already landed in main; left abandoned.
  • The cctabs-tabby-login worktree — untouched.
  • No version bump: releases are cut in their own chore(release) commit. Note for whoever releases thisSKILL.md ships in both the npm tarball and the marketplace, so this needs npm run sync-plugin.

Also found, not fixed here

Local main in the primary checkout is 5 commits behind origin/main (still at 0.4.10 with Wave-era text, while origin/main is 0.5.1). The worktree I was given was branched from that stale local main; I reset onto origin/main before working. Worth a git pull in the main checkout.

🤖 Generated with Claude Code

Fredrik Wollsén and others added 3 commits August 12, 2026 12:13
`@types/bun` is declared in package.json devDependencies but was missing from
the committed lockfile, so a fresh clone + `bun install` left it unresolved and
`npm run typecheck` failed with TS2307 "Cannot find module 'bun:test'" across
all 12 test files. Nothing about the dependency changed — only the lockfile
catching up to what package.json already asked for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rule

A session in another repo was told "open a new cctab to improve the /render-doc
skill". It ran `which cctab`, got nothing, called ListAgents, concluded no such
command existed, and handed the work to an Agent-tool worktree subagent — the
exact substitution this skill's description forbids in bold.

The description was not at fault, and neither was packaging: the transcript
shows `cctabs:cctabs` present in that session's initial skill listing, TRIGGER
list and all. Two separate real problems showed up while proving that.

**The description was being silently truncated.** Claude Code caps a skill
description at 1535 characters in the available-skills listing and appends `…`.
Ours ran 1760, so every listing it ever appeared in was cut mid-sentence at
`"do this in parallel without a new tab", or w…` — amputating the tail of the
anti-substitution rule and the whole `NOT for:` line. Nothing warns about this;
the skill still loads and still works when invoked by name, so the loss is
invisible unless you read a transcript's `skill_listing` attachment.

- Now 1432 chars, ~100 under the cap, and CLAUDE.md records the budget and the
  ordering rule so the next edit does not quietly overrun it again.
- The decisive sentence ("a subagent is NOT a tab") moves *above* the TRIGGER
  list, so it can no longer be the part that gets dropped.
- Every trigger phrase is preserved verbatim; the list was well-tuned already.
- The opening clause leads with the literal tokens `cctab` / `cctabs` /
  `terminal tabs`, because in a project with dozens of its own skills this entry
  can land 75% of the way down 80+ entries and the first clause is what reads.

**`cctab` is now a real command.** The skill has always advertised "cctab" as a
singular alias while only `cctabs` was ever installed, so looking the CLI up
under the name the docs use returned nothing. It is now a second bin on the same
entry point. This is the only part of this change that addresses the actual
failure: Claude Code injects the full skill listing **once per session** and does
not re-inject it after a compaction (only single-skill recall deltas). That
session had compacted ~1800 turns before the request, so it had no listing left
and no description wording could have reached it — probing the shell was the one
discovery path still open, and it dead-ended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 20, 2026

Copy link
Copy Markdown

Deploying cctabs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 71cd156
Status: ✅  Deploy successful!
Preview URL: https://ad9a0634.cctabs.pages.dev
Branch Preview URL: https://fix-skill-discoverability.cctabs.pages.dev

View logs

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