# Skill

> Skills: Agent Skills folders any agent of their scope can attach.

```python
check = noclick.Skill.from_dir("./skills/invoice-check")              # SKILL.md plus its scripts and files
support = noclick.Agent.from_name("support", create_if_missing=True, instructions="...", skills=[check])
```

A skill is a folder: a `SKILL.md` whose frontmatter names it (`name`) and
says what it does and when to use it (`description`; `always: true` puts it
whole in every turn), plus any other files. Every save is a new version; an
agent follows the latest unless it holds one (`skill.pinned(3)`). A coding
harness finds its skills where it reads skills; an `sdk` agent sees each
one's name and description every turn and reads one with `skill__read`.

## Skill

```typescript
class Skill
```

An Agent Skills folder of the account's (every user's agents may use it) or one user's, versioned. Delete it
and it goes to the trash, off every agent that attaches it; restoring puts it back on them.

| Attribute | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |
| `name` | `string` | Its name, from its latest `SKILL.md`. |
| `description` | `string` |  |
| `always` | `boolean` | Whether it's put whole in every turn of the agents that attach it. |
| `version` | `number` | Its latest version's number. |
| `digest` | `string` | Its latest version's content, as a digest: what restarts a coding agent's warm sandbox when it changes. |
| `fileCount` | `number` |  |
| `size` | `number` | Its latest version's size in bytes. |
| `attachedTo` | `SkillAttachment[]` | The agents that attach it, and the version each holds (null: the latest). |
| `userId` | `string | null` |  |
| `createdAt` | `Date | null` |  |
| `updatedAt` | `Date | null` |  |

### Skill.create

```typescript
static create(
  files: SkillFiles,
  options?: CallOptions & AllowExisting,
): Promise<Skill>
```

A skill from its folder, named by its `SKILL.md`; unique by name per user, or for the account outside `asUser`.
A taken name throws `Conflict` with `existingId`, or with `allowExisting: true` returns the skill already there
as it is (`saveVersion` to change it). Up to 200 files and 20 MB, `SKILL.md` up to 64 KB.

Parameters:

- `files` (`SkillFiles`, required)
- `options.allowExisting` (`boolean`): A taken name returns the object already there, as it is: nothing about it changes.
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.

Returns: The new skill at version 1.

Types:

```typescript
/** A folder's files: path → text, or bytes for a file that isn't text. */
type SkillFiles = Record<string, string | Uint8Array>;

/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}
```

### Skill.fromName

```typescript
static fromName(
  name: string,
  options?: CallOptions & { createIfMissing?: boolean; files?: SkillFiles },
): Skill
```

A lazy reference to the skill called `name`. Acting for a user, that user's own skill is found first, then the
account's. With `createIfMissing` it's created from `files` on first use.

Parameters:

- `name` (`string`, required)
- `options.createIfMissing` (`boolean`)
- `options.files` (`SkillFiles`)
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.

Returns: A skill that loads (or is created) the first time it's used. Nothing is sent yet.

Types:

```typescript
/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}

/** A folder's files: path → text, or bytes for a file that isn't text. */
type SkillFiles = Record<string, string | Uint8Array>;
```

### Skill.fromId

```typescript
static fromId(skillId: string, options?: CallOptions): Skill
```

A lazy reference to a skill by id.

Parameters:

- `skillId` (`string`, required)
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.

Returns: A skill that loads the first time you read a field. Nothing is sent yet.

Types:

```typescript
/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}
```

### Skill.get

```typescript
static get(skillId: string, options?: CallOptions): Promise<Skill>
```

Load a skill by id now; an unknown id raises `noclick.NotFound`.

Parameters:

- `skillId` (`string`, required)
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.

Returns: The skill, loaded: its latest version and the agents that attach it.

Types:

```typescript
/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}
```

### Skill.list

```typescript
static list(
  options?: ReadOptions & { limit?: number; agent?: string | ApiObject },
): Promise<Skill[]>
```

The current user's skills and the account's (or those `userFilter` covers), newest first. With `agent`, the
skills that agent attaches, in its order.

Parameters:

- `options.agent` (`string | ApiObject`)
- `options.limit` (`number`): Return at most this many.
- `options.userFilter` (`UserFilter`): Which users the read covers (`user_id` query), instead of acting as one (`user`).
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.

Returns: Every matching skill, fetched page by page.

Types:

```typescript
/**
 * Which users a read covers: `ALL_USERS`, `NO_USER`, a `User` or your id for one. Sent as the
 * `user_id` query parameter, never as the `NoClick-User` header, so it filters without acting as the user.
 */
type UserFilter = typeof ALL_USERS | typeof NO_USER | UserRef;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}

/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;
```

### Skill.listPage

```typescript
static listPage(options?: ReadOptions & PageOptions): Promise<Page<Skill>>
```

One page of skills; pass `nextCursor` back as `cursor`.

Parameters:

- `options.cursor` (`string | null`): The `next_cursor` of the page before; omit it for the first page.
- `options.limit` (`number`): Return at most this many.
- `options.userFilter` (`UserFilter`): Which users the read covers (`user_id` query), instead of acting as one (`user`).
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.

Returns: A page whose `data` holds the skills and whose `next_cursor` is `None` on the last page.

Types:

```typescript
/**
 * Which users a read covers: `ALL_USERS`, `NO_USER`, a `User` or your id for one. Sent as the
 * `user_id` query parameter, never as the `NoClick-User` header, so it filters without acting as the user.
 */
type UserFilter = typeof ALL_USERS | typeof NO_USER | UserRef;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}

/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;
```

### Skill.pinned

```typescript
pinned(version: number): SkillLink
```

This skill held at one version, for an agent's `skills`.

Parameters:

- `version` (`number`, required)

Returns: What `skills=` takes for a skill the agent holds at `version`.

### Skill.saveVersion

```typescript
saveVersion(
  files: SkillFiles,
  options?: { removed?: string[]; replace?: boolean; baseVersion?: number },
): Promise<Skill>
```

Save a new version: `files` written over the latest (the whole folder with `replace`), `removed` taken out. With
`baseVersion` it saves only while the latest is still that version (else `Conflict`). Agents following the
latest get it in their next conversation; a running coding sandbox restarts with it.

Parameters:

- `files` (`SkillFiles`, required)
- `options.removed` (`string[]`)
- `options.replace` (`boolean`)
- `options.baseVersion` (`number`)

Returns: This skill, at its new version.

Types:

```typescript
/** A folder's files: path → text, or bytes for a file that isn't text. */
type SkillFiles = Record<string, string | Uint8Array>;
```

### Skill.update

```typescript
update(changes: { name?: string; description?: string }): Promise<Skill>
```

Rename it or change its description: a new version with its `SKILL.md` frontmatter rewritten.

Parameters:

- `changes` (`{ name?: string; description?: string }`, required)

Returns: This skill, as it is now.

### Skill.versions

```typescript
versions(): Promise<SkillVersion[]>
```

Every version, newest first.

Returns: Each version's frontmatter, files, size and who saved it.

### Skill.getVersion

```typescript
getVersion(version: number): Promise<SkillVersion>
```

One version, with its files.

Parameters:

- `version` (`number`, required)

Returns: That version; an unknown one raises `noclick.NotFound`.

### Skill.restore

```typescript
restore(version: number): Promise<Skill>
```

A new version holding what `version` held.

Parameters:

- `version` (`number`, required)

Returns: This skill, at its new version.

### Skill.files

```typescript
files(options?: { version?: number }): Promise<SkillFileInfo[]>
```

The files of a version (the latest unless `version`), by path.

Parameters:

- `options.version` (`number`)

Returns: Each file's path, size and hash.

### Skill.read

```typescript
read(path: string, options?: { version?: number }): Promise<SkillFile>
```

One file of a version (the latest unless `version`): its text, or base64 when it isn't UTF-8.

Parameters:

- `path` (`string`, required)
- `options.version` (`number`)

Returns: The file; a path the version doesn't hold raises `noclick.NotFound`.

### Skill.delete

```typescript
delete(): Promise<TrashItem>
```

Delete it: to the trash, restorable for 30 days, and off every agent that attaches it until it's restored.

Returns: Its `TrashItem`: `restore()` puts it back, on its agents too.

## SkillAttachment

```typescript
interface SkillAttachment
```

An agent that attaches a skill, and the version it holds (null: the latest).

| Attribute | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |
| `name` | `string` |  |
| `pin` | `number | null` |  |

## SkillAuthor

```typescript
interface SkillAuthor
```

Who saved a version: a person in the app (`console`), a key (`api`), or an agent's turn.

| Attribute | Type | Description |
| --- | --- | --- |
| `type` | `"console" | "api" | "agent" | null` |  |
| `agentId` | `string | null` |  |
| `agentName` | `string | null` |  |

## SkillFile

```typescript
interface SkillFile
```

One file's content: its text, or base64 when it isn't UTF-8 (`encoding`).

| Attribute | Type | Description |
| --- | --- | --- |
| `path` | `string` |  |
| `version` | `number` |  |
| `size` | `number` |  |
| `sha256` | `string` |  |
| `content` | `string` |  |
| `encoding` | `"utf-8" | "base64"` |  |

## SkillFileInfo

```typescript
interface SkillFileInfo
```

One file of a version, as its manifest lists it.

| Attribute | Type | Description |
| --- | --- | --- |
| `path` | `string` |  |
| `size` | `number` |  |
| `sha256` | `string` |  |

## SkillLink

```typescript
class SkillLink
```

A skill held at one version on an agent (`skill.pinned(n)`).

| Attribute | Type | Description |
| --- | --- | --- |
| `skill` | `Skill | string` |  |
| `pin` | `number` |  |

## SkillVersion

```typescript
interface SkillVersion
```

One version of a skill: its frontmatter as that version has it, and its files.

| Attribute | Type | Description |
| --- | --- | --- |
| `version` | `number` |  |
| `digest` | `string` |  |
| `name` | `string` |  |
| `description` | `string` |  |
| `always` | `boolean` |  |
| `files` | `SkillFileInfo[]` |  |
| `size` | `number` |  |
| `createdBy` | `SkillAuthor` |  |
| `createdAt` | `Date | null` |  |
| `raw` | `JsonObject` | The response JSON exactly as the API sent it. |

Types:

```typescript
type JsonObject = { [key: string]: unknown };
```
