| name | create-service |
| description | Scaffold a new microservice that follows the project's server/handlers/adapters architecture. Use when asked to create, scaffold, or add a new service or package. Writes files and may create a git branch, so it runs only when invoked explicitly. |
| when_to_use | - User asks to create, scaffold, or add a new service or microservice
- User says "new service", "scaffold service", "create service", "add service"
- Do NOT auto-run; this writes files and touches git
|
| disable-model-invocation | true |
| allowed-tools | Read, Write, Edit, Bash |
Create Service
Scaffold a new service that follows the project architecture. This writes files and may create a branch, so it only runs when you type /create-service.
Architecture
Three layers, one direction. server.ts is thin, handlers/ hold logic, adapters/ wrap everything external.
server.ts routes only, NEVER business logic
│
▼
handlers/ business logic, one file per domain
│
▼
adapters/ external wrappers (database via StrictDB or native driver, APIs, queues)
This matches the api-conventions skill. Keep them in sync: if the layering changes, change both.
Directory structure
packages/{name}/
├── src/
│ ├── server.ts # entry point — routes only
│ ├── handlers/ # business logic
│ │ └── index.ts
│ ├── adapters/ # external wrappers
│ │ ├── index.ts
│ │ └── db.ts # data adapter — StrictDB or native driver, the only place the driver lives
│ └── types.ts # TypeScript types
├── tests/
│ └── handlers.test.ts
├── package.json
├── tsconfig.json
└── CLAUDE.md # service-specific instructions
package.json — resolve versions at scaffold time
Do not hardcode dependency versions. Before writing package.json, resolve the current stable version of each dependency (npm view <pkg> version, or context7) and pin those. Hardcoded versions rot the day they ship, and a stale pin is how you get an Express 4 runtime against Express 5 types.
Dependencies to resolve and include:
- runtime:
express (current major is 5)
- dev:
tsx, typescript, vitest, @types/express
Make the @types/express major match the express major. Verify, don't assume.
{
"name": "@project/{name}",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "tsc",
"dev": "tsx watch src/server.ts",
"start": "node dist/server.js",
"test": "vitest run"
},
"dependencies": {
"express": "<resolved>"
},
"devDependencies": {
"tsx": "<resolved>",
"typescript": "<resolved>",
"vitest": "<resolved>",
"@types/express": "<resolved, major matching express>"
}
}
Template: src/server.ts
import express from 'express';
import { handlers } from './handlers/index.js';
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
app.get('/health', (_req, res) => {
res.json({ status: 'ok', service: '{name}' });
});
app.post('/api/v1/:action', handlers.handleAction);
process.on('unhandledRejection', (reason) => {
console.error('Unhandled Rejection:', reason);
process.exit(1);
});
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
process.exit(1);
});
app.listen(PORT, () => {
console.log(`{name} running on port ${PORT}`);
});
Template: src/adapters/db.ts
The data adapter is the only place the driver is touched. Use StrictDB if it's installed, otherwise the native MongoDB driver. Never Mongoose. Handlers import this, never the driver.
import { StrictDB } from 'strictdb';
const db = new StrictDB({ uri: process.env.MONGODB_URI! });
export const dbAdapter = {
async getById(collection: string, id: unknown) {
return db.collection(collection).aggregate([{ $match: { _id: id } }]).next();
},
async upsertMany(collection: string, ops: unknown[]) {
return db.collection(collection).bulkWrite(ops);
},
};
Template: src/types.ts
export interface ServiceConfig {
port: number;
name: string;
environment: 'development' | 'staging' | 'production';
}
Template: tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "tests"]
}
Auto-branch (if on main)
Before scaffolding, check the branch:
git branch --show-current
Default (auto_branch = true in claude-mastery-project.conf):
To disable: set auto_branch = false. When disabled, warn and ask before proceeding on main.
After creating — checklist
RuleCatch
After scaffolding, check RuleCatch:
- If the RuleCatch MCP server is available, query it for violations in the new service files and report them.
- If not connected, suggest checking the RuleCatch dashboard.