---
name: synthesize-skill
description: Creates a custom maxv-<task> skill in ~/.claude/skills/ by combining capabilities from multiple already-installed source skills. Invokes anthropic-skills:skill-creator with a structured multi-source prompt, validates the generated frontmatter against claude-code-json-schema, and writes a multi-source .maxv-source.json plus NOTICE.md attributing each upstream. Always asks for confirmation before any disk write.
when_to_use: |
  Trigger phrases: "/maxvision-orchestration:synthesize-skill", "create a unified skill from A and B".
  Called by orchestrate when analyze-candidates returns mode=SYNTHESIZE and the user approves.
disable-model-invocation: true
allowed-tools: Read Bash(test *) Bash(test -d *) Bash(mkdir -p *) Bash(cp -f *) Bash(mv -f *) Bash(rm -rf *) Bash(mktemp *) Bash(cat *) Bash(date *) Bash(find *) Bash(head *) Bash(jq *) Bash(ajv *) Bash(curl *) Bash(python -m scripts.license_compat *) Skill(skill-creator)
---

# Synthesize skill

Argument: `$ARGUMENTS` — `<target-name> --sources <id1>,<id2>[,<id3>] --task "<original task>" [--force]`

> **Hard rule:** this skill writes to disk under `~/.claude/skills/maxv-<name>/`. Always require user `sim` before any write. Never auto-execute. Never overwrite an existing maxv-* folder without `--force` + a fresh re-confirmation prompt.

## Workflow

### 1. Parse arguments + preflight

```bash
set -euo pipefail

# Resolve plugin root for downstream version stamping (step 8) and schema fetch
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && -d "${CLAUDE_PLUGIN_ROOT}" ]]; then
  PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT}"
else
  # Search the standard plugin cache locations
  PLUGIN_ROOT=$(find "$HOME/.claude/plugins/cache" -mindepth 2 -maxdepth 4 -type d -path '*maxvision-orchestration*' 2>/dev/null | head -1)
fi
test -f "${PLUGIN_ROOT}/.claude-plugin/plugin.json" || {
  echo "ERROR: cannot resolve plugin root for version stamping" >&2
  exit 1
}

NAME="$(echo "$ARGUMENTS" | awk '{print $1}')"   # first positional token
TARGET="$HOME/.claude/skills/maxv-${NAME#maxv-}"  # idempotent maxv- prefix
TARGET_BAK="${TARGET}.bak"

# Parse --sources, --task, --force flags from $ARGUMENTS
# (Model interpreter normalizes; produces $SOURCES_CSV, $TASK, $FORCE=0|1)
```

Validate `NAME` is non-empty and matches `^[a-z0-9-]+$` (skills naming convention). Reject otherwise.

### 2. Verify all source candidates are installed locally

For each `id` in `$SOURCES_CSV`:
- Resolve the local path (`~/.claude/skills/<id>/SKILL.md` or `~/.claude/plugins/cache/.../<id>/SKILL.md`)
- If not found, abort with: `"Source '<id>' not installed locally. Run /maxvision-orchestration:install-skill <id> first, then retry."`

Synthesis MUST read the full local SKILL.md (not the truncated 32-KB body in `index.db`).

### 3. License compatibility check

For the set of source licenses (read from each source's `.maxv-source.json` or fallback to its catalog entry):

```bash
set -euo pipefail
# License resolution chain per source:
#   1. ~/.claude/skills/<id>/.maxv-source.json: .license (sparse_clone or synthesis-derived sources)
#   2. ~/.claude/plugins/installed_plugins.json: plugin's `license` field (marketplace sources)
#   3. <plugin-root>/.claude-plugin/plugin.json: .license (in-tree plugin)
#   4. Fallback: abort with error "License unknown for source <id> — pass --license-override <SPDX> to proceed"

# Quote each license to handle multi-word names like "BSD 3-Clause"
python -m scripts.license_compat "$LIC_A" "$LIC_B" || {
  echo "ERROR: license conflict between $LIC_A and $LIC_B — recommend INSTALL_MULTIPLE instead of SYNTHESIZE" >&2
  exit 1
}
```

Non-zero exit ⇒ conflict ⇒ hard fail (orchestrate's caller will downgrade to INSTALL_MULTIPLE).

### 4. Pre-flight target folder check

```bash
set -euo pipefail
if [[ -d "$TARGET" ]]; then
  if [[ "$FORCE" -ne 1 ]]; then
    echo "ERROR: $TARGET already exists. Pass --force + explicit confirmation to overwrite." >&2
    exit 2
  fi
  # Backup before destructive overwrite
  cp -rf "$TARGET" "$TARGET_BAK"
  rm -rf "$TARGET"
fi
mkdir -p "$TARGET"
```

### 5. Build the skill-creator briefing (structured template, expanded inline)

The `skill-creator` skill consumes a natural-language prompt — NOT a JSON API. The structure below is a briefing TEMPLATE for the model to expand into prose when invoking `Skill(skill-creator)` in step 6. Each field becomes one or more paragraphs in the actual prompt; the template just guarantees no required field is forgotten:

```json
{
  "task": "<TASK>",
  "naming_convention": "maxv-* prefix",
  "license_constraint": "<resolved>",
  "frontmatter_required": ["name", "description", "when_to_use", "allowed-tools"],
  "sources": [
    {
      "id": "<src.id>",
      "skill_md": "<full body of source's local SKILL.md>",
      "use_for": ["<capability1>", "<capability2>"]
    }
  ],
  "target_path": "~/.claude/skills/maxv-<name>/",
  "deduplication": "merge overlapping sections; keep most-specific allowed-tools",
  "attribution": "list each source verbatim in NOTICE.md (not in SKILL.md)"
}
```

When you invoke `Skill(skill-creator)` in step 6, render this briefing as natural-language paragraphs — for example: "Create a new skill named `maxv-<name>`. The original task was: <TASK>. The skill should follow the maxv-* naming convention. ... Combine these N source skills as follows: ..."

### 6. Invoke `Skill(skill-creator)` with the prompt above

The skill-creator generates `SKILL.md` directly under `$TARGET/`. The generated file MUST satisfy `claude-code-json-schema/plugin.schema.json` for skills (frontmatter required keys present).

### 7. Validate the generated SKILL.md frontmatter

```bash
set -euo pipefail
# Download claude-code-json-schema if not already cached
SCHEMA_URL="https://raw.githubusercontent.com/hesreallyhim/claude-code-json-schema/main/schemas/plugin.schema.json"
SCHEMA_CACHE="$HOME/.claude/cache/maxv-orchestration/plugin.schema.json"
test -f "$SCHEMA_CACHE" || curl -fsSL -o "$SCHEMA_CACHE" "$SCHEMA_URL"

# Extract just the frontmatter as JSON for ajv (using a python helper or sed)
# (Implementer: model interprets the extraction step; suggest python -c "import yaml,json,sys; ...")

ajv validate --spec=draft2020 -c ajv-formats -s "$SCHEMA_CACHE" -d /tmp/maxv-frontmatter.json --strict=false || {
  echo "ERROR: generated SKILL.md frontmatter fails schema. Restoring previous folder if backup exists." >&2
  rm -rf "$TARGET"
  [[ -d "$TARGET_BAK" ]] && mv -f "$TARGET_BAK" "$TARGET"
  exit 1
}
```

On schema failure, restore the backup (if any from step 4) and exit non-zero.

### 8. Write `.maxv-source.json` (synthesis schema v1.1.0)

```bash
set -euo pipefail
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
SYNTHESIZER_VERSION=$(jq -r '.version' "${PLUGIN_ROOT}/.claude-plugin/plugin.json" 2>/dev/null || echo "0.2.0")

MANIFEST_TMP=$(mktemp -p "$TARGET" .maxv-source.json.tmp.XXXXXX)
cat > "$MANIFEST_TMP" <<JSON
{
  "\$schema_version": "1.1.0",
  "synthesis": true,
  "sources": [
    {
      "repo": "<owner/repo>",
      "path": "<source_path>",
      "commit_sha": "<sha-from-source-maxv-source-json>",
      "license": "<license>",
      "use_for": ["<capability1>", "<capability2>"]
    }
  ],
  "synthesized_by": "maxvision-orchestration:synthesize-skill",
  "synthesized_at": "$NOW",
  "synthesizer_version": "$SYNTHESIZER_VERSION"
}
JSON
mv -f "$MANIFEST_TMP" "$TARGET/.maxv-source.json"
```

The `sources` array MUST have at least 2 entries (per the schema's `minItems: 2`).

For each source in `sources[]`:
- `commit_sha`: read from `.maxv-source.json:.commit_sha` if present; else from `installed_plugins.json:.<plugin>.gitCommitSha` for marketplace plugins; else error.
- `license`: read from `.maxv-source.json:.license` (NOTE: T4 schema v1.0.0 doesn't include license — fall through); else from the plugin's own `plugin.json:.license`; else require `--license-override`.

(The T4 schema v1.0.0 has no `license` field per `schemas/synthesis-manifest.schema.json` review — to track licenses for synthesized skill provenance, the synthesizer reads the upstream `plugin.json` directly when needed. v0.3 should add `license` to the v1.0 single-source schema.)

### 9. Write `NOTICE.md`

```bash
set -euo pipefail
NOTICE_TMP=$(mktemp -p "$TARGET" NOTICE.md.tmp.XXXXXX)
cat > "$NOTICE_TMP" <<'NOTICE'
# NOTICE — maxv-<name>

This skill was synthesized by maxvision-orchestration on <synthesized_at> from the following upstream sources. Each upstream is attributed and licensed independently:

## Source: <repo-1>
- License: <license>
- Commit: <commit_sha>
- Path: <path>
- Used for: <capability list>

## Source: <repo-2>
- License: ...
...

The synthesized SKILL.md combines and adapts content from these sources. Original copyright and license terms apply to the contributed portions; consult each upstream repo for its full LICENSE file.
NOTICE
mv -f "$NOTICE_TMP" "$TARGET/NOTICE.md"
```

### 10. Append telemetry (if opt-in)

```bash
set -euo pipefail
if [[ "${MAXV_TELEMETRY_OPT_IN:-}" == "true" ]]; then
  TELEMETRY="$HOME/.claude/cache/maxv-orchestration/usage.jsonl"
  mkdir -p "$(dirname "$TELEMETRY")"
  printf '{"ts":"%s","action":"synthesize","sources":%s,"target":"maxv-%s","skill_creator_used":true}\n' \
    "$NOW" "$(echo "$SOURCES_CSV" | jq -R 'split(",")')" "${NAME#maxv-}" >> "$TELEMETRY"
fi
```

(Telemetry is silent on failure — never blocks main flow.)

### 11. Report

```
✓ Synthesized: maxv-<name>
  Path:        ~/.claude/skills/maxv-<name>/
  Sources:     <id1>, <id2>[, <id3>]
  License:     <resolved>
  Schema:      v1.1.0 (synthesis manifest)
  Status:      live-watched, ready
  
  Files written:
    - SKILL.md       (generated by skill-creator)
    - NOTICE.md      (attribution to upstream sources)
    - .maxv-source.json (synthesis manifest)
```

```bash
set -euo pipefail
# Drop stale backup on success — same lesson as T18 maxv-skills index pull/rebuild
[[ -d "${TARGET_BAK}" ]] && rm -rf "${TARGET_BAK}"
```

## Guardrails

- **Single confirmation per synthesis.** Hard rule — never reuse a previous batch approval.
- **Never overwrite without `--force` + fresh re-confirmation.** If `~/.claude/skills/maxv-<name>/` exists, refuse without explicit `--force`. Even with `--force`, ALWAYS cp-rf to `.bak` before overwriting and restore on validation failure.
- **License conflict is a hard fail.** Per step 3; recommend INSTALL_MULTIPLE downgrade.
- **`Skill(skill-creator)` unavailable** ⇒ abort + tell user to install `anthropic-agent-skills` plugin (`/plugin install example-skills@anthropic-agent-skills`).
- **Never modify upstream source folders.** Read-only on `~/.claude/skills/<id>/SKILL.md` for each source.
- **Schema-invalid output triggers restore.** If ajv validation fails on the generated SKILL.md, remove the folder and restore from .bak (if any). Never leave a half-synthesized skill on disk.
- **`set -euo pipefail` scope.** Each bash code block in this skill is treated as an independent shell session by some interpreters; if executing blocks separately, repeat `set -euo pipefail` at the top of each.
- **Atomic writes for manifest + NOTICE.** All file writes in steps 8-9 use `mktemp -p $TARGET .X.tmp.XXXXXX` followed by `mv -f` to the final path. An interrupted synthesis (Ctrl-C, OOM, gh API timeout, kernel panic) leaves either the previous skill state OR the new skill state — never a half-written manifest or NOTICE. The hidden `.X.tmp.XXXXXX` suffix means stale temp files don't pollute the skill folder visually if mv hasn't completed yet.
