Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,39 +141,46 @@ describes each one, so an agent can choose without opening the files:

```yaml
# textures.yaml
schema_version: 1
schema_version: 2
name: forest-field-recordings
root: /Volumes/Samples
sources:
river:
path: ambience/river.flac
description: Wide river bed, mid-distance, no bird calls
category: organic
family: organic
tags: [water, flowing, continuous]
playback: { modes: [loop], default_mode: loop }
use_cases: [forest, travel]
provenance: { library: field-recordings@2024.1 }
playback: { modes: [loop], default_mode: loop, loopable: true }
audio: { duration_seconds: 18.2, intensity: 0.35, brightness: 0.2, tonality: atonal }
scenes: [forest, travel]
forest_birds:
path: wildlife/birds.wav
description: Single dawn chorus swell, ends on silence
category: organic
family: organic
tags: [wildlife, chirping]
playback: { modes: [one_shot], default_mode: one_shot }
use_cases: [forest, dawn]
provenance: { library: field-recordings@2024.1 }
audio: { duration_seconds: 7.4, intensity: 0.55, brightness: 0.72, tonality: tonal }
scenes: [forest, dawn]
```

Existing path-only bindings such as `river: ambience/river.flac` remain
build-compatible. They are intentionally unavailable to `texture inspect` and
`texture check` until migrated to the structured form above; scorekit never
invents discovery metadata for a legacy entry.
build-compatible and enumerable; their discovery result marks metadata as
unavailable rather than inventing it. `texture check` also verifies legacy
files exist, decode, and are audible. Schema v1 structured profiles remain
supported unchanged.

```bash
scorekit texture inspect textures.yaml --category organic --tag water
scorekit --json texture inspect textures.yaml --family organic --tag water \
--scene forest --mode loop --min-duration 5 --max-intensity 0.6 \
--limit 100 --offset 0
scorekit texture check textures.yaml
scorekit build forest.yaml --texture-profile textures.yaml -o forest.ogg --stems
```

Discovery filters are exact and conjunctive: no similarity ranking is used,
and a zero-result query returns `status: "no_match"` with exit 0. `--limit`
and `--offset` page large inventories; `total` is the full inventory count
and `matched` is the count satisfying all filters. `texture check` is the
decodability gate to run before relying on a selected source.

`texture inspect` filters exactly and conjunctively — no similarity ranking,
so "nothing fits" is an answer you can trust rather than a plausible wrong
pick. `texture check` proves every source exists, decodes, and is audible,
Expand Down
14 changes: 14 additions & 0 deletions docs-site/src/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ All commands accept the global `--json` flag. Successful diagnostic commands wri
| `profile check <profile>` | Render probes through every mapped SFZ patch in a leaf renderer profile |
| `orchestration check <file>` | Validate palette bindings and every referenced leaf profile/SFZ file |
| `inspect-instruments <scene>` | Resolve every track's instrument and report substitutions and gaps |
| `texture inspect <profile>` | Enumerate or exactly filter texture sources before writing `textures[].source` |
| `texture check <profile>` | Verify every source exists, decodes, and is audible |
| `diff <old> <new>` | Compare scene semantics |
| `batch <scenes...> --out-dir <dir>` | Build several scenes and write a JSON report |
| `mcp` | Serve MCP (Model Context Protocol) over stdio; each tool wraps one CLI command |
Expand All @@ -38,6 +40,18 @@ Scenes with `textures` require `build`/`batch --texture-profile <file>`. This
flag is independent of the musical renderer: it works alongside either an
SF2 `--soundfont` or an sfizz `--orchestration` profile.

Texture profile schema v1 structured sources and path-only mappings remain
supported. Schema v2 adds `family`, `tags`, `playback`, optional curated
`audio` descriptors (`duration_seconds`, `intensity`, `brightness`, and
`tonality`), and `scenes`. `texture inspect <profile>` supports exact
conjunctive filters (`--family`, repeated `--tag`, `--scene`, `--mode`,
audio-property bounds, and `--loopable`); `--limit`/`--offset` page results.
JSON includes the full inventory `total`, filter `matched` count, returned
page, resolved paths, and file-existence flags. No candidate is reported as
`status: "no_match"` with exit 0, never as an approximate match. Legacy
path-only entries remain enumerable with `metadata_available: false`;
`texture check` verifies file readability, decoding, and audible samples.

Standalone `midi` can encode melodic instruments with exact GM programs plus
channel-10 `drums`/`tabla`. It rejects profile-only melodic identities before
writing the output: the command has no renderer-profile input, and omitting a
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/machine-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ For the common case you don't need to write the wrapper at all:
scorekit mcp # MCP over stdio (newline-delimited JSON-RPC 2.0)
```

`scorekit mcp` exposes `doctor`, `validate`, `schema`, `lint`, `build`, `inspect_instruments`, `orchestration_check`, `inspect_textures`, `texture_check`, and `diff` as MCP tools. It is a pure protocol adapter: each tool call re-invokes the scorekit binary with `--json`, and the structured stdout/stderr is passed through verbatim as the tool result (`isError: true` carries the exact error object shown above). No HTTP, no auth, no resident state — determinism is untouched, and MCP clients get the same contract as subprocess callers. The `build` and `inspect_instruments` tools take `orchestration` (the sfizz routing input) instead of the retired per-build `profile` argument.
`scorekit mcp` exposes `doctor`, `validate`, `schema`, `lint`, `build`, `inspect_instruments`, `orchestration_check`, `inspect_textures`, `texture_check`, and `diff` as MCP tools. Texture discovery accepts exact family/tag/scene/mode/audio filters and page limits; a query with no candidate returns `status: "no_match"` rather than a ranked substitute. It is a pure protocol adapter: each tool call re-invokes the scorekit binary with `--json`, and the structured stdout/stderr is passed through verbatim as the tool result (`isError: true` carries the exact error object shown above). No HTTP, no auth, no resident state — determinism is untouched, and MCP clients get the same contract as subprocess callers. The `build` and `inspect_instruments` tools take `orchestration` (the sfizz routing input) instead of the retired per-build `profile` argument.

Example client registration (Claude Desktop / any MCP client):

Expand Down
35 changes: 20 additions & 15 deletions docs-site/src/profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,10 @@ scene uses must be mapped to a real file; failure leaves no normalized,
arranged, output, stem, or metadata artifact behind.

For compatibility, a legacy binding such as `river: ambience/river.flac` can
still be used by `build`. It cannot be enumerated or certified:
`texture inspect` and `texture check` reject profiles containing path-only
bindings until they are migrated to structured sources. This preserves old
renders without fabricating category, playback, or provenance facts.
still be used by `build`. It is also enumerable and certifiable:
`texture inspect` reports its key/path/existence and
`metadata_available: false`, while `texture check` verifies the file decodes
and is audible. No category, playback, or provenance facts are fabricated.

### Why every source carries metadata

Expand All @@ -267,27 +267,29 @@ authoring agent reads before it writes `textures[].source`. Without it, two
entries named `amb1` and `amb2` are indistinguishable without opening the
files, and there is no way to conclude that nothing in the profile fits.

For every structured source, the descriptive fields are required, not
optional: optional metadata makes the discovery contract only as good as the
laziest entry.
Schema v1 structured sources require every descriptive field. Schema v2
supports an explicit family, scenes, and optional curated audio descriptors;
the versioned schema makes both formats machine-readable:

- `description` — one line on what is actually audible.
- `category` — a **closed** vocabulary compiled into the binary, so it stays
- V1 `description` — one line on what is actually audible.
- V1 `category` — a **closed** vocabulary compiled into the binary, so it stays
a stable filter axis instead of drifting into `ambience` / `ambient` /
`ambiences`. Run `scorekit schema --texture-profile` to see the full list
with per-value meaning: `ambience`, `foley`, `impact`, `transition`,
`tonal`, `industrial`, `organic`, `sound_design`.
- `tags` and `use_cases` — open vocabularies (`[a-z][a-z0-9_-]{0,31}`, 1–16
- V2 `family` — a validated exact token, alongside `tags` and `scenes` —
open vocabularies (`[a-z][a-z0-9_-]{0,31}`, 1–16
entries) for expressive room the closed enum deliberately lacks.
- `playback.modes` — which of `loop` / `one_shot` the recording actually
supports, plus a `default_mode` that must be one of them. This is enforced
at build time: a scene that loops a one-shot is rejected before staging.
- `provenance.library` — the versioned library identity the source came from.

Physics is deliberately **not** declared here. Duration, sample rate, peak
and checksum are measured by `scorekit texture check`, because a
hand-written duration is a fact nothing can verify and every re-export
silently invalidates.
V2 `audio.duration_seconds`, `intensity`, `brightness`, and `tonality` are
curated discovery descriptors, not measured guarantees. `texture check`
independently verifies readability and reports measured duration, sample
rate, peak, RMS, and source checksum; consumers should use those measurements
when they need physical values.

### Finding sources: `texture inspect`

Expand All @@ -296,6 +298,8 @@ scorekit texture inspect textures.yaml # enumerate everythi
scorekit texture inspect textures.yaml --category impact
scorekit texture inspect textures.yaml --tag rain --tag soft
scorekit texture inspect textures.yaml --mode loop --use-case forest
scorekit texture inspect textures.yaml --family industrial --scene factory \
--min-duration 2 --max-intensity 0.7 --limit 100 --offset 0
scorekit --json texture inspect textures.yaml --source river
```

Expand All @@ -304,7 +308,8 @@ scorekit never ranks by similarity. It answers "which sources satisfy all of
these constraints", never "which is closest" — so `"status": "no_match"` is
a truthful answer rather than a plausible wrong pick, and it exits 0 the way
`diff` does. A `--category` outside the closed vocabulary is a typo, not an
empty result set, and exits 2.
empty result set, and exits 2. `--limit`/`--offset` paginate; `total` is
inventory size and `matched` is the complete count after filtering.

### Certifying sources: `texture check`

Expand Down
Loading
Loading