# AI Agent — General Instructions You are an autonomous coding agent working on **UltimateAgents**, an Orchestration Service that assigns and coordinates AI agents to complete tasks inside isolated running containers. This document defines how you operate, what rules you follow, and which workflow you repeat for every task. Read this document completely before starting any work. --- ## 1. Project Context UltimateAgents is a C# / .NET 9 backend system. There is no separate frontend application — the user-facing surface is a CLI tool (`UltimateAgents.Cli`). | Layer | Stack | |---|---| | **API** | ASP.NET Core 9, minimal API + controllers, FluentValidation, JWT Bearer | | **Application** | C# use cases, plain service handlers (commands/queries), hosted background services | | **Domain** | Pure C# 13 entities, value objects, enums — zero framework dependencies | | **Infrastructure** | Dapper, SQLite, in-process C# event dispatcher, local runtime adapter | | **CLI** | System.CommandLine, calls the API over HTTP | Supporting documentation you must know and respect: | Document | Purpose | |---|---| | [features.md](features.md) | Complete feature list, data models, and expected behaviour | | [Architecture.md](Architecture.md) | System architecture, component relationships, data flow, tech stack decisions | | [Backend-Developer.md](Backend-Developer.md) | Developer guidelines, conventions, pitfalls, useful commands | **Always** consult the relevant document before writing code. If your planned change contradicts any rule defined in those documents, the document wins — adjust your approach. --- ## 2. General Rules ### 2.1 Follow the Docs - Every coding convention, naming rule, project structure decision, and library choice is defined in the docs above. Do not deviate. - Architecture decisions follow [Architecture.md](Architecture.md) — layer boundaries, dependency direction, interface abstractions, deployment model. - Developer conventions follow [Backend-Developer.md](Backend-Developer.md) — Dapper and SQLite patterns, DI wiring, logging fields, environment config, testing setup. - Feature behaviour follows [features.md](features.md) — task model, specialised task types, group execution, scheduling types, complexity rules, agent matching, escalation flow. ### 2.2 Write Production-Quality Code - Write code as if it ships today. No TODOs, no placeholders, no half-implementations. - Every public method has explicit C# XML doc comments (`/// `). - No `object` or untyped generics where a proper type can be defined. - No magic numbers or strings — use named constants or enum values. - No dead code, no commented-out blocks, no unused `using` directives. - Prefer `record` for value objects and DTOs. Prefer `sealed class` for domain entities. - All async methods must be `async Task` or `async Task` — never `async void`. ### 2.3 Keep It Small and Focused - One class per file. - One use case per command/query handler. - One service per domain concept. - If a file grows beyond ~200 lines, split it. - Controllers must contain no business logic — delegate immediately to Application services. ### 2.4 Respect the Dependency Direction (Strict) ``` Api → Application → Domain Infrastructure → Application → Domain Cli → Api (via HTTP client only) ``` - `Domain` has zero NuGet dependencies. - `Application` depends only on `Domain` and its own interfaces (`Application/Interfaces/`). - `Infrastructure` implements those interfaces — it is the **only** project that references Dapper, the runtime adapter, or the event dispatcher implementation. - Never reference `Infrastructure` from `Api` directly for business operations — always go through `Application` interfaces. ### 2.5 Never Break Existing Code - Before changing any file, understand what it does and who depends on it. - Run the existing test suite before and after your changes. If tests fail after your change, fix them before moving on. - Do not remove or rename public types, methods, or API endpoints without updating all callers and contracts. ### 2.6 Think Before You Code - Read the task description carefully. If it is ambiguous, check [features.md](features.md) and [Architecture.md](Architecture.md) for clarification. - Plan your changes before writing code. Identify which files are affected, which layers are involved, and what tests are needed. - Prefer the simplest correct solution. Do not over-engineer. --- ## 3. Task Workflow Repeat the following cycle for every task. Do not skip steps. ### Step 1 — Pick a Task - Open `tasks.md` and pick the next unfinished task (highest priority first). - Mark the task as **in progress**. - Read the task description thoroughly. Understand the expected outcome before proceeding. ### Step 2 — Plan Your Steps - Break the task into concrete implementation steps. - Identify which files need to be created, modified, or deleted. - Identify which layers are affected: Domain entity, value object, enum → Application command/query/interface → Infrastructure implementation → API controller/DTO → CLI command. - Identify edge cases and error scenarios. - Write down your plan before touching any code. ### Step 3 — Write Code Follow the checklist for each layer touched: **Domain layer** - Add or update entities, value objects, enums, or domain services in `UltimateAgents.Domain/`. - No framework dependencies — pure C# only. - Enforce invariants in constructors and factory methods. Never expose setters for invariant-protected state. **Application layer** - Add a command or query class and its handler in `UltimateAgents.Application/`. - Define any new repository or runtime interfaces in `Application/Interfaces/`. - Apply `ComplexityEvaluator.Evaluate()` whenever a task is created or its estimate changes. - Call `DependencyGraph.HasCycle()` in `CreateTaskCommand` before persisting any task with a `NextTaskId`. - Call `DependencyGraph.HasCycle()` in `CreateGroupCommand` before persisting any group with a `NextGroupId`. **Infrastructure layer** - Implement new interfaces in `UltimateAgents.Infrastructure/`. - Add Dapper persistence and SQL schema scripts if the schema changed. - Include `task_type` discriminator column for specialised task types when adding new persistence. - Never pass user-supplied strings directly to `IContainerRuntime` exec calls. **API layer** - Add or extend controllers in `UltimateAgents.Api/Controllers/`. - Add request/response DTOs in `Api/Models/` and a FluentValidation validator. - Never add try/catch for domain exceptions in controllers — the global `ExceptionMiddleware` handles them. **CLI layer** - Add subcommands in `UltimateAgents.Cli/Commands/` using `System.CommandLine`. - CLI calls the REST API over HTTP — no direct Application or Infrastructure references. ### Step 4 — Add Logging - Use **Serilog** with structured properties. Never use `Console.Write` or `Debug.Write`. - Log every task state transition, agent assignment, container start/stop, escalation, and retry. - Every log entry for a task/agent event must include: `TaskId`, `AgentId`, `ContainerId`, `Event`, and `ErrorContext` (on error). - Log levels: - `Information` — state transitions, lifecycle events. - `Warning` — retries, recoverable anomalies. - `Error` — escalations, unhandled exceptions, data integrity issues. - `Debug` — detailed internal flow (disabled in production). - **Never** log task `Prompt` content at `Information` or above — it may be sensitive. ### Step 5 — Write Tests - Write tests for every new or changed piece of functionality. - **Domain / Application (unit tests):** xUnit + Moq. No database, no Docker. Mock all interfaces. - **API (integration tests):** xUnit with a local SQLite test database. Test the full HTTP → DB → response cycle. - Test the happy path **and** error/edge cases. - Follow the naming pattern: `MethodName_Scenario_ExpectedResult`. - Coverage targets: - Domain layer: **≥ 90 %** line coverage. - Application layer: **≥ 80 %** line coverage. - API controllers: covered by integration tests. ```bash dotnet test tests/UltimateAgents.Domain.Tests dotnet test tests/UltimateAgents.Application.Tests dotnet test tests/UltimateAgents.Api.Tests ``` ### Step 6 — Review Your Code Run a thorough self-review before considering the task done. #### 6.1 — Build and Static Analysis ```bash dotnet build --no-incremental -warnaserror dotnet format --verify-no-changes ``` - Zero build warnings, zero errors. - Code is correctly formatted (`dotnet format`). #### 6.2 — Test Coverage - Run `dotnet test` with coverage and confirm thresholds are met. - If coverage is below the threshold, write additional tests before proceeding. #### 6.3 — Coding Principles - [ ] **Clean Code** — Meaningful names, small methods, no magic values, guard clauses over deep nesting. - [ ] **Separation of Concerns** — Each class has a single, well-defined responsibility. Layers are not mixed. - [ ] **Single Responsibility Principle** — Every class and method has one reason to change. - [ ] **DRY** — No duplicated logic. Shared behaviour is extracted into domain services or helpers. - [ ] **KISS** — The simplest correct solution is used. No over-engineering. - [ ] **Type Safety** — All types are explicit. No `object` casts without justification. No `#pragma warning disable` without a comment. #### 6.4 — Architecture Compliance Verify against [Architecture.md](Architecture.md): - [ ] Files are in the correct project and directory (entities in `Domain/Entities/`, handlers in `Application/`, etc.). - [ ] Dependency direction is respected — no `Infrastructure` or `Api` references leaking into `Domain`. - [ ] No circular project references. - [ ] No business logic in controllers or CLI commands. - [ ] No Dapper or runtime adapter code outside `Infrastructure`. - [ ] New API endpoints are documented in the route table in `Architecture.md § 5.1` (or update it). - [ ] DTOs use `task_type` discriminator for specialised task fields — no polymorphic base DTO. - [ ] DTOs are separate from domain entities. - [ ] New interfaces are defined in `Application/Interfaces/`, not in `Infrastructure`. #### 6.5 — Security Checklist - [ ] No raw SQL with user input (use Dapper parameterized queries only). - [ ] No user-supplied strings passed to container exec calls. - [ ] No secrets, passwords, or tokens in code or config files. - [ ] All new API endpoints are protected by JWT Bearer authentication. - [ ] All new request models have FluentValidation validators. ### Step 7 — Update Documentation If your change introduces new features, new endpoints, new services, or changes existing behaviour, update the relevant docs: - [features.md](features.md) — if feature behaviour or data model changed. - [Architecture.md](Architecture.md) — if new modules, services, interfaces, or data flows were added. - [Backend-Developer.md](Backend-Developer.md) — if new conventions, pitfalls, or commands are relevant. Keep documentation accurate and in sync with the code. Outdated docs are worse than no docs. ### Step 8 — Mark Task Complete - Open `tasks.md` and mark the task as **done**. - Add a brief summary of what was implemented or changed. ### Step 9 — Commit - Stage all changed files. - Write a commit message in **imperative tense**, max 72 characters for the subject line. - Good: `Add goto task prompt merge in OrchestratorEngine` - Bad: `added stuff` / `WIP` / `fix` - If the change is large, include a body explaining **why**, not just **what**. - Branch naming: `feature/`, `fix/`, `chore/`. - Ensure the commit passes: build, formatter check, all tests. - **Never** push directly to `main` — always use a feature branch and open a pull request. ### Step 10 — Next Task - Return to **Step 1** and pick the next task. --- ## 4. Workflow Summary ``` ┌─────────────────────────────────────────────────┐ │ 1. Pick task from tasks.md │ │ 2. Plan your steps │ │ 3. Write code (Domain → App → Infra → API) │ │ 4. Add structured Serilog logging │ │ 5. Write xUnit tests │ │ 6. Review your code │ │ ├── 6.1 Build -warnaserror / format │ │ ├── 6.2 Test coverage thresholds │ │ ├── 6.3 Coding principles │ │ ├── 6.4 Architecture compliance │ │ └── 6.5 Security checklist │ │ 7. Update documentation if needed │ │ 8. Mark task complete in tasks.md │ │ 9. Git commit on feature branch │ │ 10. Pick next task ──────────── loop ──────┐ │ │ ▲ │ │ │ └──────────────────────────────────┘ │ └─────────────────────────────────────────────────┘ ``` --- ## 5. When You Are Stuck - Re-read the task description and the relevant docs. - Search the existing codebase for similar patterns — follow established conventions before inventing new ones. - Check [Backend-Developer.md § 13](Backend-Developer.md) (Common Pitfalls) — your problem may already be documented. - If a decision is genuinely ambiguous and no document covers it, choose the simplest option that is consistent with existing code and document your reasoning in an XML doc comment. --- ## 6. What You Must Never Do - **Never** commit code that does not build or has compiler errors. - **Never** commit code without tests. - **Never** use libraries not already in the solution or explicitly approved — check existing `.csproj` files first. - **Never** suppress build warnings with `#pragma warning disable` without a justification comment. - **Never** hard-code secrets, connection strings, or tokens — use environment variables or `appsettings.json` (see [Backend-Developer.md § 14](Backend-Developer.md)). - **Never** write to `Console` or `Debug` for operational logging — use Serilog. - **Never** push directly to `main` — always use feature branches. - **Never** skip the review step — sloppy code compounds over time. - **Never** leave a task half-done — finish it or revert it. - **Never** pass user-controlled input directly into container exec calls or raw SQL.