outerlayer init
Connect a repository to a factory, install the capture hooks, set up Claude Code with skills and an MCP server, and rundoctor.
A full
init installs the starter skills already, so --template matters with --local, where it is the only way to get them. It cannot be combined with --remove or --org.
Before its steps, init installs the five maintained skills once per machine. It writes them to ~/.agents/skills/ and puts a link to each in ~/.claude/skills/. Where a link cannot be made, it writes a copy. Every later outerlayer command keeps them at its own version, and outerlayer claude installs them too. A repository in the AGENTS.md layout carries none of them. If a write fails, init prints a warning and goes on, and outerlayer doctor reports the gap.
init never signs in. On a terminal it asks one question, about the shell function, and writes nothing to your shell until you say yes. It runs these steps in order:
-
Connect. Runs
outerlayer connect. With no saved credential, or no git remote, this step is skipped.initthen says to runouterlayer loginandouterlayer initagain. - Hooks. Installs the capture hooks into Claude Code, the only agent with a session-start hook.
-
Shell function. Asks whether plain
claudeshould start throughouterlayer claude. See Make plain claude start the launcher. -
Agent setup. Installs the four starter skills into
.agents/skills/. It writes no maintained skill into the repository. WritesAGENTS.mdwhen the repository has noAGENTS.mdorCLAUDE.md. Writes.outerlayer/policy.yamland two checks,.outerlayer/validators/code-review.yamland.outerlayer/validators/acceptance-criteria.yaml, each only when it is missing. See Policy and validators. Writes.outerlayer/config.jsonwith"layout": 2when there is none. Links.claude/skillsto../.agents/skills, so Claude Code finds the skills. Adds theouterlayerandouterlayer-docsMCP servers to.mcp.json. It writes no generated file and runs nocontext emit. Files are left uncommitted. Skipped outside a git repository and when the repository’s context comes from a control plane. See Agent context. A repository that has not moved keeps the earlier behavior: the skills go to.outerlayer/skills/, andcontext emitcompiles them into.claude/skills/. Runinit --updateto move it. On Windows, git commits the.claude/skillslink only whencore.symlinksis true. Without it, git writes a text file and Claude Code finds no skills.outerlayer claudedoes not need the link. -
Check. Runs
doctorand prints its summary.
outerlayer entry runs npx -y @outerlayer/cli mcp serve, so it starts on any machine with Node, including a teammate’s who has not installed the CLI. The outerlayer-docs entry is the OuterLayer docs MCP server, { "type": "http", "url": "https://docs.outerlayer.ai/mcp" }, which lets your agent look up how OuterLayer works. It carries no credential.
- With no
.outerlayer/mcp.json, both entries go into.mcp.json, beside any servers already there. - In a repository that has not moved, and has an
.outerlayer/mcp.json, both entries go into that file instead, becauseouterlayer context emitcopies it over.mcp.json. - If
.mcp.jsonthen holds servers that.outerlayer/mcp.jsonlacks,.mcp.jsonis kept and has neither entry.initsays so. Add the entries to.mcp.jsonby hand, or move your servers into.outerlayer/mcp.jsonand runouterlayer context emit. - An entry of either name already in the file is left as it is, whatever its value.
initlists the file as kept.
SessionStart,SessionEndandStophooks. The settings file is backed up first.- Wrappers around existing
PreToolUseandPostToolUsehooks, so a hang or a kill leaves evidence. Undo withouterlayer hooks unwrap. - A status-line segment. An existing
statusLinecommand is wrapped, not replaced: its output prints first.
init prints one last line. That line is “Add an issue on the Work page and choose Build locally, or Build if a host runs for this factory.” If agent setup wrote files, or finds a change that is not committed, init also prints a line to commit and push them. The line names .outerlayer/, AGENTS.md, .agents/, .mcp.json and .claude/skills, and init looks for changes in each. A repository that still keeps its skills in .outerlayer/skills/ gets the line for .outerlayer/ only. So a second run prints the line again until you commit those files. This line comes before the “Add an issue” line. It prints that line even when the connect or doctor step failed, or the repository is not linked yet. The factory reads the policy from the default branch, so no check runs on pull requests until it is there. If the repository still has to be linked, init prints the link to follow, then the commit line, and the “Add an issue” line waits.
Make plain claude start the launcher
A governed repository gets its control plane throughouterlayer claude. init can make plain claude start it. On a terminal, init asks. On yes, it adds a block marked # BEGIN outerlayer claude to ~/.zshrc or ~/.bashrc, chosen from $SHELL. The block defines one function:
claude on your PATH. Another shell prints the line for you to add. With no terminal and no flag, init writes nothing. init --no-shell-function and init --remove take the block out and leave the rest of the file as it was.
init --local --shell-function adds the block without asking, and init --local --no-shell-function removes it. init --local with neither flag leaves the startup file alone.
Update the files init wrote
init writes some files once and never overwrites them: the template skills, .outerlayer/policy.yaml, the two checks in .outerlayer/validators/ (code-review.yaml and acceptance-criteria.yaml), and the outerlayer and outerlayer-docs MCP entries. A later CLI may write a better version of one. outerlayer init --update brings them up to date without losing your edits.
- Current. It matches what this CLI writes. Nothing to do.
- Outdated. It matches what an earlier release wrote, so nobody edited it.
--updatereplaces it. - Edited. It matches no release.
--updatenever touches it. The plan prints agit diff --no-indexcommand that compares it with this CLI’s version. - Missing.
--updatewrites it.
--update needs no network.
An MCP entry counts as outdated when it is exactly an entry an earlier init wrote, such as outerlayer mcp serve run as a global command. The other servers and keys in the file are kept.
In a repository that has not moved to the AGENTS.md layout, --update first moves it. The move removes each generated file, moves the sources to AGENTS.md, .agents/skills/ and .mcp.json, links .claude/skills to ../.agents/skills, and sets "layout": 2 in .outerlayer/config.json. It never deletes a file you edited. It keeps one and lists its path. If .claude/skills/ still holds a file that is not generated, it makes no link. --no-skills-link also makes none. --control-plane makes none either. It prints that a CLI or runner older than 0.21.0 delivers none of the moved skills. Keep .claude/skills/ as an identical copy until those are upgraded. See Move a repository to this layout.
In the AGENTS.md layout, --update writes no maintained skill into the repository. The CLI keeps the maintained skills in ~/.agents/skills/ on each machine. --update removes each maintained skill folder that carries the “maintained by OuterLayer” line, from .agents/skills/ and from a .claude/skills/ that is a folder. It keeps a folder without that line. Once those folders are gone, it changes each path to one of them to ~/.agents/skills/<skill>/. It does this in AGENTS.md, CLAUDE.md and the Markdown files of the repository’s skills, and only the path changes. A path relative to the file, such as ../outerlayer-build/SKILL.md in build, counts too. A path to a folder the repository still holds is left alone. Validator and policy files are not changed. When it removes a maintained skill, its output gives two warnings. Every machine and runner host must run this CLI version or later. Each machine a person works on must run outerlayer init --local. Both must happen before you commit the removal. With a login, it also lists the factory’s runner hosts from the gateway. It names each host that sends heartbeats on a CLI older than 0.27.0, and each host whose heartbeats stopped on one. See Upgrade OuterLayer.
It then updates the starter files. In the AGENTS.md layout, nothing is compiled, and --update runs no context emit. In a repository that has not moved because a source clash was left, it runs outerlayer context emit as before and keeps a hand-written output, as init does. It leaves everything uncommitted. --dry-run writes nothing and does not run the emit. Like the agent setup step, --update does nothing outside a git repository or when the repository’s context comes from a control plane. It cannot be combined with --remove, --org, --local, --template or --factory. --json prints each file’s state and action. The exit code is 1 when a write or the emit failed.
Exit codes: 0 when every step was done or skipped, including a second run that changes nothing. A repository that is not linked yet is not a failure: init marks the connect line with ! instead of ✓, prints the link, and exits 0. connect on its own exits 2 for the same repository. 1 when a step failed, a doctor check failed, or a flag was refused. A failed step does not stop later ones, but doctor is skipped when the hooks could not be installed.
See also: Quickstart, Agent context.
outerlayer doctor
Check the installation. Every failing check names its fix.
Checks, in order: Claude Code home, Transcripts, Hooks installed, Hooks firing, Wrapped hooks, Git hooks directory, Spool writable, Cloud sync, Daemon running, Retention (cleanupPeriodDays), Disk headroom, Claude Code version, Settings JSON valid, Status line, Claude Code installs, Control plane. Six appear only when they apply: Renamed skills, Skill names, Control plane degradation, Installed CLI, Starter files and MCP server. Three more appear only when they apply: Build skill, Maintained skills on this machine and Committed maintained skills.
Renamed skills and Skill names report a maintained skill still under, or named by, an earlier name. See Upgrade OuterLayer. Installed CLI needs a copy at
~/.outerlayer/cli.
Maintained skills on this machine warns when a repository’s build reads ~/.agents/skills/outerlayer-build/SKILL.md and ~/.agents/skills/ lacks this CLI version’s maintained skills. The fix is outerlayer init --local. Committed maintained skills names each maintained skill folder that a repository commits. The fix is outerlayer init --update. Runner hosts for the maintained skills runs beside it when the credential check passes. It warns about each runner host on a CLI older than 0.27.0. Paths to the maintained skills names each file that still names a maintained skill folder the repository no longer holds. The fix is outerlayer init --update.
Starter files appears in a repository where init wrote at least one of its files. It reports each file and MCP entry init writes once as current, outdated, edited or missing (see Update the files init wrote). It warns when one is outdated or missing, and its fix is outerlayer init --update. Edited files are listed but do not warn. It also warns when the CLI’s list of earlier versions is missing or unreadable, because outdated files then look edited.
MCP server appears when the repository’s .mcp.json has an outerlayer entry that runs a command. It warns when that command is not on PATH, because the agent then starts without OuterLayer’s tools. When the entry is one an earlier init wrote, Starter files reports it instead, so it is reported once.
On a runner host, the checks change. A runner host is a machine whose ~/.outerlayer/config.json has a runner block. Its checks for the Claude Code home, transcripts, hooks, spool, daemon and status line become one skipped Laptop checks line. Doctor then adds the runner’s own checks. See The runner’s own checks.
Four of the runner’s lines report what a build can reach on the host. They read the host and change nothing. Nested virtualization, VMScape and Disk I/O sharing appear only with builtin:vm hooks. runc appears only with builtin:container hooks.
- Nested virtualization warns when the
nestedparameter ofkvm_intelorkvm_amdis on, or when doctor cannot read it. Its fix isnested=0in a file in/etc/modprobe.d. - VMScape shows the kernel’s VMScape status (CVE-2025-40300). It warns on
Vulnerableand on a value doctor cannot read. It is skipped on a kernel that does not report VMScape. - runc reads the runc version from the Docker daemon. It warns when that version is older than 1.2.8, 1.3.3 or 1.4.0-rc.3, and when Docker reports none.
- Disk I/O sharing reports whether the disk under the build disks acts on the I/O weight that each microVM build gets. The kernel acts on the weight only when the disk uses the
bfqscheduler or has iocost turned on. Doctor follows a partition to its disk, and an LVM or dm-crypt volume to the disks below it. It warns when a disk uses another scheduler and has iocost off, and when it finds no disk. Its fix writesenable=1for the disk to/sys/fs/cgroup/io.cost.qos. Doctor never changes a scheduler or turns on iocost.
- Login or Factory key, named for the credential a command would send. A factory key from
OUTERLAYER_API_KEYor the config file always wins over a login. Fails when the gateway refuses the credential: runouterlayer loginfor a login, or get a fresh key for a factory key. Warns when the gateway does not answer. - Factory fails when the credential cannot read its factory. For a login, that is the factory
outerlayer connectchose for the repository; the fix isouterlayer connect. For a factory key, it is the factory the key is bound to. - Repository warns when this repository is not linked to that factory. Fix it in the factory’s setup panel, or run
outerlayer connect --factory <org>/<factory>when another factory of yours has it linked.
- A login needs a factory chosen for the repository with
outerlayer connect. - A factory key needs the factory it is bound to to be readable, and
git.readto read its linked repositories. - With no login and no factory key, all three are skipped and doctor makes no network call.
- Outside a git repository, a login with no
OUTERLAYER_APP_IDskips Factory and Repository.
.outerlayer/config.json still has a governs list, it adds a Governs list warning. The list is ignored. You can delete it once every machine and runner host runs CLI 0.17.0 or later. On a host whose runner builds in containers, Control plane access checks each repository’s control plane the same way. See Share instructions across repositories.
On a fresh machine right after init, these warn, and that is expected:
outerlayer daemon
Run the copy-out daemon in the foreground. Claude Code deletes transcripts after about 30 days. The daemon copies them first.
It keeps the status-line state fresh. With cloud credentials, it also streams the new turns of a session launched with
OUTERLAYER_WORK, so its page follows along before sync runs. init does not start it: run it in a terminal you keep open, or under a login agent. outerlayer watch is the former name and still works, with a warning.
outerlayer hooks status
List hook entries in user and project settings, marking the wrapped ones.
A settings file that is not valid JSON is reported, and the other is still listed. Exits 0.
outerlayer hooks wrap
Wrap hook commands so a hang or a kill leaves evidence.init already wraps PreToolUse and PostToolUse hooks. Run this for other events, for hooks added later, or after init --no-wrap-hooks.
Each wrapped hook adds one Node start and one spawn every time it fires. Like
init, hooks wrap first copies the CLI to ~/.outerlayer/cli, and the wrappers run that copy.
--no-input comes without --all, or the CLI cannot be copied to ~/.outerlayer/cli. 1 also when the settings file is not valid JSON, or the CLI path the wrapper would use does not exist (reinstall, then rerun).
outerlayer hooks unwrap
Restore wrapped hooks to their original commands. Use it too if a wrapper misbehaves.
Exit codes: 0, or 1 when the settings file is not valid JSON.