smithery/creatifcoding

common-conventions

TMNL codebase conventions for file organization, barrel exports, naming patterns, comments, and module structure. The meta-skill for consistency.

Installation

$ npx skills add smithery/creatifcoding --skill common-conventions

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/creatifcoding · top by installs.

npx skills add smithery/creatifcoding

Browse all from smithery/creatifcoding

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 17,696 B
  • docs SUMMARY.md 171 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

TMNL Common Conventions

Overview

TMNL maintains strict conventions for code organization, naming, and documentation. This skill codifies patterns observed across the codebase to ensure consistency.

Mandatory Conventions (Non-negotiable):

  1. Schema discipline — All domain types use Effect Schema
  2. Typography 12px floor — No text smaller than 12px
  3. Atom-as-State doctrine — No Effect.Ref for React consumers
  4. Dependency audit — Grep before cutting imports

Pattern 1: Library Module Structure

When: Creating a new library at src/lib/{feature}/

Standard Directory Layout

src/lib/{feature}/
├── index.ts              # Barrel export (required)
├── types.ts              # TypeScript types (UI props, configs)
├── schemas/              # Effect Schema definitions
│   └── index.ts
├── services/             # Effect.Service implementations
│   ├── index.ts
│   └── {Feature}Service.ts
├── atoms/                # effect-atom definitions
│   └── index.ts
├── hooks/                # React hooks
│   └── use{Feature}.ts
├── components/           # React components (if UI-heavy)
│   └── {Component}.tsx
├── machines/             # XState machines (if stateful)
│   └── {feature}-machine.ts
├── v1/, v2/              # Version directories (for evolution)
└── CLAUDE.{feature}.md   # Agent handoff documentation

When to Use Each Directory

Directory When to Create
services/ Multiple Effect services, or single complex service
service.ts (root) Single simple service (e.g., src/lib/commands/service.ts)
atoms/ effect-atom state management
hooks/ Multiple React hooks
use{Feature}.tsx (root) Single hook
schemas/ Domain types requiring validation
types.ts UI props, configs, non-validated types
machines/ XState state machines
v1/, v2/ Major version evolution (not breaking changes)

Pattern 2: Barrel File (index.ts) Structure

When: Every src/lib/{feature}/ directory requires a barrel export.

Standard Format

/**
 * {Feature} Library
 *
 * {Brief description}
 *
 * @example
 * ```tsx
 * import { Component, useFeature } from '@/lib/{feature}'
 * ```
 */

// ═══════════════════════════════════════════════════════════════════════════
// CORE EXPORTS
// ═══════════════════════════════════════════════════════════════════════════

export { MainComponent } from './components/Main'
export { FeatureService } from './services'

// ═══════════════════════════════════════════════════════════════════════════
// SCHEMAS
// ═══════════════════════════════════════════════════════════════════════════

export * from './schemas'

// ═══════════════════════════════════════════════════════════════════════════
// ATOMS (effect-atom)
// ═══════════════════════════════════════════════════════════════════════════

export {
  stateAtom,
  configAtom,
  operationsAtom,
} from './atoms'

// ═══════════════════════════════════════════════════════════════════════════
// REACT HOOKS
// ═══════════════════════════════════════════════════════════════════════════

export { useFeature, useFeatureState } from './hooks'

// ═══════════════════════════════════════════════════════════════════════════
// TYPES
// ═══════════════════════════════════════════════════════════════════════════

export type { FeatureConfig, FeatureState } from './types'

Section Separators

Use box-drawing characters for major sections:

// ═══════════════════════════════════════════════════════════════════════════
// SECTION NAME (all caps)
// ═══════════════════════════════════════════════════════════════════════════

Use simple dashes for subsections:

// ───────────────────────────────────────────────────────────────────────────
// Subsection name
// ───────────────────────────────────────────────────────────────────────────

Version Re-exports

For modules with v1/v2:

// Default exports from v1
export * from './v1'

// Explicit v2 namespace
export * as v2 from './v2'

Usage:

import { Slider } from '@/lib/slider'         // v1 (default)
import { Slider } from '@/lib/slider/v2'      // v2 (explicit)

Pattern 3: Naming Conventions

Atoms

Pattern Example Usage
{noun}Atom resultsAtom State atom
{noun}sAtom layersAtom Collection atom
{verb}Atom computedAtom Derived/computed atom
{feature}OpsAtom layerOpsAtom Operation atoms (mutations)
{verb}Op searchOp, clearOp Individual operation

Services

Pattern Example Usage
{Feature}Service DataManagerService Effect.Service class
{Feature}ServiceShape ChannelServiceShape Interface type
{Behavior}Behavior LinearBehavior, DecibelBehavior Strategy pattern

Hooks

Pattern Example Usage
use{Feature} useSlider Main feature hook
use{Feature}Value useSliderValue Read-only value hook
use{Feature}State useMinibufferState State + updater
use{Feature}Ops useOverlayOps Operations only
useAtom{Feature} useAtomValue Atom-specific

Components

Pattern Example Usage
{Name}.tsx Slider.tsx Component file
{Name}Props SliderProps Props interface
{Name}Context DataGridContext Context type
{Name}Provider CommandProvider Context provider

Machines

Pattern Example Usage
{feature}Machine minibufferMachine XState machine
{Feature}Machine MinibufferMachine Type alias
{Feature}Actor MinibufferActor ActorRef type

Pattern 4: Comment Styles

File Header (JSDoc)

/**
 * {Module Name} — {Brief description}
 *
 * {Longer description if needed}
 *
 * @example
 * ```tsx
 * // Usage example
 * ```
 */

Architectural Notes

For non-obvious design decisions:

// ARCHITECTURAL NOTE:
// CommandProvider lives here (commands/), not in minibuffer/.
// Minibuffer is a generic prompt engine. Commands USES minibuffer, not the reverse.

TODO/FIXME

// TODO(prime): Migrate to v2 API after EPOCH-0003
// FIXME: This breaks when input is empty
// HACK: Workaround for WSLg rendering bug

Pattern 5: Types vs Schemas

When to Use types.ts

  • React component props
  • UI configuration
  • Local function parameters
  • Types that don't need runtime validation
// src/lib/slider/v1/types.ts
export interface SliderProps {
  value: number
  onChange: (value: number) => void
  min?: number
  max?: number
}

export interface SliderConfig {
  min: number
  max: number
  step: number
  defaultValue: number
}

When to Use schemas/

  • Domain types requiring validation
  • Event payloads
  • API responses
  • Discriminated unions with pattern matching
  • EventLog integration
// src/lib/overlays/schemas/core.ts
import { Schema } from 'effect'

export const OverlayId = Schema.String.pipe(
  Schema.brand('OverlayId')
)
export type OverlayId = typeof OverlayId.Type

export const OverlayOpened = Schema.TaggedStruct('OverlayOpened', {
  id: OverlayId,
  timestamp: Schema.DateFromSelf,
})

Pattern 6: Test File Organization

Location Patterns

Pattern Example When
tests/ directory src/lib/stx/tests/ Multiple test files
.test.ts suffix service.test.ts Single test file
.bun.test.ts suffix eventlog-integration.bun.test.ts Bun-specific

Test Naming

// src/lib/feature/__tests__/feature.test.ts
describe('FeatureService', () => {
  describe('operation', () => {
    it('does X when Y', () => { ... })
    it('fails with Z when W', () => { ... })
  })
})

Effect Service Tests

Use @effect/vitest with it.effect():

import { describe, it } from '@effect/vitest'

describe('MyService', () => {
  it.effect('returns data', () =>
    Effect.gen(function* () {
      const service = yield* MyService
      const result = yield* service.getData()
      expect(result).toBeDefined()
    }).pipe(Effect.provide(MyService.Default))
  )
})

Atom Tests

Use Registry.make():

it('atom updates', () => {
  const r = Registry.make()
  expect(r.get(counterAtom)).toBe(0)
  r.set(counterAtom, 1)
  expect(r.get(counterAtom)).toBe(1)
})

Pattern 7: Documentation Files

Per-Module Documentation

File Purpose Audience
CLAUDE.{feature}.md Agent handoff AI assistants
README.md User-facing docs Developers
ARCHITECTURE.md Deep design analysis Architects
AGENTS.{feature}.md Agent-specific notes AI assistants

CLAUDE.{feature}.md Structure

# {Feature} — Claude Context

## Overview
{Brief description}

## Key Files
- `service.ts` — Main service implementation
- `atoms/index.ts` — Reactive state

## Patterns Used
- Effect.Service<>() for DI
- Atom.runtime() for state

## Gotchas
- Don't use X because Y
- Always Z before W

## Related Skills
- effect-patterns
- effect-atom-integration

Pattern 8: Service File Patterns

Single Service (Root Level)

// src/lib/commands/service.ts

/**
 * TMNL Commands — Effect Service
 */

// ───────────────────────────────────────────────────────────────────────────
// Atoms (Reactive State)
// ───────────────────────────────────────────────────────────────────────────

export const commandsAtom = Atom.make<ReadonlyMap<string, Command>>(new Map())

// ───────────────────────────────────────────────────────────────────────────
// Service Implementation
// ───────────────────────────────────────────────────────────────────────────

export class CommandService extends Effect.Service<CommandService>()('app/CommandService', {
  effect: Effect.gen(function* () {
    // ...
  }),
}) {}

Multiple Services (Directory)

src/lib/overlays/services/
├── index.ts              # Re-exports all services
├── OverlayRegistry.ts    # Registry service
├── PortHub.ts            # Port management
└── EventDispatcher.ts    # Event dispatch

Anti-Patterns

1. Barrel File Without Sections

// WRONG — Unorganized exports
export * from './components'
export * from './hooks'
export * from './types'
export * from './atoms'

// CORRECT — Sectioned exports
// ═══════════════════════════════════════════════════════════════════════════
// COMPONENTS
// ═══════════════════════════════════════════════════════════════════════════
export { Slider } from './components/Slider'

// ═══════════════════════════════════════════════════════════════════════════
// HOOKS
// ═══════════════════════════════════════════════════════════════════════════
export { useSlider } from './hooks/useSlider'

2. Types in Wrong Location

// WRONG — Domain type without Schema
// src/lib/feature/types.ts
export interface UserEvent {
  _tag: 'UserCreated'
  id: string
  name: string
}

// CORRECT — Domain type with Schema
// src/lib/feature/schemas/events.ts
export const UserCreated = Schema.TaggedStruct('UserCreated', {
  id: Schema.String,
  name: Schema.NonEmptyString,
})

3. Inconsistent Naming

// WRONG — Mixed naming styles
export const user_state_atom = Atom.make(...)  // snake_case
export const UseUserHook = () => { ... }       // PascalCase for hook
export const userservice = Effect.Service()    // no separator

// CORRECT — Consistent camelCase with type suffix
export const userStateAtom = Atom.make(...)
export const useUser = () => { ... }
export const UserService = Effect.Service()

4. Missing JSDoc on Exports

// WRONG — No documentation
export const searchOp = runtimeAtom.fn<string>()(...)

// CORRECT — JSDoc on public exports
/**
 * Search operation. Triggers search with given query.
 *
 * @param query - Search query string
 * @returns Effect that updates resultsAtom
 */
export const searchOp = runtimeAtom.fn<string>()(...)

Checklist: New Module Creation

When creating src/lib/{feature}/:

  • Create index.ts with JSDoc header and sectioned exports
  • Create types.ts for non-domain types (UI props, configs)
  • Create schemas/ for domain types using Effect Schema
  • Create services/ (or service.ts) with Effect.Service<>()
  • Create atoms/index.ts with Atom definitions
  • Create hooks/ with React hooks
  • Use section comments: // ═══════...
  • Add ARCHITECTURAL NOTE for non-obvious decisions
  • Create CLAUDE.{feature}.md for agent handoff
  • Prefer Atom.make<T>() over Effect.Ref<T> for React
  • Test with @effect/vitest for services, Registry.make() for atoms

Canonical Examples

Convention Best Example File
Barrel file Overlays src/lib/overlays/index.ts
Service pattern Commands src/lib/commands/service.ts
Atom organization Slider src/lib/slider/v1/atoms/index.ts
Schema usage Commands src/lib/commands/types.ts
Hook naming Commands src/lib/commands/useCommandWire.tsx
Version strategy Slider src/lib/slider/index.ts
Test organization STX src/lib/stx/tests/

Integration Points

  • tmnl-file-organization — Directory structure details
  • effect-patterns — Service definition patterns
  • effect-atom-integration — Atom patterns
  • tmnl-typography-discipline — Typography rules
  • effect-schema-mastery — Schema patterns