14 KiB
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 | Complete feature list, data models, and expected behaviour |
| Architecture.md | System architecture, component relationships, data flow, tech stack decisions |
| 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 — layer boundaries, dependency direction, interface abstractions, deployment model.
- Developer conventions follow Backend-Developer.md — Dapper and SQLite patterns, DI wiring, logging fields, environment config, testing setup.
- Feature behaviour follows 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 (
/// <summary>). - No
objector 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
usingdirectives. - Prefer
recordfor value objects and DTOs. Prefersealed classfor domain entities. - All async methods must be
async Taskorasync Task<T>— neverasync 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)
Domainhas zero NuGet dependencies.Applicationdepends only onDomainand its own interfaces (Application/Interfaces/).Infrastructureimplements those interfaces — it is the only project that references Dapper, the runtime adapter, or the event dispatcher implementation.- Never reference
InfrastructurefromApidirectly for business operations — always go throughApplicationinterfaces.
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 and 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.mdand 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()inCreateTaskCommandbefore persisting any task with aNextTaskId.- Call
DependencyGraph.HasCycle()inCreateGroupCommandbefore persisting any group with aNextGroupId.
- Call
Infrastructure layer
- Implement new interfaces in
UltimateAgents.Infrastructure/. - Add Dapper persistence and SQL schema scripts if the schema changed.
- Include
task_typediscriminator column for specialised task types when adding new persistence.
- Include
- Never pass user-supplied strings directly to
IContainerRuntimeexec 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
ExceptionMiddlewarehandles them.
CLI layer
- Add subcommands in
UltimateAgents.Cli/Commands/usingSystem.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.WriteorDebug.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, andErrorContext(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
Promptcontent atInformationor 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.
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
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 testwith 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
objectcasts without justification. No#pragma warning disablewithout a comment.
6.4 — Architecture Compliance
Verify against Architecture.md:
- Files are in the correct project and directory (entities in
Domain/Entities/, handlers inApplication/, etc.). - Dependency direction is respected — no
InfrastructureorApireferences leaking intoDomain. - 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_typediscriminator for specialised task fields — no polymorphic base DTO. - DTOs are separate from domain entities.
- New interfaces are defined in
Application/Interfaces/, not inInfrastructure.
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 — if feature behaviour or data model changed.
- Architecture.md — if new modules, services, interfaces, or data flows were added.
- 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.mdand 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
- Good:
- If the change is large, include a body explaining why, not just what.
- Branch naming:
feature/<short-description>,fix/<short-description>,chore/<short-description>. - 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 (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
.csprojfiles first. - Never suppress build warnings with
#pragma warning disablewithout a justification comment. - Never hard-code secrets, connection strings, or tokens — use environment variables or
appsettings.json(see Backend-Developer.md § 14). - Never write to
ConsoleorDebugfor 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.