> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# LuaSkill

> Skill class that groups tools under a name and the prompt context that tells the model when to use them

`LuaSkill` groups [tools](/reference/sdk/luatool) under a name and a `context`: text injected into the prompt whenever the [skill](/concepts/skills-and-tools) is active, which is how the model decides when to call the tools. Register skills on `LuaAgent.skills`; `lua compile` bundles each tool the skill references and emits the skill itself as metadata, and the skill is pushed and deployed as one unit with its tools. Test a tool with `lua test skill --name <tool-name>`; the name is the tool's, not the skill's.

*Verified against lua-cli 3.33.0.*

```ts theme={null}
import { LuaSkill } from 'lua-cli';
```

## Quick example

```ts src/skills/orders.skill.ts theme={null}
import { LuaSkill } from 'lua-cli';
import LookupOrderTool from './tools/LookupOrderTool';
import { cancelOrder } from './tools/cancelOrder';

export default new LuaSkill({
  name: 'orders',
  description: 'Order lookup and cancellation',
  context:
    'Use lookup_order when the customer asks about an order. ' +
    'Use cancel_order only after the customer confirms the order number.',
  tools: [new LookupOrderTool(), cancelOrder],
});
```

## Constructor

```ts theme={null}
new LuaSkill(config: LuaSkillConfig)
```

<ParamField path="name" type="string" required>
  Server-side identifier, kebab-case. Also the value of `--name` for `lua push skill` and `lua deploy skill`.
</ParamField>

<ParamField path="description" type="string" required>
  One or two sentences shown in listings.
</ParamField>

<ParamField path="context" type="string | { base?: string; voice?: string; text?: string }" required>
  Prompt text injected while the skill is active. The object form renders `base` everywhere, appends `voice` in voice sessions and `text` on text channels, and needs at least one key.
</ParamField>

<ParamField path="tools" type="LuaTool[]">
  Tools added at construction. Equivalent to calling `addTools()`.
</ParamField>

<ParamField path="condition" type="() => Promise<boolean>">
  Gate for the whole skill, evaluated on every message with every runtime object available. `false` hides the tools and leaves the context out of the prompt, so the model doesn't know the tools exist. A throw or a 30-second timeout counts as `false`. To hide one tool while the skill stays visible, use [`LuaTool.condition`](/reference/sdk/luatool#condition) instead.
</ParamField>

The constructor throws when:

* `name` is empty or blank: ``LuaSkill requires a non-empty `name` (used as the server-side identifier).``
* `context` is an object with none of `base`, `voice`, `text`: `Skill context object must have at least one of: base, voice, text`
* a tool's `name` contains anything other than letters, digits, `-`, and `_` (see `addTool()`)

`lua compile` resolves tools from the `tools` array and from `addTool()` and `addTools()` calls on the skill's variable, following imports and re-exports. It warns `Skill has no tools - consider adding tools or removing the skill` and `Skill should have a context`; neither stops the build.

## Methods

### getContext()

Returns the `context` passed to the constructor, unchanged. `SkillContextText` is `string | { base?: string; voice?: string; text?: string }`.

```ts theme={null}
skill.getContext(): SkillContextText
```

**Errors** — none.

### getCondition()

Returns the `condition` function, or `undefined` when the skill has none.

```ts theme={null}
skill.getCondition(): (() => Promise<boolean>) | undefined
```

**Errors** — none.

### addTool()

Adds one tool after validating its name.

```ts theme={null}
skill.addTool<TInput extends ZodType>(tool: LuaTool<TInput>): void
```

<ParamField path="tool" type="LuaTool" required>
  A tool instance or object.
</ParamField>

**Returns** — nothing.

**Example**

```ts theme={null}
skill.addTool(new LookupOrderTool());
```

**Errors** — `Invalid tool name "<name>". Tool names can only contain alphanumeric characters, hyphens (-), and underscores (_). No spaces or other special characters are allowed.` Duplicate names are not rejected.

### addTools()

Validates every name first, then adds all the tools; one invalid name adds nothing.

```ts theme={null}
skill.addTools(tools: LuaTool<any>[]): void
```

<ParamField path="tools" type="LuaTool[]" required>
  Tool instances or objects.
</ParamField>

**Returns** — nothing.

**Example**

```ts theme={null}
skill.addTools([new LookupOrderTool(), cancelOrder]);
```

**Errors** — the same `Invalid tool name` error as `addTool()`.

### run()

Runs one of the skill's tools by name, after parsing the input with that tool's `inputSchema`. Meant for unit tests; the platform and `lua test` execute the compiled tool directly and never call it.

```ts theme={null}
skill.run(input: Record<string, any>): Promise<any>
```

<ParamField path="input" type="object" required>
  `input.tool` names the tool; the remaining keys are the tool's arguments.
</ParamField>

**Returns** — whatever the tool's `execute` returns.

**Example**

```ts theme={null}
const result = await skill.run({ tool: 'lookup_order', orderNumber: 'A-1001' });
```

**Errors** — `Tool <name> not found` when no tool has that name; a `ZodError` when the input fails the schema.

## Types

`LuaSkillConfig` and `SkillContextText` aren't exported by name. Derive the config type when you need to type a config object separately; the context type is `LuaSkillConfig['context']`.

```ts theme={null}
import { LuaSkill } from 'lua-cli';

type LuaSkillConfig = ConstructorParameters<typeof LuaSkill>[0];
```

## See also

* [LuaTool](/reference/sdk/luatool)
* [About skills and tools](/concepts/skills-and-tools)
* [Write skill context](/build/write-skill-context)
* [lua test](/reference/cli/test)
* [lua push](/reference/cli/push)
