feat: scc launch, the scc-cli npm name, and an entry file that tells the truth per harness - #13
Merged
Merged
Conversation
…proxy `scc launch [harness]` resolves the workspace, picks the harness it was scaffolded for, and starts that agent from the workspace root — through `headroom wrap <slug>` when Headroom is available. Headroom is the default rather than a flag, which is the deliberate opposite of how RTK is wired. RTK edits a file the user owns and changes how every later command is typed, so it stays opt-in. Headroom wraps one process for one session and changes nothing on disk, so defaulting costs nothing when it is absent: a missing binary, a declined install, an unattended run, or a harness Headroom does not wrap all degrade to starting the agent bare with a warning naming the reason. `--no-headroom` forces that path. This is the one command that does not obey the 0/1/2 exit-code contract: it returns whatever the agent returned. A launcher that flattened the status of what it launched would be unusable in a script. scc's own failures still report 1, and they all happen before anything starts. internal/headroom keeps the agent-slug table and the install path (uv, then pip — never npm, which ships the SDK and no CLI), so a third party's vocabulary ages in one package instead of in the dispatcher. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J54qbk8RpC2tZH8LBz6T2b
`npm i -g scc-cli` is now the documented install, and the command it puts on PATH is still `scc`. npm resolves the package name and installs the bin name, and those never had to match — the bare `scc` on npm has belonged to an unrelated project since 2013. @protonspy/scc stays published from the same source so earlier installs keep receiving versions. Both launchers ship one shim, so the shim now reads its own package.json for SCC_PROG instead of naming a package: hardcoding either spelling would tell half the users to re-run under a package they never installed. Launchers are emitted under npm/dist/launchers/ rather than beside the platform packages, and that is load-bearing. Publishing walks dist/scc-*/ first and dist/launchers/*/ second; a second launcher at the top level would be swept into the platform glob and reach the registry ahead of the binaries its optionalDependencies name, which is a broken install for anyone in that window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J54qbk8RpC2tZH8LBz6T2b
…it already has Claude Code loads .claude/rules/*.md at launch with the same priority as CLAUDE.md. An entry file telling that agent to "read the rule when the concern is live" therefore describes a mechanism that already ran: it asks for a re-read that puts the same ~26KB in context twice, and it leaves the one document the agent is meant to trust wrong about its own environment. paths.Harness gains PreloadsRules, and entry.md branches on it — the trigger lists stay a single copy shared by both arms, because two copies would diverge the first time somebody edited a trigger and Codex and Claude would then follow silently different methodologies. Codex and opencode keep the instruction, since there rules/ is scc's own directory and nothing loads it. The same pass gives each rule its own trigger line instead of running four of them together in a sentence. project.md most of all: it was the third item of a prose list, and a build command that did not come from it is a guess. The test asserts the two lead-ins are mutually exclusive rather than merely present — a template shipping both would satisfy a contains check while contradicting itself in the file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J54qbk8RpC2tZH8LBz6T2b
Corrects a claim that was load-bearing and false: paths.RulesSeg said "no harness loads it on its own", which holds for Codex and opencode but not for the harness the project is named after. Confirm per harness with /context. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J54qbk8RpC2tZH8LBz6T2b
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.
Four surfaces, one release. Each commit builds and tests green on its own.
scc launch <harness>Resolves the workspace, picks the harness it was scaffolded for, starts that agent from the workspace root — through Headroom's compression proxy when it can.
Headroom is the default, which is the deliberate opposite of how RTK is wired. RTK edits a file the user owns and changes how every later command is typed, so it stays opt-in. Headroom wraps one process for one session and touches nothing on disk — so it degrades instead of failing: missing binary, declined install, unattended run, or a harness Headroom does not wrap all end in the agent starting bare with a warning saying why.
This is the one command that does not obey the 0/1/2 exit-code contract — it returns whatever the agent returned. A launcher that flattened the status of what it launched is unusable in a script. scc's own failures still report 1, and all happen before anything starts.
scc-clion npmnpm i -g scc-cli, and the command is stillscc. The baresccon npm has belonged to an unrelated project since 2013; npm resolves the package name and installs the bin name, and those never had to match.@protonspy/sccstays published from the same source so earlier installs keep receiving versions. Since one shim serves both names, it now reads its ownpackage.jsonforSCC_PROG— a hardcoded spelling would tell half the users to re-run under a package they never installed.Launchers moved to
npm/dist/launchers/. That is load-bearing, not tidy: publishing walksdist/scc-*/first anddist/launchers/*/second, and a second launcher at the top level would be swept into the platform glob and reach the registry ahead of the binaries itsoptionalDependenciesname.The entry file, per harness
Claude Code loads
.claude/rules/*.mdat launch with the same priority asCLAUDE.md. So an entry file telling that agent to "read the rule when the concern is live" describes a mechanism that already ran: it asks for a re-read that puts the same ~26KB in context twice, and it leaves the one document the agent is meant to trust wrong about its own environment.paths.HarnessgainsPreloadsRules;entry.mdbranches on it. The trigger lists stay one shared copy — two copies would diverge the first time somebody edited a trigger, and Codex and Claude would then follow silently different methodologies. Codex and opencode keep the read-it-yourself instruction, since thererules/is scc's own directory and nothing loads it.Same pass: each rule gets its own trigger line instead of four running together in a sentence.
project.mdmost of all — it was the third item of a prose list, and a build command that did not come from it is a guess.Also corrects
paths.RulesSeg, which claimed "no harness loads it on its own". True for two of three.Verified
build-packages.mjsrun against synthetic artifacts: 8 packages, correct publish order, both launchersnpm publish --dry-runclean, each resolving its own name.mainand running the newupdateagainst workspaces it created.Known, not addressed here
scc updatenever rewrites the entry file — it isOwned: true, and that check short-circuits before the manifest comparison, so even a provably untouchedCLAUDE.mdis kept.--forcedoes not reach it either. Deleting the file and re-runningupdaterecreates it correctly, but nothing in the output says so. The repo's own convention says the manifest is what distinguishes pristine from edited; theOwnedbranch discards that distinction. Worth a follow-up.🤖 Generated with Claude Code
https://claude.ai/code/session_01J54qbk8RpC2tZH8LBz6T2b