Files
UltimateAgents/docs/Instructions.md
2026-04-16 20:50:38 +02:00

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 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<T> — 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 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.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.
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 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:

  • 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:

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/<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 .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).
  • 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.