> For the complete documentation index, see [llms.txt](https://docs.yemreak.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.yemreak.com/contents/d7de2f0f.md).

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

> [reddit/1pet056](https://www.reddit.com/r/ClaudeAI/comments/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](https://github.com/yemreak/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:**

```typescript
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:**

```typescript
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:**

```typescript
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) |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.yemreak.com/contents/d7de2f0f.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
