agentsclimarketplace

Create infrastructure

Skill anoopsg/agent_rules/src/exclusive/skills/create-infrastructure

Creates new domains in the infrastructure layer using dart_mappable for models, Chopper for networking, and Riverpod for repositories. Use when the user asks to create a repository, API service, data model, or set up new infrastructure components.From its SKILL.md

Install
npx -y skills add anoopsg/agent_rules --skill create-infrastructure

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
  • runs commandsInstructs the agent to run 1 command, including `melos run translate`.

SKILL.md

4.0 KB, 948 tokens by cl100k_base, as published. Nobody here has run it

Infrastructure Creation Skill

This skill defines the process for creating a new domain in the infrastructure/ layer, covering models, networking, and repositories.

1. Directory Structure

Infrastructure is organized by domain in lib/src/infrastructure/:

lib/src/infrastructure/my_domain/
├── models/             # DTOs and Domain Models
│   └── user_model.dart # Uses dart_mappable
├── services/           # Remote API definitions (Chopper)
│   └── my_service.dart
├── my_repository.dart  # Business logic interface
└── my_domain.dart      # Barrel file

2. Data Modeling (dart_mappable)

Always use @MappableClass() for models to get built-in JSON conversion and equality. Models must be immutable.

@MappableClass()
class UserProfile with UserProfileMappable {
  const UserProfile({
    required this.id,
    required this.email,
  });

  final String id;
  final String email;
}

3. Networking (Chopper)

Define API services as abstract classes extending ChopperService. Use apiClient to consume them.

3.1 Define the Service

@ChopperApi()
abstract class MyService extends ChopperService {
  static MyService create([ChopperClient? client]) => _$MyService(client);

  @GET(path: '/profile')
  Future<Response<UserProfile>> getProfile();
}

3.2 Register the Service

Add the service to apiClient in lib/src/infrastructure/_clients/api_client.dart:

@Riverpod(keepAlive: true)
ApiClient apiClient(Ref ref) {
  return ApiClient(
    services: [
      MyService.create(), // Register here
    ],
  );
}

4. Repositories

Repositories bridge the gap between clients (API, Storage) and the Features.

  • Rule: NEVER import from src/features/ into src/infrastructure/.
  • Pattern: Return Result<T, Failure> for operations that can fail.

4.1 Define Error Codes & Failures

Errors are centralized. You must define a technical code and its translation.

  1. Register the Code in lib/src/infrastructure/error_codes.dart:
enum AppErrorCode implements ErrorCode {
  myFeature404('myFeature404'), // Key in i18n
  // ...
}
  1. Add Translations under the errors key in lib/i18n/*.i18n.json for ALL locales:
// en.i18n.json
"errors": {
  "myFeature404": "The requested resource was not found."
}

// ar.i18n.json
"errors": {
  "myFeature404": "لم يتم العثور على المورد المطلوب."
}
  1. Generate Translations: Run the following command to sync the JSON changes with the Dart code:
melos run translate
  1. Define the Failure:
final class MyApiFailure extends Failure {
  const MyApiFailure({super.error}) : super(code: AppErrorCode.myFeature404);
}

4.2 Implementation

class MyRepository {
  MyRepository({required MyService service}) : _service = service;
  final MyService _service;

  Future<Result<UserProfile, Failure>> getProfile() async {
    try {
      final response = await _service.getProfile();
      if (response.isSuccessful) return Ok(response.body!);
      return Err(MyApiFailure(error: response.error));
    } catch (e) {
      return Err(MyApiFailure(error: e));
    }
  }
}

5. Riverpod Integration

Provide the repository via a global provider. Obtain the required service from the apiClientProvider.

@Riverpod(keepAlive: true)
MyRepository myRepository(Ref ref) {
  final service = ref.watch(apiClientProvider).getService<MyService>();
  return MyRepository(service: service);
}

6. Persistence

Use StorageClient for general persistence or SecureStorageClient for sensitive data (tokens). Always use AppKeys for storage keys.

final storage = ref.watch(storageClientProvider);
await storage.write(AppKeys.settings, 'value');

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.