# CocoaSkills RFC 0007 — Skill Dependencies

Status: draft
Date: 2026-07-02
Author: Ivan Oparin
Target: v0.9.0
Russian translation: [v0.9-design.ru.md](v0.9-design.ru.md)

A skill can require other skills. This RFC defines the manifest form of a requirement, the resolution of the dependency closure, the install semantics, and the security boundary.

## 1. Overview

- `Skillfile.json` keeps schema v1 and lists the skills a project installs directly.
- `csk-skill.json` schema v4 adds `dependencies.skills`. Each entry names a provider skill and carries its git URL, an exact ref, and an activation mode. An entry is self-contained: the requirement holds everything needed to fetch its provider.
- Three activation modes control what a dependency contributes to the consumer: `full` gives the prompt context and the commands, `runtime` gives the commands, `context` gives the prompt context.
- The resolver expands requirements transitively. Within one closure a skill name resolves to one commit and one source.
- A machine-level source allowlist authorizes every fetch.
- The installer materializes each node according to its effective mode, prints the resolved closure, and records it in the install markers.
- A workflow is a skill that declares dependencies and exports no commands. A consumer installs a workflow with a single `Skillfile.json` entry.

## 2. Motivating cases

Two recurring cases drive the design.

An orchestrator skill runs a multi-step process. Its SKILL.md delegates whole steps to provider skills such as an issue tracker, a monitoring client, and a review tool: the agent reads their instructions and runs their commands. The orchestrator publishes that composition once; a consumer installs the workflow with one project entry.

A library-style skill builds on a command that another skill exports. The consumer's scripts call the provider executable, the binary is available on `PATH`, and the usage is documented in the consumer's own SKILL.md. The requirement is reproducible: csk fetches the provider and installs the command.

The first case activates entire skills. The second activates a single command. The mode field covers both.

## 3. Requirement manifest

Requirements live in `csk-skill.json` schema v4 under `dependencies.skills`.

```jsonc
{
  "schema_version": 4,
  "runtime_roots": ["scripts"],
  "capabilities": { "exec": ["trk", "git"], "network": "none" },
  "commands": {
    "report": { "type": "script", "unix_path": "scripts/report", "win_path": "scripts/report.cmd" }
  },
  "dependencies": {
    "skills": {
      "skill-tracker": {
        "git": "git@gitlab.example.com:skills/skill-tracker.git",
        "ref": { "kind": "tag", "value": "v1.4.2" },
        "mode": "runtime",
        "commands": ["trk"]
      }
    },
    "commands": {
      "git": { "type": "system", "command": "git", "hint": "Install git and retry." }
    }
  }
}
```

Rules:

- `git` and `ref` are required. `ref.kind` is `tag` or `revision`; the value pins an exact release. Branch refs and version ranges on requirement entries are parse errors; ranges arrive together with the skill semver contract (section 10).
- `mode` defaults to `full`. The optional `commands` list applies to `runtime` requirements and narrows the activation to the named exports. Each named command must exist in the provider as `type: script`.
- System dependencies keep their existing form: `dependencies.commands` entries with `type: system` declare a binary that the project environment provides, checked with `shutil.which`. Manifest fields that execute code at install time (`install`, `check`, `post_install`, version probes) remain rejected.
- `Skillfile.json` files stay valid as they are. A direct project skill behaves as a `full` requirement rooted in the project.

A workflow publishes its composition through the same mechanism. The orchestrator skill declares its providers and exports no commands:

```jsonc
{
  "schema_version": 4,
  "capabilities": { "exec": "none", "network": "none" },
  "dependencies": {
    "skills": {
      "skill-tracker": { "git": "git@gitlab.example.com:skills/skill-tracker.git", "ref": { "kind": "tag", "value": "v1.4.2" } },
      "skill-monitor": { "git": "git@gitlab.example.com:skills/skill-monitor.git", "ref": { "kind": "tag", "value": "v2.0.1" } },
      "skill-review":  { "git": "git@gitlab.example.com:skills/skill-review.git",  "ref": { "kind": "revision", "value": "8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d" } }
    }
  }
}
```

The consumer installs the workflow with one entry in an unchanged `Skillfile.json`:

```json
{
  "schema_version": 1,
  "project": { "alias": "demo-project" },
  "agents": ["claude_code"],
  "skills": [
    {
      "name": "triage-workflow",
      "git": "git@gitlab.example.com:workflows/triage-workflow.git",
      "tag": "v1.0.0"
    }
  ]
}
```

## 4. Activation modes

| Mode | Prompt context | Command shims |
|------|----------------|---------------|
| `full` | provider SKILL.md and references | all exported commands |
| `runtime` | — | exported commands, optionally narrowed by `commands` |
| `context` | provider SKILL.md and references | — |

`full` serves delegation: the agent reads the provider contract and runs its commands. `runtime` serves plumbing: the consumer's scripts call the provider executable, and the consumer's own SKILL.md documents the behavior it exposes. `context` serves rules-only providers such as convention or methodology skills.

When several consumers require one provider, the effective surface is the union of the edges: a `full` edge yields `full`; otherwise the runtime command sets merge, and a `context` edge adds the prompt context.

## 5. Resolution

1. Collect the project skills from `Skillfile.json`.
2. Authorize the source of every pending fetch against the machine allowlist (section 7).
3. Fetch each skill at its exact ref and read its `csk-skill.json`.
4. Expand `dependencies.skills` recursively over unvisited nodes.
5. Unify by name: within one closure a skill name resolves to one commit and one canonical source. A skill that appears both directly and as a requirement unifies under the same rule, with the direct entry contributing a `full` edge. When requirement chains disagree, the resolver reports the conflict and lists the chains.
6. Reject dependency cycles.
7. Order providers before consumers and hand the plan to the installer.

A version conflict is resolved at the declarations: the owners of the disagreeing requirements align their refs and release.

For development, `Skillfile.dev.json` substitutes providers locally. The file sits next to `Skillfile.json`, belongs to the managed `.gitignore` block that `csk init` writes, and stays out of version control. A substitution applies to the whole closure and accepts a local path or a git source with any ref kind, branches included:

```json
{
  "substitutions": {
    "skill-tracker": { "path": "../skill-tracker" },
    "skill-monitor": { "git": "git@gitlab.example.com:skills/skill-monitor.git", "ref": { "kind": "branch", "value": "fix/api" } }
  }
}
```

`csk install` and `csk status` print every active substitution. A git substitution passes the source allowlist (section 7); a path substitution reads the local checkout. Strict audit fails while substitutions are active. Committed manifests remain the single declaration of the graph.

## 6. Install semantics

The installer materializes each node once, according to its effective mode, over the existing layers: the prompt context copies into `.agents/skills/<name>/` and mirrors into the agent adapters; runtime roots copy into the runtime store; command shims land in `.agents/bin`.

- Active shims obey a uniqueness rule: within a closure one command name maps to one provider.
- `csk install` prints the resolved closure and, per node, which commands enter `.agents/bin` and whether the prompt context is materialized.
- The install marker (`.csk-install.json`) of each node extends the existing content-hash record with the resolved commit, the canonical source, the effective mode, and the requirers. The markers make the installed closure auditable offline.
- Project closures resolve project-locally. Global skills serve interactive use; a project closure fetches its own copy of every node.

## 7. Security boundary

Authorization decisions live in machine configuration. `~/.cocoaskills/config.json` accepts an `allowed_sources` list of canonical URL prefixes; the resolver checks every source, direct and transitive, before the first network operation for that source. An unset list allows all sources and suits personal machines; organizations pin the list to their hosting.

```json
{
  "allowed_sources": [
    "gitlab.example.com/skills/",
    "gitlab.example.com/workflows/"
  ]
}
```

Canonical form: lowercase host, transport and `.git` suffix removed, path preserved. SSH and HTTPS URLs of one repository normalize to one identity. Cryptographic signing of this configuration is future work (section 10).

The existing protections apply to every node of the closure: hardened cloning (`GIT_ALLOW_PROTOCOL`, argument separation), snapshot content hashing, the audit pipeline with capability checks and trust pins, and `--strict-tags`.

## 8. Failure catalog

Resolution and install stop with a specific error when:

- two requirement chains pin one skill name to different commits;
- two requirement chains pull one skill name from different sources;
- two active providers export one command name;
- the dependency graph contains a cycle;
- a `commands` list names an export the provider lacks;
- a source falls outside the allowlist;
- a requirement entry carries a branch ref or a version range;
- a declared system command is absent from `PATH`.

## 9. Compatibility and migration

- Existing projects install unchanged. `Skillfile.json` schema v1 files stay valid, and skills with schema v1–v3 manifests act as closure leaves.
- Schema v4 is the first schema that declares skill-to-skill requirements. Older manifests with dependency hints are accepted for compatibility, and csk reports a migration warning when it can identify them.
- A workflow repository publishes its composition as a skill: SKILL.md plus a `csk-skill.json` whose `dependencies.skills` names the provider skills. Consumers install that workflow skill with a single project entry.
- A workflow repository may keep a `Skillfile.json` for the author's development checkout. The published composition lives in `csk-skill.json`.

## 10. Future work

- Version ranges, the skill semver contract, and a lockfile. Ranges make resolution outcomes depend on the available tags, and the lockfile lands in the same RFC that introduces them.
- A committed override mechanism, revisited together with version ranges; an override then satisfies every declared constraint.
- Signed machine configuration: with strict verification enabled, csk requires a cryptographic signature on the security configuration (section 7) and validates it against a trust chain; configuration that fails the check is rejected.
- MCP server requirements as a dependency surface.
- Partial context: importing selected provider references instead of the whole SKILL.md.
- Command re-export and namespacing.
