Claude-skill-registry mymind-coding-patterns

Coding conventions and patterns for the mymind codebase. Use this skill when writing or modifying any code in this project to ensure consistency with established patterns.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/coding-patterns" ~/.claude/skills/majiayu000-claude-skill-registry-mymind-coding-patterns && rm -rf "$T"
manifest: skills/data/coding-patterns/SKILL.md
source content

MyMind Coding Patterns

Stack

  • Runtime: Bun
  • Framework: Next.js 15 (App Router)
  • Database: PGlite (PostgreSQL) with pgvector for embeddings
  • ORM: Drizzle
  • Validation: Zod (preferred over type casting)
  • Formatting: Biome (2 spaces, organize imports)

Skills (Tools)

Skills are executable tools that Claude can call. They live in

src/skills/
.

Defining a Skill

import { z } from "zod";
import { defineSkill, type SkillResult } from "./types";

const MyParamsSchema = z.object({
  input: z.string().describe("Description for Claude"),
  optional: z.number().optional(),
});

type MyParams = z.infer<typeof MyParamsSchema>;

interface MyResult {
  // typed result
}

export const mySkill = defineSkill({
  name: "my_skill", // snake_case
  description: "What this skill does and when to use it",
  parameters: MyParamsSchema,

  async execute(params: MyParams): Promise<SkillResult<MyResult>> {
    try {
      // do the thing
      return {
        success: true,
        data: { /* result */ },
        message: "Human-readable success message",
      };
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      return {
        success: false,
        error: `Failed to do thing: ${message}`,
      };
    }
  },
});

export default mySkill;

Registering Skills

Add new skills to

src/skills/index.ts
:

import { mySkill } from "./my-skill";

const skills: Skill[] = [
  // ... existing
  mySkill,
];

export { mySkill } from "./my-skill";

Database Access

Always use

withDb()
wrapper - it handles connection lifecycle:

import { withDb } from "@/db/client";
import { items, tags } from "@/db/schema";
import { eq } from "drizzle-orm";

const result = await withDb(async ({ db }) => {
  const rows = await db
    .select()
    .from(items)
    .where(eq(items.type, "bookmark"))
    .limit(10);
  return rows;
});

Schema Types

Use Drizzle's inferred types:

import { type Item, type NewItem } from "@/db/schema";

// Item = select type (has id, createdAt, etc.)
// NewItem = insert type (id optional, etc.)

API Routes

Request Validation

Always use Zod

.parse()
- never type cast:

// ✅ Good
const params = MySchema.parse(await request.json());

// ❌ Bad - no runtime validation
const params = (await request.json()) as MyParams;

Response Shape

// Success
return NextResponse.json({
  success: true,
  items: result.data,
  total: result.total,
});

// Error
return NextResponse.json(
  { success: false, error: "What went wrong" },
  { status: 400 }
);

Zod Error Handling

try {
  const params = Schema.parse(body);
  // ...
} catch (error) {
  if (error instanceof z.ZodError) {
    return NextResponse.json(
      { success: false, error: error.issues },
      { status: 400 }
    );
  }
  throw error;
}

Imports

Use path alias for src:

// ✅ Good
import { withDb } from "@/db/client";
import { saveBookmark } from "@/skills";

// ❌ Avoid relative paths across directories
import { withDb } from "../../../db/client";

Naming Conventions

ThingConventionExample
Skill namessnake_case
save_bookmark
,
list_items
FunctionscamelCase
scrapeUrl
,
extractText
Types/InterfacesPascalCase
SkillResult
,
ItemMetadata
Fileskebab-case
save-bookmark.ts
,
list-items.ts
Zod schemasPascalCase + Schema
SaveBookmarkSchema

Don't

  • Don't use type casting (
    as
    ) for external data - validate with Zod
  • Don't create DB connections manually - use
    withDb()
  • Don't use
    any
    - prefer
    unknown
    with narrowing
  • Don't forget to add
    .describe()
    on Zod fields for tool schemas