agentleFS
moasqmoasq/ios-dev-agent/.agents/skills/feedback-states/SKILL.md

feedback-states

Skill4 starsChanged 6 months agoMITView on GitHub

Use when implementing loading, error, empty, or success states. Covers Loadable switch handling, mutation buttons, loading indicators.

The file

We split this skill into the rules it gives an agent

11 rules. About 0 are common, 8 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈8

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this guide when implementing loading, error, empty, and success states.

    line 8
  2. Very specific:

    Every view displaying async data MUST switch on Loadable<T>:

    line 11
  3. Very specific:

    NEVER use if let to unwrap only success — all 4 states must be handled.

    line 31
  4. Distinctive:

    Every mutation button (save, delete) MUST disable while loading and show inline spinner:

    line 34
  5. Distinctive:

    Always provide a retry path — never leave users stuck.

    line 62
  6. Distinctive:

    NEVER use modal alert for success — too disruptive

    line 67
  7. Distinctive:

    Always explain WHY disabled (caption text below button)

    line 71
  8. Distinctive:

    Don't hide actions — show them disabled with explanation

    line 72
  9. Distinctive:

    ALWAYS disable triggering button while loading

    line 76
  10. Distinctive:

    Never block entire UI for partial operation — use inline spinner

    line 77
  11. Very specific:

    Use Loadable<T> for all async state — never var isLoading: Bool

    line 78

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Feedback States

Use this guide when implementing loading, error, empty, and success states.

MANDATORY: Handle All 4 Loadable States

Every view displaying async data MUST switch on Loadable<T>:

switch viewModel.items {
case .notInitiated, .loading:
    ProgressView("Loading...")
case .success(let items) where items.isEmpty:
    ContentUnavailableView("No Items Yet", systemImage: "tray",
        description: Text("Tap + to create your first item"))
case .success(let items):
    List(items) { item in ItemRow(item: item) }
case .failure(let error):
    ContentUnavailableView {
        Label("Load Failed", systemImage: "exclamationmark.triangle")
    } description: {
        Text(error.localizedDescription)
    } actions: {
        Button("Retry") { Task { await viewModel.loadItems() } }
    }
}

NEVER use if let to unwrap only success — all 4 states must be handled.

Mutation Button Pattern

Every mutation button (save, delete) MUST disable while loading and show inline spinner:

Button {
    Task { await viewModel.save() }
} label: {
    if viewModel.saveState.isLoading {
        ProgressView().controlSize(.small)
    } else {
        Text("Save")
    }
}
.disabled(viewModel.saveState.isLoading)

Loading Patterns

PatternUse CaseCode
Inline spinnerButton actionProgressView().controlSize(.small)
Full-screenInitial loadProgressView("Loading...")
Pull-to-refreshList refresh.refreshable { await refresh() }
SkeletonContent placeholder.redacted(reason: .placeholder)
OverlayBlocking operation.overlay { if loading { ProgressView() } }

Error Handling UI

  1. Inline validation — show immediately below form fields
  2. Alert — for blocking errors (network failure, permission denied)
  3. Banner — for non-critical errors (sync failed, partial data)

Always provide a retry path — never leave users stuck.

Success Feedback

  • Haptic: UINotificationFeedbackGenerator().notificationOccurred(.success)
  • Visual: brief animation (checkmark, scale bounce)
  • NEVER use modal alert for success — too disruptive

Disabled State

  • .disabled(condition) — SwiftUI auto-handles opacity
  • Always explain WHY disabled (caption text below button)
  • Don't hide actions — show them disabled with explanation

Rules

  • Show indicator for operations > 300ms
  • ALWAYS disable triggering button while loading
  • Never block entire UI for partial operation — use inline spinner
  • Use Loadable<T> for all async state — never var isLoading: Bool

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.