Repository navigation
Conversation
…d of skipping them The claude-code-skills injection skipped any host skill file over 90 KB because a single execInContainer write is capped near 128 KiB (MAX_ARG_STRLEN on the env-var stdin carrier). The claude.ai-synced docx/xlsx/pptx skills ship ISO-IEC29500 XSDs (wml.xsd, sml.xsd, dml-main.xsd) above that, so their validate.py broke inside the sandbox. writeContainerFileBytes now splits payloads across execs into a .codebay-part file that the last slice renames into place; the per-file guard rises to 16 MiB and any remaining skips are logged as one summary line.
… files Reverts the chunked-write approach. Anthropic's own claude.ai skills (manifest creatorType "anthropic", or source "anthropic*" on manifests that predate creatorType) are no longer copied into sandboxes: the sandbox's Claude Code syncs them itself for the same login, and their ISO-IEC29500 schemas were what tripped the 90 KB exec cap. User/org synced skills are still copied with a manifest trimmed to exactly those dirs; a bucket with nothing left, or no readable manifest, is dropped along with its .bucket marker. .last-complete-round and the sync's .staging/.trash dirs are never copied. Oversized-file skips now log one summary line.
Claude Code 2.1.283 lands a synced skill in its sanitized name (path-hostile characters → _, trailing dots/spaces dropped) and never in its skillId, so match on that, keep only manifest rows whose dir was copied, and read the bucket marker only when it's a plain file.
This branch has not been deployed
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.
Root cause
claude-code-skillsinjection (src/container-injections/claude-code-skills.ts) copies the host~/.claude/CLAUDE.mdand everything under~/.claude/skills/into the container, oneexecInContainerwrite per file. It skips any file overMAX_FILE_BYTES = 90_000. That limit exists because a single exec carries its payload in one env var, which Linux caps at 128 KiB (MAX_ARG_STRLEN), and base64 inflates the bytes by 4/3.skills/synced/<org>_<account>/is: Claude Code's own sync of the skills enabled on the user's claude.ai account. The bucket directory is named<org-uuid>_<account-uuid>, lowercased (unboundin place of the account when there isn't one), and next to it sits a.bucket-<id>marker. Inside are amanifest.json(skillId,name,description,source,updatedAtandcreatorTypefor each skill) and a.last-complete-roundfile..xsdschema files bundled with Anthropic's own skills (the docx/xlsx/pptx family). I haven't checked which scripts load them, but a copy missing them isn't the skill as published.Fix
Anthropic's own skills are no longer copied into sandboxes. The Claude Code inside the sandbox syncs them itself, and I checked this against the 2.1.283 binary. The
syncClaudeAiSkillssetting's description says: "synced skills are available in every session, re-synced every 10 minutes". Any Claude Code logged in to the same account therefore downloads the complete skills, unless the user has turned the setting off. Copying them was redundant and, because of the size cap, produced incomplete copies.creatorType: "anthropic", which covers bothsource: "anthropic"andsource: "anthropic-example"entries. For a manifest withoutcreatorType, the fallback is asourcestarting withanthropic. Manifest entries are matched to directories the way Claude Code names them: thenamewith<>:"|?*\/replaced by_and trailing dots/spaces dropped, compared case-insensitively. A directory is never matched byskillId, since Claude Code never names one that way. Skills authored by the user or their org are still copied, as is everything else under~/.claude/skills/.staleDirs/pendingClaimsfields are dropped. Claude Code reads the manifest'sskills[].nameto decide which bucket directories it owns, so the rewritten manifest matches what is on disk..last-complete-roundis not copied. It's the sync's reuse stamp, judged by mtime; a freshly copied one could make the sandbox skip listing and so delay re-downloading the dropped skills..bucket-marker:skillsarray (without a manifest, authorship can't be judged; if the sandbox's Claude Code is signed in with sync on, its own sync brings the contents back).skills/.stagingandskills/.trashare skipped too.MAX_FILE_BYTESis back to 90 KB, and anything still skipped is reported in a single summary line instead of one line per file.The earlier chunked-write change to
container-files.server.tsis reverted.Tests
New tests in
injections.isolated.test.tscheck that:.stagingand.trashare skipped;creatorType/sourcefallback works;anthropic-exampleskills carryingcreatorType: "anthropic") is handled;creatorTypefalls back tosource;team/notes→team_notes) is matched to its directory;skillIdisn't copied, and rows with no directory leave the manifest;.bucket-marker isn't invented.bun run checkspasses.Live boot
Booted a nested instance against a fake host config (via the
claude_config_dirsetting) holding a synced bucket with an Anthropicdocxskill (150 KB.xsd), a user skill namedteam/notesinteam_notes/, an unlistedorphan/dir,.last-complete-round,staleDirs/pendingClaims, plus a plain skill, a.trashdir andCLAUDE.md. The boot log saidInjecting 5 global skill/CLAUDE.md file(s)…/✓ Global skills & CLAUDE.md injectedwith no size warning. The sandbox gotCLAUDE.md,skills/mine/, the bucket marker,team_notes/, and a manifest listing onlyteam/notes, withoutstaleDirs/pendingClaims. Anthropic'sdocx,orphan,.last-complete-roundand.trashwere all left out.The re-sync of Anthropic's skills inside the sandbox wasn't exercised live, because the fake config has no credentials. From reading the 2.1.283 sync code: a listed remote skill missing from the manifest is downloaded as new, and a kept row with an unchanged
updatedAtand aSKILL.mdon disk is carried over without a download.Caveat: this only restores Anthropic's skills when the sandbox's Claude Code is logged in to claude.ai with skill sync on. With an API key, a custom endpoint, or
syncClaudeAiSkillsoff, they're absent from the sandbox, where before they were copied (minus the oversized files).