# Configuring kasetto.yaml

Declare skills, commands, MCP servers, and instructions in one kasetto.yaml - sources, agents, scope, and composing configs with extends.

When `--config` is omitted, Kasetto looks for config in this order:

1. `$KASETTO_CONFIG` env var
2. `./kasetto.yaml`
3. `source:` key in `$XDG_CONFIG_HOME/kasetto/config.yaml`
4. `$XDG_CONFIG_HOME/kasetto/kasetto.yaml` (or `~/.config/kasetto/kasetto.yaml`)

Point it at a specific file or URL with `--config`, or run `kst init` for local `./kasetto.yaml` (`kst init --global` writes the global config file).
To persist a remote URL as your default, add a `source:` key to `~/.config/kasetto/config.yaml` (see [Persisting a Default Remote Config](#persisting-a-default-remote-config)).

<Callout type="info">

Two similarly named files live in `~/.config/kasetto/`, and they do different jobs:

- **`kasetto.yaml`** is a config. It holds your agents, skills, MCPs, commands, and instructions. `kst init --global` writes this one.
- **`config.yaml`** is a preferences file. Its only job is a `source:` key naming the config to use, and it never contains skills itself.

Because `./kasetto.yaml` is checked first, a project that has its own config always wins over a persisted `source:`.

</Callout>

## Example

{/* kasetto-config:start */}
```yaml
# Option A: preset destination by agent (see README for supported agent values)
agent:
  - codex
  - claude-code

# Option B: manual destination (takes precedence if both are set)
# destination: ./.agents/skills

skills:
  # "*" syncs every skill in the source. Each is a directory with a SKILL.md,
  # discovered in the source root or its skills/ subdirectory
  - source: https://github.com/vercel-labs/next-skills
    # ref: v1.0.0   # pin to a tag or commit; omit to track the default branch
    skills: "*"

  # or list skills by name
  - source: https://github.com/anthropics/skills
    skills:
      - doc-coauthoring
      - frontend-design
      - pptx

  # sub-dir: resolve the named skills under this path, e.g. skills/productivity/grill-me/
  - source: https://github.com/mattpocock/skills
    sub-dir: skills/productivity
    skills:
      - grill-me
      - caveman

  # path: a skill in a non-standard location → <path>/<name>/, here skills/engineering/improve-codebase-architecture/
  - source: https://github.com/mattpocock/skills
    skills:
      - name: improve-codebase-architecture
        path: skills/engineering

commands:
  # names resolve to commands/<name>.md in the source (nested dirs namespace, e.g. git:commit)
  - source: https://github.com/gsd-build/get-shit-done
    commands:
      - gsd:explore
      - gsd:fast

instructions:
  # instructions wire CLAUDE.md / .cursor/rules / AGENTS.md etc. from instructions/<name>.{md,mdc}
  # "*" syncs every instruction; aggregate files (CLAUDE.md, AGENTS.md) get managed blocks
  - source: https://github.com/pivoshenko/pivoshenko.ai
    instructions:
      - docs-autoupdate
      - multi-agent-dispatch

mcps:
  # names resolve to mcps/<name>.json in the source
  - source: https://github.com/pivoshenko/pivoshenko.ai
    branch: main   # track a specific branch (use ref: to pin a tag or commit)
    mcps:
      - github
      - vercel
      - kaggle
```
{/* kasetto-config:end */}

## Reference

### Top-Level Fields

| Key           | Required | Description                                                         |
| ------------- | -------- | ------------------------------------------------------------------- |
| `agent`       | no       | One or more [supported agent presets](/docs/agents) - string or list |
| `destination` | no       | Explicit install path - overrides `agent` if both are set           |
| `scope`       | no       | `"global"` (default) or `"project"` - where to install              |
| `skills`      | **yes**  | List of skill sources                                               |
| `mcps`        | no       | List of MCP server sources                                          |
| `commands`    | no       | List of slash-command sources                                       |
| `instructions`       | no       | List of instruction sources (CLAUDE.md / .cursor/rules / AGENTS.md ...)      |
| `secrets`     | no       | Secret-injection policy for `${kst_...}` placeholders (see [Secret Injection](/docs/secrets)) |
| `extends`     | no       | Path or URL of a parent config to inherit from (string or list)     |

### Skill Source Fields

| Key       | Required | Description                                                                                    |
| --------- | -------- | ---------------------------------------------------------------------------------------------- |
| `source`  | **yes**  | Git host URL or local path (GitHub, GitLab, Bitbucket, Codeberg/Gitea)                         |
| `branch`  | no       | Branch for remote sources (default: `main`, falls back to `master`)                            |
| `ref`     | no       | Git tag, commit SHA, or ref - takes priority over `branch`                                     |
| `sub-dir` | no       | Relative subdirectory within the source used as the discovery root (`sub_dir` alias supported) |
| `skills`  | **yes**  | `"*"` for all, or a list of names / `{ name, path }` objects                                   |

### Skill Entry Fields

Each entry in the `skills` list can be a string (the skill name) or an object:

| Key    | Required | Description                                                                                   |
| ------ | -------- | --------------------------------------------------------------------------------------------- |
| `name` | **yes**  | Name of the skill directory to install                                                        |
| `path` | no       | Parent directory containing `<name>/SKILL.md`, resolved relative to the source root (or `sub-dir` if set). Absolute paths are honored as-is. |

| Form                                | Resolves to                                |
| ----------------------------------- | ------------------------------------------ |
| `- code-reviewer`                   | discovered (root or `skills/`)             |
| `- { name: x }`                     | discovered (root or `skills/`)             |
| `- { name: x, path: dir }`          | `dir/x/SKILL.md`                           |
| `- { name: x, path: nested/dir }`   | `nested/dir/x/SKILL.md`                    |

### MCP Source Fields

| Key      | Required | Description                                                          |
| -------- | -------- | -------------------------------------------------------------------- |
| `source` | **yes**  | Git host URL or local path containing MCP server config              |
| `branch` | no       | Branch for remote sources (default: `main`, falls back to `master`)  |
| `ref`    | no       | Git tag, commit SHA, or ref - takes priority over `branch`           |
| `mcps`   | **yes**  | `"*"` to discover all, or a list of names / `{ name, path }` objects |

When `mcps: "*"`, Kasetto auto-discovers MCP config files in this order:

1. `.mcp.json` at the source root
2. `mcp.json` at the source root
3. Any `.json` file inside the `mcps/` subdirectory

### MCP Entry Fields

Each entry in the `mcps` list can be a plain string (name) or an object, the same as skill entries:

| Form                              | Resolves to             |
| --------------------------------- | ----------------------- |
| `- github`                        | `mcps/github.json`      |
| `- github.json`                   | `mcps/github.json`      |
| `- { name: x }`                   | `mcps/x.json`           |
| `- { name: x, path: dir }`        | `dir/x.json`            |
| `- { name: x, path: nested/dir }` | `nested/dir/x.json`     |

Paths are resolved relative to the source root; absolute paths are honored as-is. `.json` is appended automatically when the name has no extension.


MCP config files must contain a `mcpServers` object with server definitions. Servers are merged
into each agent's native settings file (e.g., `.claude.json` for Claude Code, `.cursor/mcp.json`
for Cursor). See [how sync works](/docs/how-sync-works) for merge behavior details.

A pack can reference secrets with `${kst_<name>}` placeholders (tokens, passwords, API keys) instead
of committing them. They're resolved at sync time from the environment or a credentials file. See
[Secret Injection](/docs/secrets).

### Instruction Source Fields

Instructions wire each agent's instruction file (`CLAUDE.md`, `.cursor/rules/*.mdc`, `AGENTS.md`,
`.github/copilot-instructions.md`, and so on) from a single source. An instruction is Markdown with
optional YAML frontmatter, discovered in the source's `instructions/` directory.

| Key       | Required | Description                                                                                    |
| --------- | -------- | ---------------------------------------------------------------------------------------------- |
| `source`  | **yes**  | Git host URL or local path containing a `instructions/` directory                                      |
| `branch`  | no       | Branch for remote sources (default: `main`, falls back to `master`)                            |
| `ref`     | no       | Git tag, commit SHA, or ref - takes priority over `branch`                                     |
| `sub-dir` | no       | Relative subdirectory within the source used as the discovery root (`sub_dir` alias supported) |
| `instructions`   | **yes**  | `"*"` to discover all, or a list of names / `{ name, path }` objects                           |

When `instructions: "*"`, Kasetto walks `instructions/**/*.{md,mdc}` (nested directories namespace with `:`,
e.g. `house:security`).

### Instruction Entry Fields

Each entry in the `instructions` list can be a plain string (name) or an object, the same as command entries:

| Form                              | Resolves to                       |
| --------------------------------- | --------------------------------- |
| `- style`                         | `instructions/style.{md,mdc}`            |
| `- house:security`                | `instructions/house/security.{md,mdc}`   |
| `- { name: x, path: dir }`        | `dir/x.{md,mdc}`                  |

### How Instructions Land per Agent

Each instruction is transformed into the target agent's native format. Two destination shapes exist:

- **Aggregate file**: many instructions merge into one shared file (`CLAUDE.md`, `AGENTS.md`,
  `GEMINI.md`, `.github/copilot-instructions.md`, ...). Each instruction is wrapped in a managed
  `<!-- kasetto:instruction:ID ... -->` comment block, so your own hand-written content and other instructions in
  the same file are preserved. `remove`/`clean` strip only kasetto's blocks and never delete the
  file.
- **Per-instruction directory**: one file per instruction. Cursor (`.cursor/rules/<name>.mdc`) gets reconstructed
  MDC frontmatter (`description`, `globs`, `alwaysApply`); other directory agents
  (`.windsurf/rules`, `.clinerules`, `.continue/rules`, ...) get the Markdown body only.

`globs`/`alwaysApply` are only meaningful for Cursor; they are dropped for agents that don't scope
instructions. See [supported agents](/docs/agents) for the per-agent destinations.

## Extending Another Config

Use `extends` to inherit from a parent config. Local relative paths resolve against the extending file's directory; HTTPS URLs are fetched with the same auth env vars as `--config`.

```yaml
# child.yaml
extends: ./team-base.yaml
scope: project
skills:
  - source: https://github.com/example/extra-pack
    skills: "*"
```

`extends` accepts a single string or a list. With a list, parents merge left-to-right; the child overrides them all.

```yaml
extends:
  - ./org-base.yaml
  - https://example.com/team-overlay.yaml
```

### Merge Rules

| Field         | Rule                                                                                                                          |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `destination` | Replace - child wins                                                                                                          |
| `scope`       | Replace - child wins                                                                                                          |
| `agent`       | Replace - child wins                                                                                                          |
| `skills`      | Merge by `(source, ref-or-branch, sub-dir)` identity. Same identity replaces; new entries append.                             |
| `mcps`        | Same as `skills` (`sub-dir` is always empty for MCP sources, so identity is `(source, ref-or-branch)`).                       |
| `commands`    | Same as `skills`.                                                                                                            |
| `instructions`       | Same as `skills`.                                                                                                            |

Identity-based merging lets a child *narrow* a parent's `skills: "*"` to a specific list, or pin a different `ref`, while still adding new sources.

Cycles are detected and rejected. Maximum chain depth is 8.

## Remote Configs

Kasetto can fetch configs from any HTTPS URL:

```bash
kst sync --config https://example.com/team-skills.yaml
```

Great for sharing a single config across a team without checking it into every repository.

### Real-World Example

[pivoshenko/pivoshenko.ai](https://github.com/pivoshenko/pivoshenko.ai) is a public config that pulls skills from several community packs for Claude Code and OpenCode:

```bash
kst sync --config https://github.com/pivoshenko/pivoshenko.ai/blob/main/kasetto.yaml
```

Kasetto recognises browser URLs from GitHub, GitLab, and Gitea / Codeberg / Forgejo, and auto-rewrites them to the matching raw-content endpoint. You can paste any of these directly:

- `https://github.com/owner/repo/blob/main/kasetto.yaml`
- `https://gitlab.com/group/repo/-/blob/main/kasetto.yaml`
- `https://codeberg.org/owner/repo/src/branch/main/kasetto.yaml`

Kasetto prints a short `note: rewrote browser URL to raw content: ...` line so you can see what was fetched. Authentication is resolved against the rewritten host, so the same tokens that work for raw URLs apply here too.

If the URL points to a private repository, Kasetto uses the same token-based authentication as skill sources. See [authentication](/docs/authentication) for the full list of supported environment variables.

### Persisting a Default Remote Config

To stop passing `--config` on every run, put the URL in the `source:` key of `~/.config/kasetto/config.yaml`:

```yaml
# ~/.config/kasetto/config.yaml
source: https://github.com/pivoshenko/pivoshenko.ai/blob/main/kasetto.yaml
```

Bare `kst sync` now resolves that URL on its own, on every machine where you drop the same two-line file. Browser URLs are rewritten here exactly as they are for `--config`, and private repositories authenticate the same way.

Three things still take precedence, in this order: `$KASETTO_CONFIG`, an explicit `--config`, and a `./kasetto.yaml` in the current directory. That last one matters most in practice. Inside a repository that ships its own config, the persisted `source:` is ignored, so a global default and a project config coexist without either fighting the other.

The value does not have to be a URL. An absolute local path works too, which is useful for keeping a config outside the repositories that consume it.

## Multiple Agents

The `agent` field accepts a single value or a list. With a list, Kasetto installs skills, commands, and instructions to every agent's directory and merges MCPs into every agent's settings file:

```yaml
agent:
  - claude-code
  - cursor
  - codex

skills:
  - source: https://github.com/org/skill-pack
    skills: "*"
```

Handy when you juggle multiple agents and want them all to share the same skill set.

## Agent vs Destination

If you set both, `destination` wins. Use `agent` for convenience with [supported presets](/docs/agents), or `destination` when you need full control over the install path.

<Callout type="tip">


Use `destination` when targeting an agent that isn't in the supported list.

</Callout>
## Scope: Global vs Project

By default, skills are installed globally into the agent's home-directory path. Add `scope: project` to your config, or pass `--project` on the command line, to install into the current project directory instead.

The `--project` / `--global` flags always override whatever `scope` is set in the config file.

## Environment Variables

These environment variables affect Kasetto's behavior:

| Variable          | Effect                                                                                          |
| ----------------- | ----------------------------------------------------------------------------------------------- |
| `NO_COLOR`        | Disables colored output. Set to any value.                                                      |
| `CLICOLOR_FORCE`  | Forces color even when stdout is not a TTY. Set automatically by `--color always`.              |
| `KASETTO_CONFIG`  | Overrides config discovery to use the exact path or URL (see [Configuration](#configuration)).  |
| `KASETTO_NO_CACHE`| Disables the on-disk source cache, forcing a fresh download + extract on every fetch. Set to any value. |
