koa-typescript — Claude Code skill: Koa.js and TypeScript rules
Tells your agent how to write Koa.js APIs in TypeScript: onion middleware, async/await, project layout.
npx skills add Mindrally/skills --skill koa-typescript -a claude-codeWhat koa-typescript does
The skill loads into your coding agent as a set of instructions and shapes the code it writes afterwards. Inside are TypeScript conventions: declare types for variables and functions, skip any, document public classes and methods with JSDoc, PascalCase for types, camelCase for variables, kebab-case for file names. The folder layout is spelled out too: routes/ with one directory per resource, then middleware/, services/, models/, utils/, config/, plus app.ts and server.ts.
The bulk of it covers Koa's onion model. Your agent gets a middleware example with await next(), the note that code after that call runs on the way back up, and a rule to use async/await everywhere. Other sections handle typing the context with ParameterizedContext and ctx.state, the order of app.use() calls, routing with @koa/router, a centralized error handler built on an AppError class, validation with Zod, JWT auth through koa-jwt plus role checks, security with koa-helmet and koa-ratelimit, and tests on Jest or Mocha via supertest.
One thing to weigh: the skill states opinions, it does not inspect your code. If your project already validates with Joi or routes without prefixes, the agent will start pulling these examples into your codebase anyway — worth reading SKILL.md before you commit to it. The source text cuts off inside the performance section, so caching and response compression get less coverage than the rest.
What it helps with
- set one TypeScript style for an agent working on a Koa codebase
- split an API into routes, services and middleware folders
- explain the onion model and why await next() matters
- type ctx.state instead of reaching for any
- build a centralized error handler with a custom error class
Example prompts for the agent
- write a Koa middleware that logs requests and response time
- add a router for the users resource with Zod body validation
- create a middleware that checks the role in ctx.state.user
How to install koa-typescript
1Skills CLI (Vercel)
npx skills add Mindrally/skills --skill koa-typescript -a claude-code2Manually: put the files in place
~/.claude/skills/koa-typescript/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/koa-typescript/
1Skills CLI (Vercel)
npx skills add Mindrally/skills --skill koa-typescript -a codex2Manually: put the files in place
.agents/skills/koa-typescript/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add Mindrally/skills --skill koa-typescript -a cursor2Manually: put the files in place
.cursor/skills/koa-typescript/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install Mindrally/skills koa-typescript2Manually: put the files in place
.github/skills/koa-typescript/SKILL.md1Skills CLI (Vercel)
npx skills add Mindrally/skills --skill koa-typescript -a gemini-cli2Platform CLI
gemini skills install https://github.com/Mindrally/skills --path koa-typescriptManually: put the files in place
.devin/skills/koa-typescript/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add Mindrally/skills --skill koa-typescript -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about koa-typescript
How do I install koa-typescript in Claude?
Run npx skills add Mindrally/skills --skill koa-typescript -a claude-code. The skill file lands at ~/.claude/skills/koa-typescript/SKILL.md.
What does koa-typescript do?
It gives your agent guidelines for Koa.js and TypeScript APIs: project structure, onion middleware, context typing, error handling, validation, auth and tests.
Which platforms can use this skill?
Beyond Claude there are install commands for Codex, Cursor, GitHub Copilot, Gemini CLI and OpenCode, each with its own file path.
Source text
SKILL.md · Apache-2.0
---
name: koa-typescript
description: Guidelines for building modern APIs with Koa.js and TypeScript, featuring the onion middleware model and async/await patterns
metadata:
maintainer: Mindrally
source: https://github.com/Mindrally/skills
---
# Koa TypeScript Development
You are an expert in Koa.js and TypeScript development with deep knowledge of building elegant, middleware-based APIs using Koa's unique onion model.
## TypeScript General Guidelines
### Basic Principles
- Use English for all code and documentation
- Always declare types for variables and functions
- Avoid using `any` type - create necessary types instead
- Use JSDoc to document public classes and methods
- Write concise, maintainable, and technically accurate code
- Use functional and declarative programming patterns
- Prefer iteration and modularization to adhere to DRY principles
### Nomenclature
- Use PascalCase for types and interfaces
- Use camelCase for variables, functions, and methods
- Use kebab-case for file and directory names
- Use UPPERCASE for environment variables
- Use descriptive variable names with auxiliary verbs
### Functions
- Write short functions with a single purpose
- Use arrow functions for middleware
- Use async/await consistently throughout the codebase
- Use the RO-RO pattern for multiple parameters
## Koa-Specific Guidelines
### Project Structure
```
src/
routes/
{resource}/
index.ts
controller.ts
validators.ts
middleware/
auth.ts
errorHandler.ts
requestId.ts
logger.ts
services/
{domain}Service.ts
models/
{entity}.ts
utils/
config/
app.ts
server.ts
```
### Middleware Patterns
Koa uses a unique "onion" middleware model. Middleware functions are composed and executed in a stack-like manner.
```typescript
import { Middleware } from 'koa';
// Middleware pattern with async/await
const responseTime: Middleware = async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
};
```
- Always use `async/await` for middleware
- Call `await next()` to pass control to downstream middleware
- Code after `await next()` runs during the "upstream" phase
- Use this pattern for request/response transformations
### Context (ctx) Best Practices
- Use `ctx.state` to pass data between middleware
- Type your context for better type safety
- Avoid mutating context directly when possible
- Use context for request/response access
```typescript
import { ParameterizedContext, Middleware } from 'koa';
interface AppState {
user?: User;
requestId: string;
}
type AppContext = ParameterizedContext<AppState>;
const authMiddleware: Middleware<AppState> = async (ctx, next) => {
ctx.state.user = await validateToken(ctx.headers.authorization);
await next();
};
```
### Application Setup
```typescript
import Koa from 'koa';
import Router from '@koa/router';
import bodyParser from 'koa-bodyparser';
import cors from '@koa/cors';
import helmet from 'koa-helmet';
import { errorHandler } from './middleware/errorHandler';
import { requestLogger } from './middleware/logger';
const app = new Koa();
// Error handling (first in chain)
app.use(errorHandler);
// Security
app.use(helmet());
app.use(cors());
// Body parsing
app.use(bodyParser());
// Logging
app.use(requestLogger);
// Routes
app.use(router.routes());
app.use(router.allowedMethods());
export default app;
```
### Routing with koa-router
- Use koa-router for declarative routing
- Organize routes by resource
- Keep route handlers thin
- Use middleware for cross-cutting concerns
```typescript
import Router from '@koa/router';
import * as controller from './controller';
import { validateUserInput } from './validators';
const router = new Router({ prefix: '/api/users' });
router.get('/', controller.listUsers);
router.get('/:id', controller.getUser);
router.post('/', validateUserInput, controller.createUser);
router.put('/:id', validateUserInput, controller.updateUser);
router.delete('/:id', controller.deleteUser);
export default router;
```
### Error Handling
- Create centralized error handling middleware
- Place error handler at the top of the middleware stack
- Use custom error classes for different error types
- Never expose internal error details in production
```typescript
import { Middleware } from 'koa';
class AppError extends Error {
constructor(
public status: number,
message: string,
public expose: boolean = true
) {
super(message);
}
}
const errorHandler: Middleware = async (ctx, next) => {
try {
await next();
} catch (err) {
const error = err as Error & { status?: number; expose?: boolean };
ctx.status = error.status || 500;
ctx.body = {
error: {
message: error.expose ? error.message : 'Internal Server Error',
...(process.env.NODE_ENV === 'development' && { stack: error.stack })
}
};
ctx.app.emit('error', err, ctx);
}
};
```
### Request Validation
- Use koa-joi-router or Zod for validation
- Validate body, query, and params
- Return clear validation error messages
- Create reusable validation middleware
```typescript
import { z } from 'zod';
import { Middleware } from 'koa';
const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
const validate = (schema: z.ZodSchema): Middleware => {
return async (ctx, next) => {
try {
ctx.request.body = schema.parse(ctx.request.body);
await next();
} catch (error) {
if (error instanceof z.ZodError) {
ctx.status = 400;
ctx.body = { errors: error.errors };
return;
}
throw error;
}
};
};
```
### Authentication
- Implement JWT authentication with koa-jwt
- Store authenticated user in `ctx.state.user`
- Create authorization middleware for role-based access
```typescript
import jwt from 'koa-jwt';
app.use(jwt({ secret: process.env.JWT_SECRET }).unless({ path: [/^\/public/] }));
const requireRole = (role: string): Middleware => {
return async (ctx, next) => {
if (ctx.state.user?.role !== role) {
ctx.throw(403, 'Forbidden');
}
await next();
};
};
```
### Security
- Use koa-helmet for security headers
- Implement rate limiting with koa-ratelimit
- Enable CORS with @koa/cors
- Validate and sanitize all inputs
- Use HTTPS in production
### Testing
- Use Jest or Mocha for testing
- Use supertest with app.callback() for integration tests
- Test middleware in isolation
- Mock context for unit tests
```typescript
import request from 'supertest';
import app from '../app';
describe('GET /api/users', () => {
it('should return users list', async () => {
const response = await request(app.callback())
.get('/api/users')
.expect(200);
expect(response.body).toBeInstanceOf(Array);
});
});
```
### Performance
- Use koa-compress for response compression
- Implement caching with koa-redis-cache
- Use connection pooling for databases
- Implement pagination for list endpoints
- Consider koa-static for serving static files
### Environment Configuration
- Use dotenv for environment variables
- Validate required environment variables at startup
- Create separate configs for different environments
- Never commit secrets to version control
© Mindrally · Apache-2.0 · Mindrally/skills