Skip to main content

outerlayer init

Connect a repository to a factory, install the capture hooks, set up Claude Code with skills and an MCP server, and run doctor.
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:
  1. Connect. Runs outerlayer connect. With no saved credential, or no git remote, this step is skipped. init then says to run outerlayer login and outerlayer init again.
  2. Hooks. Installs the capture hooks into Claude Code, the only agent with a session-start hook.
  3. Shell function. Asks whether plain claude should start through outerlayer claude. See Make plain claude start the launcher.
  4. Agent setup. Installs the four starter skills into .agents/skills/. It writes no maintained skill into the repository. Writes AGENTS.md when the repository has no AGENTS.md or CLAUDE.md. Writes .outerlayer/policy.yaml and two checks, .outerlayer/validators/code-review.yaml and .outerlayer/validators/acceptance-criteria.yaml, each only when it is missing. See Policy and validators. Writes .outerlayer/config.json with "layout": 2 when there is none. Links .claude/skills to ../.agents/skills, so Claude Code finds the skills. Adds the outerlayer and outerlayer-docs MCP servers to .mcp.json. It writes no generated file and runs no context 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/, and context emit compiles them into .claude/skills/. Run init --update to move it. On Windows, git commits the .claude/skills link only when core.symlinks is true. Without it, git writes a text file and Claude Code finds no skills. outerlayer claude does not need the link.
  5. Check. Runs doctor and prints its summary.
Where the agent setup step puts the MCP server entries. The 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, because outerlayer context emit copies it over .mcp.json.
  • If .mcp.json then holds servers that .outerlayer/mcp.json lacks, .mcp.json is kept and has neither entry. init says so. Add the entries to .mcp.json by hand, or move your servers into .outerlayer/mcp.json and run outerlayer context emit.
  • An entry of either name already in the file is left as it is, whatever its value. init lists the file as kept.
What the hooks step writes:
  • SessionStart, SessionEnd and Stop hooks. The settings file is backed up first.
  • Wrappers around existing PreToolUse and PostToolUse hooks, so a hang or a kill leaves evidence. Undo with outerlayer hooks unwrap.
  • A status-line segment. An existing statusLine command is wrapped, not replaced: its output prints first.
It writes nothing when the CLI binary the hooks would point at does not exist. It never starts a background process. When every step passed and the repository is linked, 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 through outerlayer 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:
The launcher finds the real 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.
Each file is in one of four states:
  • Current. It matches what this CLI writes. Nothing to do.
  • Outdated. It matches what an earlier release wrote, so nobody edited it. --update replaces it.
  • Edited. It matches no release. --update never touches it. The plan prints a git diff --no-index command that compares it with this CLI’s version.
  • Missing. --update writes it.
The CLI tells outdated from edited with a list of every version each file has had in a release. The list goes back to 0.4.0, the first release with the starter skills. The list ships inside the package, so --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 nested parameter of kvm_intel or kvm_amd is on, or when doctor cannot read it. Its fix is nested=0 in a file in /etc/modprobe.d.
  • VMScape shows the kernel’s VMScape status (CVE-2025-40300). It warns on Vulnerable and 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 bfq scheduler 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 writes enable=1 for the disk to /sys/fs/cgroup/io.cost.qos. Doctor never changes a scheduler or turns on iocost.
None of these four lines fails doctor. Doctor still exits 0 when all four warn. Three more checks read the gateway. They change nothing.
  • Login or Factory key, named for the credential a command would send. A factory key from OUTERLAYER_API_KEY or the config file always wins over a login. Fails when the gateway refuses the credential: run outerlayer login for 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 connect chose for the repository; the fix is outerlayer 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.
What each credential needs for these checks to pass:
  • 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.read to 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_ID skips Factory and Repository.
Doctor adds a GitHub App: owner/name check per connected repository. When the factory has no connected repository, one GitHub App check warns and names the two steps on the factory’s Work page that link one. The GitHub App check runs only when the credential check passes. It warns when the installation has not accepted a permission builds need, naming each one and the installation’s settings page. It warns when the default branch does not require a pull request; see Protect the default branch. After the GitHub App checks, doctor adds a Governance check when the credential check passes. It asks the gateway which control plane governs this repository, the answer every session and build takes. It passes with the control plane, its ref and the commit the gateway stored, or with “self-governed” when the repository supplies its own context. It warns when the gateway names a control plane but has no commit for it, and when the gateway is too old to report either. The fix for an old gateway is to update the CLI and the gateway to the same release. When doctor runs in a control plane whose .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:
Exit codes: 0 when no check fails (warnings allowed), 1 when any check fails. See also: Troubleshooting.

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.
See also: What leaves your machine.

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.
Exit codes: 0 when it wrapped hooks or found none to wrap. 1 when --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.