From code-factory
Use when configuring a repository to run with Code Factory — creates `.code-factory/config.toml`, sets up a devcontainer if missing, and validates that build/lint/test work inside it. Triggers on "setup code factory", "configure code factory", "onboard this repo to code factory".
How this skill is triggered — by the user, by Claude, or both
Slash command
/code-factory:setup-code-factoryThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Configure a repository so Code Factory can run against it. Produces `.code-factory/config.toml`, ensures `.devcontainer/devcontainer.json` exists and is usable, then verifies the devcontainer builds and the project's build/lint/test commands run inside it.
Configure a repository so Code Factory can run against it. Produces .code-factory/config.toml, ensures .devcontainer/devcontainer.json exists and is usable, then verifies the devcontainer builds and the project's build/lint/test commands run inside it.
The skill is idempotent — if any artifact already exists, treat it as authoritative and only fill gaps. Do not overwrite user-authored config without asking.
digraph setup {
"Detect project" [shape=box];
"Write config.toml" [shape=box];
"Check devcontainer" [shape=diamond];
"Write devcontainer" [shape=box];
"Install devcontainer CLI" [shape=box];
"Build devcontainer" [shape=box];
"Run build/lint/test inside" [shape=box];
"Report results" [shape=box];
"Done" [shape=doublecircle];
"Detect project" -> "Write config.toml";
"Write config.toml" -> "Check devcontainer";
"Check devcontainer" -> "Write devcontainer" [label="missing"];
"Check devcontainer" -> "Install devcontainer CLI" [label="exists"];
"Write devcontainer" -> "Install devcontainer CLI";
"Install devcontainer CLI" -> "Build devcontainer";
"Build devcontainer" -> "Run build/lint/test inside";
"Run build/lint/test inside" -> "Report results";
"Report results" -> "Done";
}
Run these checks in parallel. Record findings — they drive every downstream decision.
Primary language & build system — look for:
package.json → Node/TypeScript (read engines.node, scripts)pyproject.toml, setup.py, requirements.txt → PythonCargo.toml → Rustgo.mod → GoGemfile → Rubypom.xml, build.gradle → JVM*.csproj, *.sln → .NETIf multiple are present, the one with the most source files wins; note the others as secondary.
Nix — any of: flake.nix, flake.lock, shell.nix, default.nix at the repo root, or a .envrc referencing use flake / use nix.
Docker — any Dockerfile (anywhere), docker-compose.yml, docker-compose.yaml, or compose.yaml in the repo.
Build / lint / test / format commands — pull from:
package.json → scripts (look for build, lint, test, format, typecheck)Makefile → targetsjustfile, Taskfile.ymlCONTRIBUTING.md, README.md (grep for install/test instructions)cargo build/test/clippy/fmt, go build/test/vet, pytest, ruff, etc.)LSPs needed — infer from the primary language plus any file extensions with >5 files in the repo. Examples:
typescript-language-serverpyrightrust-analyzergoplsbash-language-serverdockerfile-language-server-nodejsnil or nixd.code-factory/config.tomlConfig schema: https://code-factory-action.xmtp.team/schema.json
Create .code-factory/config.toml if it does not exist. If it does, read it, merge additions without clobbering user values, and ask before changing anything already set.
ALWAYS include the schema directive as the very first line of the file:
#:schema https://code-factory-action.xmtp.team/schema.json
This is non-negotiable — every .code-factory/config.toml produced or touched by this skill must start with that directive. When merging into an existing file that lacks it, add it as the first line (this is the one edit allowed without asking, since it is purely an editor hint).
Required rules:
[[sandbox.volumes]] entry with path = "/nix/store" and size = "25Gi".sandbox.docker = true.medium; pick one based on the project):
sandbox.size = "large". (Rust and Nix builds routinely exceed medium.)sandbox.size = "small".sandbox.size at the default (emit it commented out — see below).large rule wins.sandbox.size (default "medium") — uncomment only if a rule above sets it.sandbox.docker (default false) — uncomment only if Docker is detected.harness.provider (default "claude_code").scheduled_jobs (default []).on_event.failed_run (default []).[[sandbox.volumes]] entry beyond the Nix one is project-specific and should NOT be scaffolded.# default: so intent is obvious (# default: size = "medium").Shapes: every config scaffolds the full schema surface — defaults appear commented out, detected rules are uncommented and set.
Plain project (no docker, no nix, language outside the small/large rules — e.g. Go):
#:schema https://code-factory-action.xmtp.team/schema.json
[sandbox]
# default: size = "medium"
# default: docker = false
# [harness]
# default: provider = "claude_code"
# default: scheduled_jobs = []
# [[on_event.failed_run]]
# workflows = []
# branches = []
# prompt_additions = ""
Node/TypeScript project, no Docker:
#:schema https://code-factory-action.xmtp.team/schema.json
[sandbox]
size = "small"
# default: docker = false
# [harness]
# default: provider = "claude_code"
# default: scheduled_jobs = []
# [[on_event.failed_run]]
# workflows = []
# branches = []
# prompt_additions = ""
Node project with Docker:
#:schema https://code-factory-action.xmtp.team/schema.json
[sandbox]
# default: size = "medium"
docker = true
# [harness]
# default: provider = "claude_code"
# default: scheduled_jobs = []
# [[on_event.failed_run]]
# workflows = []
# branches = []
# prompt_additions = ""
Rust project with Nix:
#:schema https://code-factory-action.xmtp.team/schema.json
[sandbox]
size = "large"
# default: docker = false
[[sandbox.volumes]]
path = "/nix/store"
size = "25Gi"
# [harness]
# default: provider = "claude_code"
# default: scheduled_jobs = []
# [[on_event.failed_run]]
# workflows = []
# branches = []
# prompt_additions = ""
Project with both Docker and Nix:
#:schema https://code-factory-action.xmtp.team/schema.json
[sandbox]
size = "large"
docker = true
[[sandbox.volumes]]
path = "/nix/store"
size = "25Gi"
# [harness]
# default: provider = "claude_code"
# default: scheduled_jobs = []
# [[on_event.failed_run]]
# workflows = []
# branches = []
# prompt_additions = ""
After writing, validate the TOML parses (python3 -c "import tomllib; tomllib.load(open('.code-factory/config.toml','rb'))").
.devcontainer/devcontainer.jsonIf the file already exists, do not modify it — at all. Read it, record the image and features, proceed to validation. If you see gaps (missing LSPs, missing docker feature, wrong moby setting, outdated image tag), surface them as suggestions in your final report for the user to apply themselves. Never edit, rewrite, merge, or "fix" an existing devcontainer.json without the user explicitly asking for that specific change. This includes reformatting, reordering keys, or adding comments.
The only exception is if validation in step 4 fails because of a container problem — even then, stop and ask the user before changing their devcontainer.json.
If missing, create .devcontainer/devcontainer.json with these guidelines:
Use a Microsoft devcontainer image matching the primary language. Look up the latest tag rather than hardcoding — check the registry by running:
# Example for typescript-node — replace the repo for other languages
curl -s "https://mcr.microsoft.com/api/v1/catalog/devcontainers/typescript-node/tags" | python3 -m json.tool | head -40
Common repos (mcr.microsoft.com/devcontainers/<name>):
typescript-node — Node.js + TypeScriptjavascript-node — plain Node.jspythongorustjavauniversal — if multi-languagePrefer a concrete major-version tag (e.g. :24 for Node 24) over :latest so builds are reproducible.
Docker enabled — add docker-outside-of-docker with moby disabled:
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"moby": false
}
}
Nix enabled — add:
"ghcr.io/devcontainers/features/nix:1": {}
Other common features (add when the language is primary or secondary):
ghcr.io/devcontainers/features/node:1ghcr.io/devcontainers/features/python:1ghcr.io/devcontainers/features/go:1ghcr.io/devcontainers/features/rust:1ghcr.io/devcontainers/features/github-cli:1Install LSPs via postCreateCommand (or per-language package manager). VS Code / Cursor extensions should go under customizations.vscode.extensions. Example:
"postCreateCommand": "npm install -g typescript-language-server && pipx install pyright",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
}
If postCreateCommand is more than a single command, move it into a shell script under .devcontainer/ (e.g. .devcontainer/post-create.sh) and reference it from the JSON:
"postCreateCommand": ".devcontainer/post-create.sh"
Make the script executable (chmod +x), start it with #!/usr/bin/env bash and set -euo pipefail, and keep inline-JSON postCreateCommand reserved for genuine one-liners. This keeps the devcontainer.json readable, lets the script be linted/tested, and avoids quoting pitfalls with && chains.
Whatever commands you found in step 1 must succeed inside the container. If the primary image lacks required tooling (e.g. the project needs pnpm but the image ships npm), add an install step to postCreateCommand or a feature.
{
"name": "<repo-name>",
"image": "mcr.microsoft.com/devcontainers/<language>:<tag>",
"features": {
// docker-outside-of-docker (if docker), nix (if nix), language features as needed
},
"postCreateCommand": "<install-deps-and-lsps>",
"customizations": {
"vscode": {
"extensions": []
}
},
"remoteUser": "vscode"
}
Validate the JSON parses before moving on.
Install the devcontainer CLI and build the container, then exercise the project's commands inside it. Every step must pass before reporting success.
# 1. Install the CLI
npm install -g @devcontainers/cli
# 2. Build and start the container
devcontainer up --workspace-folder .
# 3. Run each detected command inside the container
devcontainer exec --workspace-folder . <build-cmd>
devcontainer exec --workspace-folder . <lint-cmd>
devcontainer exec --workspace-folder . <format-cmd> # or --check variant
devcontainer exec --workspace-folder . <test-cmd>
If any command fails:
devcontainer.json (missing tool, wrong image, missing feature) or in the project config itself (misconfigured script).Do not claim success if any step fails — surface the exact failure and either fix it or stop and ask the user.
Summarize:
.code-factory/config.toml, .devcontainer/devcontainer.json)..code-factory/config.toml (new or merged).devcontainer/devcontainer.json (new only if missing)| Mistake | Fix |
|---|---|
Omitting the #:schema directive at the top of .code-factory/config.toml | Always emit #:schema https://code-factory-action.xmtp.team/schema.json as the first line |
Touching an existing .devcontainer/devcontainer.json | Never edit it — record suggestions in the final report and let the user decide |
Hardcoding :latest image tags | Use a major-version tag so builds are reproducible |
Adding docker-outside-of-docker with moby: true or default | Must be "moby": false per spec |
Forgetting /nix/store volume for Nix repos | Always add it at 25Gi when Nix is detected |
| Skipping validation because "it looks right" | Always devcontainer up and run the project's real commands |
| Disabling a failing check to make validation pass | Fix the root cause; never bypass lint/test |
| Inventing build commands | Read them from package.json, Makefile, README — don't guess |
npx claudepluginhub xmtplabs/code-factory --plugin code-factoryGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.