Claude Skills
CollectionsCompareWorkflowsNominate
Sign inSign up
© 2026 Curated Agent Skills·Learn more about Agent Skills
Back to repository

stack-templates

verified

Templates for creating handlers, CLI commands, MCP tools, and daemon services following Outfitter Stack conventions. Use when scaffolding new components, creating handlers, adding commands, or when "create handler", "new command", "add tool", "scaffold", "template", or "daemon service" are mentioned.

View on GitHub

Marketplace

outfitter

outfitter-dev/agents

Plugin

outfitter-stack

Repository

outfitter-dev/agents
18stars

plugins/outfitter-stack/skills/stack-templates/SKILL.md

Last Verified

February 1, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/outfitter-dev/agents/blob/main/plugins/outfitter-stack/skills/stack-templates/SKILL.md -a claude-code --skill stack-templates

Installation paths:

Claude
.claude/skills/stack-templates/
Powered by add-skill CLI

Instructions

# Stack Templates

Templates for creating @outfitter/* components.

## Component Types

| Type | Package | Template |
|------|---------|----------|
| Handler | `@outfitter/contracts` | [handler](#handler) |
| Handler Test | `@outfitter/testing` | [handler-test](#handler-test) |
| CLI Command | `@outfitter/cli` | [cli-command](#cli-command) |
| MCP Tool | `@outfitter/mcp` | [mcp-tool](#mcp-tool) |
| Daemon | `@outfitter/daemon` | [daemon-service](#daemon-service) |

## Handler

Transport-agnostic business logic returning `Result<T, E>`:

```typescript
import {
  Result,
  ValidationError,
  NotFoundError,
  createValidator,
  type Handler,
} from "@outfitter/contracts";
import { z } from "zod";

// 1. Input schema
const InputSchema = z.object({
  id: z.string().min(1),
});
type Input = z.infer<typeof InputSchema>;

// 2. Output type
interface Output {
  id: string;
  name: string;
}

// 3. Validator
const validateInput = createValidator(InputSchema);

// 4. Handler
export const myHandler: Handler<unknown, Output, ValidationError | NotFoundError> = async (
  rawInput,
  ctx
) => {
  const inputResult = validateInput(rawInput);
  if (inputResult.isErr()) return inputResult;
  const input = inputResult.value;

  ctx.logger.debug("Processing", { id: input.id });

  const resource = await fetchResource(input.id);
  if (!resource) {
    return Result.err(new NotFoundError("resource", input.id));
  }

  return Result.ok(resource);
};
```

## Handler Test

Test handlers directly without transport layer:

```typescript
import { describe, test, expect } from "bun:test";
import { createContext } from "@outfitter/contracts";
import { myHandler } from "../handlers/my-handler.js";

describe("myHandler", () => {
  test("returns success for valid input", async () => {
    const ctx = createContext({});
    const result = await myHandler({ id: "valid-id" }, ctx);

    expect(result.isOk()).toBe(true);
    expect(result.value).toMatchObject({ id: "valid-id" });
  });

  test("returns 

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
6600 chars