sous compiles AI coding agent configuration from templates. You write skills, memories, and
instructions once as LiquidJS templates in layered sources, then sous renders them into the
formats agents actually read: .claude/ plus CLAUDE.md for Claude Code, .codex/ plus
AGENTS.md for Codex. The CLI binary is named xcv.
New to sous? Watch the animated introduction at sous.io.
- Share one set of agent configs across every project you work in, and with teammates.
- Write a rule once as a template with variables; each project gets its own rendered copy.
- Compile the same source to more than one agent's format.
- Keep machine-specific values (absolute paths, tokens) in an untracked env file, out of git, with shared team defaults in a committed one.
Install the CLI:
npm install -g @sous-io/sousOr run it from a clone (useful when developing sous itself):
git clone git@github.com:sous-io/sous.git
cd sous
npm install
npm linkThen set up a project. A project needs a .sous/ directory holding a config file, named
sous.config.js, sous.config.mjs, or sous.config.json:
cd /path/to/your/project
mkdir .sous
$EDITOR .sous/sous.config.jsA config that compiles one file:
export const config = {
projects: {
myproject: {
name: "My Project",
_vars: { projectRoot: "${sousDir}/.." },
compilation: {
targets: [
{
entryPoint: "${sousDir}/AGENTS.md",
outputs: [{ destinationFile: "${projectRoot}/CLAUDE.md" }],
},
],
},
},
},
};${sousDir} is the .sous/ directory sous found, so a config can name paths relative to
itself without hardcoding anything machine-specific. With a single project defined you do
not need defaultProject; sous uses the only one. Then build:
xcv buildxcv build compiles every configured target and prunes outputs that are no longer in the
config. Config discovery walks up from the current directory until it finds a .sous/
directory holding a config, so you can run it from anywhere inside the project. Pass
--config <path> to point at one explicitly instead.
Values reach the config through its top-level _env block, which maps a config variable
to an environment variable. Both env files use KEY=value lines and are loaded before
anything resolves. There are two layers:
.sous/.envis committed. Put shared team defaults here, never secrets..sous/.env.localis gitignored. Put machine-specific values and secrets here.
Precedence, highest first: your shell environment, then .env.local, then .env. So
FOO=bar xcv build beats both files, and .env.local beats .env per key. This repo
ships .sous/.env.local.example documenting the layer.
Useful commands:
| Command | What it does |
|---|---|
xcv build |
Compile, then prune stale outputs |
xcv build --watch |
Rebuild on source changes |
xcv compile |
Compile only |
xcv prune |
Remove outputs no longer in the config |
xcv clear |
Delete every file sous wrote for the project |
xcv launch claude |
Build, then start the agent |
Sources are markdown files. A file with .tpl. in its name is rendered through LiquidJS and
the .tpl. is dropped from the output name (skill.tpl.md becomes skill.md). Files without
.tpl. are copied verbatim. Any line of the form @path/to/file.md pulls in another file, so
one instruction block can be composed into several outputs.
Config lists targets. Each target names an entry point or a glob, plus one or more outputs, and each level can define variables:
// One entry point to one file.
{
entryPoint: "${sousDir}/memory/MEMORY.root.tpl.md",
outputs: [{ destinationFile: "${projectRoot}/CLAUDE.md" }],
}
// One glob to a directory, mirroring the source tree under it.
{
entryGlob: "${sousDir}/skills/**/*",
outputs: [{ destinationDir: "${projectRoot}/.claude/skills" }],
}Variables resolve later-wins across scopes: auto-injected, env, root, project, compilation,
target, output. Templates read them as {{ varName }}; config files reference them as ${varName}.
The auto-injected ones include ${sousDir} and ${sousConfigPath} for the discovered
config, and ${sousTemplatePath} for the template being rendered.
Sources come in three tiers, each able to build on the one above it:
- Built-in shared prompts that ship with sous, covering skill authoring, templating, and the sous conventions themselves.
- Team-shared, a repo your team owns, holding the configs everyone should get.
- Per-project, the project's own
.sous/directory, for anything specific to it.
The built-in tier is reachable without knowing where sous is installed. @include paths
accept aliases, and two are always defined: ~sous-shared for the shared prompts that ship
with sous, and ~project for the project root. So @~sous-shared/_partials/sub-agent-delegation.md
composes a built-in block into your own instruction file, and an entryGlob can point at a
built-in skill bundle to compile it into your project. Define your own aliases with an
_aliases block to do the same for a team-shared repo.
Sous records every file and directory it writes in a state file, .sous/sous.state.json by
default, which is what lets prune and clear clean up precisely instead of guessing.
- Ubuntu is where sous is developed and tested.
- macOS should work for the core CLI, but is not tested yet. Reports welcome.
- Windows is not supported.
- The browser-automation skill bundle is Linux only. It depends on Linux Chrome paths and the GNOME keyring.
Node 22 is required; the version is pinned in .nvmrc.
See CONTRIBUTING.md. Note the licensing terms for contributions.
Apache License 2.0. See LICENSE.