From 2f9f52619beb0e26b9160b63f15163dc6de3a242 Mon Sep 17 00:00:00 2001 From: ladybluenotes Date: Sat, 8 Aug 2026 09:41:02 -0700 Subject: [PATCH 1/6] chore: stabilize consumer foundations and trust docs --- docs/cli/intent-hooks.md | 8 ++++--- docs/cli/intent-list.md | 6 +++--- docs/cli/intent-load.md | 4 +++- docs/concepts/configuration.md | 21 ++++++++++++------- docs/concepts/trust-model.md | 21 ++++++++++++++----- docs/getting-started/quick-start-consumers.md | 4 ++-- package.json | 3 +-- packages/intent/src/shared/utils.ts | 2 +- .../source-policy-surfaces.test.ts | 2 +- packages/intent/tests/staleness.test.ts | 4 ++-- 10 files changed, 47 insertions(+), 28 deletions(-) diff --git a/docs/cli/intent-hooks.md b/docs/cli/intent-hooks.md index 44e1c9f0..905f9041 100644 --- a/docs/cli/intent-hooks.md +++ b/docs/cli/intent-hooks.md @@ -3,7 +3,7 @@ title: intent hooks id: intent-hooks --- -`intent hooks install` installs lifecycle hooks that surface available Intent skills and enforce loading matching guidance before edits in supported agents. +`intent hooks install` installs lifecycle hooks that surface available Intent skills and gate supported edit tools until they observe an Intent load command. ```bash npx @tanstack/intent@latest hooks install [--scope project|user] [--agents copilot,claude,codex|all] @@ -17,14 +17,16 @@ npx @tanstack/intent@latest hooks install [--scope project|user] [--agents copil ## Behavior - Installs hook behavior without writing an `intent-skills` guidance block. -- Adds a session-start skill catalog for supported agents so the agent sees available `skill-id: description` entries before it starts work. -- Keeps edit enforcement in place: supported edit tools are blocked until the agent runs `intent load ` for matching guidance. +- Returns a session-start skill catalog as agent context with available `skill-id: description` entries. +- Blocks supported edit tools until the hook observes a recognized `intent load ` command. - `--scope project` writes project-local hook config for agents that support it. - `--scope user` writes user-level agent config and stores runner scripts under `~/.tanstack/intent/hooks`. - `--agents all` is the default. In project scope, Copilot is skipped because the supported Copilot CLI hook location is user-scoped. - Run `intent install` separately when you also want to write project guidance. - Use `package.json#intent.skills` and `package.json#intent.exclude` to control which skills are surfaced in the session catalog. +The hook records a recognized load command before that command completes. It does not verify that the command succeeded, that the selected skill matched the task, that the agent received the returned content, or that the model applied the guidance. Hook output is an edit gate and observation signal, not proof of activation or correct agent behavior. See [Lifecycle boundaries](../concepts/trust-model#lifecycle-boundaries). + ## Hook support | Agent | Project scope | User scope | Hooks installed | diff --git a/docs/cli/intent-list.md b/docs/cli/intent-list.md index c1fe1e9a..e2859e38 100644 --- a/docs/cli/intent-list.md +++ b/docs/cli/intent-list.md @@ -16,7 +16,7 @@ npx @tanstack/intent@latest list [--json] [--debug] [--global] [--global-only] [ - `--global`: include global packages after project packages - `--global-only`: list global packages only - `--show-hidden`: show unlisted hidden skill sources when run outside an agent session -- `--no-notices`: suppress non-critical notices on stderr +- `--no-notices`: suppress non-critical notices on stderr; the acknowledged-risk notice for `intent.skills: ["*"]` remains visible ## What you get @@ -118,7 +118,7 @@ The list as a whole has three special forms: - **Empty** (`"skills": []`): no package is surfaced, with an info notice printed to stderr. - **Wildcard** (`"skills": ["*"]`): every discovered package is surfaced, with an acknowledged-risk notice printed to stderr. This exact trust-all entry is distinct from a scoped package pattern such as `@tanstack/*`. -A package that ships skills but is not listed or matched by a pattern is dropped. When packages are dropped this way, Intent prints one summary line naming them so you can opt in. In agent sessions, hidden sources are reported by count only; run `intent list --show-hidden` outside the agent session to review candidates. An exact entry or pattern that matches no discovered package is reported as well. Package patterns support `*` wildcards. Matching is currently by package name. See [Configuration](../concepts/configuration) and [Trust model](../concepts/trust-model). +A package that ships skills but is not listed or matched by a pattern is dropped. When packages are dropped this way, Intent prints one policy notice naming them so you can opt in. In agent sessions, hidden sources are reported by count only; run `intent list --show-hidden` outside the agent session to review candidates. An exact entry or pattern that matches no discovered package is reported as well. Package patterns support `*` wildcards. Matching uses both package name and source kind. See [Configuration](../concepts/configuration) and [Trust model](../concepts/trust-model). ## Excludes @@ -136,7 +136,7 @@ Manage persistent excludes with `intent exclude add|remove|list`. A pattern without `#` excludes a whole package. A pattern with `#` excludes a single skill (`@scope/pkg#search-params`), and the skill segment may itself be a glob (`@scope/pkg#experimental-*`). A pattern may cross package boundaries at skill granularity (`*#experimental-*`). The `#*` shortcut (`@scope/pkg#*`) excludes the whole package. Only exact names and `*` wildcards are supported on each segment. Bare package-name patterns keep working unchanged. -An excluded package never triggers the unlisted-source warning, because an exclude is an explicit decision rather than an oversight. +An excluded package never triggers the unlisted-source notice, because an exclude is an explicit decision rather than an oversight. ## Common errors diff --git a/docs/cli/intent-load.md b/docs/cli/intent-load.md index 28043d29..e39a7edd 100644 --- a/docs/cli/intent-load.md +++ b/docs/cli/intent-load.md @@ -22,7 +22,7 @@ npx @tanstack/intent@latest load # [--path] [--json] [--debug] [ - Validates `#` before scanning - Scans project-local packages by default - Includes global packages only when `--global` or `--global-only` is passed -- Refuses before scanning when the target package is not permitted by `package.json#intent.skills` +- Checks the target package name against `package.json#intent.skills` before resolution, then enforces its source kind after resolution - Refuses before scanning when the target package or skill matches `intent.exclude` - Prefers local packages when `--global` is used and the same package exists locally and globally - Accepts an unambiguous short skill name when a package-prefixed skill exists @@ -30,6 +30,8 @@ npx @tanstack/intent@latest load # [--path] [--json] [--debug] [ - Prints the scanner-reported path when `--path` is passed - Prints debug details to stderr when `--debug` is passed +A successful load proves that Intent resolved the selected skill under current policy and returned its content. It does not prove that the skill was relevant to the task, reached an agent's active context, or was followed correctly. See [Lifecycle boundaries](../concepts/trust-model#lifecycle-boundaries). + The package can be scoped or unscoped. The skill can include slash-separated sub-skill names. Examples: diff --git a/docs/concepts/configuration.md b/docs/concepts/configuration.md index 8b9d27ad..8d1a3ef5 100644 --- a/docs/concepts/configuration.md +++ b/docs/concepts/configuration.md @@ -3,7 +3,7 @@ title: Configuration id: configuration --- -Intent reads consumer configuration from the `intent` object in `package.json`. Two keys control which skills reach your agent: `skills` (the allowlist) and `exclude` (the blocklist). +Intent reads consumer configuration from the `intent` object in `package.json`. Two keys control which discovered skills Intent surfaces: `skills` (the allowlist) and `exclude` (the blocklist). ```json { @@ -14,11 +14,13 @@ Intent reads consumer configuration from the `intent` object in `package.json`. } ``` -Intent merges these keys from every `package.json` between the current working directory and the workspace or project root. A monorepo package inherits the root configuration and adds its own. +Intent resolves `skills` from the nearest `package.json` between the current working directory and the workspace or project root that declares a non-null value. A nearer declaration replaces a parent declaration; an omitted or null value inherits the nearest parent declaration. Intent combines `exclude` arrays from the root through the current working directory, then adds excludes passed by the caller. ## `intent.skills` -`intent.skills` is the allowlist. Only packages it permits contribute skills to `list`, `load`, `install`, and `stale`. See [Trust model](./trust-model) for the reasoning. +`intent.skills` is a package-source allowlist. Permitted packages surface in `list` and `stale`, can resolve through `load`, and contribute mappings to `install --map`. The default `install` command writes generic loading guidance without scanning packages. See [Trust model](./trust-model) for the reasoning and lifecycle boundaries. + +The allowlist permits packages, not individual skills. An entry containing `#` is invalid; use `intent.exclude` for skill-specific filtering. ### Source entries @@ -26,12 +28,13 @@ Each array entry names one source: | Entry | Kind | Meaning | | ----- | ---- | ------- | -| `@scope/pkg` or `pkg` | npm | A package reachable through the dependency tree, direct or transitive. | +| `@scope/pkg` or `pkg` | npm | An npm package reachable through the dependency tree, direct or transitive. | | `workspace:@scope/pkg` | workspace | A package in the current workspace. | -| `@scope/*` or `workspace:@scope/*` | npm or workspace | Every discovered package of that kind whose name matches the pattern. | +| `@scope/*` | npm | Every discovered npm package whose name matches the pattern. | +| `workspace:@scope/*` | workspace | Every discovered workspace package whose name matches the pattern. | | `git:/#` | git | Reserved. Not yet supported, and rejected until a future version adds it. | -A malformed entry fails the whole command, and every bad entry is reported at once. Package patterns support `*` wildcards, including scoped patterns such as `@tanstack/*`. Intent matches allowlist entries against discovered package names. This matching will tighten in a future version. +A malformed entry fails the whole command, and every bad entry is reported at once. Package patterns support `*` wildcards, including scoped patterns such as `@tanstack/*`. Intent matches both the package name and source kind: a bare entry permits only an npm source, and a `workspace:` entry permits only a workspace source. ### Special forms @@ -41,7 +44,7 @@ The list as a whole has three special forms: - **Empty.** `"skills": []`. No package is surfaced. Intent prints an info notice to stderr. - **Wildcard.** `"skills": ["*"]`. Every discovered package is surfaced. Unlike a package pattern such as `@tanstack/*`, this exact entry crosses package scopes and source kinds. Intent prints an acknowledged-risk notice to stderr, since unvetted skills may reach your agent. -A package that ships skills but is not listed is dropped. When packages are dropped this way, Intent prints one summary line naming them so you can opt in. A listed package that was not discovered is reported as well. +A package that ships skills but is not listed is dropped. In human output, Intent adds one policy notice naming packages dropped this way so you can opt in. Agent sessions receive only the hidden package and skill counts. A listed package that was not discovered is reported as a notice as well. ### Existing projects @@ -58,6 +61,8 @@ npx @tanstack/intent@latest install --map --no-notices For CI or wrapper scripts, set `INTENT_NO_NOTICES=1` to suppress notices without changing command arguments. +Discovery and resolution warnings are separate from policy notices and are not suppressed by these options. The acknowledged-risk notice for `"skills": ["*"]` also remains visible when other notices are suppressed. + ## `intent.exclude` `intent.exclude` removes packages or individual skills after the allowlist resolves. @@ -86,4 +91,4 @@ Pattern grammar: - A pattern may cross package boundaries at skill granularity: `*#experimental-*`. - The `#*` shortcut excludes the whole package: `@scope/pkg#*`. -Only exact names and `*` wildcards are supported on each segment. Bare package-name patterns keep working unchanged. An excluded package does not trigger the unlisted-source warning, because an exclude is an explicit decision. +Only exact names and `*` wildcards are supported on each segment. Excludes are source-kind agnostic, so a package pattern excludes matching npm and workspace sources. An excluded package does not trigger the unlisted-source notice, because an exclude is an explicit decision. diff --git a/docs/concepts/trust-model.md b/docs/concepts/trust-model.md index 65ea0b4b..2902b47c 100644 --- a/docs/concepts/trust-model.md +++ b/docs/concepts/trust-model.md @@ -3,17 +3,17 @@ title: Trust model id: trust-model --- -Intent surfaces skills from your dependencies into your coding agent's guidance. A skill is instructions an agent follows, so the set of packages allowed to contribute skills is a trust decision. Intent makes that decision explicit through the `intent.skills` allowlist. +Intent discovers skills from your dependencies and can surface permitted skills through its CLI and agent integrations. A skill is instructions an agent follows, so the set of packages allowed to contribute skills is a trust decision. Intent makes that decision explicit through the `intent.skills` allowlist. ## Explicit sources A package ships skills in a `skills/` directory. Discovery finds every installed package that has one, including transitive dependencies. Discovery does not grant trust. -`package.json#intent.skills` is the gate. A discovered package contributes skills only when an exact entry or `*` pattern in the allowlist matches it. An unlisted package is dropped, and Intent reports it so you can opt in or ignore it. +`package.json#intent.skills` is the gate. A discovered package contributes skills only when an exact entry or `*` pattern in the allowlist matches its package name and source kind. An unlisted package is dropped, and Intent reports it so you can opt in or ignore it. The gate is opt-in today. A project with no `intent.skills` key still surfaces every discovered package, and Intent prints a deprecation notice to stderr on each run until you set `intent.skills`. A future version will require an explicit allowlist. See the [special forms](./configuration#special-forms) in Configuration. -Trust does not propagate. A listed package may depend on another package that ships skills, but that dependency stays unlisted unless another entry matches it. Exact entries allow one source; patterns such as `@tanstack/*` explicitly allow every matching source. +Trust does not propagate. A listed package may depend on another package that ships skills, but that dependency stays unlisted unless another entry matches it. A bare entry such as `foo` permits an npm source, while `workspace:foo` permits a workspace source. Their wildcard forms remain kind-specific. The exact `*` entry permits every discovered npm and workspace source. ## Static discovery @@ -21,8 +21,19 @@ Intent reads package data as files. It never imports, requires, or executes the One exception is sanctioned: in Yarn Plug'n'Play projects, Intent loads Yarn's PnP runtime (`.pnp.cjs`) to map package identities to readable locations. It loads no package entry points, bins, lifecycle scripts, or other package-provided JavaScript. An ESLint rule enforces this invariant in the discovery code. -## What the allowlist does not cover yet +## Lifecycle boundaries -Matching is currently by package name. A `workspace:foo` entry and a bare `foo` entry both authorize a discovered package named `foo`, because the scanner does not yet distinguish a workspace member from a published package of the same name. This errs toward permitting a same-named package, never toward denying one you listed. A future version tightens matching once the scanner carries that signal. +Intent uses these states as separate boundaries: + +1. **Available.** Intent discovered the skill from an installed or workspace package. +2. **Permitted.** Project policy allows the package and skill to surface. `intent.exclude` can remove a package or skill after `intent.skills` permits its source. +3. **Loaded.** A supported load path resolved the skill and returned its content. +4. **Delivered.** Intent placed guidance where an agent integration can access it, such as a managed guidance block or session hook context. +5. **Activated.** The agent selected or received the skill for a particular task. +6. **Applied.** The model followed the skill correctly. + +Intent can report discovery and policy results, confirm a successful `intent load`, verify a managed block it writes, and emit hook context. Those observations cover Available, Permitted, Loaded, and Intent's side of Delivered. Activated and Applied depend on agent behavior and are not states Intent can prove. A hook observing an `intent load` command does not prove that the command succeeded, that the skill was relevant, or that the model used its guidance. + +## Unsupported sources The `git:` source kind is reserved. Intent parses and validates the shape, then rejects it until a future version can pin the resolved ref and content hash. A git entry never loads silently. diff --git a/docs/getting-started/quick-start-consumers.md b/docs/getting-started/quick-start-consumers.md index 374742a8..031b5892 100644 --- a/docs/getting-started/quick-start-consumers.md +++ b/docs/getting-started/quick-start-consumers.md @@ -56,7 +56,7 @@ npx @tanstack/intent@latest hooks install --scope user --agents copilot Cursor and generic `AGENTS.md` agents use the guidance block only. -Hooks add the available Intent skill catalog to supported agent sessions and keep the edit gate active until the agent loads matching full guidance. To tailor what appears in the session catalog, configure `intent.skills` and `intent.exclude` in `package.json`. +Hooks return the available Intent skill catalog as context for supported agent sessions and keep the edit gate active until they observe a supported `intent load` command. They do not verify that the command succeeded, that the skill matched the task, or that the agent applied its guidance. To tailor what appears in the session catalog, configure `intent.skills` and `intent.exclude` in `package.json`. ## 2. Choose which packages' skills to use @@ -74,7 +74,7 @@ List the packages or `*` package patterns you trust. Intent then surfaces skills ## 3. Use skills in your workflow -When your agent works on a task that matches an available skill, it loads the matching `SKILL.md` into context. +The installed guidance tells your agent to select and load a skill when it matches the task. Intent can return the selected `SKILL.md`, but it cannot guarantee that an agent selected the correct skill or followed its guidance. See [Lifecycle boundaries](../concepts/trust-model#lifecycle-boundaries). Load a skill manually: diff --git a/package.json b/package.json index f94a303b..38c8df9e 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "scripts": { "build": "nx affected --skip-nx-cache --targets=build --exclude=examples/**", "build:all": "nx run-many --targets=build --exclude=examples/**", - "build:core": "nx run-many --targets=build --projects=packages/agents", "changeset": "changeset", "changeset:publish": "changeset publish", "changeset:version": "changeset version && pnpm install --no-frozen-lockfile && pnpm format", @@ -40,7 +39,7 @@ "test:knip": "knip", "test:lib": "nx affected --targets=test:lib --exclude=examples/**", "test:lib:dev": "pnpm test:lib && nx watch --all -- pnpm test:lib", - "test:pr": "tsc --noEmit && nx affected --targets=test:eslint,test:sherif,test:knip,test:docs,test:lib,test:types,build", + "test:pr": "tsc --noEmit && nx affected --targets=test:eslint,test:sherif,test:knip,test:docs,test:lib,test:integration,test:types,build", "test:sherif": "sherif", "test:types": "nx affected --targets=test:types --exclude=examples/**", "watch": "pnpm run build:all && nx watch --all -- pnpm run build:all" diff --git a/packages/intent/src/shared/utils.ts b/packages/intent/src/shared/utils.ts index f3d6930e..2fc1679c 100644 --- a/packages/intent/src/shared/utils.ts +++ b/packages/intent/src/shared/utils.ts @@ -153,7 +153,7 @@ export function getDeps( for (const field of fields) { const d = pkgJson[field] if (d && typeof d === 'object') { - for (const name of Object.keys(d as Record)) { + for (const name of Object.keys(d)) { deps.add(name) } } diff --git a/packages/intent/tests/integration/source-policy-surfaces.test.ts b/packages/intent/tests/integration/source-policy-surfaces.test.ts index 5bbede6f..b2664cc1 100644 --- a/packages/intent/tests/integration/source-policy-surfaces.test.ts +++ b/packages/intent/tests/integration/source-policy-surfaces.test.ts @@ -73,7 +73,7 @@ describe('source policy — all four surfaces filter excluded and unlisted', () it('list surfaces only the listed package', () => { writeStandaloneFixture() - const result = listIntentSkills({ cwd: root }) + const result = listIntentSkills({ audience: 'human', cwd: root }) expect(result.packages.map((pkg) => pkg.name)).toEqual([LISTED]) expect(result.notices.some((notice) => notice.includes(UNLISTED))).toBe( diff --git a/packages/intent/tests/staleness.test.ts b/packages/intent/tests/staleness.test.ts index fa266570..b85954d9 100644 --- a/packages/intent/tests/staleness.test.ts +++ b/packages/intent/tests/staleness.test.ts @@ -73,11 +73,11 @@ function mockFetchVersion(version: string): void { globalThis.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ version }), - } as Response) + }) } function mockFetchNotOk(): void { - globalThis.fetch = vi.fn().mockResolvedValue({ ok: false } as Response) + globalThis.fetch = vi.fn().mockResolvedValue({ ok: false }) } beforeEach(() => { From 0ab7e3da9d6618f86627d12d80682508dac6aa7d Mon Sep 17 00:00:00 2001 From: ladybluenotes Date: Sat, 8 Aug 2026 09:42:58 -0700 Subject: [PATCH 2/6] chore: remove stale lockfile milestone wording --- packages/intent/src/core/skill-sources.ts | 8 +------- packages/intent/tests/skill-sources.test.ts | 7 +++++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/intent/src/core/skill-sources.ts b/packages/intent/src/core/skill-sources.ts index 61b1ae0c..a26435a5 100644 --- a/packages/intent/src/core/skill-sources.ts +++ b/packages/intent/src/core/skill-sources.ts @@ -1,12 +1,6 @@ // Static-discovery invariant: this module only inspects strings. It never // resolves, requires, or executes any discovered package. -/** - * Exact entries keep the `kind` + `id` identity M2's lockfile reuses. Patterns - * select multiple discovered identities and remain distinct from exact entries. - * The `git` variant is never constructed in M1 (git entries are rejected at - * parse time) but is defined here so M2 builds on this shape. - */ type SkillSource = | ({ raw: string; kind: 'npm' | 'workspace' } & ( { id: string } | { pattern: string } @@ -172,7 +166,7 @@ function parseEntry( case 'git': return { raw, - message: `Git source "${trimmed}" is not supported until the lockfile lands (M2).`, + message: `Git source "${trimmed}" is not supported.`, } default: return { diff --git a/packages/intent/tests/skill-sources.test.ts b/packages/intent/tests/skill-sources.test.ts index d80ec2cf..48747ffe 100644 --- a/packages/intent/tests/skill-sources.test.ts +++ b/packages/intent/tests/skill-sources.test.ts @@ -103,8 +103,9 @@ describe('parseSkillSources — malformed entries (fail-whole-list)', () => { expect(error.issues).toHaveLength(1) expect(error.issues[0]).toMatchObject({ raw: 'git:github.com/me/skills#main', + message: + 'Git source "git:github.com/me/skills#main" is not supported.', }) - expect(error.issues[0]?.message).toContain('not supported until') }) it('rejects an unknown prefix', () => { @@ -279,7 +280,9 @@ describe('parseSkillSources — error reporting', () => { 'git:github.com/me/skills#main', ]) expect(error.issues).toHaveLength(2) - expect(error.issues[0]?.message).toContain('not supported until') + expect(error.issues[0]?.message).toBe( + 'Git source "git:github.com/me/skills#main" is not supported.', + ) expect(error.issues[1]?.message).toBe('Duplicate entry.') }) From c0246c5ab56ef2ec5c9ffe319c2c16f5cfed63aa Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 8 Aug 2026 16:43:43 +0000 Subject: [PATCH 3/6] ci: apply automated fixes --- packages/intent/tests/skill-sources.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/intent/tests/skill-sources.test.ts b/packages/intent/tests/skill-sources.test.ts index 48747ffe..c170c182 100644 --- a/packages/intent/tests/skill-sources.test.ts +++ b/packages/intent/tests/skill-sources.test.ts @@ -103,8 +103,7 @@ describe('parseSkillSources — malformed entries (fail-whole-list)', () => { expect(error.issues).toHaveLength(1) expect(error.issues[0]).toMatchObject({ raw: 'git:github.com/me/skills#main', - message: - 'Git source "git:github.com/me/skills#main" is not supported.', + message: 'Git source "git:github.com/me/skills#main" is not supported.', }) }) From 5471d11fa4ede07a1123b7f98d99e9785e3d4fd3 Mon Sep 17 00:00:00 2001 From: ladybluenotes Date: Sat, 8 Aug 2026 09:44:24 -0700 Subject: [PATCH 4/6] style: format skill source assertions --- packages/intent/tests/skill-sources.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/intent/tests/skill-sources.test.ts b/packages/intent/tests/skill-sources.test.ts index 48747ffe..c170c182 100644 --- a/packages/intent/tests/skill-sources.test.ts +++ b/packages/intent/tests/skill-sources.test.ts @@ -103,8 +103,7 @@ describe('parseSkillSources — malformed entries (fail-whole-list)', () => { expect(error.issues).toHaveLength(1) expect(error.issues[0]).toMatchObject({ raw: 'git:github.com/me/skills#main', - message: - 'Git source "git:github.com/me/skills#main" is not supported.', + message: 'Git source "git:github.com/me/skills#main" is not supported.', }) }) From 309325217cdc68bc67b85548c2f1756aac960ca6 Mon Sep 17 00:00:00 2001 From: ladybluenotes Date: Sat, 8 Aug 2026 09:47:24 -0700 Subject: [PATCH 5/6] chore: add source error changeset --- .changeset/quiet-sources-rest.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/quiet-sources-rest.md diff --git a/.changeset/quiet-sources-rest.md b/.changeset/quiet-sources-rest.md new file mode 100644 index 00000000..8b153007 --- /dev/null +++ b/.changeset/quiet-sources-rest.md @@ -0,0 +1,5 @@ +--- +'@tanstack/intent': patch +--- + +Remove internal milestone wording from unsupported `git:` source errors. From 3c0f6fca5246142be8cd03ed81326509e6860e35 Mon Sep 17 00:00:00 2001 From: ladybluenotes Date: Sat, 8 Aug 2026 10:04:44 -0700 Subject: [PATCH 6/6] update docs structure --- docs/cli/intent-hooks.md | 18 ++- docs/cli/intent-install.md | 23 ++-- docs/cli/intent-list.md | 27 ++-- docs/cli/intent-load.md | 16 +++ docs/cli/intent-setup.md | 59 ++++----- docs/cli/intent-stale.md | 22 +++- docs/cli/intent-validate.md | 12 +- docs/concepts/configuration.md | 27 ++-- docs/concepts/trust-model.md | 22 ++-- docs/getting-started/quick-start-consumers.md | 30 +++-- .../quick-start-maintainers.md | 116 ++++++++++-------- docs/overview.md | 14 +-- 12 files changed, 238 insertions(+), 148 deletions(-) diff --git a/docs/cli/intent-hooks.md b/docs/cli/intent-hooks.md index 905f9041..f8b593ba 100644 --- a/docs/cli/intent-hooks.md +++ b/docs/cli/intent-hooks.md @@ -16,16 +16,30 @@ npx @tanstack/intent@latest hooks install [--scope project|user] [--agents copil ## Behavior +### Session behavior + - Installs hook behavior without writing an `intent-skills` guidance block. - Returns a session-start skill catalog as agent context with available `skill-id: description` entries. - Blocks supported edit tools until the hook observes a recognized `intent load ` command. +- Uses `package.json#intent.skills` and `package.json#intent.exclude` to control which skills appear in the session catalog. + +### Installation behavior + - `--scope project` writes project-local hook config for agents that support it. - `--scope user` writes user-level agent config and stores runner scripts under `~/.tanstack/intent/hooks`. - `--agents all` is the default. In project scope, Copilot is skipped because the supported Copilot CLI hook location is user-scoped. - Run `intent install` separately when you also want to write project guidance. -- Use `package.json#intent.skills` and `package.json#intent.exclude` to control which skills are surfaced in the session catalog. -The hook records a recognized load command before that command completes. It does not verify that the command succeeded, that the selected skill matched the task, that the agent received the returned content, or that the model applied the guidance. Hook output is an edit gate and observation signal, not proof of activation or correct agent behavior. See [Lifecycle boundaries](../concepts/trust-model#lifecycle-boundaries). +The hook records a recognized load command before that command completes. + +Hooks do not verify that: + +- The command succeeded. +- The selected skill matched the task. +- The agent received the returned content. +- The model applied the guidance. + +Hook output is an edit gate and observation signal, not proof of activation or correct agent behavior. See [Lifecycle boundaries](../concepts/trust-model#lifecycle-boundaries). ## Hook support diff --git a/docs/cli/intent-install.md b/docs/cli/intent-install.md index 85b70e92..8b0abbf1 100644 --- a/docs/cli/intent-install.md +++ b/docs/cli/intent-install.md @@ -25,15 +25,20 @@ npx @tanstack/intent@latest install [--map] [--dry-run] [--print-prompt] [--glob ## Behavior +### Default guidance + - Writes lightweight skill loading guidance by default. - Creates `AGENTS.md` when no managed block exists. - Updates an existing managed block in a supported config file. - Preserves all content outside the managed block. +- Verifies the managed block before reporting success. + +### Mapping mode + - Scans packages and writes compact `id`, `run`, and `for` mappings only when `--map` is passed. - Surfaces packages permitted by `package.json#intent.skills` in `--map` mode. See [Configuration](../concepts/configuration). - Skips reference, meta, maintainer, and maintainer-only skills in `--map` mode. - Writes compact skill identities and runnable guidance commands instead of local file paths in `--map` mode. -- Verifies the managed block before reporting success. - Prints `No intent-enabled skills found.` and does not create a config file when `--map` finds no actionable skills. Supported config files: `AGENTS.md`, `CLAUDE.md`, `.cursorrules`, `.github/copilot-instructions.md`. @@ -76,13 +81,15 @@ tanstackIntent: ## Status messages -- Created: `Created AGENTS.md with 1 mapping.` -- Updated: `Updated AGENTS.md with 2 mappings.` -- Unchanged: `No changes to AGENTS.md; 2 mappings already current.` -- Guidance created: `Created AGENTS.md with skill loading guidance.` -- Guidance unchanged: `No changes to AGENTS.md; skill loading guidance already current.` -- Placement tip: `Tip: Keep the intent-skills block near the top of AGENTS.md so agents read it before task-specific instructions.` -- No actionable skills in `--map` mode: `No intent-enabled skills found.` +| Result | Message | +| --- | --- | +| Mapping created | `Created AGENTS.md with 1 mapping.` | +| Mappings updated | `Updated AGENTS.md with 2 mappings.` | +| Mappings unchanged | `No changes to AGENTS.md; 2 mappings already current.` | +| Guidance created | `Created AGENTS.md with skill loading guidance.` | +| Guidance unchanged | `No changes to AGENTS.md; skill loading guidance already current.` | +| Placement tip | `Tip: Keep the intent-skills block near the top of AGENTS.md so agents read it before task-specific instructions.` | +| No actionable skills in `--map` mode | `No intent-enabled skills found.` | To suppress trust and migration notices in automation, pass `--no-notices`. diff --git a/docs/cli/intent-list.md b/docs/cli/intent-list.md index e2859e38..b3c05f73 100644 --- a/docs/cli/intent-list.md +++ b/docs/cli/intent-list.md @@ -11,30 +11,38 @@ npx @tanstack/intent@latest list [--json] [--debug] [--global] [--global-only] [ ## Options +### Output + - `--json`: print JSON instead of text output - `--debug`: print discovery debug details to stderr +- `--no-notices`: suppress non-critical notices on stderr; the acknowledged-risk notice for `intent.skills: ["*"]` remains visible + +### Scan scope + - `--global`: include global packages after project packages - `--global-only`: list global packages only - `--show-hidden`: show unlisted hidden skill sources when run outside an agent session -- `--no-notices`: suppress non-critical notices on stderr; the acknowledged-risk notice for `intent.skills: ["*"]` remains visible ## What you get +### Selection + - Scans project and workspace dependencies for intent-enabled packages and skills - Surfaces packages permitted by `package.json#intent.skills` (see [Allowlist](#allowlist)) - Includes global packages only when `--global` or `--global-only` is passed -- Includes warnings from discovery - Excludes packages and skills matched by package.json `intent.exclude` -- Prints debug details to stderr when `--debug` is passed -- If no packages are discovered, prints `No intent-enabled packages found.` + +When both local and global packages are scanned, local packages take precedence. `SOURCE` shows whether the selected package came from local discovery or explicit global scanning. + +### Text output + - Summary line with package count and skill count - Package table columns: `PACKAGE`, `SOURCE`, `VERSION`, `SKILLS` - Skill tree grouped by package -- Optional warnings section (`⚠ ...` per warning) -- Optional notices section on stderr (`ℹ ...` per notice), suppressed by `--no-notices` +- Discovery warnings (`⚠ ...`) on stdout +- `No intent-enabled packages found.` when no packages are discovered -`SOURCE` is a lightweight indicator showing whether the selected package came from local discovery or explicit global scanning. -When both local and global packages are scanned, local packages take precedence. +Policy notices (`ℹ ...`) are written to stderr. ## JSON output @@ -141,5 +149,4 @@ An excluded package never triggers the unlisted-source notice, because an exclud ## Common errors - Scanner failures are printed as errors -- Unsupported environments: - - Deno projects without `node_modules` +- Deno projects without `node_modules` are unsupported diff --git a/docs/cli/intent-load.md b/docs/cli/intent-load.md index e39a7edd..48fc0654 100644 --- a/docs/cli/intent-load.md +++ b/docs/cli/intent-load.md @@ -19,13 +19,21 @@ npx @tanstack/intent@latest load # [--path] [--json] [--debug] [ ## What you get +### Resolution + - Validates `#` before scanning - Scans project-local packages by default - Includes global packages only when `--global` or `--global-only` is passed - Checks the target package name against `package.json#intent.skills` before resolution, then enforces its source kind after resolution - Refuses before scanning when the target package or skill matches `intent.exclude` + +### Selection + - Prefers local packages when `--global` is used and the same package exists locally and globally - Accepts an unambiguous short skill name when a package-prefixed skill exists + +### Output + - Prints raw `SKILL.md` content by default - Prints the scanner-reported path when `--path` is passed - Prints debug details to stderr when `--debug` is passed @@ -62,12 +70,20 @@ npx @tanstack/intent@latest load some-lib#core --path ## Common errors +### Invalid skill identity + - Missing separator: `Invalid skill use "@tanstack/query": expected #.` - Empty package: `Invalid skill use "#core": package is required.` - Empty skill: `Invalid skill use "@tanstack/query#": skill is required.` + +### Resolution failures + - Missing package: `Cannot resolve skill use "...": package "..." was not found.` - Missing skill: `Cannot resolve skill use "...": skill "..." was not found in package "...".` - Skill suggestion: `Did you mean @tanstack/router-core#router-core/auth-and-guards?` + +### Policy refusals + - Unlisted package: `Cannot load skill use "...": package "..." is not listed in intent.skills.` - Excluded package: `Cannot load skill use "...": package "..." is excluded by Intent configuration.` - Excluded skill: `Cannot load skill use "...": skill "..." is excluded by Intent configuration.` diff --git a/docs/cli/intent-setup.md b/docs/cli/intent-setup.md index 72edc876..96f8fb9e 100644 --- a/docs/cli/intent-setup.md +++ b/docs/cli/intent-setup.md @@ -3,31 +3,34 @@ title: setup commands id: intent-setup --- -Intent exposes publishing setup as two commands. - -```bash -npx @tanstack/intent@latest edit-package-json -npx @tanstack/intent@latest setup -``` +Intent exposes publishing setup as two commands. + +```bash +npx @tanstack/intent@latest edit-package-json +npx @tanstack/intent@latest setup +``` ## Commands -- `edit-package-json`: add or normalize `package.json` entries needed to publish skills -- `setup`: copy workflow templates to `.github/workflows` -- `setup-github-actions`: legacy alias for `setup` +- `edit-package-json`: add or normalize `package.json` entries needed to publish skills +- `setup`: copy workflow templates to `.github/workflows` +- `setup-github-actions`: legacy alias for `setup` ## What each command changes -- `edit-package-json` - - Requires a valid `package.json` in current directory - - Ensures `keywords` includes `tanstack-intent` - - Ensures `files` includes required publish entries - - Preserves existing indentation -- `setup` - - Copies the `check-skills.yml` workflow template from `@tanstack/intent/meta/templates/workflows` to `.github/workflows` - - Applies variable substitution (`PACKAGE_NAME`, `PACKAGE_LABEL`, `PAYLOAD_PACKAGE`, `REPO`, `DOCS_PATH`, `SRC_PATH`, `WATCH_PATHS`) - - Detects the workspace root in monorepos and writes repo-level workflows there - - Skips files that already exist at destination +### `edit-package-json` + +- Requires a valid `package.json` in the current directory +- Ensures `keywords` includes `tanstack-intent` +- Ensures `files` includes required publish entries +- Preserves existing indentation + +### `setup` + +- Copies the `check-skills.yml` workflow template from `@tanstack/intent/meta/templates/workflows` to `.github/workflows` +- Applies variable substitution (`PACKAGE_NAME`, `PACKAGE_LABEL`, `PAYLOAD_PACKAGE`, `REPO`, `DOCS_PATH`, `SRC_PATH`, `WATCH_PATHS`) +- Detects the workspace root in monorepos and writes repo-level workflows there +- Skips files that already exist at the destination ## Required `files` entries @@ -39,15 +42,15 @@ npx @tanstack/intent@latest setup ## Common errors - Missing or invalid `package.json` when running `edit-package-json` -- Missing template source when running `setup` - -## Notes - -- `setup` skips existing files -- `check-skills.yml` validates skills on PRs and opens review PRs from release/manual runs -- To adopt updated workflow templates, delete or move the old generated workflow files first, then rerun `setup` -- If your repo has an older generated `validate-skills.yml`, remove it after adopting the current `check-skills.yml`; PR validation now lives in `check-skills.yml` -- In monorepos, run `setup` from either the repo root or a package directory; Intent writes workflows to the workspace root +- Missing template source when running `setup` + +## Notes + +- `setup` skips existing files +- `check-skills.yml` validates skills on PRs and opens review PRs from release/manual runs +- To adopt updated workflow templates, delete or move the old generated workflow files first, then rerun `setup` +- If your repo has an older generated `validate-skills.yml`, remove it after adopting the current `check-skills.yml`; PR validation now lives in `check-skills.yml` +- In monorepos, run `setup` from either the repo root or a package directory; Intent writes workflows to the workspace root ## Related diff --git a/docs/cli/intent-stale.md b/docs/cli/intent-stale.md index b027f8b4..70e35a6b 100644 --- a/docs/cli/intent-stale.md +++ b/docs/cli/intent-stale.md @@ -15,14 +15,22 @@ npx @tanstack/intent@latest stale [--json] ## Behavior +### Scope + - Checks the current package by default - From a monorepo root, checks workspace packages that ship skills and also reports public workspace packages with no skill or artifact coverage - Applies the `package.json#intent.skills` allowlist when falling back to installed dependencies; workspace packages are first-party and checked regardless. See [Configuration](../concepts/configuration). - When `dir` is provided, scopes the check to the targeted package or skills directory - Computes one staleness report per package + +### Coverage + - Reads repo-root `_artifacts/*domain_map.yaml` and `_artifacts/*skill_tree.yaml` when present - Flags public workspace packages that are not represented by generated skills or artifact coverage - Skips workspace packages with `"private": true` + +### Output and workflow state + - Prints text output by default or JSON with `--json` - Prints a non-failing workflow update reminder when `.github/workflows/check-skills.yml` is missing the current `intent-workflow-version` stamp - If no packages are found, prints `No intent-enabled packages found.` @@ -74,12 +82,14 @@ Ignored packages are excluded from missing coverage signals. Private workspace p Report fields: -- `library`: package name -- `currentVersion`: latest version from npm registry (or `null` if unavailable) -- `skillVersion`: `library_version` from skills (or `null`) -- `versionDrift`: `major | minor | patch | null` -- `skills`: array of per-skill checks -- `signals`: array of artifact and workspace coverage checks +| Field | Meaning | +| --- | --- | +| `library` | Package name | +| `currentVersion` | Latest version from npm registry, or `null` if unavailable | +| `skillVersion` | `library_version` from skills, or `null` | +| `versionDrift` | `major`, `minor`, `patch`, or `null` | +| `skills` | Per-skill checks | +| `signals` | Artifact and workspace coverage checks | Skill fields: diff --git a/docs/cli/intent-validate.md b/docs/cli/intent-validate.md index b54b4d2a..634b4b0e 100644 --- a/docs/cli/intent-validate.md +++ b/docs/cli/intent-validate.md @@ -49,21 +49,25 @@ npx @tanstack/intent@latest validate --fix ## Validation checks -For each discovered `SKILL.md`: +### File structure - Frontmatter delimiter and structure are valid - YAML frontmatter parses successfully - Required fields exist: `name`, `description` - `name` is a single leaf segment matching the skill's parent directory (no slashes); the namespace is carried by the directory path -- `name` uses only lowercase letters, numbers, and hyphens -- `name` is at most 64 characters +- `name` uses only lowercase letters, numbers, and hyphens and is at most 64 characters + +### Field rules + - Only spec top-level keys are allowed (`name`, `description`, `license`, `compatibility`, `metadata`, `allowed-tools`); Intent-specific scalars (`type`, `library`, `library_version`, `framework`) must live under `metadata` - `metadata`, when present, is a mapping of string values - `description` length is at most 1024 characters - `type: framework` requires `requires` to be an array - Total file length is at most 500 lines -If `/_artifacts` exists, it also validates artifacts: +### Artifacts + +When `/_artifacts` exists, Intent also checks: - Required files: `domain_map.yaml`, `skill_spec.md`, `skill_tree.yaml` - Required files must be non-empty diff --git a/docs/concepts/configuration.md b/docs/concepts/configuration.md index 8d1a3ef5..270fcc60 100644 --- a/docs/concepts/configuration.md +++ b/docs/concepts/configuration.md @@ -14,11 +14,20 @@ Intent reads consumer configuration from the `intent` object in `package.json`. } ``` -Intent resolves `skills` from the nearest `package.json` between the current working directory and the workspace or project root that declares a non-null value. A nearer declaration replaces a parent declaration; an omitted or null value inherits the nearest parent declaration. Intent combines `exclude` arrays from the root through the current working directory, then adds excludes passed by the caller. +## Configuration inheritance + +- **`intent.skills`:** Intent uses the nearest non-null declaration between the current working directory and the workspace or project root. A nearer declaration replaces its parent. An omitted or null value inherits the nearest parent declaration. +- **`intent.exclude`:** Intent combines arrays from the root through the current working directory, then adds excludes passed by the caller. ## `intent.skills` -`intent.skills` is a package-source allowlist. Permitted packages surface in `list` and `stale`, can resolve through `load`, and contribute mappings to `install --map`. The default `install` command writes generic loading guidance without scanning packages. See [Trust model](./trust-model) for the reasoning and lifecycle boundaries. +`intent.skills` is a package-source allowlist. A permitted package can: + +- Appear in `list` and `stale`. +- Resolve through `load`. +- Contribute mappings to `install --map`. + +The default `install` command writes generic loading guidance without scanning packages. See [Trust model](./trust-model) for the reasoning and lifecycle boundaries. The allowlist permits packages, not individual skills. An entry containing `#` is invalid; use `intent.exclude` for skill-specific filtering. @@ -38,17 +47,19 @@ A malformed entry fails the whole command, and every bad entry is reported at on ### Special forms -The list as a whole has three special forms: - -- **Absent.** No `intent.skills` key. Every discovered package is surfaced, and Intent prints a deprecation notice to stderr on each run until you set `intent.skills`. This is the upgrade path for existing projects. A future version will require an explicit allowlist. -- **Empty.** `"skills": []`. No package is surfaced. Intent prints an info notice to stderr. -- **Wildcard.** `"skills": ["*"]`. Every discovered package is surfaced. Unlike a package pattern such as `@tanstack/*`, this exact entry crosses package scopes and source kinds. Intent prints an acknowledged-risk notice to stderr, since unvetted skills may reach your agent. +| Form | Result | Notice | +| --- | --- | --- | +| **Absent:** no `intent.skills` key | Surfaces every discovered package as an upgrade path for existing projects. A future version will require an explicit allowlist. | Deprecation notice on stderr on each run until you set `intent.skills`. | +| **Empty:** `"skills": []` | Surfaces no packages. | Info notice on stderr. | +| **Wildcard:** `"skills": ["*"]` | Surfaces every discovered package across package scopes and source kinds. This is broader than a pattern such as `@tanstack/*`. | Acknowledged-risk notice on stderr because unvetted skills may reach your agent. | A package that ships skills but is not listed is dropped. In human output, Intent adds one policy notice naming packages dropped this way so you can opt in. Agent sessions receive only the hidden package and skill counts. A listed package that was not discovered is reported as a notice as well. ### Existing projects -A project that has not set `intent.skills` keeps working. Intent surfaces every discovered package and prints the deprecation notice described under the absent form. Nothing breaks. Add an allowlist when you are ready, before a future version requires one. Run `intent list` to confirm which packages are surfaced. +Run `intent list` to see which packages the current policy surfaces. + +A project without `intent.skills` uses the absent form: Intent surfaces every discovered package and prints its deprecation notice. Add an allowlist to permit specific sources before a future version requires one. ### Suppressing notices temporarily diff --git a/docs/concepts/trust-model.md b/docs/concepts/trust-model.md index 2902b47c..38cd69c2 100644 --- a/docs/concepts/trust-model.md +++ b/docs/concepts/trust-model.md @@ -23,16 +23,18 @@ One exception is sanctioned: in Yarn Plug'n'Play projects, Intent loads Yarn's P ## Lifecycle boundaries -Intent uses these states as separate boundaries: - -1. **Available.** Intent discovered the skill from an installed or workspace package. -2. **Permitted.** Project policy allows the package and skill to surface. `intent.exclude` can remove a package or skill after `intent.skills` permits its source. -3. **Loaded.** A supported load path resolved the skill and returned its content. -4. **Delivered.** Intent placed guidance where an agent integration can access it, such as a managed guidance block or session hook context. -5. **Activated.** The agent selected or received the skill for a particular task. -6. **Applied.** The model followed the skill correctly. - -Intent can report discovery and policy results, confirm a successful `intent load`, verify a managed block it writes, and emit hook context. Those observations cover Available, Permitted, Loaded, and Intent's side of Delivered. Activated and Applied depend on agent behavior and are not states Intent can prove. A hook observing an `intent load` command does not prove that the command succeeded, that the skill was relevant, or that the model used its guidance. +Intent uses six lifecycle stages in order. It can observe the first three and its side of delivery. Activation and application depend on agent behavior. + +| State | Meaning | Observable by Intent | +| --- | --- | --- | +| **1. Available** | Intent discovered the skill from an installed or workspace package. | Yes. | +| **2. Permitted** | Project policy allows the package and skill to surface. `intent.exclude` can remove a package or skill after `intent.skills` permits its source. | Yes. | +| **3. Loaded** | A supported load path resolved the skill and returned its content. | Yes. | +| **4. Delivered** | Intent placed guidance where an agent integration can access it, such as a managed guidance block or session hook context. | Intent can confirm its output, not agent receipt. | +| **5. Activated** | The agent selected or received the skill for a particular task. | No. | +| **6. Applied** | The model followed the skill correctly. | No. | + +A hook observing an `intent load` command does not prove that the command succeeded, that the skill was relevant, or that the model used its guidance. ## Unsupported sources diff --git a/docs/getting-started/quick-start-consumers.md b/docs/getting-started/quick-start-consumers.md index 031b5892..03280df1 100644 --- a/docs/getting-started/quick-start-consumers.md +++ b/docs/getting-started/quick-start-consumers.md @@ -3,19 +3,17 @@ title: Quick Start for Consumers id: quick-start-consumers --- -Get started using Intent to help your agent discover and load package skills. - ## 1. Run install -The install command guides your agent through the setup process: - ```bash npx @tanstack/intent@latest install ``` +This command creates or updates skill-loading guidance for your agent. + Examples use `npx` for npm projects. In pnpm, Yarn, or Bun projects, use the matching runner: `pnpm dlx`, `yarn dlx`, or `bunx`. -This creates or updates an `intent-skills` guidance block. It: +The command: 1. Checks for existing `intent-skills` guidance in your config files (`AGENTS.md`, `CLAUDE.md`, `.cursorrules`, etc.) 2. Writes lightweight instructions for skill discovery and loading @@ -56,7 +54,15 @@ npx @tanstack/intent@latest hooks install --scope user --agents copilot Cursor and generic `AGENTS.md` agents use the guidance block only. -Hooks return the available Intent skill catalog as context for supported agent sessions and keep the edit gate active until they observe a supported `intent load` command. They do not verify that the command succeeded, that the skill matched the task, or that the agent applied its guidance. To tailor what appears in the session catalog, configure `intent.skills` and `intent.exclude` in `package.json`. +Hooks return the available Intent skill catalog as context for supported agent sessions and keep the edit gate active until they observe a supported `intent load` command. + +Hooks do not verify that: + +- The command succeeded. +- The skill matched the task. +- The agent applied the guidance. + +To control what appears in the session catalog, configure `intent.skills` and `intent.exclude` in `package.json`. ## 2. Choose which packages' skills to use @@ -74,9 +80,7 @@ List the packages or `*` package patterns you trust. Intent then surfaces skills ## 3. Use skills in your workflow -The installed guidance tells your agent to select and load a skill when it matches the task. Intent can return the selected `SKILL.md`, but it cannot guarantee that an agent selected the correct skill or followed its guidance. See [Lifecycle boundaries](../concepts/trust-model#lifecycle-boundaries). - -Load a skill manually: +Load a skill when it matches the task: ```bash npx @tanstack/intent@latest load @tanstack/react-query#core @@ -84,6 +88,8 @@ npx @tanstack/intent@latest load @tanstack/react-query#core This prints the skill content for the installed package version. +Intent cannot guarantee that an agent selected the correct skill or followed its guidance. See [Lifecycle boundaries](../concepts/trust-model#lifecycle-boundaries). + If you want explicit task-to-skill mappings in your agent config, opt in: ```bash @@ -92,15 +98,13 @@ npx @tanstack/intent@latest install --map ## 4. Keep skills up-to-date -Skills version with library releases. When you update a library: - ```bash npm update @tanstack/react-query ``` -The new version brings updated skills automatically. The skills are shipped with the library, so you get the version that matches your installed code. If a package is installed both locally and globally and global scanning is enabled, Intent prefers the local version. +Skills version with library releases. Updating a library also updates its packaged skills, so the skill version matches the installed code. If a package is installed both locally and globally and global scanning is enabled, Intent prefers the local version. -If you need to see what skills have changed, run: +List the installed skills: ```bash npx @tanstack/intent@latest list diff --git a/docs/getting-started/quick-start-maintainers.md b/docs/getting-started/quick-start-maintainers.md index d8378a4a..e91c9443 100644 --- a/docs/getting-started/quick-start-maintainers.md +++ b/docs/getting-started/quick-start-maintainers.md @@ -52,7 +52,7 @@ This prints a comprehensive prompt that walks you and your agent through three p - Validates against the Intent specification > [!NOTE] -> This is a context-heavy process that involves domain discovery, GitHub issues analysis, and interactive maintainer interviews. The agent will scan your documentation, recent issues and discussions, and ask targeted questions to surface implicit knowledge and common failure modes. The more information you provide about your library's patterns, pitfalls, and real-world usage problems, the better the generated skills will be. Expect multiple rounds of refinement and regular context compaction before completion. +> Plan for multiple review rounds and regular context compaction. The agent scans documentation, recent issues, and discussions, then asks targeted questions about implicit knowledge and common failure modes. Provide concrete patterns, pitfalls, and real-world usage problems to improve the generated skills. ### 2. Validate skills @@ -62,17 +62,19 @@ After scaffolding, validate that all SKILL.md files are well-formed: npx @tanstack/intent@latest validate ``` -This checks: +This checks skill structure: + - Valid YAML frontmatter in every SKILL.md - Required fields (`name`, `description`) are present - Skill `name` is a leaf segment matching its parent directory -- Intent-specific scalars (`type`, `library`, `library_version`, `framework`) live under `metadata`, not at the top level - Description length <= 1024 characters - Line count limits (500 lines max per skill) -- Framework skills have a `requires` array -- Artifact files exist and are non-empty -If any artifacts are present (domain_map.yaml, skill_spec.md, skill_tree.yaml), they must parse as valid YAML. +It also checks Intent metadata and artifacts: + +- Intent-specific scalars (`type`, `library`, `library_version`, `framework`) live under `metadata`, not at the top level +- Framework skills have a `requires` array +- Required artifact files exist and are non-empty; YAML artifacts parse successfully ### 3. Commit skills and artifacts @@ -102,8 +104,8 @@ Run these commands to prepare your package for skill publishing: # Update package.json with required fields npx @tanstack/intent@latest edit-package-json -# Copy the CI workflow template -npx @tanstack/intent@latest setup +# Copy the CI workflow template +npx @tanstack/intent@latest setup ``` **What these do:** @@ -113,13 +115,13 @@ npx @tanstack/intent@latest setup - `files` array entries for `skills/` - For single packages: also adds `!skills/_artifacts` to exclude artifacts from npm - For monorepos: skips the artifacts exclusion (artifacts live at repo root) -- `setup` copies `check-skills.yml` to `.github/workflows/` for automated validation and staleness checking - -`setup` does not overwrite existing workflow files. To pick up newer generated workflows, delete or move the old generated files in `.github/workflows/`, then rerun `npx @tanstack/intent@latest setup`. - -If your repo already has an older generated `validate-skills.yml`, remove it after adopting the current `check-skills.yml`; PR validation now runs from `check-skills.yml`. - -### 5. Ship skills with your package +- `setup` copies `check-skills.yml` to `.github/workflows/` for automated validation and staleness checking + +`setup` does not overwrite existing workflow files. To pick up newer generated workflows, delete or move the old generated files in `.github/workflows/`, then rerun `npx @tanstack/intent@latest setup`. + +If your repo already has an older generated `validate-skills.yml`, remove it after adopting the current `check-skills.yml`; PR validation now runs from `check-skills.yml`. + +### 5. Ship skills with your package Skills ship inside your npm package. When you publish: @@ -127,30 +129,36 @@ Skills ship inside your npm package. When you publish: npm publish ``` -Consumers who install your library automatically get the skills. They discover local installed skills with `intent list`, add loading guidance with `intent install`, and load matching skills with `intent load`. +Consumers who install your library automatically get the skills. They discover local installed skills with `intent list`, add loading guidance with `intent install`, and load matching skills with `intent load`. **Version alignment:** - Skills version with your library releases -- Agents always load the skill matching the installed library version -- No drift between code and guidance +- `intent load` returns skill content from the installed package version +- Packaging code and skills together keeps their versions aligned --- ## Ongoing Maintenance (Manual or Agent-Assisted) -### 6. Set up the CI workflow - -After running `setup`, you'll have `check-skills.yml` in `.github/workflows/`: - -**check-skills.yml** (runs on PRs touching skills/artifacts, release, or manual trigger) -- Validates SKILL.md frontmatter and structure -- Ensures files stay under 500 lines -- Automatically detects stale skills and coverage gaps after you publish a new release -- Opens one grouped review PR with an agent-friendly prompt -- Includes the reason each skill or package was flagged -- Requires you to copy the prompt into Claude Code, Cursor, or your agent to update skills - -### 7. Update stale skills +### 6. Set up the CI workflow + +After running `setup`, you'll have `check-skills.yml` in `.github/workflows/`: + +**check-skills.yml** (runs on PRs touching skills/artifacts, release, or manual trigger) + +Validation: + +- Validates SKILL.md frontmatter and structure +- Ensures files stay under 500 lines +- Automatically detects stale skills and coverage gaps after you publish a new release + +Review handoff: + +- Opens one grouped review PR with an agent-friendly prompt +- Includes the reason each skill or package was flagged +- Requires you to copy the prompt into Claude Code, Cursor, or your agent to update skills + +### 7. Update stale skills When you publish a new release, `check-skills.yml` automatically opens a PR flagging skills that need review. @@ -160,31 +168,35 @@ Manually check which skills need updates with: npx @tanstack/intent@latest stale ``` -When run from a package, this checks that package's shipped skills. When run from a monorepo root, it checks workspace packages with skills and flags public workspace packages missing skill or `_artifacts` coverage. - -This detects: -- **Version drift** — skill targets an older library version than currently installed -- **New sources** — sources declared in frontmatter that weren't tracked before -- **Artifact drift** — `_artifacts` entries that no longer match generated skills -- **Missing package coverage** — public workspace packages not represented by generated skills or artifact coverage - -If a public workspace package is intentionally out of scope for skills, record that decision in repo-root `_artifacts`: - -```yaml -coverage: - ignored_packages: - - '@tanstack/internal-tooling' - - name: packages/devtools-fixture - reason: test fixture only -``` - -Private workspace packages are skipped automatically. - -**To update stale skills:** +When run from a package, this checks that package's shipped skills. When run from a monorepo root, it checks workspace packages with skills and flags public workspace packages missing skill or `_artifacts` coverage. + +This detects: +- **Version drift** — skill targets an older library version than currently installed +- **New sources** — sources declared in frontmatter that weren't tracked before +- **Artifact drift** — `_artifacts` entries that no longer match generated skills +- **Missing package coverage** — public workspace packages not represented by generated skills or artifact coverage + +If a public workspace package is intentionally out of scope for skills, record that decision in repo-root `_artifacts`: + +```yaml +coverage: + ignored_packages: + - '@tanstack/internal-tooling' + - name: packages/devtools-fixture + reason: test fixture only +``` + +Private workspace packages are skipped automatically. + +**Prepare the update:** + 1. Review the PR opened by `check-skills.yml` 2. Copy the agent prompt from the PR description 3. Paste it into Claude Code, Cursor, or your coding agent 4. The agent reads the stale skills and updates them based on library changes + +**Finish the update:** + 5. Run `npx @tanstack/intent@latest validate` locally to verify 6. Commit and merge the PR diff --git a/docs/overview.md b/docs/overview.md index 237fffeb..0b1d65f2 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -5,7 +5,7 @@ id: overview `@tanstack/intent` is a CLI for shipping and consuming Agent Skills as package artifacts. -Skills are markdown documents that teach AI coding agents how to use your library correctly. Intent versions them with your releases and ships them inside npm packages. It discovers skills from your project and workspace dependencies, then helps agents load them when working on matching tasks. +Skills are markdown documents that teach AI coding agents how to use your library correctly. Intent versions them with your releases and ships them inside npm packages. It discovers skills from project and workspace dependencies, then provides commands and guidance for loading them. ## What Intent does @@ -16,21 +16,21 @@ Intent provides tooling for two workflows: - Discover skills from your project and workspace dependencies - Control which packages' skills are surfaced with an allowlist - Add lightweight skill loading guidance to your agent config -- Add hook enforcement for agents that support blocking lifecycle hooks -- Keep skills synchronized with library versions +- Add session catalogs and edit gates for supported agents +- Use skills packaged with installed library versions **For maintainers (library teams):** - Scaffold skills through AI-assisted domain discovery - Validate SKILL.md format and packaging - Ship skills in the same release pipeline as code -- Track staleness when source docs change +- Review version, source, artifact, and package coverage signals ## How it works ### Discovery and installation -Examples use `npx` for npm projects. In pnpm, Yarn, or Bun projects, use the matching runner: +Use the runner for your package manager: | Tool | Pattern | | ---- | -------------------------------------------- | @@ -57,7 +57,7 @@ Creates or updates lightweight `intent-skills` guidance in your config files (`A npx @tanstack/intent@latest hooks install ``` -Installs hook enforcement for supported agents. Project-scoped hooks are available for Claude Code and Codex. GitHub Copilot CLI project guidance can live in `.github/copilot-instructions.md`, while blocking hooks are user-scoped. Cursor and generic `AGENTS.md` agents use guidance only. +Installs session catalogs and edit gates for supported agents. Project-scoped hooks are available for Claude Code and Codex. GitHub Copilot CLI project guidance can live in `.github/copilot-instructions.md`, while blocking hooks are user-scoped. Cursor and generic `AGENTS.md` agents use guidance only. See [intent hooks](./cli/intent-hooks) for what hooks can observe. ```bash npx @tanstack/intent@latest load @tanstack/query#fetching @@ -85,4 +85,4 @@ Enforces SKILL.md format rules and packaging requirements before publish. npx @tanstack/intent@latest stale ``` -Detects when skills reference outdated source documentation or library versions. +Reports version drift and source, artifact, or package coverage signals that may require skill review.