stack-patterns

Outfitter Stack Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "stack-patterns" with this command: npx skills add outfitter-dev/agents/outfitter-dev-agents-stack-patterns

Outfitter Stack Patterns

Primary reference for @outfitter/* package conventions.

Handler Contract

Handlers are pure functions that:

  • Accept typed input and context

  • Return Result<TOutput, TError>

  • Know nothing about transport (CLI flags, HTTP headers, MCP tool schemas)

type Handler<TInput, TOutput, TError extends OutfitterError> = ( input: TInput, ctx: HandlerContext ) => Promise<Result<TOutput, TError>>;

Example

import { Result, NotFoundError, type Handler } from "@outfitter/contracts";

export const getUser: Handler<{ id: string }, User, NotFoundError> = async (input, ctx) => { ctx.logger.debug("Fetching user", { userId: input.id }); const user = await db.users.findById(input.id);

if (!user) { return Result.err(new NotFoundError("user", input.id)); } return Result.ok(user); };

Why? Testability (just call the function), reusability (same handler for CLI/MCP/HTTP), type safety (explicit types), composability (handlers wrap handlers).

Result Types

Uses Result<T, E> from better-result for explicit error handling.

import { Result } from "@outfitter/contracts";

// Create const ok = Result.ok({ name: "Alice" }); const err = Result.err(new NotFoundError("user", "123"));

// Check if (result.isOk()) { console.log(result.value); // TypeScript knows T } else { console.log(result.error); // TypeScript knows E }

// Pattern match const message = result.match({ ok: (user) => Found ${user.name}, err: (error) => Error: ${error.message}, });

// Combine const combined = combine2(result1, result2); // tuple or first error

Error Taxonomy

Ten categories map to exit codes and HTTP status:

Category Exit HTTP When to Use

validation

1 400 Invalid input, schema failures

not_found

2 404 Resource doesn't exist

conflict

3 409 Already exists, version mismatch

permission

4 403 Forbidden action

timeout

5 504 Operation took too long

rate_limit

6 429 Too many requests

network

7 503 Connection failures

internal

8 500 Unexpected errors, bugs

auth

9 401 Authentication required

cancelled

130 499 User interrupted (Ctrl+C)

import { ValidationError, NotFoundError, getExitCode } from "@outfitter/contracts";

new ValidationError("Invalid email", { field: "email" }); new NotFoundError("user", "user-123");

getExitCode(error.category); // 2 for not_found getStatusCode(error.category); // 404 for not_found

Validation

Use Zod with createValidator for type-safe validation returning Results:

import { createValidator } from "@outfitter/contracts"; import { z } from "zod";

const InputSchema = z.object({ name: z.string().min(1), email: z.string().email(), });

const validateInput = createValidator(InputSchema);

// In handler const inputResult = validateInput(rawInput); if (inputResult.isErr()) return inputResult; const input = inputResult.value; // typed as z.infer<typeof InputSchema>

Context

HandlerContext carries cross-cutting concerns:

import { createContext } from "@outfitter/contracts";

const ctx = createContext({ logger: myLogger, // structured logger config: resolvedConfig, // merged configuration signal: controller.signal, // cancellation workspaceRoot: "/project", });

// ctx.requestId is auto-generated UUIDv7 for tracing

Field Type Description

requestId

string

Auto-generated UUIDv7

logger

Logger

Structured logger

config

ResolvedConfig

Merged config

signal

AbortSignal

Cancellation signal

workspaceRoot

string

Project root

cwd

string

Current directory

Package Reference

Package Purpose When to Use

@outfitter/contracts

Result types, errors, Handler contract Always (foundation)

@outfitter/types

Type utilities, collection helpers Type manipulation

@outfitter/cli

CLI commands, output modes, formatting CLI applications

@outfitter/mcp

MCP server, tool registration, Zod schemas AI agent tools

@outfitter/config

XDG paths, config loading, env handling Configuration needed

@outfitter/logging

Structured logging, sinks, redaction Logging needed

@outfitter/daemon

Background services, IPC, health checks Long-running services

@outfitter/file-ops

Secure paths, atomic writes, file locking File operations

@outfitter/state

Pagination, cursor state Paginated data

@outfitter/testing

Test harnesses, fixtures, Bun test Testing

Selection guidance:

  • All projects start with @outfitter/contracts

  • CLI apps add @outfitter/cli (includes UI components)

  • MCP servers add @outfitter/mcp

  • Projects with config add @outfitter/config

  • File operations need @outfitter/file-ops for safety

Type Utilities

@outfitter/types provides collection helpers and type utilities:

Collection Helpers

import { sortBy, dedupe, chunk } from "@outfitter/types";

// Sort by property const users = [{ name: "Bob" }, { name: "Alice" }]; sortBy(users, "name"); // [{ name: "Alice" }, { name: "Bob" }] sortBy(users, u => u.name); // Same, with accessor function

// Remove duplicates dedupe([1, 2, 2, 3, 3, 3]); // [1, 2, 3] dedupe(users, u => u.name); // Dedupe by property

// Split into chunks chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]

Type Utilities

Standard TypeScript utility types for common patterns:

import type { Prettify, DeepPartial, Nullable } from "@outfitter/types";

// Prettify: Flatten complex intersection types for better IntelliSense type Combined = { a: string } & { b: number }; type Pretty = Prettify<Combined>; // Shows { a: string; b: number }

// DeepPartial: Make all properties optional recursively type Config = { db: { host: string; port: number } }; type PartialConfig = DeepPartial<Config>;

// Nullable: T | null type MaybeUser = Nullable<User>;

Domain Error Mapping

Map your domain errors to the 10 taxonomy categories:

Domain Error Stack Category Error Class Exit HTTP

Not found not_found

NotFoundError

2 404

Invalid input validation

ValidationError

1 400

Already exists conflict

ConflictError

3 409

No permission permission

PermissionError

4 403

Auth required auth

AuthError

9 401

Timed out timeout

TimeoutError

5 504

Connection failed network

NetworkError

7 503

Limit exceeded rate_limit

RateLimitError

6 429

Bug/unexpected internal

InternalError

8 500

User cancelled cancelled

CancelledError

130 499

Mapping examples:

// "User not found" -> NotFoundError new NotFoundError("user", userId);

// "Invalid email format" -> ValidationError new ValidationError("Invalid email", { field: "email" });

// "User already exists" -> ConflictError new ConflictError("Email already registered", { email });

// "Cannot delete admin" -> PermissionError new PermissionError("Cannot delete admin users");

// Unexpected errors -> InternalError new InternalError("Database connection failed", { cause: error });

Bun-First APIs

Prefer Bun-native APIs:

Need Bun API

Hashing Bun.hash()

Globbing Bun.Glob

Semver Bun.semver

Shell Bun.$

Colors Bun.color()

String width Bun.stringWidth()

SQLite bun:sqlite

UUID v7 Bun.randomUUIDv7()

References

Core Patterns

  • Handler Contract

  • Error Taxonomy

  • Result Utilities

  • Conversion Patterns

Package Deep Dives

  • CLI Patterns - Output modes, pagination, formatting utilities

  • MCP Patterns - Tool registration, resources, schemas

  • File Operations - Atomic writes, locking, secure paths

  • Logging Patterns - Structured logging, sinks, redaction

  • Testing Patterns - Test harnesses, fixtures

  • Daemon Patterns - Lifecycle, IPC, health checks

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

codebase-recon

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

graphite-stacks

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

code-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

hono-dev

No summary provided by upstream source.

Repository SourceNeeds Review