Skills

Creating a Custom Skill

This guide walks through creating a complete custom skill from scratch. We will build a weather skill that gives an agent the ability to check current weather conditions.

Step 1 — Create the underlying tool

Skills bundle tools, so first create the tool that the skill will expose. Create src/tools/weather-lookup.ts:

typescript
// src/tools/weather-lookup.ts
import { z } from 'zod';
import { registerTool } from './registry';

const Params = z.object({
  location: z.string().describe('City name or "lat,lon" coordinates'),
  units: z.enum(['celsius', 'fahrenheit']).default('celsius'),
});

registerTool({
  name: 'weather_lookup',
  description: 'Get current weather conditions for a location',
  parameters: Params,
  execute: async (params, ctx) => {
    const apiKey = process.env.WEATHER_API_KEY;
    if (!apiKey) {
      return { error: 'WEATHER_API_KEY not configured' };
    }

    const url = \`https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(params.location)}&appid=${apiKey}&units=${params.units === 'celsius' ? 'metric' : 'imperial'}\`;
    const response = await fetch(url);

    if (!response.ok) {
      return { error: \`Weather API error: ${response.status}\` };
    }

    const data = await response.json();
    return {
      location: data.name,
      temperature: data.main.temp,
      description: data.weather[0].description,
      humidity: data.main.humidity,
      windSpeed: data.wind.speed,
    };
  },
});

Step 2 — Register the tool import

Add the import to src/tools/index.ts so it self-registers at startup:

typescript
// src/tools/index.ts
// ... existing imports ...
import './weather-lookup';

Step 3 — Create the skill definition

Create src/skills/definitions/weather/index.ts:

typescript
// src/skills/definitions/weather/index.ts
import type { SkillDefinition } from '../../types';

const skill: SkillDefinition = {
  manifest: {
    id: 'weather',
    displayName: 'Weather',
    category: 'utilities',
    description: 'Check current weather conditions for any location',
    tools: ['weather_lookup'],
  },

  async init() {
    // Validate that the API key is present and warn if missing
    if (!process.env.WEATHER_API_KEY) {
      console.warn('[weather skill] WEATHER_API_KEY not set — weather_lookup will return errors');
    }
  },

  getPromptContext() {
    return \`You have access to the weather_lookup tool.
Use it when the user asks about current weather, temperature, or conditions for any location.
Always specify whether you are reporting in celsius or fahrenheit.
If the user does not specify units, use celsius by default.\`;
  },
};

export default skill;

Step 4 — Assign the skill to an agent

yaml
agents:
  - id: assistant
    skills:
      - weather       # Add your new skill
    tools:
      allow:
        - weather_lookup

Step 5 — Verify

bash
# Type-check first
npm run typecheck

# Start the gateway (skill auto-discovered on startup)
npm run dev

# Test via CLI
npx astra chat
> What is the weather in Tokyo right now?
💡If the skill does not appear in agent responses, check the gateway startup logs for [skills] Discovered: weather. If missing, verify the file path is exactly src/skills/definitions/weather/index.ts and that the default export is a valid SkillDefinition.

Standard skill categories

Use one of these established category values in your manifest to ensure correct grouping in the UI:

  • code — Code development and review tools
  • vcs — Version control tools
  • research — Web and document research tools
  • data — Data analysis and transformation tools
  • devops — Infrastructure and operations tools
  • productivity — Project management and communication tools
  • security — Security review and audit tools
  • knowledge — Team knowledge and memory tools
  • utilities — General-purpose utilities