Assets
Ship references, scripts, configuration, and generated files with a portable plugin.
Assets are non-feature files that travel with a plugin: reference documents, scripts, JSON configuration, templates, and other files the emitted instructions or runtime needs.
Add skill resources
Files beside a SKILL.md are collected automatically:
skills/
└── dependency-audit/
├── SKILL.md
├── policy.json
└── scripts/
└── scan.mjsSoubi preserves their relative paths. Harnesses without skill-adjacent resources report a fallback instead of silently discarding them.
Attach files to a feature
Commands, TypeScript skills, and TypeScript agents accept an assets array:
import { defineSkill, file } from "soubi";
export default defineSkill({
instructions: file("./audit.md"),
assets: ["./policy.json", "./scripts/scan.mjs"],
});Paths resolve relative to the module that declares them.
Add plugin-wide assets
Files under assets/ are collected recursively. You can also list individual paths in plugin.config.ts:
import { defineConfig } from "soubi";
export default defineConfig({
id: "dependency-audit",
assets: ["NOTICE.md"],
});Load a directory
Use readDir when files live elsewhere or need a destination prefix:
import path from "node:path";
import { fileURLToPath } from "node:url";
import { defineConfig, readDir } from "soubi";
const here = path.dirname(fileURLToPath(import.meta.url));
export default defineConfig({
id: "dependency-audit",
files: readDir(path.join(here, "scripts"), {
prefix: "scripts",
}),
});readDir preserves executable bits. Its exclude option skips entries by name.
Keep destination paths portable
Every destination must be relative and use ordinary path segments. Absolute paths, empty segments, and . or .. traversal are rejected before Soubi writes output.
Use soubi check to see where a target cannot carry an asset, then inspect the generated tree before installation.