kylesnowschwartz/simpleclaude/sc-dirty-room
Claude Code and agent skill by kylesnowschwartz/simpleclaude
- community
Checking that the SKILL.md file is still in the repository.
Lift-and-shift port of a repository, library, API, protocol, or other software artifact to a different language, runtime, or platform, with the original source available as a reference. This skill SHOULD be used when the user says "port from X to Y", "lift and shift", "rewrite in Go", "rewrite in Rust", "translate this codebase", "convert to TypeScript", "language migration", "rewrite in another language", "carry over the algorithms", "borrow techniques from", "dirty room", "dirty-room design", "sc-dirty-room", or wants to reimplement an existing artifact while studying its internals to preserve algorithms, data structures, or idioms worth keeping. NOT for legally-constrained reimplementation — use /sc-clean-room when copyright isolation matters.
Install
npx vskill@latest install kylesnowschwartz/simpleclaude/sc-dirty-roomSKILL.md
Dirty-Room Design
This is a bastardization of the technique used by Compaq 1982 to clone the IBM PC BIOS.
A structured approach to porting a software artifact to a different language or platform while consulting its internals. A reading agent examines the original and produces discovery, fixtures, and a translation brief — notes on which algorithms, data structures, and idioms are worth carrying across the language boundary. The implementation agent receives all three artifacts and explicit permission to read the original source directly.
The clean-room skill builds a wall between specification and implementation to preserve copyright independence; the dirty-room takes notes through the open window because the constraints here are technical, not legal. Use this when the goal is a faithful port rather than an independent reimplementation.
EXECUTION MODEL
Phases 0 through 6 run in sequence. The core phases (1-4) MUST NOT be skipped or reordered.
- Phase 0 establishes scope, target language, and pins the artifact version
- Phase 1 (Read) examines the original via a
Task()agent and produces discovery, fixtures, and a translation brief - Phase 2 (Refine) finalises the spec and translation brief for handoff
- Phase 3 (Port) builds in a
Task()agent that may consult the original directly - Phase 4 (Verify) confirms equivalence via spec compliance and fixture replay
- Phases 5-6 present results and offer next steps
After each phase, present the output to the user and wait for approval before proceeding.
No isolation, by design
The implementation agent in Phase 3 receives the original artifact's path and may read it freely. The reading agent's notes flow through to the porter. This is the explicit difference from /sc-clean-room — the wall is gone because the work is a translation, not a clean reimplementation. Process-level separation between agents is preserved only for token efficiency; it is no longer load-bearing for independence.
Phase 0: Resolve Target, Scope, and Languages
Parse $ARGUMENTS. The first argument is the target, anything after is a scope, focus, or target-language hint.
Target resolution
| Argument | Target | Version pin | |
|---|---|---|---|
| Repository URL | Clone or fetch the repo | Record commit SHA | |
| Local path | Examine directly | Record git commit SHA; if not a git repo, record a checksum | |
| Package name | Locate via registry (npm, PyPI, RubyGems, crates.io, etc.) | Record exact package version | |
| Protocol or API name | Fetch public docs and specs | Record document revision or access date |
Version pinning is mandatory. Record an immutable identifier so all artifacts reference the same version.
Scope and language negotiation
Use AskUserQuestion:
- Source language and runtime
- Target language and runtime (this is the defining input; if same as source, ask whether a direct implementation is a better fit)
- Which parts to port (the whole thing, a subset, a single module)
- Quality attributes that matter (performance parity, API compatibility, idiomatic target-language code)
- What is explicitly out of scope
- Licence check: confirm the user has rights to study the original and produce a port. If unclear, redirect to /sc-clean-room.
Tell the user: "Target: [what]. Scope: [boundaries]. Languages: [source] → [target]."
Run directory
Slug: <artifact-name>-<source-lang>-to-<target-lang> (lowercase, hyphens). Create with mkdir -p .agent-history/dirty-room/<slug>.
Run git check-ignore -q .agent-history/ — if it fails, warn the user to add the ignore rule.
If the directory already exists, ask: start fresh, resume, or abort.
Classify the artifact
| Type | Reading focus | |
|---|---|---|
| Library/Package | Exported functions, types, behaviour contracts, internal algorithms | |
| CLI Tool | Command interface, input/output formats, exit codes, argument parsing strategy | |
| API/Service | Routes, request/response schemas, error codes, middleware ordering | |
| Protocol | Message types, sequencing, state transitions, framing | |
| Data Format | Syntax, semantics, edge cases, error recovery, parser strategy | |
| Algorithm | Inputs, outputs, invariants, complexity, optimisations worth preserving |
Run State
Before leaving Phase 0, fix the following named variables.
Substitution contract. Two grammars appear in this skill and must not be confused:
- Tokens of the form
<UPPER_SNAKE>are Run State variables. The orchestrator MUST replace them with the resolved value before sending any prompt to aTask()agent. Every Phase 1 and Phase 3 prompt body performs this literal substitution before invocation. - Tokens of the form
[brief description]inside example artifact templates (thediscovery.md,fixtures.md,specification.md, andverification.mdblocks) are human-readable scaffolds the spawned agent fills with its findings — do NOT replace these.
| Variable | Definition | Derivation rule | |
|---|---|---|---|
ARTIFACT_NAME | Short canonical name of the original artifact | Lowercase, hyphens; strip versions, namespaces, and registry decorations. For repo URLs, use the repo's basename; for packages, the registry name without scope (@org/foo → foo); for protocols, the common abbreviation (e.g. http2, grpc). | |
SOURCE_LANG / TARGET_LANG | Canonical language tokens | Lowercase, hyphens. Use the canonical short names: go, rust, python, typescript, javascript, ruby, java, kotlin, swift, c, cpp, csharp, elixir, erlang, scala, clojure, haskell, ocaml. Pick the closest match for variants (ts → typescript, py → python). | |
SLUG | Run identifier | <ARTIFACT_NAME>-<SOURCE_LANG>-to-<TARGET_LANG> | |
RUN_DIR | Run directory (absolute path) | <repo-root>/.agent-history/dirty-room/<SLUG>/ | |
SOURCE_PATH | Absolute path to the materialised original | Set by Phase 0 Materialisation, below. | |
TARGET_PATH | Absolute path where the port will be written | Confirm with the user; default to <repo-root>/<ARTIFACT_NAME>-<TARGET_LANG>/ if unspecified. | |
SOURCE_VERSION | Immutable version pin of the materialised source | Read after Materialisation; this is the version_pin field recorded by the Materialisation recipe in <RUN_DIR>provenance.json. | |
SCOPE | Negotiated scope of the port | Captured during Phase 0 scope negotiation. A short prose summary of which parts are in scope and out of scope. | |
IMPL_PREFS | Porter's preferred architecture, test strategy, libraries | Captured at the start of Phase 3, immediately before the porting Task() is launched, via AskUserQuestion. | |
APPROVAL_SIGNAL | What counts as user approval at each blocking gate | An explicit affirmative from the user — "yes", "approved", "proceed", "lgtm", "go ahead", or equivalent. Silence, partial approval ("looks mostly good but…"), or any qualified response does NOT count; re-ask explicitly until you receive an unambiguous affirmative or an explicit halt. |
Echo the Run State back to the user as a compact block before Phase 1 so they can confirm:
(IMPL_PREFS is filled in at Phase 3.)
Phase 0 Materialisation
After resolving Run State, the orchestrator MUST materialise the source on disk and record its version pin to <RUN_DIR>provenance.json before proceeding to Phase 1. Run exactly one row from the table below — the row whose target type matches what the user supplied.
provenance.json shape (uniform across all rows):
| Target type | Materialisation recipe | ||
|---|---|---|---|
| Repository URL | git clone <url> <RUN_DIR>source/<ARTIFACT_NAME> then capture git -C <RUN_DIR>source/<ARTIFACT_NAME> rev-parse HEAD as version_pin. source_path = <RUN_DIR>source/<ARTIFACT_NAME>. | ||
| Local path | No copy. source_path = absolute path of <SOURCE_INPUT>. If git -C <SOURCE_INPUT> rev-parse HEAD succeeds, use its output as version_pin. Otherwise compute `find <SOURCE_INPUT> -type f -exec sha256sum {} \; \ | sha256sum and use that digest as version_pin`. | |
| Package name | Resolve and unpack into <RUN_DIR>source/<ARTIFACT_NAME>/ per ecosystem, then record the resolved version as version_pin: <br>• npm: npm pack <pkg>@<ver> then tar -xzf <pkg>-<ver>.tgz -C <RUN_DIR>source/<ARTIFACT_NAME> --strip-components=1 <br>• PyPI: pip download --no-deps --no-binary=:all: -d <RUN_DIR>source/ <pkg>==<ver> then unpack the sdist into <RUN_DIR>source/<ARTIFACT_NAME>/ <br>• RubyGems: gem fetch <pkg> -v <ver> then gem unpack <pkg>-<ver>.gem --target=<RUN_DIR>source/ <br>• crates.io: cargo download <pkg>==<ver> -x -o <RUN_DIR>source/<ARTIFACT_NAME>/ (or fetch the .crate and tar -xzf it) | ||
| Protocol / API | curl -fsSL <spec-url> -o <RUN_DIR>source/<ARTIFACT_NAME>/<filename> (repeat per document). version_pin = the document's published revision if stated in the spec, otherwise the ISO-8601 fetch date. source_path = <RUN_DIR>source/<ARTIFACT_NAME>. |
Update SOURCE_PATH and SOURCE_VERSION in Run State from <RUN_DIR>provenance.json (the source_path and version_pin fields, respectively). From Phase 1 onward, all agent prompts derive <SOURCE_PATH> and <SOURCE_VERSION> from <RUN_DIR>provenance.json.
Phase 1: Read the Source
Examine the original to document what it does, how it does the parts worth preserving, and capture behavioural fixtures for verification.
BLOCKING: Complete the reading before moving to Phase 2.
Launch as a Task() agent. This agent reads the original freely. Its output goes to disk; the orchestrator reads those files afterward. Unlike clean-room, there is no contamination concern — the implementation agent will see the same source material itself.
Per the substitution contract above, replace every <UPPER_SNAKE> token in the prompt body with its Run State value before invoking. Leave the [bracket] scaffolds inside the example artifact templates untouched — those are for the spawned agent to fill.
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingplugins/sc-extras/skills/sc-dirty-room/SKILL.md
Popularity
- Repository stars
- 103
- Repository forks
- 15
- 7-day trend score
- 23
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/kylesnowschwartz/simpleclaude/sc-dirty-room)