feat(launch): lazy-MCP loading, token accounting, R015 lint, startup banners#94
Merged
Conversation
…code - picker: render "N skills" instead of "+N skills" in the combine multiselect (formatTallyDelta + per-row headline) so counts read as plain numbers - /goal: add TL;DR + Arguments section, make auto-vs-interactive mode explicit, de-duplicate the continuation-cap guardrail - prune provably-dead code flagged by biome (REGISTRY_PATH, REPO_ROOT, conf, padVisual, body, ctxEndBefore, unused stderr destructure) lint: 1 error + 12 warnings → 0 errors, 4 warnings; tsc clean; touched-module tests green. Excludes unrelated in-progress picker layout work and other WIP. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cue cost estimated each MCP server's cost from its config-entry byte length (JSON.stringify(server)/200), which has no relation to tool count or schema size — undercounting the dominant always-on cost ~50x (e.g. ~400 tok reported for servers whose schemas cost ~19k). Replace with cache-backed per-server accounting (src/lib/mcp-token-estimate.ts): a repo seed (resources/mcp-token-estimates.json, flagged estimate) overridden per-id by probed runtime measurements. Add `--budget N` to `cue cost` and `cue cost --compare`: exits 1 when a profile exceeds the budget (human + --json), for use as a CI token-budget gate. Uncached servers are flagged, not faked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prune a profile's MCP servers to what its skills actually need so unused tool
schemas don't burn always-on context. Interactive launches keep the existing
opt-out picker + remembered per-dir overrides; non-interactive launches stay
fail-open (keep all) unless CUE_PRUNE_MCPS opts in:
CUE_PRUNE_MCPS=auto drop unused PROFILE-declared MCPs (user-global MCPs
stay untouched — the existing tested invariant holds)
CUE_PRUNE_MCPS=all also drop unused GLOBAL servers present in the runtime
.claude.json (heavy ones a coding profile never calls);
a louder opt-in because it removes globally-set config
Precedence: --disable-mcp > remembered override > CUE_PRUNE_MCPS > keep-all.
disabledMcpIds (incl globals under =all) flow to the materializer, which evicts
exactly those keys from .claude.json and never touches an unnamed user MCP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse the verbose pre-agent startup output. The token-overhead banner goes from 6 lines to 2 (formatTokenWarning) with the full per-profile / heaviest-bodies / drop-hint breakdown moving to `cue cost`. The doctor, skill-description-lint, and missing-MCP blocks each collapse to a single line ending in a `-> command` pointer (cue doctor --fix / cue validate / cue mcps add). A heavy composite launch drops from ~12 lines to <=5. Tests rewritten to pin the new compact shapes.
…ars) A SKILL.md is untrusted content loaded into the model's context, so it carries the markdown->exfiltration risk that vercel-labs/markdown-sanitizers hardens against. R015 flags, as errors: - dangerous URL schemes (javascript:/vbscript:/data:text/html, data:image/svg) and raw <script>/<iframe>/<object>/<form>/on*= handlers, in PROSE only (reuses R009's code-fence split, so fenced examples are exempt); - invisible / bidirectional control chars anywhere (zero-width, word-joiner, RLO/LRO, BOM, soft hyphen) -- the markdown sanitizer's own blind spot. Invisible chars are auto-fixable (stripped); dangerous URLs/HTML are not. The on*= check is tag-scoped (<... on*=) so prose like "once = 'daily'" doesn't false-positive, and quote-optional so unquoted <img onerror=fn()> is caught. Rides the existing cue lint-skill + skill-md-lint-action gate. Verified: 80 tests pass; 0 findings across all 1028 skill .md.
uv tool install aborts when a tool's ~/.local/bin entrypoint symlinks are left dangling (tool dir wiped). existsSync reports the binary missing, so cue reinstalls, but uv refuses to overwrite the leftover symlink without --force — looping the full install + failure on every launch. Detect the collision and retry once with --force to relink in place.
Replace the conditional 4-line formatTokenWarning block with a single identity line printed on every real launch (stderr): agent, profile (composites collapsed to primary +N), skill/MCP counts, and always-on token cost. Token segment drops under the 2K floor; the cue cost pointer appears only for heavy (>=10K) profiles. alwaysOnForBadge (tmux badge) preserved; banner stays out of --dry-run/--rematerialize. Tests rewritten to pin the new shape.
added 3 commits
June 30, 2026 12:05
Verified this session (112 tests pass, typecheck clean, independent review DONE_WITH_CONCERNS — concern resolved): - merge(M1): renderMerged static mode now emits non-core rules/commands/hooks (previously computed in the preview but never rendered → silent data loss) - merge(M2): --optimize dedupe is real — collapses same-slug skills last-wins to mirror the runtime materializer's flat-symlink override (was a no-op) - merge(M4): estTokens uses the honest shared estimators (skillAlwaysOnTokens + sumMcpTokens), consistent with `cue cost`, replacing flat per-skill guesses - picker(A1): companion pre-check set is conflict-consistent — a companion that conflicts with an already-checked one starts unchecked instead of being silently pruned at confirm (WYSIWYG) Also bundles unrelated in-progress working-tree work (profiles, personas, hooks, evals harness, legal/ros2 profiles, shell/status/loader edits) at the user's request. Submodules (resources/skills, resources/mcps) intentionally NOT bumped — their commits aren't pushed yet.
# Conflicts: # README.md # profiles/_types.ts # profiles/schema.json # src/commands/ai.ts # src/commands/cost.ts # src/commands/launch.ts # src/commands/score.ts # src/lib/mcp-overrides.test.ts # src/lib/mcp-overrides.ts # src/lib/mcp-token-estimate.test.ts # src/lib/mcp-token-estimate.ts # src/lib/pair-suggestions.ts # src/lib/profile-loader.ts # src/lib/profile-merge.ts # src/lib/skill-dependencies.getNeeded.test.ts # src/lib/skill-dependencies.ts
handleHookSource correctly returns not-found for a declared-but-unmaterialized hook script; the test picked the first hook with any scriptPath, so it failed in environments (incl. main) where a settings.json hook references a script not on disk. Require existsSync before asserting the source serves.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Launch/loading improvements for cue, built on
feat/lazy-mcp-loading:--budgetCI gate (cue cost).--forceretry on stale uv entrypoint collision.▸ claude · 🏭 gstack +4 · 96 skills · 7 MCPs · 🔴 ~23K always-on · → cue cost).Test plan
bun test— no new failures vsmain(baseline-red repo: prove the failing set is unchanged).tsc --noEmitclean.--dry-run/--rematerialize.