install
CLI reference for the apothem install command.
Install a harness adapter configuration from the shared profile.
Synopsis
apothem install --harness NAME|all [--profile PATH] [--dry-run]
[--clean|--fresh] [--yes] [--project PATH]
[--quiet|-q] [--verbose|-v]
[--format plain|json] [--json] [--no-color]Loads and validates the shared profile, selects a named adapter or the
registry-wide all set, validates the materialization plan, and writes
harness-native configuration plus support cohorts. Project-scope adapters
require --project PATH.
The continuous-form alias apothem installing (also accepted as
apothem Installing) resolves to the same handler.
First run without a profile
When --profile is omitted and no profile exists at the default path
(~/.config/apothem/profile.yaml), install writes the starter profile there
first, prints Created a starter profile at <path>, and continues. The starter
profile carries placeholder identity fields, so the install also prints the
placeholder-identity note; personalize the profile, then run
update to apply it. Under --json the creation
is reported as a warnings entry with "operation": "profile_created".
--dry-runnever writes the profile: the preview uses the starter profile in memory and reports"operation": "profile_scaffold_preview".- An explicit
--profile PATHthat does not exist is never created; the command exits 1 withprofile.not_found.
Blast-radius preview
install --harness all fans out into mixed scopes: project-scope adapters write
under the supplied --project root, while user-scope adapters write under your
home directory — outside that root. Before the install writes any file, the command
prints the concrete targets grouped under two headings: those inside the project
root and those under your home directory. A third heading lists the shared
folders in your home directory that the project-scope adapters write, outside
--project: the skills folder and ~/.config/apothem/ (see
Folders in your home directory). The one
exception is --clean: its clean-slate step runs before this preview and writes
a backup and removes prior targets, as described below.
When the selection writes outside the project root, whether to a home-rooted
adapter's folder or to a shared folder, an interactive confirmation guards the
home-rooted writes. --yes, a non-interactive shell (no TTY),
--dry-run, and --format json each proceed without prompting. Only --dry-run
writes nothing; --format json skips the preview and the confirmation prompt but
still performs the writes. Declining the home-directory prompt aborts before the install writes. With
--clean, the clean-slate step runs first under its own per-target confirmation:
it writes a backup under ~/.apothem/backups and removes the targets it confirms.
Those removals and the backup stay in place when the install prompt is declined.
Folders in your home directory
Seven project-scope adapters write Apothem's skills, and the rules and templates the skills cite, to folders in your user home:
cursor, github-copilot, windsurf, zed -> ~/.agents/skills/ (codex writes it too)
codebuddy -> ~/.codebuddy/skills/
kiro -> ~/.kiro/skills/
trae -> ~/.trae/skills/
all seven -> ~/.config/apothem/rules/ and templates/ (codex uses them too)--projectselects the rules file and the project the install belongs to. It does not change where the skills go: an install with--project Aand one with--project Bwrite the same folders.- Every install that names a folder writes the same files. A second install
finds them and reports
unchanged, and the order you install in does not matter. - The home folders are written before anything in the project. If a write there
fails, the adapter's install stops with the error and the project is
unchanged. The error names the path in the way, for example a file called
~/.agentswhere the folder belongs. - Each skill folder is written to a hidden
.<name>.apothem-stagingfolder beside it and renamed into place when complete, so a failed or interrupted write never leaves a half-written skill folder under its final name. Run the install again to finish; it replaces a leftover staging folder. - A symbolic link at or above one of these folders, as dotfile managers create
for
~/.configor~/.agents, is followed when it leads to somewhere inside your home directory. A link that leaves your home directory stops the install withtarget escapes the allowed materialization root, and so does a link inside a skill folder. - The install adds no skill or rule file to your repository. The project gets
the adapter's rules file, plus the
.apothem/data folder every project install creates. - A skill folder that has an Apothem skill's name and that Apothem did not write
is skipped. The install prints a
Warning:line and the--format jsonenvelope carries awarningsentry with"outcome": "warning"and"operation": "skill_conflict"that names the folder. Rename or move the folder, then runupdate. - Every such install, update, and dry run prints a
Note:that names the folders it writes outside--project. In the JSON envelope it is awarningsentry with"operation": "user_level_write"and apathslist.
Capability notes
Each adapter projects only the capabilities its harness supports natively;
capabilities with no native surface are reported, not silently dropped. In plain
mode this is a single grouped note per harness (for example
Note: <harness> - 9 capabilities not projected; pass --verbose for detail);
under --verbose each capability prints its own rationale line. Any other
adapter warning prints on its own Warning: line in plain mode too, for example
the Zed warning that names an instruction file the new .rules hides. The
--format json envelope always carries the full warnings array regardless of
verbosity.
Install and update also print advisories as Note: lines. An advisory never
changes what the install writes. When an install writes a shared root, a path
other tools also load (for example the skills folder ~/.agents/skills/),
the note names those tools, and puts a tool that loads the path only under a
condition in parentheses, for example Open-Claw (only under its default state directory). An install that writes a folder other installs write too (the
holder role) says the folder stays until the last Apothem install that uses
it is uninstalled, and names the installs that use it now. When an install
targets a tool that already loads Apothem content from another install's shared
root, the note names the install that placed it: the registered owner while it
still uses the folder, otherwise the oldest install that does. In the
--format json envelope each advisory is a warnings entry with
"outcome": "advisory" and "operation": "shared_root"; its role is owner,
holder, or reader, holders lists the installs using the folder, and
owner_of_record names the owner of record.
An install that registers hooks also prints notes about the hook file. A
hook_review advisory names the step the tool needs before it runs the hooks (a
restart and a review, or trusting the workspace), or the hazard of a hook file
that a repository commits and that names this machine's interpreter. A
hook_import advisory appears for a tool that also runs the hooks in Claude Code's
settings files, such as those the Apothem install for Claude Code writes, and names
the tool's own switch for turning that import off and what the switch also stops. Each is a warnings entry with
"outcome": "advisory", the harness, the path of the hook file and a
message.
A hook command holds the project path and the interpreter path inside double
quotes, which sh, Git Bash and PowerShell each read. A path that contains $, a
backtick, a double quote or a backslash would make the command run a different
file, so the install (and --dry-run) stops with an error that names the path and
writes nothing; move or rename the project and run it again. A space or an
apostrophe in a path is fine.
The profile's MCP servers get three advisories, each naming the profile field:
| Operation | Condition | Fix |
|---|---|---|
mcp_deprecated_transport | transport: sse (the MCP specification deprecates HTTP+SSE) | Use streamable-http when the server supports it. |
mcp_plain_http | an http:// URL to a host that is not loopback | Use an https:// URL. |
mcp_literal_credential | a headers or env value shaped like a token (ghp_, gho_, ghu_, ghs_, ghr_, github_pat_, sk-, xoxa-, xoxb-, xoxo-, xoxp-, xoxr-, xoxs-, or Bearer with a long token) | Keep the secret in an environment variable and write ${GITHUB_TOKEN}-style references. |
The credential advisory never prints the value it found. A value that contains
a ${...} reference is never flagged.
Operator configs with comments
Some harness configs are files you also edit, such as settings.json,
opencode.json (which may be JSONC), openclaw.json (JSON5), and
config.yaml. Install merges its keys into these files and keeps every key you
added.
A merge rewrites the file as plain JSON or YAML, which would drop comments, trailing commas, and JSON5 syntax. So:
- When the merge would not change any value (for example, you already added Apothem's keys yourself), the file is left byte-for-byte as it is.
- When the merge must change a value in a file that carries comments or JSON5
syntax, or in a file that does not parse at all, install writes nothing for
that harness and exits 1 with the error code
config.unparseable. Thefixfield names the keys install would add, so you can convert the file to plain JSON or YAML, or add those keys by hand and re-run. - When a key install fills with a mapping or a list (for example
skills.external_dirsinconfig.yaml) holds a scalar value, or the other container shape, in your file, install writes nothing for that harness and exits 1 with the same error code, because filling the key would discard your value. The error names the key; change it to the shape it names, or remove it, and re-run. A key you left empty (skills:with nothing under it) is filled.
Options
| Option | Description |
|---|---|
--harness NAME | Harness adapter to install, or all for the registry-wide set (required). With all, harnesses listed in the profile's exclude_harnesses are skipped, but a harness named explicitly is installed even when listed. Run apothem harnesses list for registered names. |
--profile PATH | Path to shared profile YAML. Defaults to ~/.config/apothem/profile.yaml. |
--dry-run | Preview install without writing files. |
--clean, --fresh | Opt-in clean slate: back up and remove the prior per-harness install state before installing. |
--yes | Skip per-target confirmation during a clean-slate removal (required for non-interactive --clean runs). |
--project PATH | Project root for project-scope harnesses. |
--quiet, -q | Suppress informational output; only errors are emitted. |
--verbose, -v | Print each non-projected capability's rationale instead of the grouped per-harness note. |
--format plain|json | Output format (default: plain). |
--json | Shorthand for --format json. |
--no-color | Disable ANSI color codes in output. |
-h, --help | Show help and exit. |
JSON output
When --json (or --format json) is supplied, a single JSON document
is written to stdout:
{
"schema_version": 1,
"status": "success",
"command": "install",
"action": "installed",
"harness": "claude-code",
"profile_path": "C:\\Users\\Example\\.config\\apothem\\profile.yaml",
"project": null,
"files_written": ["C:\\Users\\Example\\.claude\\settings.json"],
"results": [],
"warnings": [],
"error": null,
"output_path": "C:\\Users\\Example\\.claude\\settings.json"
}For --dry-run, nothing is written and results lists every path the install
would write, each with the outcome it would have (created, updated or
unchanged) and, for a file you also edit, the unified diff in
detail.diff — the same plan apothem diff
shows:
{
"schema_version": 1,
"status": "dry_run",
"command": "install",
"action": "dry_run",
"harness": "claude-code",
"files_written": [],
"results": [
{
"harness": "claude-code",
"outcome": "created",
"operation": "write_text",
"path": "C:\\Users\\Example\\.claude\\settings.json",
"message": "dry run: no filesystem changes made"
}
],
"warnings": [],
"error": null
}When --clean is supplied, the envelope additionally carries a clean object
describing the removal phase — the per-target disposition list, whether the run
was a preview, and the timestamped backup directory (null in a dry run):
{
"clean": {
"dry_run": true,
"backup_dir": null,
"targets": [
{
"path": "C:\\Users\\Example\\.claude",
"present": true,
"removed": false,
"skipped_reason": null
}
]
}
}A clean dry run previews both phases in one document: the removal preview under
clean and the fresh-write preview under results.
Expected validation errors use the same envelope and include an error object:
{
"schema_version": 1,
"status": "error",
"command": "install",
"harness": "all",
"files_written": [],
"error": {
"code": "project.required",
"field": "project",
"reason": "project-scope harnesses require --project: cursor, gemini-cli, github-copilot, kimi-code, windsurf, codebuddy, kiro, trae, zed, glm.",
"fix": "Pass --project PATH or select only user-scope harnesses."
}
}Examples
apothem install --harness claude-code
apothem install --harness claude-code --dry-run
apothem install --harness cursor --project . --profile ~/profile.yaml --json
apothem install --harness all --project . --dry-run --json
apothem installing --harness claude-code # continuous-form alias
apothem Installing --harness claude-code # capitalized variantExit codes
| Code | Meaning |
|---|---|
| 0 | Adapter installed successfully or dry-run planned cleanly |
| 1 | Expected validation, profile, harness, project, or adapter error |
| 2 | Partial batch materialization after at least one write |
| 64 | Usage error: an unknown option or command, or a missing or invalid option value. Under --json the error is a JSON envelope with code cli.usage. |
See also
apothem installing— continuous-form alias for this command (documented here; the CLI accepts both forms)- apothem update — re-apply current profile to a harness
- apothem verify — confirm adapter is live
- Getting Started — full installation guide