Skip to content
Open
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
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,13 @@ catalog shared catalog shared catalog, warm-starts

## Skills are the product

Skills are not configuration — they are the capability surface. **26 skills** ship in the vsix from `packages/extension/skills/`, versioned with the product: **24 public** — they load for every session — plus **2 entitled surfaces**, `piccolissimo` and `intonatissimo`, which ship in the vsix but stage only for entitled sessions ([ADR-0011](docs/adr/0011-entitled-skill-surface.md)). Additional skills load from your own vault mounts and from co-located Julia packages behind entitlements.
Skills are not configuration — they are the capability surface. **38 skills** ship in the vsix from `packages/extension/skills/`, versioned with the product, and all of them are public: they load for every session. Premium-tier guidance does not ship in this repository ([ADR-0011](docs/adr/0011-entitled-skill-surface.md)). Additional skills load from your own vault mounts and from co-located Julia packages behind entitlements.

| Surface | What it covers |
|---|---|
| Research loop | `research`, `analyze`, `hypothesis-review`, `dream-reflect`, `open-threads`, `paper-writer`, `create-research-project`, `migrate-research-project` |
| Lab + catalog + vault | `amico-lab`, `amico-catalog`, `amico-vault`, `amico-strategy`, `amico-schema-check`, `amico-slack` |
| Engineering | `debugging`, `tdd`, `verification`, `brainstorming`, `deliberate`, `grill-me`, `grill-with-docs`, `improve-codebase-architecture`, `teach`, `report-a-bug` |
| Entitled surfaces | `piccolissimo`, `intonatissimo` — usage guidance for the `-issimo` performance tiers; ship in the vsix, stage only for entitled sessions |
| Internal library — not in the vsix | `transmon`, `fluxonium`, `atoms` (Rydberg), `bosonic`, `ions`, `setup`, `solve`, `simulate`, `warm-start`, `constraints`, `objectives`, `problem-types`, `structural-analysis`, `demo`, `pasqal`, `plot`, `compose`, `multistart` — these live in the internal library and resolve only from the private plugin checkout, per the skill-surface decisions of record ([ADR-0003](docs/adr/0003-skill-surfaces-two-tier-checkout-gate.md), [ADR-0011](docs/adr/0011-entitled-skill-surface.md)) |

The extension stages the union of the shipped bundle and your vault mounts at startup; mount presence is the eligibility proof. The boundary as it stands: the extension, the `amico` CLI, and the public skills are open — entitled builds add proprietary capabilities behind entitlements.
Expand Down
24 changes: 23 additions & 1 deletion docs/adr/0011-entitled-skill-surface.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Skill surfaces are three-tier: public ships and loads for all, entitled ships and loads only for entitled sessions, internal stays vault-only

Status: accepted (2026-08-27; content policy amended 2026-09-05 — see the Amendment record)
Status: accepted (2026-08-27; content policy amended 2026-09-05 and 2026-11-07 — see the Amendment records)

ADR-0003's two surface tiers amend to three. `public` ships in the .vsix and loads for every
session, as before. `internal` stays exactly as ADR-0003 left it: private-vault content
Expand Down Expand Up @@ -99,3 +99,25 @@ review (director + independent reviewer, per the dev gate) — the pass had not
was written; it completed 2026-09-05: **approved** (independent reviewer, findings tracked:
the slice-3 content lens folded here; the internal-location vocabulary seam tracked as a chore
for the parents' next amendment).

---

**Amendment (2026-11-07): private-package skills leave the public repo.** In-repo entitled
placement no longer applies to skills about private packages. Shipping usage guidance
world-readable was the premise of the entitled tier ("ship usage, keep internals"); for
private packages that premise is withdrawn — usage guidance is itself proprietary. Such skills
live in the team vault as `surface: internal`, admitted by mount presence and staged for
headless sessions through the internal-skills allowlist (`ops/server/stage-internal-skills.sh`).
The `issimo` entitlement keeps its meaning — the staging gate described above — for any paid
guidance about public packages. The tier machinery is untouched: three surfaces, root admission
(`{public, entitled}` in-repo, `{internal}` vault-only), and the entitlement check stand as
written.

Public skills refer to private capabilities only neutrally (the "premium tier"). The review-time
content policy gains a mechanical backstop: the skill-library lint's `private-package` rule fails
any shippable skill (surface `public`, `entitled`, or untagged) that names a package on the
denylist in `packages/extension/scripts/lint-skills-private-packages.txt`, which is the single
place the list lives. The rule is on by default for the repo library and exempts `internal` cards.
Exceptions go in `lint-skills-known.txt`, and that list is empty.

Implementation: harmoniqs/amicode#2147.
4 changes: 4 additions & 0 deletions ops/server/stage-internal-skills.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ ALLOWLIST=(
harmony
shape
sweep
# private-package usage cards: vault-only, never in the public library
altissimo
piccolissimo
intonatissimo
)

for skill in "${ALLOWLIST[@]}"; do
Expand Down
25 changes: 25 additions & 0 deletions packages/extension/scripts/lint-skills-private-packages.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# lint-skills-private-packages.txt — the private-package DENYLIST for the
# `private-package` rule of scripts/lint-skills.mjs. This file is the single
# place the list lives.
#
# This repository is public, so everything in the skill library is
# world-readable. A shippable skill (surface public, entitled, or untagged)
# must not name a private package. Usage guidance for private packages lives
# in the team vault as `surface: internal` skills, which this rule exempts.
#
# One package name per line, matched case-insensitively as a whole word.
# The rule is on by default for the repo library (packages/extension/skills)
# and opt-in for other roots via `--denylist <file>`. Exceptions go in
# lint-skills-known.txt as `<skill>/SKILL.md:private-package`. Keep that list
# empty: reword to "premium tier" instead.
Piccolissimo
Intonatissimo
Altissimo
Prestissimo
Passaggissimo
Coro
Legatissimo
Telaio
Favo
Strettissimo
amicissimo
69 changes: 59 additions & 10 deletions packages/extension/scripts/lint-skills.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@
// `~/...armonia-data.../`) → WARNING — the rot-prone class
// (the armonia-aaron-trowbridge rename rotted these once);
// warnings never fail the lint
// private-package a shippable skill (surface public / entitled / untagged)
// names a package on the private-package DENYLIST
// (scripts/lint-skills-private-packages.txt — the one file
// the list lives in), whole-word, case-insensitive, anywhere
// in the file (frontmatter `name:` included) → ERROR. The repo
// is public; private-package skills live in the team vault as
// `surface: internal`, which this rule exempts. On by default
// for the repo library; opt-in elsewhere via --denylist
// agents unknown `agents:` value — WARNING only (the ontology sweep
// is a later slice); warnings never fail the lint
//
// node scripts/lint-skills.mjs [--dir <skills-root>] [--known <file>] [--json]
// node scripts/lint-skills.mjs [--dir <skills-root>] [--known <file>] [--denylist <file>] [--json]
//
// --dir skills library root (default: this repo's source tree,
// packages/extension/skills)
Expand All @@ -31,6 +39,10 @@
// that referenced path (`skill/SKILL.md:companion:guide.md`) —
// unlisted occurrences in the same file still fail. Listed
// occurrences are reported as known-warnings, never errors.
// --denylist private-package denylist file (one name per line, `#`
// comments). Default: scripts/lint-skills-private-packages.txt
// when --dir is the repo library, otherwise the rule is off —
// vault roots legitimately carry private-package content.
// --json machine-readable report on stdout (the dream-side pass consumes
// this; findings land in the vault ledger)
//
Expand All @@ -47,14 +59,15 @@ import { fileURLToPath } from "node:url";

const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
const DEFAULT_DIR = path.join(SCRIPT_DIR, "..", "skills");
const DEFAULT_DENYLIST = path.join(SCRIPT_DIR, "lint-skills-private-packages.txt");

const AGENT_VALUES = new Set([
"researcher", "experimenter", "librarian", "hypothesizer", "analyzer",
"implementer", "director", "dreamer", "dispatcher", "orchestrator",
"engineer", "pulse-designer",
]);
const SURFACE_VALUES = new Set(["public", "internal", "entitled"]);
const RULES = ["amico-plugin", "companion", "name", "surface", "vpath"];
const RULES = ["amico-plugin", "companion", "name", "surface", "vpath", "private-package"];

// F28 — the known-rotted vault-path idioms: the old ops-repo vault tree, the
// pre-rename personal vault name, and the retired transcript substrate.
Expand All @@ -67,25 +80,26 @@ const VPATH_ERROR_SHAPES = [
// rotted once already (the armonia-aaron-trowbridge rename), so they warn.
const VPATH_HOME_RE = /~\/[A-Za-z0-9_/.-]*(vaults|armonia-data)[A-Za-z0-9_/.-]*\//;

const USAGE = `usage: node scripts/lint-skills.mjs [--dir <skills-root>] [--known <file>] [--json]`;
const USAGE = `usage: node scripts/lint-skills.mjs [--dir <skills-root>] [--known <file>] [--denylist <file>] [--json]`;

function fail(msg) {
console.error(`lint-skills: ${msg}\n${USAGE}`);
return 2;
}

function parseArgs(argv) {
const out = { dir: DEFAULT_DIR, known: null, json: false };
const out = { dir: DEFAULT_DIR, known: null, denylist: null, json: false };
for (let i = 0; i < argv.length; i++) {
const a = argv[i];
if (a === "--help" || a === "-h") return { help: true };
if (a === "--json") out.json = true;
else if (a === "--dir") out.dir = argv[++i];
else if (a === "--known") out.known = argv[++i];
else if (a === "--denylist") out.denylist = argv[++i];
else if (a.startsWith("--")) return { error: `unknown flag ${a}` };
else return { error: `unexpected argument ${a}` };
}
if (out.dir === undefined || out.known === undefined) return { error: "missing value for flag" };
if (out.dir === undefined || out.known === undefined || out.denylist === undefined) return { error: "missing value for flag" };
return out;
}

Expand Down Expand Up @@ -113,6 +127,22 @@ function loadKnown(file) {
return set;
}

// The private-package denylist → one whole-word, case-insensitive matcher per
// name. Names are escaped, so a denylist line can never become a regex.
function loadDenylist(file) {
let text;
try {
text = fs.readFileSync(file, "utf8");
} catch (e) {
return { error: `cannot read --denylist file: ${e.message}` };
}
return text
.split("\n")
.map((l) => l.trim())
.filter((l) => l && !l.startsWith("#"))
.map((name) => ({ name, re: new RegExp(`\\b${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i") }));
}

// Conservative companion-path collection: markdown-link targets ending in
// `.md` (any shape), plus backticked paths ending in `.md` that carry a `/`.
// Everything that smells like a template, an external path, or an escape is
Expand Down Expand Up @@ -143,7 +173,7 @@ function isResolvable(ref) {
return true;
}

function lintSkill(skillDir, relDir) {
function lintSkill(skillDir, relDir, denylist = []) {
const findings = [];
const file = path.join(skillDir, "SKILL.md");
const rel = relDir ? path.join(relDir, "SKILL.md") : "SKILL.md";
Expand All @@ -164,6 +194,7 @@ function lintSkill(skillDir, relDir) {
});

// (2) frontmatter (between the first two `---` lines)
let surface = null;
if (lines[0]?.trim() === "---") {
const end = lines.indexOf("---", 1);
if (end > 0) {
Expand All @@ -174,6 +205,7 @@ function lintSkill(skillDir, relDir) {
if (key === "name" && value && value !== path.basename(skillDir)) {
findings.push({ rel, line: i + 1, rule: "name", severity: "error", msg: `frontmatter name \`${value}\` ≠ directory \`${path.basename(skillDir)}\`` });
}
if (key === "surface") surface = value;
if (key === "surface" && value && !SURFACE_VALUES.has(value)) {
findings.push({ rel, line: i + 1, rule: "surface", severity: "error", msg: `surface \`${value}\` not in {public, internal, entitled}` });
}
Expand Down Expand Up @@ -206,6 +238,18 @@ function lintSkill(skillDir, relDir) {
}
});

// (3b) private-package names in a shippable card — internal cards are
// vault-only (the packaging leak-guard refuses them in the .vsix).
if (surface !== "internal") {
lines.forEach((line, idx) => {
for (const { name, re } of denylist) {
if (re.test(line)) {
findings.push({ rel, line: idx + 1, rule: "private-package", severity: "error", msg: `names private package \`${name}\` — the repo is public; private-package guidance lives in the team vault as surface: internal (reword to "premium tier")` });
}
}
});
}

// (4) dead companion files — resolve inside the skill's own directory only
for (const { ref, line } of collectCompanionRefs(text)) {
const cleaned = ref.replace(/^\.\//, "").split("#")[0].trim();
Expand All @@ -220,7 +264,7 @@ function lintSkill(skillDir, relDir) {
return findings;
}

function lintDir(root) {
function lintDir(root, denylist = []) {
const findings = [];
let skills = 0;
const entries = fs.readdirSync(root, { withFileTypes: true });
Expand All @@ -229,7 +273,7 @@ function lintDir(root) {
const skillMd = path.join(root, ent.name, "SKILL.md");
if (!fs.existsSync(skillMd)) continue; // not a skill dir
skills++;
findings.push(...lintSkill(path.join(root, ent.name), ent.name));
findings.push(...lintSkill(path.join(root, ent.name), ent.name, denylist));
}
return { findings, skills };
}
Expand Down Expand Up @@ -267,7 +311,12 @@ function main(argv) {
const known = loadKnown(parsed.known);
if (known.error) return fail(known.error);

const { findings, skills } = lintDir(parsed.dir);
const isLibrary = path.resolve(parsed.dir) === path.resolve(DEFAULT_DIR);
const denyFile = parsed.denylist ?? (isLibrary ? DEFAULT_DENYLIST : null);
const denylist = denyFile ? loadDenylist(denyFile) : [];
if (denylist.error) return fail(denylist.error);

const { findings, skills } = lintDir(parsed.dir, denylist);
const lines = render(findings, known);
const errors = lines.filter((l) => l.includes(" error: ")).length;
const warnings = lines.filter((l) => l.includes(" warning: ")).length;
Expand All @@ -294,4 +343,4 @@ if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
process.exit(main(process.argv.slice(2)));
}

export { main, lintDir, lintSkill, collectCompanionRefs, isResolvable, loadKnown };
export { main, lintDir, lintSkill, collectCompanionRefs, isResolvable, loadKnown, loadDenylist };
6 changes: 3 additions & 3 deletions packages/extension/skills/amico-catalog/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ agents: [researcher, librarian, dreamer]
surface: public
---

Pulse catalog management for the Amico system. Covers warm-start retrieval, pulse ingestion, and versioning. Phase 0 scope: basic warm-start retrieval and ingestion only — the catalog CLI's query/ingest surface does not yet filter by or record the schema-v3 compiler stack fields (system hash, device id, verification block); that follow-up is tracked at harmoniqs/amicissimo#497. The schema-v3 fields themselves have landed in the compilation package (see "Compiler Stack Fields" below) — the ground truth lives there, not here.
Pulse catalog management for the Amico system. Covers warm-start retrieval, pulse ingestion, and versioning. Phase 0 scope: basic warm-start retrieval and ingestion only — the catalog CLI's query/ingest surface does not yet filter by or record the schema-v3 compiler stack fields (system hash, device id, verification block); that follow-up is tracked separately. The schema-v3 fields themselves have landed in the compilation package (see "Compiler Stack Fields" below) — the ground truth lives there, not here.

## Catalog Structure

Expand Down Expand Up @@ -52,7 +52,7 @@ The compiler-stack fields phase landed 2026-10-04 with the compilation package's
- **Query/ranking** — filters by platform, gate, device id, system hash (exact-hash option); superseded versions drop from ranking unless requested.
- **Ingestion** — provenance per block (git commit, source script); the bundled public library is IP-gated by a device-profile allowlist.

Phase 0 of THIS card's surface (the vault catalog + `amico catalog` CLI) does not implement these yet: retrieval remains by platform+gate only. The CLI follow-up (schema-v3 fields in query/ingest, verification-aware ranking) is tracked at **harmoniqs/amicissimo#497**. Until it lands, a session needing hash-exact or verification-aware lookup should use the compilation package's query API directly.
Phase 0 of THIS card's surface (the vault catalog + `amico catalog` CLI) does not implement these yet: retrieval remains by platform+gate only. The CLI follow-up (schema-v3 fields in query/ingest, verification-aware ranking) is a tracked follow-up. Until it lands, a session needing hash-exact or verification-aware lookup should use the compilation package's query API directly.

## Warm-Start Retrieval

Expand Down Expand Up @@ -101,4 +101,4 @@ Old versions remain in catalog (never deleted) but are not candidates for warm-s

## Phase 0 Scope

No compiler stack fields in THIS catalog's metadata or CLI yet (the fields themselves landed in the compilation package's schema v3 — see "Compiler Stack Fields" above; CLI adoption is harmoniqs/amicissimo#497). No multi-branch catalog management yet. Retrieval is by platform+gate only; system-specific matching (e.g., by Hamiltonian hash) is done through the compilation package's query API, not this catalog.
No compiler stack fields in THIS catalog's metadata or CLI yet (the fields themselves landed in the compilation package's schema v3 — see "Compiler Stack Fields" above; CLI adoption is a tracked follow-up). No multi-branch catalog management yet. Retrieval is by platform+gate only; system-specific matching (e.g., by Hamiltonian hash) is done through the compilation package's query API, not this catalog.
2 changes: 1 addition & 1 deletion packages/extension/skills/amico-schema-check/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ These are ambiguous and reported for human review:

## Escalation

Ambiguous issues are logged to `dream-journal.md` with tag `needs-human-review`. If more than 5 unfixable issues are found, route the finding to the amicissimo proposals surface (agents never edit INTENT): "Schema issues found in N notes — human review needed (see dream-journal)."
Ambiguous issues are logged to `dream-journal.md` with tag `needs-human-review`. If more than 5 unfixable issues are found, route the finding to the house proposals surface (agents never edit INTENT): "Schema issues found in N notes — human review needed (see dream-journal)."

## Output

Expand Down
Loading
Loading