/ documentation

maleta install

Resolve and materialize skills and plugins from a Maleta, with destinations, collisions, dry runs, idempotency, and clear exit codes.

#Usage and options

Standard installation
bash
maleta install --file ./maleta.json --tool claude
Plan without writing
bash
maleta install --file ./maleta.json --tool claude --dry-run

Without --file, it reads maleta.json relative to the current directory. Without --tool, it uses targetTool from the file. Accepted values are all, claude, codex, and agents. --dry-run is available only for install and sync.

#Skills and destinations

  • A builtin source is looked up in the local assets at claude/skills/<name>. The shared folder is added automatically when a valid builtin skill exists.
  • A GitHub source uses the declared repository, path, and optional ref. Content is resolved through the GitHub API from the declared public repository and written as bytes; it is not executed.
  • The destination for claude is ~/.claude/skills/<skill.name>/. The destinations for codex and agents are ~/.agents/skills/<skill.name>/. all expands to both directories (Codex and Agents share the second one).

#Plugins

Plugins are applied by the Claude command. If the selection runs with --tool codex or --tool agents, each plugin is skipped with an incompatibility message. The plan can add the marketplace with claude plugin marketplace add <repo> and install with claude plugin install <id>.

  • [skip] plugin '<id>' is Claude-only and is unsupported for --tool <tool>
  • [skip] plugin '<id>' is not present in the local plugin manifest; not installed
  • [ok] plugin '<id>' installed

#Safe, idempotent writes

The operation is additive: it copies the existing tree to a staging directory and overwrites only files from the selection. It does not prune and preserves unmanaged files. Identical bytes are not rewritten and appear as [ok] <label> already aligned -> <dest>. Replacement uses transactional staging, backup, and rollback; temporary directories are named .maleta-stage-* and <stage>.old during the operation.

#Destination safeguards

The CLI rejects an unsafe directory name with unsafe target directory name: <name>. It also rejects a destination containing a symlink with destination path contains a symlink: <path>, a destination that is not a directory with destination is not a directory: <path>, and a file path that is not a regular file.

#Dry run

With --dry-run, the CLI makes no network requests and writes nothing to disk. The materialization line is:

Materialization line in a dry run
text
[dry-run] would install <label> -> <dest>
Plugin lines in a dry run
text
[dry-run] claude plugin marketplace add <repo>
[dry-run] claude plugin install <id>

An empty selection prints [warn] no skills or plugins selected; edit the selected Maleta file or export one from https://app.maleta.dev before the usual install: no relevant changes footer, including with --dry-run. Otherwise, with --dry-run and at least one materialization action planned, no footer is printed. With no relevant changes—no files changed and no plugin commands run—the footer is install: no relevant changes; when the local selection is applied, the footer is install: applied local selection.

#How it differs from sync

Exact differences
Aspectinstallsync
Plugin pre-checkNone.Runs claude plugin list before installation.
Plugin already installedReinstalls it.Skips it with [ok] plugin '<id>' already installed.
Changed file[ok] install <label> -> <dest>[ok] sync <label> -> <dest>
Footerinstall: no relevant changes or install: applied local selectionsync: no relevant changes or sync: applied local selection

#Exit codes

CodeCondition
0No failures (`failures === 0`); skipped or unsupported items also result in 0.
1Document, plan, GitHub resolution, limit, collision, staging/transfer, or plugin error.
2Invalid command, option, or flag value.
4The file's targetOs differs from the host: [error] targetOs '<x>' does not match the local host '<y>'; refusing install.