my 2nd response to TLDR - Prompts don't scale. MCPs don't scale. Hooks do.

reddit/1pet056

You're right - those 3 examples are "lintable". I picked them because they're easy to explain.

Context: I'm building a macOS app (yemreak-macos) - voice dictation with clipboard context for AI conversations. This is my first Swift project, so I'm learning the patterns as I go. Every time I discover a rule that AI keeps violating, I write a hook for it. These examples come from that process.

Think of hooks as a personalized linter - project-specific rules that only make sense in YOUR codebase.

eslint = universal rules (syntax, types) hooks = YOUR rules (architecture, naming conventions, layer boundaries)

eslint can't know "this module shouldn't import that module based on my folder structure"

Concrete Examples

1. Layer Enforcement (Transport can't call Capability)

Source Code:

const CAPABILITY_PATTERN = /\w+Capability\.shared\./

export const noCapabilityInTransportRule: FileRule = {
  name: 'noCapabilityInTransport',
  active: true,

  check(params: FileRuleCheckParams): RuleCheckResult {
    // Only check Transport files
    const isTransport = params.filePath.includes('/Transport/')
                     || params.filePath.endsWith('HTTP.swift')
    if (!isTransport) return { matched: false }

    const match = params.content.match(CAPABILITY_PATTERN)
    if (match) {
      return {
        matched: true,
        violation: `[swift] noCapabilityInTransport violation

File: ${params.filePath}
Found: ${match[0]}

CONSTRAINT: Transport -> Intent (not Capability)

CORRECT:
await IntentExecutor.shared.trigger(.context(.action), source: .http)`
      }
    }
    return { matched: false }
  }
}

What AI sees when blocked:

[swift] noCapabilityInTransport violation

File: MenuBar.swift
Found: AudioCapability.shared.start()

CONSTRAINT: Transport -> Intent (not Capability)

CORRECT:
await IntentExecutor.shared.trigger(.context(.action), source: .http)

2. Architecture Injection on First Read

Source Code:

export const architectureRule: GeneralRule = {
  key: 'architecture',
  toolMatcher: '^(Read|Write|Edit)$',

  async decision(params: RuleContext): Promise<RuleResult> {
    const archFiles = await findArchitectureFiles({
      cwd: params.cwd,
      filePath: filePathResult.path,
      scopeType // Read or Write
    })
    if (archFiles.length === 0) return { type: 'pass' }

    // Check if already reminded this session
    const reminded = await loadReminded({ cwd: params.cwd, sessionId: params.sessionId })
    const newFiles = archFiles.filter(f => !reminded.includes(f.path))
    if (newFiles.length === 0) return { type: 'pass' }

    // Mark as reminded, then block with architecture content
    for (const f of newFiles) {
      await markReminded({ cwd: params.cwd, sessionId: params.sessionId, archPath: f.path })
    }

    return {
      type: 'violation',
      decision: 'deny',
      reason: formatArchitectureAction(newFiles) // <be-aware>...</be-aware>
    }
  }
}

What AI sees when blocked:

<be-aware from="macos/Sources/Contexts/ARCHITECTURE.md">
Transport → Intent → Capability → (return) → Intent → Feedback

Transport: Keyboard entry, menu clicks, HTTP handlers
Intent: Single entry point, orchestration
Capability: External side effects (audio, API, file)
</be-aware>
<retry>Retry action with that awareness</retry>

3. Locality Enforcement (MVI Pattern)

Source Code:

const LOCALITY: Record<LocalityType, LocalityConfig> = {
  hotkeyLocality: {
    patterns: [/\.keyboardShortcut\s*\(/, /addLocalMonitorForEvents/],
    allowedSuffix: 'Hotkeys.swift',
    allowedExceptions: ['HotkeyCapability.swift'],
    message: 'Hotkey code must be in *Hotkeys.swift'
  },

  panelEscape: {
    patterns: [/\.onKeyPress\s*\(\s*\.escape/, /\.keyboardShortcut\s*\(\s*\.escape/],
    allowedSuffix: '__NONE__',
    allowedExceptions: ['BasePanelController.swift'],
    message: 'Panel cannot handle Escape - use Tier 2'
  }
}

// In check():
for (const [localityType, config] of Object.entries(LOCALITY)) {
  if (fileName.endsWith(config.allowedSuffix)) continue
  if (config.allowedExceptions.includes(fileName)) continue

  for (const pattern of config.patterns) {
    if (pattern.test(line)) {
      return { matched: true, violation: generateLocalityViolation(...) }
    }
  }
}

What AI sees when blocked:

[swift] OnMviViolation (panelEscape)

File: DictationPanel.swift
CONSTRAINT: Panel cannot handle Escape - use Tier 2

Found:
Line 23: .keyboardShortcut(.escape)

CORRECT:
Move to BasePanelController (Tier 2 handles Escape)

Summary

Category
Example
Linter can do?

Layer enforcement

Transport can't call Capability

No

Architecture injection

Show ARCHITECTURE.md on first read

No

Locality

Hotkey code only in *Hotkeys.swift

No

Lint-like

no-magic-number

Yes (examples only)

Last updated

Was this helpful?