Source profileQuality 93/100

eugenelim/agent-ready-repo/packs/frontend-engineering/.apm/skills/component-contract/SKILL.md

component-contract

Design a UI component's public interface — props/slots/events, controlled vs. uncontrolled ownership, composition patterns, lifecycle contract, and usage documentation — before writing any implementation.

Source repository stars
15
Declared platforms
0
Static risk flags
0
Last source update
2026-08-05
Source checked
2026-08-05

Decision brief

What it does—and where it fits

Load this skill when designing a new shared component — one that will be used by multiple callers in the codebase. Do not load it for one-off components local to a single page; the additional design overhead is not warranted. Load component-contract when:

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/eugenelim/agent-ready-repo --skill "packs/frontend-engineering/.apm/skills/component-contract"
    Safe inspection promptEditorial

    Inspect the Agent Skill "component-contract" from https://github.com/eugenelim/agent-ready-repo/blob/9563bc93aa5b0750b327be2fd95676ff2a5ec63b/packs/frontend-engineering/.apm/skills/component-contract/SKILL.md at commit 9563bc93aa5b0750b327be2fd95676ff2a5ec63b. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Usage documentation template

      Every shared component must ship a usage doc. Minimum viable format:

      Every shared component must ship a usage doc. Minimum viable format:
    2. 02

      Output rendering

      Table — When presenting several items that share the same fields, render a Markdown table. Cap at 5 columns; beyond that, switch to a per-item detail list. Right-align numeric columns. Key–value / one record — For a single record's fields, use an aligned key: value list, not a t…

      Table — When presenting several items that share the same fields, render a Markdown table. Cap at 5 columns; beyond that, switch to a per-item detail list. Right-align numeric columns. Key–value / one record — For a sin…
    3. 03

      The API-first principle

      A component's public interface is its most durable artifact. The implementation changes; the interface is what callers depend on. Once multiple callers depend on a component's props, events, and slots, changing the interface is a breaking change. An interface designed carelessly…

      The interface is the deliverable of this design pass — not the implementation.The interface should be the minimum that satisfies the callers' needsA component's public interface is its most durable artifact. The implementation changes; the interface is what callers depend on. Once multiple callers depend on a component's props, events, and slots, changing the inte…
    4. 04

      Controlled vs. uncontrolled ownership

      Uncontrolled component: the component manages its own state internally. The caller does not control the value; it just receives change notifications.

      Uncontrolled component: the component manages its own state internally. The caller does not control the value; it just receives change notifications.Controlled component: the caller owns the state. The component is a pure rendering function — it displays what it's given and reports changes.The rule for when to support both: provide uncontrolled by default (simpler for most callers), with a controlled override for callers that need to manage state themselves (e.g., when the value must be derived from exter…
    5. 05

      Props design rules

      Review the “Props design rules” section in the pinned source before continuing.

      Review and apply the “Props design rules” source section.

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score93/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars15SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    eugenelim/agent-ready-repo
    Skill path
    packs/frontend-engineering/.apm/skills/component-contract/SKILL.md
    Commit
    9563bc93aa5b0750b327be2fd95676ff2a5ec63b
    License
    Apache-2.0
    Collected
    2026-08-05
    Default branch
    main
    View the original SKILL.md

    Skill: component-contract

    Load this skill when designing a new shared component — one that will be used by multiple callers in the codebase. Do not load it for one-off components local to a single page; the additional design overhead is not warranted. Load component-contract when:

    • Building a new component that will go into a shared UI library or component directory
    • Refactoring a component that has grown multiple callers and its interface is inconsistent
    • Reviewing a component's public interface before it is published or exported

    The contract must be written before any implementation code. An interface designed after the implementation reflects the implementation's needs, not the caller's needs — it is the wrong order.


    Output rendering

    Table — When presenting several items that share the same fields, render a Markdown table. Cap at ~5 columns; beyond that, switch to a per-item detail list. Right-align numeric columns. Key–value / one record — For a single record's fields, use an aligned key: value list, not a two-row table. Rationale / narrative — Use short ## headings and 2–3 sentence paragraphs. Don't force narrative into a table.

    The API-first principle

    A component's public interface is its most durable artifact. The implementation changes; the interface is what callers depend on. Once multiple callers depend on a component's props, events, and slots, changing the interface is a breaking change. An interface designed carelessly at the start becomes technical debt proportional to its adoption.

    The principle has two implications:

    1. The interface is the deliverable of this design pass — not the implementation.
    2. The interface should be the minimum that satisfies the callers' needs today, with room to extend without breaking.

    Controlled vs. uncontrolled ownership

    Uncontrolled component: the component manages its own state internally. The caller does not control the value; it just receives change notifications.

    // Uncontrolled: caller provides an initial value; component manages the rest
    <InputField defaultValue="Initial text" onChange={handleChange} />
    

    Controlled component: the caller owns the state. The component is a pure rendering function — it displays what it's given and reports changes.

    // Controlled: caller owns the value; component is a display layer
    <InputField value={controlledValue} onChange={setValue} />
    

    The rule for when to support both: provide uncontrolled by default (simpler for most callers), with a controlled override for callers that need to manage state themselves (e.g., when the value must be derived from external state, validated before setting, or synchronized with another control).

    The most common pattern: accept both value (controlled) and defaultValue (uncontrolled). When value is provided, operate in controlled mode; when only defaultValue is provided, operate in uncontrolled mode.


    Props design rules

    RuleWrongRightReason
    Name props for what they AREshowModal={true}isOpen={true}show is a verb (what to do); isOpen is a state (what it is)
    Boolean props name the positive statedisabledStateisDisabledDouble negatives (isNotDisabled) are harder to reason about
    Avoid encoding implementationuseFlexLayoutlayout="horizontal"The implementation detail leaks into the API; the caller shouldn't care how layout is achieved
    Prefer composition over configuration<Button showIcon={true} iconName="check"><Button><CheckIcon />Submit</Button>Multiple boolean props that add/configure content make the component harder to extend without changing the API
    Consistent naming conventionMixed on_click, onClick, handleClickAlways on + PascalCase event nameConsistency reduces cognitive load for callers

    Slots and composition patterns

    Default slot (children): the most flexible composition pattern. The caller provides any content they need; the component provides the container and behavior.

    Use the default slot when: the component's job is behavior/wrapper (a modal, a tooltip, a card), not content generation.

    Named slots: when the component has multiple content regions with distinct semantic roles (a card with header, body, and footer; a dialog with title and content).

    In JSX:

    <Card>
      <Card.Header>Card title</Card.Header>
      <Card.Body>Card content goes here.</Card.Body>
      <Card.Footer><Button>OK</Button></Card.Footer>
    </Card>
    

    In Vue / Web Components (explicit slot names):

    <card-component>
      <template slot="header">Card title</template>
      <template slot="body">Card content.</template>
    </card-component>
    

    Render props: a function-as-children pattern that gives the caller control over rendering while the component provides data. Appropriate for components that manage complex state and expose it to the caller for rendering.

    Use render props when: the component manages state the caller needs to render (e.g., a dropdown that tracks open/selected but lets the caller render the options).


    Events contract

    RuleDetail
    Naming: on + PascalCase past-tense eventonChange, onSubmit, onDismiss — not handle_click, not clicked
    Payload shapeDefine the shape of the event payload in the contract. If it carries data (the new value, the selected item), document it explicitly.
    What the component does NOT do after emittingThe component emits the event and stops. It does not optimistically update its own controlled state. The caller owns the state update.
    Avoid emitting raw browser eventsWrap browser events in component-level events with meaningful names. onChange on a text field is a component event; it should not expose the browser's InputEvent object unless the caller genuinely needs browser-level access.

    Lifecycle contract

    Document what the component expects on mount, during its lifetime, and on unmount:

    • On mount: any async operations it initiates (data fetching, subscriptions, DOM measurements). What state is it in before those operations complete?
    • During lifetime: any external dependencies it listens to (context, global stores, DOM resize observers). What happens when those change?
    • On unmount: what it tears down (subscriptions, timers, event listeners). A component that does not clean up its subscriptions on unmount is a memory leak.
    • Strict mode double-invocation: React 18+ strict mode double-invokes useEffect (and the equivalent in other frameworks) in development. Does the component survive a mount/unmount/mount cycle without observable side effects? If not, the lifecycle contract has a bug.

    Usage documentation template

    Every shared component must ship a usage doc. Minimum viable format:

    ## ComponentName
    
    **Purpose:** One sentence describing what this component does and why it exists.
    
    **When to use:** [conditions], not [counter-conditions].
    
    ### Props
    
    | Name | Type | Default | Description |
    |------|------|---------|-------------|
    | `value` | `string` | — | Controlled value. Provide with `onChange` for controlled mode. |
    | `defaultValue` | `string` | `''` | Initial value for uncontrolled mode. |
    | `isDisabled` | `boolean` | `false` | Disables the component; renders `aria-disabled`. |
    | `onChange` | `(value: string) => void` | — | Called on every value change. |
    
    ### Events
    
    | Name | Payload | When it fires |
    |------|---------|--------------|
    | `onChange` | `string` | Every time the user changes the value |
    | `onBlur` | `FocusEvent` | When the component loses focus |
    
    ### Slots
    
    | Name | Required | Description |
    |------|----------|-------------|
    | default | Yes | Content rendered inside the component |
    | `label` | No | If provided, replaces the built-in label element |
    
    ### Accessibility contract
    
    - Manages `aria-disabled` when `isDisabled` is true.
    - Accepts focus via Tab; announces its label to screen readers via `<label>` association.
    - Does not trap focus.
    
    ### Example
    
    [Minimal complete usage example — the smallest correct usage, not a feature tour]
    

    Anti-patterns

    Anti-patternProblemFix
    Prop drilling beyond 2 levelsComponent requires callers to pass the same prop through 3+ levels of nestingExtract a context (React Context, Vue provide/inject) to share the value without threading it through props
    God component (more than one primary job)A component renders a form AND handles data fetching AND manages a modalSplit into two components: one for UI (receives data via props), one for data management (renders the UI component)
    Implicit global state mutationComponent writes to a global store directly rather than emitting an eventThe component emits; the caller (or a coordinating layer) decides whether and how to update global state
    Spreading all props on the root element<div {...props}> passes unknown props to the DOMExplicitly whitelist which props are valid for the root element; spread the rest only if a forwarded-refs pattern is intentional

    Alternatives

    Compare before choosing

    Computed 9732,671

    K-Dense-AI/scientific-agent-skills

    esm

    Use when working directly with the `esm` Python SDK, ESM3 or ESMC model IDs, Forge/Biohub inference clients, or ESMFold2 folding workflows.

    Computed 976

    mgiovani/cc-arsenal

    team-review

    Multi-agent review team: architecture, security, performance, testing, style, docs/UX, plus an adversary that cross-examines the other 6, for security-sensitive, architectural, or large PRs (15+ files) where a single-agent pass risks missing cross-cutting issues. Use for auth/payments/PII changes, schema/pattern changes, compliance sign-off, or when asked to 'get the review team on this' / 'multi-agent review' / 'thorough review before merge'. For a standard PR or a quick pre-merge check, use /r

    Computed 9515

    eugenelim/agent-ready-repo

    work-loop

    Use when implementing or resuming a non-trivial repository change: a feature, behavior-changing fix, refactor, migration, framework or dependency upgrade, schema or API change, performance work, infrastructure or build-system change, reversion, or an existing build spec under `docs/specs/`. Also use for bare continuation commands ('resume', 'continue', 'keep going', 'pick up where I left off', 'let's get going') when conversation or workspace context identifies active build work. Do not use for

    Computed 9438,502

    wshobson/agents

    architecture-decision-records

    Write and maintain Architecture Decision Records (ADRs) following best practices for technical decision documentation. Use when documenting significant technical decisions, reviewing past architectural choices, or establishing decision processes.