# Skills

Skills are compositions of domain tool handlers that aggregate multiple service calls into a single result. They provide a "broad question" entry point (e.g., "tell me about this account") that would otherwise require the AI to call 4-6 tools sequentially.

Skills use the same `ToolDefinition` interface as tools and run through the same execution pipeline. The distinction is organizational: tools live in `../tools/`, skills live here.

## Structure

Each skill has its own directory:

```
skills/
  account-overview/
    definition.ts    ← single ToolDefinition (one per skill)
    handler.ts       ← handler that composes domain tool handlers
    index.ts         ← barrel export
  contract-overview/
  revenue-overview/
  index.ts           ← top-level barrel: exports SKILL_DEFINITIONS + buildSkillHandlers
```

## Adding a New Skill

1. **Create a directory** for the skill (kebab-case):

   ```
   skills/my-new-skill/
     definition.ts
     handler.ts
     index.ts
   ```

2. **Write the definition** in `definition.ts`:

   ```ts
   import type { ToolDefinition } from "../../../types";

   export const myNewSkill: ToolDefinition = {
     name: "my_new_skill",              // snake_case, descriptive
     description: "...",                 // what it aggregates and when to use it
     inputSchema: { ... },
     domain: "skill",                   // always "skill"
     label: "Doing the thing",          // shown in UI while executing
     source: { type: "account" },       // link to the primary entity in the app
     core: true,                        // skills are typically core (always available)
     hint: "...",
     examples: [{ label, input }],
   };
   ```

3. **Write the handler** in `handler.ts`:

   ```ts
   import type { ToolHandlerResult } from "../../../types";
   import type { ToolHandler } from "../../tools/handler-utils";
   import { resilientCall, collectErrors } from "../../tools/handler-utils";

   export function buildMyNewSkillHandler(
     h: (name: string) => ToolHandler,
   ): ToolHandler {
     return async (input, headers) => {
       const calls: [string, Promise<ToolHandlerResult>][] = [
         ["get_x", resilientCall("x", () => h("get_x")(input, headers))],
         ["get_y", resilientCall("y", () => h("get_y")(input, headers))],
       ];

       const settled = await Promise.all(
         calls.map(
           async ([name, p]) => [name, await p] as [string, ToolHandlerResult],
         ),
       );

       return {
         data: { /* structured result */ errors: collectErrors(settled) },
         error: null,
       };
     };
   }
   ```

4. **Create the barrel** `index.ts`:

   ```ts
   export { myNewSkill } from "./definition";
   export { buildMyNewSkillHandler } from "./handler";
   ```

5. **Register** in the top-level `skills/index.ts`:
   - Add to `SKILL_DEFINITIONS` array
   - Add to `buildSkillHandlers` return map

## Conventions

- **Use `resilientCall` for every sub-call.** One failing service shouldn't break the whole skill. Partial results with an `errors` array are better than a total failure.
- **Use `collectErrors` to surface partial failures.** The AI can reason about what data is missing.
- **Skills are typically `core: true`.** They're broad entry points the AI should always have access to. Only defer a skill if it's highly specialized.
- **Skills compose existing handlers.** They receive the handler map via `buildSkillHandlers` and look up handlers by name. Never make direct HTTP calls from a skill — delegate to domain handlers.
- **Keep descriptions focused on what the skill returns**, not on when NOT to use it. The AI should choose the right tool naturally.

## How Skills Differ from Tools

|                     | Tools                                     | Skills                                    |
| ------------------- | ----------------------------------------- | ----------------------------------------- |
| **Purpose**         | Single service call                       | Aggregation of multiple tools             |
| **Location**        | `ai/tools/{domain}/`                      | `ai/skills/{name}/`                       |
| **Handler pattern** | Direct HTTP call via `safeGet`/`safePost` | Calls domain handlers via the handler map |
| **Fault isolation** | Returns error from one service            | Uses `resilientCall` — partial success OK |
| **Core/deferred**   | Usually deferred                          | Usually core                              |
| **Interface**       | `ToolDefinition`                          | `ToolDefinition` (same)                   |
