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
2 changes: 1 addition & 1 deletion .changeset/fair-tools-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@tanstack/intent': minor
---

Add grouped interactive first-run skill permission setup to `intent install`. Preview discovered skills and their permission scope, choose package-wide or exact-skill access, and confirm before saving. Excluded skills cannot be selected, empty discovery leaves setup available for retry, and completion reports available skills and the next command.
Add interactive first-run skill permission setup to `intent install`. Enable all sources, choose packages or scopes, or select individual skills in compact searchable lists. Save package and scope rules without expanding them into individual names. Optional skill review shows only selected packages and opens individual skill lists only for packages chosen for review. Keep all other selections and exclusions, with one confirmation before saving. Inspect descriptions and existing exclusions on demand; excluded skills cannot be enabled, empty discovery leaves setup available for retry, and completion reports available skills and the next command.
31 changes: 19 additions & 12 deletions docs/cli/intent-install.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,28 @@ Otherwise, first-run setup requires an interactive terminal. Non-TTY execution f

#### First-run flow

1. **Review** discovered npm and workspace packages, versions, and skill descriptions. Excluded candidates appear in the overview but cannot be selected.
2. **Choose** permissions. After the overview, Intent asks about allow-all; choose No to select individual packages or skills. Press Space to toggle grouped choices and Enter to review.
3. **Confirm** the exact `intent.skills` value, destination file, and trust change. Confirmation defaults to No.
4. **Finish** with verified guidance, available skill and package counts, and a package-manager-aware `list` command. If no skills are enabled, Intent explains how to edit `intent.skills`.
1. **Choose what to enable.** Pick **Enable all**, **Choose packages or scopes**, or **Choose individual skills**. Package and skill lists support search.
2. **Confirm once.** Check the current skill count, saved rules, and destination file. Choose **Continue with all selected skills** to save, **Review individual skills** to inspect specific packages, or **Cancel**. Cancel is selected by default.
3. **Finish** with verified guidance, available skill and package counts, and a command to list those skills.

#### Permission choices
Descriptions, exclusions, and information about skill updates are optional choices on the setup screen.

| Choice | Effect |
| --- | --- |
| All skills in a package | Permits its current and future skills. |
| Individual skill | Permits only the named skill. |
| Allow all sources | Writes `["*"]` and skips narrower selection. |
| Select nothing | Explicitly confirms writing `[]`, disabling current and future sources until `intent.skills` is edited. |
#### What gets enabled

| Choice | Saved rule | Includes future additions? |
| --- | --- | --- |
| Enable all | `"*"` | All npm and workspace sources. |
| A package | `"@tanstack/ai"` | New skills in that package. |
| A whole scope | `"@tanstack/*"` | New npm packages and skills in that scope. |
| An individual skill | `"@tanstack/ai#skill"` | Only that skill name. |

Workspace choices use the `workspace:` prefix. Scope rules are saved only when explicitly selected; choosing several packages does not grant access to the whole scope.

**Review individual skills** lists only packages covered by your selection. Choose the packages you want to review, or leave the list empty to continue with all selected skills. Each chosen package opens its own skill list; other packages keep their selection. Unchecking a skill covered by a package, scope, or all-sources rule keeps the broad rule and adds that skill to `intent.exclude`. Existing exclusions always win and cannot be enabled through the picker.

Skill instructions can change when dependencies update. Enabling access does not freeze content or record approval of specific instructions. Update notifications are not available yet.

Existing `intent.exclude` rules always apply and remain unchanged.
Selecting nothing requires explicit confirmation before writing `[]` to disable all skills. Unchecking every current skill under a broad rule excludes those skills; the rule still covers future additions.

#### Files and retry behavior

Expand Down
26 changes: 19 additions & 7 deletions docs/concepts/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,27 @@ Run `intent list` to see which packages the current policy surfaces.
| Saved or inherited `intent.skills` | Updates guidance only. Keeps permissions unchanged and does not prompt. |
| No effective `intent.skills` | Starts interactive permission setup. Non-TTY execution fails without writes. |

First-run setup discovers candidates before policy filtering and shows their versions and descriptions. It previews the selected allowlist and nearest owning `package.json`, then requires confirmation before saving permissions and installing guidance.
First-run setup offers **Enable all**, **Choose packages or scopes**, and **Choose individual skills**, followed by one confirmation before saving to the nearest owning `package.json` and installing guidance.

- **Excluded candidates** stay visible in the overview but cannot be selected. Exclusions remain unchanged.
- **Package-wide choices** include current and future skills and remove redundant selected children. Exact choices permit only the named skill.
- **Allow-all** is offered separately after the overview and saves `["*"]` alone.
- **An empty selection** explicitly confirms disabling all skills with `[]`.
- **Empty or fully excluded discovery** writes nothing, so setup can be retried.
- **Compact rules:** Enable all saves `"*"`; package choices save names such as `"@tanstack/ai"`; explicit scope choices save patterns such as `"@tanstack/*"`. These rules include future matching skills and packages. Individual choices save exact names such as `"@tanstack/ai#skill"`.
- **Optional skill review:** choose **Review individual skills** at confirmation, then pick which selected packages to inspect. Leave the list empty to keep all selected skills. Only those packages open individual skill lists; unchecking a skill covered by a broad rule adds an exclusion. Existing and inherited exclusions stay in force.
- **Changing instructions:** access choices do not record approval of specific content. Skills can change with dependency updates; update notifications are not available yet.
- **Empty selection:** explicitly confirms disabling all skills with `[]`. Empty or fully excluded discovery writes nothing, so setup can be retried.

See [Default install](../cli/intent-install#default-install) for picker controls, previews, and cancellation behavior.
For example, enabling a scope and unchecking one skill saves:

```json
{
"intent": {
"skills": ["@tanstack/*"],
"exclude": ["@tanstack/ai#skill"]
}
}
```

This permits matching npm packages, including future additions, except the excluded skill. Selecting several packages individually never silently expands to a scope rule.

See [Default install](../cli/intent-install#default-install) for picker controls and cancellation behavior.

### Suppressing notices temporarily

Expand Down
13 changes: 7 additions & 6 deletions docs/concepts/trust-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ A package ships skills in a `skills/` directory. Discovery finds every installed

When configured, `package.json#intent.skills` controls which discovered skills can surface through the CLI and agent integrations:

- **Package entries** permit current and future skills from matching packages.
- **Exact skill entries** permit only the named skill.
- **Package entries** enable skills from matching packages, including skills added later.
- **Exact skill entries** enable only the named skill; its instructions can still change.
- **Source kinds stay separate:** `foo` permits an npm source; `workspace:foo` permits a workspace source. Their wildcard patterns remain kind-specific. The exact `*` entry permits every discovered npm and workspace source.

Enabling a source does not record approval of its specific instructions. Skill content can change when dependencies update, and Intent does not yet track or notify you about those changes.

Trust does not propagate to dependencies. A dependency that ships skills needs its own matching entry. Intent omits unlisted packages and reports them so you can opt in or ignore them.

### Projects without an allowlist
Expand All @@ -33,10 +35,9 @@ This also applies to inherited policy within a resolved workspace. Malformed JSO

When no effective policy exists, `intent install` follows this flow:

1. **Discover:** show npm and workspace packages, versions, and skill descriptions. Excluded candidates appear in the overview but cannot be selected.
2. **Choose:** select package-wide or exact-skill permissions. An empty selection explicitly confirms disabling all skills.
3. **Review:** show the exact `intent.skills` value and destination file.
4. **Confirm:** replace `package.json` atomically only after affirmative confirmation, then install guidance.
1. **Discover:** summarize npm and workspace skill counts. Descriptions and exclusions are available through optional inspection.
2. **Choose:** enable all sources, choose packages or scopes, or select individual skills. Package and scope selections stay compact and include future matching skills. A whole scope requires an explicit selection.
3. **Confirm once:** show the current skill count, saved rules, and destination file. Optional individual review opens skill lists only for the selected packages you choose to inspect. It can add exclusions while retaining broad rules; unreviewed packages keep their selection. Only affirmative confirmation saves permissions and exclusions atomically, then installs guidance. An empty selection explicitly confirms disabling all skills.

| Outcome | Files changed |
| --- | --- |
Expand Down
11 changes: 4 additions & 7 deletions docs/getting-started/quick-start-consumers.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ Run this in an interactive terminal. On first use, Intent helps you choose which

Examples use `npx` for npm projects. In pnpm, Yarn, or Bun projects, use the matching runner: `pnpm dlx`, `yarn dlx`, or `bunx`.

The command:
1. **Choose what to enable.** Pick **Enable all**, **Choose packages or scopes**, or **Choose individual skills**. Package and skill lists support search.
2. **Confirm and finish.** Check the saved rules and destination `package.json`. Choose **Continue with all selected skills** to save, or **Review individual skills** to pick which selected packages to inspect before confirming. Intent writes permissions and guidance, verifies the guidance, and shows a command to list available skills.

1. Shows discovered packages, versions, skill descriptions, and exclusions
2. Lets you choose package-wide or individual skill permissions
3. Previews the exact `intent.skills` configuration and destination `package.json`, then asks for confirmation
4. Writes the confirmed permissions and creates or updates the `intent-skills` guidance block, preserving unrelated content
5. Verifies the guidance and reports the available skill count and a command to list those skills
**Enable all** saves `"*"`. A package choice saves `"@tanstack/ai"`; a whole scope saves `"@tanstack/*"`. These rules include future matching skills. Individual choices use `"@tanstack/ai#skill"`. Unchecking a skill during review adds an exclusion while keeping its broad rule.

Choose **No** when asked about allowing all current and future skill sources to select specific packages and skills. Press Space to toggle choices and Enter to review your selection. A package's **All skills** choice includes its current and future skills; an individual choice permits only that named skill. Excluded skills appear in the discovery overview but cannot be selected.
Skill instructions can change when dependencies update. Update notifications are not available yet. See **About skill access and updates** in the installer for details.

Selecting nothing requires explicit confirmation to disable all skills. If no skills are found, or all are excluded, Intent explains the next step and leaves permissions and guidance unchanged. Install a package that ships skills or review your exclusions, then run `install` again.

Expand Down
9 changes: 4 additions & 5 deletions packages/intent/src/commands/install/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ import {
verifyIntentSkillsBlockFile,
writeIntentSkillsBlock,
} from './guidance.js'
import {
createPermissionPrompts,
setupInitialPermissions,
} from './permissions.js'
import { setupInitialPermissions } from './permissions.js'
import { createPermissionPrompts } from './permission-prompts.js'
import type { GlobalScanFlags } from '../support.js'
import type { IntentCoreOptions } from '../../core/index.js'
import type { ScanResult } from '../../shared/types.js'
Expand Down Expand Up @@ -302,9 +300,10 @@ export async function runInstallCommand(
)
}

printWriteResult(result)
if (permissions) {
console.log(`Guidance: ${result.status} ${target}.`)
} else {
printWriteResult(result)
}
printPlacementTip(result.targetPath)
if (available && permissions) {
Expand Down
33 changes: 31 additions & 2 deletions packages/intent/src/commands/install/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,44 @@ function formattingOptions(content: string): {
export function preparePackageSkillsUpdate(
packageJsonPath: string,
skills: Array<string>,
additionalExcludes: Array<string> = [],
): PreparedPackageSkillsUpdate {
const source = readFileSync(packageJsonPath, 'utf8')
parsePackageJson(source, packageJsonPath)
const content = applyEdits(
const original = parsePackageJson(source, packageJsonPath)
let content = applyEdits(
source,
modify(source, ['intent', 'skills'], skills, {
formattingOptions: formattingOptions(source),
}),
)
if (additionalExcludes.length > 0) {
const intent = original.intent as Record<string, unknown> | undefined
const existing = intent?.exclude ?? []
if (
!Array.isArray(existing) ||
existing.some((value) => typeof value !== 'string')
) {
throw new Error(
`Cannot update ${packageJsonPath}: intent.exclude must contain an array of strings.`,
)
}
const exclude = [...new Set([...existing, ...additionalExcludes])]
content = applyEdits(
content,
modify(content, ['intent', 'exclude'], exclude, {
formattingOptions: formattingOptions(source),
}),
)
const updated = parsePackageJson(content, packageJsonPath).intent as Record<
string,
unknown
>
if (JSON.stringify(updated.exclude) !== JSON.stringify(exclude)) {
throw new Error(
`Cannot update ${packageJsonPath}: intent.exclude validation failed.`,
)
}
}
const updated = parsePackageJson(content, packageJsonPath)
const updatedIntent = updated.intent as Record<string, unknown>
if (JSON.stringify(updatedIntent.skills) !== JSON.stringify(skills)) {
Expand Down
Loading
Loading