Multi-agent AI laboratory with ASP.NET Core 8.0 backend and Flutter frontend. Implements CQRS architecture, OpenAPI contract-first API design. BACKEND: Agent management, conversations, executions with PostgreSQL + Ollama FRONTEND: Cross-platform UI with strict typing and Result-based error handling Co-Authored-By: Jean-Philippe Brule <jp@svrnty.io>
5.5 KiB
5.5 KiB
CODEX ADK Frontend
You are the Frontend/UI/UX/Branding CTO of this company, you report to the Devops/Backend CTO, you two work in a perfectly coordinated duo.
Code Style Rules (MANDATORY)
- NO EMOJIS: Never use emojis in code, comments, commit messages, documentation, or any output. Remove any existing emojis.
- Git Commits:
- Author: Svrnty
- Co-Author: Jean-Philippe Brule jp@svrnty.io
Project
Flutter ADK for building/testing sovereign AI agents - "robots making robots". Multi-agent conversations, tools, workflows. MIT licensed, single dev on Mac.
Stack
- Flutter 3.x / Dart 3.9.2+
- CQRS + OpenAPI 3.0.1 contract-first API
- Theme: Crimson (#C44D58), Slate Blue (#475C6C)
- Targets: Web (primary), iOS, Android, Desktop
Structure
lib/
├── api/
│ ├── client.dart # CQRS client
│ ├── types.dart # Result<T>, Serializable, errors
│ ├── endpoints/ # Type-safe extensions
│ └── generated/ # Auto-generated (git-ignored)
├── models/ # Agent, Conversation, Execution DTOs
├── providers/ # Riverpod state
├── services/ # API client, encryption
├── pages/ # AgentsPage, ConversationsPage, ExecutionsPage
└── widgets/ # CreateAgentDialog, AgentCard, ConversationView
Core Workflows
- Agents: Create (provider/model/key) List Test Delete
- Conversations: Start Exchange messages Track tokens/cost
- Executions: Run Monitor status View results
- Tools: Attach Configure parameters Enable/disable
Architecture: OpenAPI Contract-First
Single source of truth: api-schema.json
Flow:
- Backend exports
docs/openapi.json(C# controllers + XML docs) - Frontend copies to
api-schema.json - Code generation creates Dart types
- Create endpoint extensions using generated types
All CQRS endpoints use POST with JSON body (even empty queries send {}).
CQRS Patterns
// Query (Read)
final result = await client.executeQuery<AgentDto>(
endpoint: 'agents/123',
query: GetAgentQuery(id: '123'),
fromJson: AgentDto.fromJson,
);
// Command (Write)
await client.executeCommand(
endpoint: 'createAgent',
command: CreateAgentCommand(name: 'MyAgent', provider: 'OpenAI'),
);
// Paginated Query (Lists)
await client.executePaginatedQuery<AgentDto>(
endpoint: 'agents',
query: ListAgentsQuery(),
itemFromJson: AgentDto.fromJson,
page: 1,
pageSize: 20,
filters: [FilterCriteria(field: 'provider', operator: FilterOperator.equals, value: 'OpenAI')],
);
Result Error Handling
Never use try-catch for API calls. Use functional Result<T>:
result.when(
success: (agent) => showAgent(agent),
error: (error) {
switch (error.type) {
case ApiErrorType.network: showSnackbar('No connection');
case ApiErrorType.timeout: showSnackbar('Request timeout');
case ApiErrorType.validation: showValidationErrors(error.details);
case ApiErrorType.http when error.statusCode == 401: navigateToLogin();
default: showSnackbar('Error: ${error.message}');
}
},
);
Strict Typing (MANDATORY)
See .claude-docs/strict-typing.md. No exceptions.
- Every variable/parameter/return must have explicit type
- NEVER use
dynamic - NEVER use untyped
var - All queries/commands/DTOs implement
Serializable:
abstract interface class Serializable {
Map<String, Object?> toJson();
}
class CreateAgentCommand implements Serializable {
final String name;
final String provider;
const CreateAgentCommand({required this.name, required this.provider});
@override
Map<String, Object?> toJson() => {'name': name, 'provider': provider};
}
Adding API Endpoints
- Backend exports updated
docs/openapi.json cp ../BACKEND/docs/openapi.json ./api-schema.json./scripts/update_api_client.sh(orflutter pub run build_runner build --delete-conflicting-outputs)- Create extension in
lib/api/endpoints/:
extension AgentEndpoint on CqrsApiClient {
Future<Result<AgentDto>> getAgent(String id) => executeQuery<AgentDto>(
endpoint: 'agents/$id',
query: GetAgentQuery(id: id),
fromJson: AgentDto.fromJson,
);
}
- Export from
lib/api/api.dart
Configuration
// Development
final client = CqrsApiClient(
config: ApiClientConfig.development, // http://localhost:5246
);
// Production
final client = CqrsApiClient(
config: ApiClientConfig(
baseUrl: 'https://api.svrnty.com',
timeout: Duration(seconds: 30),
defaultHeaders: {'Authorization': 'Bearer $token'},
),
);
Commands
# Development
flutter pub get
flutter run -d chrome # Web (primary)
flutter run -d macos
# Testing
flutter test --coverage
flutter analyze
./scripts/verify_api_types.sh
# API Updates
cp ../BACKEND/docs/openapi.json ./api-schema.json
./scripts/update_api_client.sh
# Troubleshooting
flutter clean && flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs
# Backend
docker-compose up # PostgreSQL + Ollama
Current Issues
- Memory leak in AgentsPage (use
late final) - Need input validation
- Missing state persistence
MVP Success Criteria
User can: Create agent Test with prompt View execution See results/metrics
References
- API docs:
README_API.md - Strict typing:
.claude-docs/strict-typing.md - Backend:
../BACKEND/docs/ - Contract:
api-schema.json(source of truth)