# How to Use the `narrow-react-prop-types` Skill to Tighten React Component Prop Types

> Learn to use narrow-react-prop-types to tighten React component TypeScript prop types from production call sites. Improve your component type safety with this powerful automation.

- Repository: [HumanLayer/skills](https://github.com/humanlayer/skills)
- Tags: how-to-guide
- Published: 2026-09-07

---

**The `narrow-react-prop-types` skill is a CodeLayer-driven automation that tightens React component TypeScript prop types by deriving them from live production call sites rather than stories or test mocks.**

This skill helps monorepos maintain strict, accurate prop contracts by preventing demo-only props from polluting component APIs. The workflow runs via GitHub Actions, uses an AI agent to analyze real usage patterns, and generates pull requests with narrowed type definitions.

## Understanding the Core Workflow

The `narrow-react-prop-types` skill operates on a single principle: **live code paths are the source of truth**. Instead of allowing Storybook stories, test files, or mock data to dictate optional props, the skill forces type definitions to reflect only what production code actually passes.

This approach reduces unnecessary optional branches, eliminates "demo-only" props like `defaultFoo`, and encourages deriving types from existing values using TypeScript utilities like `Parameters<typeof fn>[0]` and `ReturnType<typeof fn>`.

## Step-by-Step Execution Flow

The workflow follows a ten-step process defined in [`plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md`](https://github.com/humanlayer/skills/blob/main/plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md):

1. **Identify suspect components** flagged by previous runs or manual selection
2. **Find live usage** across the monorepo, excluding test and Storybook files
3. **Analyze prop passing patterns** at each call site
4. **Derive required vs. optional status** based on actual usage
5. **Identify removable props** never used in production
6. **Tighten type definitions** in component source files
7. **Update supporting code** (call sites, tests) to match new contracts
8. **Run validation** (typecheck, quality checks)
9. **Generate PR** with structured evidence
10. **Persist memory** for iterative refinement

## Key Files and Their Roles

| File | Path | Purpose |
|------|------|---------|
| **Skill definition** | [`plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md`](https://github.com/humanlayer/skills/blob/main/plugins/narrow-react-prop-types/skills/narrow-react-prop-types/SKILL.md) | Human-readable specification the agent follows |
| **Response template** | [`plugins/narrow-react-prop-types/skills/narrow-react-prop-types/response-template.md`](https://github.com/humanlayer/skills/blob/main/plugins/narrow-react-prop-types/skills/narrow-react-prop-types/response-template.md) | PR body layout with change tables and evidence |
| **Workflow definition** | [`.github/workflows/agent-narrow-component-props.yml`](https://github.com/humanlayer/skills/blob/main/.github/workflows/agent-narrow-component-props.yml) | GitHub Actions orchestration |
| **Agent memory** | [`.github/agent-memory/narrow-component-props.md`](https://github.com/humanlayer/skills/blob/main/.github/agent-memory/narrow-component-props.md) | Persistent context between runs |
| **Plugin metadata** | [`.claude-plugin/plugin.json`](https://github.com/humanlayer/skills/blob/main/.claude-plugin/plugin.json) | Claude plugin system registration |

## Installing and Running the Skill

### Add the Skill to Your Repository

```bash

# Install via the skills CLI

npx skills add humanlayer/skills --skill narrow-react-prop-types

```

This command registers the skill and copies the necessary workflow and configuration files into your repository.

### Manual Workflow Dispatch

Create a custom workflow to trigger narrowing on specific components:

```yaml

# .github/workflows/narrow-props.yml

name: Narrow React Props
on:
  workflow_dispatch:
    inputs:
      target_path:
        description: "Path to a specific component or package (optional)"
        required: false
        type: string

jobs:
  narrow:
    uses: ./plugins/narrow-react-prop-types/.github/workflows/agent-narrow-component-props.yml@main
    with:
      target_path: ${{ inputs.target_path }}

```

The reusable workflow in [`agent-narrow-component-props.yml`](https://github.com/humanlayer/skills/blob/main/agent-narrow-component-props.yml) handles:
- Installing **Bun** and Node.js
- Caching dependencies
- Running `bun install`
- Invoking `@humanlayer/cli` with `claude-opus-4-8`

## Generated Pull Request Structure

The agent populates [`response-template.md`](https://github.com/humanlayer/skills/blob/main/response-template.md) to produce structured PRs:

```markdown

## React Component Prop Narrowing Complete

### Summary

Narrowed props in **3** components.

### Changes Made

| Component | File | Change | Rationale |
|-----------|------|--------|-----------|
| `UserMenu` | `packages/ui/src/UserMenu.tsx` | Made `onLogout` required | All live call sites provide it |
| `DataTable` | `apps/riptide-ui/src/DataTable.tsx` | Removed `defaultSort` prop | Never used by production code |

### Live Call Sites Checked

| Call Site | File | Observation |
|-----------|------|-------------|
| `Dashboard` | `apps/riptide-ui/src/Dashboard.tsx` | Always passes `onLogout` |
| `AdminPanel` | `apps/riptide-ui/src/AdminPanel.tsx` | Provides `defaultSort` via constant |

### Validation

- [x] Typecheck passed (`bun --bun run typecheck --filter @codelayer/riptide-ui`)
- [x] Quality checks passed (`bun run quality`)

```

## Iterative Refinement via Agent Memory

The skill supports ongoing refinement through [`.github/agent-memory/narrow-component-props.md`](https://github.com/humanlayer/skills/blob/main/.github/agent-memory/narrow-component-props.md). After reviewing a generated PR, team members can comment `/iterate` with instructions like:

- "Exclude `experimental` props from narrowing"
- "Ignore call sites in `apps/admin` until Q3 migration complete"
- "Prioritize components in `packages/core-ui`"

The agent reads this persistent memory on subsequent runs, gradually improving its accuracy without reconfiguration.

## Why This Approach Works

**Preventing specification drift** – Stories and tests often accumulate "convenience" props that production code never needs. Living documentation becomes misleading documentation.

**DRY type definitions** – Deriving prop types from actual function parameters and return values eliminates duplication between implementation and interface.

**Machine-verified contracts** – Every narrowed prop ships with a table of live call sites proving the change is safe. This evidence is generated, not hand-maintained.

**Gradual, safe adoption** – The workflow creates branches and PRs; nothing merges automatically. Teams review evidence, adjust boundaries via agent memory, and merge when confident.

## Summary

- The **`narrow-react-prop-types`** skill automates prop type tightening using live call sites as the source of truth
- Execution runs via **[`agent-narrow-component-props.yml`](https://github.com/humanlayer/skills/blob/main/agent-narrow-component-props.yml)**, invoking Claude Opus through the CodeLayer CLI
- The ten-step process in **[`SKILL.md`](https://github.com/humanlayer/skills/blob/main/SKILL.md)** guides the agent from identification through validation
- **[`.github/agent-memory/narrow-component-props.md`](https://github.com/humanlayer/skills/blob/main/.github/agent-memory/narrow-component-props.md)** enables iterative refinement between runs
- Generated PRs follow **[`response-template.md`](https://github.com/humanlayer/skills/blob/main/response-template.md)** with structured evidence tables for review

## Frequently Asked Questions

### What distinguishes `narrow-react-prop-types` from a linter?

A linter enforces syntactic rules; this skill performs semantic analysis across your entire monorepo. It traces actual values passed at call sites, distinguishes production from test code, and generates evidence-backed code changes rather than just warnings.

### Which files does the skill treat as "live" versus "test"?

The agent excludes paths matching common patterns: `*.test.*`, `*.spec.*`, `**/__tests__/**`, `**/.storybook/**`, and `*.stories.*`. Configuration in [`SKILL.md`](https://github.com/humanlayer/skills/blob/main/SKILL.md) can customize these exclusions per repository.

### Can the skill handle breaking changes to widely-used components?

Yes. The workflow flags high-usage components in the risk assessment section of generated PRs. For components with many call sites, the agent can suggest deprecation patterns or gradual migration strategies rather than immediate breaking changes.

### How does agent memory persist between runs?

Context writes to [`.github/agent-memory/narrow-component-props.md`](https://github.com/humanlayer/skills/blob/main/.github/agent-memory/narrow-component-props.md) as Markdown. This file tracks previous decisions, excluded paths, pending refactorings, and team preferences. Commenting `/iterate` on any generated PR appends to this memory, shaping future agent behavior without code changes.