---
title: Extension helper API reference
description: Look up the inputs, fixed identities, build callbacks, Snapshot relationships, and failure behavior of every specific defineX helper.
sidebar:
  label: Extensions
---

Import the helpers and Vector types on this page from `@evilkiwi/vector`. Each helper captures an extension identity when called. Most helpers also store a synchronous `build(context)` callback. Root helpers receive the no-config `Context`; builder methods receive their builder-bound `Context<RuntimeConfig, Computed>`. The callback returns the exported build type, which excludes identity fields supplied by Vector. `defineSkill()` can instead capture one External Skill descriptor.

The remaining host fields are owned by the OpenCode 2 packages pinned in Vector's package manifest. Use those declarations and Vector's exported build types instead of copying host shapes.

## Omit a callback-built extension

Every domain-specific Build alias on this page accepts optional Vector metadata under `$vector`. Set `$vector.disabled` to exactly `true` to omit that extension from the candidate Snapshot:

```ts title="src/extensions/review.ts"
import { defineCommand } from '@evilkiwi/vector';

export const review = defineCommand({
  name: 'review',
  build: ({ cwd }) => ({
    template: 'Review this change.',
    $vector: { disabled: cwd.endsWith('/readonly') },
  }),
});
```

Every selected callback still runs once. Vector checks the returned metadata after the callback, omits the extension before Snapshot preflight only when `$vector.disabled === true`, and strips `$vector` from every included host value. Omission does not cascade to dependent entries. Existing Snapshot checks reject a default or materialized extension that references an omitted entry.

This metadata applies to agents, commands, catalog providers, models, integrations, integration methods, MCP servers, references, Inline Skills, tools, and websearch providers. External Skills use descriptors rather than callbacks and do not accept `$vector`. It also does not apply to `defineVector()`, `computeContext`, Instruction Files, or default selectors.

Host-native states remain distinct. MCP `disabled` registers an inactive server, catalog provider `activation` controls host activation, and model `enabled` controls host model availability. None of these fields omits its extension; use `$vector.disabled` for omission.

## Agent, catalog, and model helpers

| Helper                    | Fixed identity fields | Extension Plan field | Build result           | Snapshot checks                                                         |
| ------------------------- | --------------------- | -------------------- | ---------------------- | ----------------------------------------------------------------------- |
| `defineAgent()`           | `id`                  | `agents`             | `AgentBuild`           | Agent IDs are unique; `defaultAgent` names an agent in the Snapshot.    |
| `defineCatalogProvider()` | `id`                  | `catalogProviders`   | `CatalogProviderBuild` | Provider IDs are unique.                                                |
| `defineModel()`           | `id`, `providerID`    | `models`             | `ModelBuild`           | Provider/model keys are unique and the provider exists in the Snapshot. |

`defaultModel` must name an enabled model whose provider is present and enabled in the Snapshot. It cannot select a variant because the pinned host setter accepts only a provider and model.

```ts title="TypeScript"
declare function defineAgent(definition: { id: string; build(context: Context): AgentBuild }): AgentDefinition;

declare function defineCatalogProvider(definition: {
  id: string;
  build(context: Context): CatalogProviderBuild;
}): CatalogProviderDefinition;

declare function defineModel(definition: {
  id: string;
  providerID: string;
  build(context: Context): ModelBuild;
}): ModelDefinition;
```

## Command, skill, and reference helpers

| Helper              | Fixed identity fields | Extension Plan field | Build result                                  | Snapshot checks                                                             |
| ------------------- | --------------------- | -------------------- | --------------------------------------------- | --------------------------------------------------------------------------- |
| `defineCommand()`   | `name`                | `commands`           | `CommandBuild`                                | Command names are unique; an optional agent names an agent in the Snapshot. |
| `defineSkill()`     | `id`                  | `skills`             | `SkillBuild` or one External Skill descriptor | Skill IDs are unique.                                                       |
| `defineReference()` | `name`                | `references`         | `ReferenceBuild`                              | Reference names are unique.                                                 |

```ts title="TypeScript"
declare function defineCommand(definition: { name: string; build(context: Context): CommandBuild }): CommandDefinition;

declare function defineSkill(
  definition:
    | {
        id: string;
        build(context: Context): SkillBuild;
        external?: never;
      }
    | {
        id: string;
        build?: never;
        external:
          | { type: 'local'; path: string }
          | {
              type: 'managed';
              manager: 'skills';
              source: string;
              ref?: string;
              sync?: 'when-missing' | 'always';
            };
      },
): SkillDefinition;

declare function defineReference(definition: {
  name: string;
  build(context: Context): ReferenceBuild;
}): ReferenceDefinition;
```

An Inline Skill uses `{ id, build }` and keeps the existing synchronous behavior. A Local Skill and Managed Skill use `{ id, external }`; `build` and `external` are mutually exclusive, and each definition resolves one skill.

### Local Skills

`external.path` names the exact skill directory. Use an absolute path or a path beginning with `~/`. Other relative forms fail activation. Vector expands `~/`, resolves symlinks, validates the canonical directory, and uses its canonical `SKILL.md` file path as the skill location.

```ts title="src/extensions/review.ts"
import { defineSkill } from '@evilkiwi/vector';

export const review = defineSkill({
  id: 'review',
  external: { type: 'local', path: '~/team-skills/review' },
});
```

### Managed Skills

The managed descriptor uses the exact `skills` manager. `source` accepts GitHub `owner/repo`, credential-free remote Git and HTTP(S) sources supported by the manager, including GitLab repositories without `.git`, HTTPS `skills.sh`, direct skill files, and archives. GitHub shorthand normalizes to GitHub. Local paths, `file:` sources, URL credentials or query parameters, embedded `#ref`, and embedded `@skill` selectors fail activation. Ambient SSH authentication remains available for SSH sources.

Pass a Git ref through the separate `ref` field only for a remote Git source. The manager does not apply refs to `skills.sh`, direct skill files, or archive downloads, so Vector rejects those combinations. Vector always passes the definition `id` as the selected skill. `sync` defaults to `when-missing`; `always` requests a mutating update on every activation.

```ts title="src/extensions/review.ts"
import { defineSkill } from '@evilkiwi/vector';

export const review = defineSkill({
  id: 'review',
  external: {
    type: 'managed',
    manager: 'skills',
    source: 'acme/team-skills',
    ref: 'main',
    sync: 'when-missing',
  },
});
```

Managed Skills use a user cache shared across plugins and projects. A valid `when-missing` entry bypasses manager execution. Missing or invalid entries repair under a per-skill lock. Concurrent waiters consume the preceding attempt's success or failure without repeating remote work, while a later independent `always` activation performs a new staged update. Any External Skill failure prevents all host transform registration. Vector does not expose a general installer or CLI, prune the cache, watch sources, or promise reader-atomic replacement.

The manager may sanitize its installed directory name. Vector requires exactly one staged skill directory, renames it to the exact definition `id`, and then applies canonical basename and frontmatter validation. This preserves IDs with uppercase letters, spaces, or Unicode without adding broader Agent Skills naming rules.

### External Skill files

The canonical directory basename and parsed frontmatter `name` must both exactly equal the definition `id`. `description` is required and must be a non-empty string. Vector preserves the Markdown body and uses the canonical absolute `SKILL.md` file path as the location.

Top-level `slash` accepts a boolean. Namespaced `metadata` values override it: `opencode/slash` and `opencode/autoinvoke` accept booleans or trimmed, case-insensitive `true` and `false` strings. Top-level `autoinvoke` is ignored, as are other unknown fields. Vector does not apply broader Agent Skills naming or length rules.

## Web search helper

```ts title="TypeScript"
declare function defineWebSearchProvider(definition: {
  id: string;
  build(context: Context): WebSearchProviderBuild;
}): WebSearchProviderDefinition;
```

Select the result in `ExtensionPlan.webSearchProviders`. IDs are unique. A non-`false` `defaultWebSearchProvider` names one of these providers. A provider `execute()` callback may return results directly or by promise.

## Integration helpers

```ts title="TypeScript"
declare function defineIntegration(definition: {
  id: string;
  build(context: Context): IntegrationBuild;
}): IntegrationDefinition;
```

Select the result in `ExtensionPlan.integrations`. Integration IDs are unique.

`defineIntegrationMethod()` accepts four method variants:

| `type`    | Additional fixed field | Build result member                                 |
| --------- | ---------------------- | --------------------------------------------------- |
| `oauth`   | `id`                   | OAuth member of `IntegrationMethodDefinition`       |
| `command` | `id`                   | Command member of `IntegrationMethodDefinition`     |
| `key`     | None                   | Key member of `IntegrationMethodDefinition`         |
| `env`     | None                   | Environment member of `IntegrationMethodDefinition` |

Every method also fixes `integrationID`. Select it in `ExtensionPlan.integrationMethods`. The target integration must exist in the same Snapshot, and each integration/type/method identity must be unique. OAuth authorization, completion, and refresh callbacks may return credentials directly or by promise.

## MCP server helper

```ts title="TypeScript"
declare function defineMCPServer(definition: {
  name: string;
  build(context: Context): MCPServerBuild;
}): MCPServerDefinition;
```

Select the result in `ExtensionPlan.mcpServers`. MCP server names are unique.

## Tool helper

```ts title="TypeScript"
declare function defineTool<
  Input extends Tool.ValueSchema = Tool.ValueSchema,
  Output extends Tool.ValueSchema | undefined = Tool.ValueSchema | undefined,
>(definition: {
  name: string;
  build(context: Context): ToolBuild<Input, Output>;
}): ToolDefinition<Record<never, never>, Input, Output>;
```

Select the result in `ExtensionPlan.tools`. The name is normalized by replacing characters outside letters, digits, `_`, and `-` with `_`. The normalized value starts with an ASCII letter and contains at most 64 characters. A name that cannot meet that contract throws synchronously. Namespace segments are provider-safe. Direct tool name `execute` is reserved when CodeMode is explicitly disabled. Duplicate exposed names fail preflight.

Tool `execute()` receives validated input and `ToolExecutionContext`, including `sessionID`, `agent`, `messageID`, `id`, and async `progress(update)`. It may return a result directly or by promise.

## Builder-bound helpers

`createVectorBuilder()` returns the same specific helpers bound to inferred Runtime Configuration and computed Context types. These methods do not declare their own Runtime Configuration generic. `defineTool()` retains its `Input` and `Output` generics. Root helpers remain available as no-config, no-computed-context helpers. See [`defineVector()`](/api/define-vector), [`createVectorBuilder()`](/api/create-vector-builder), and [Context](/api/context).
