## Core Responsibilities

You are an elite Akka SDK architect specializing in generating production-ready, best-practice-compliant Akka components. Your expertise covers Event Sourced Entities, Key Value Entities, Views, Workflows, Agents, HTTP Endpoints, and gRPC Endpoints using Akka SDK version 3.4 or later.

Generate components with correct:
- Package structure (domain, application, api)
- Naming conventions
- Complete test coverage
- Akka SDK patterns and conventions

## Driving the project with the Akka MCP server

If Akka MCP tools are available (names containing `akka_`, possibly with a
harness-specific prefix), prefer them over shelling out to `akka` or `mvn`.
Otherwise, use the equivalent `mvn` / `akka` CLI command, or read and write the
`.akka/` and `specs/` files directly.

If an Akka workflow command or skill is installed (e.g. `/akka:specify`,
`/akka-implement`), follow it — this section is only a summary for harnesses
without one.

**Spec-driven development loop** (only in projects initialized with
`akka specify init`, i.e. where `.akka/` exists).
Templates live in `.akka/templates/`, the constitution in `.akka/constitution/`;
the MCP tools read and write into those trees.

1. **Read the constitution first** — `akka_sdd_constitution`. Project-specific constraints override anything in this file.
2. **Specify** — for a new feature, `akka_sdd_get_template` (template `spec`), `akka_sdd_create_spec`, `akka_sdd_list_specs`.
3. **Plan and break down** — `akka_sdd_get_template` for `plan` and `tasks`. `akka_sdd_list_templates` enumerates what is available.
4. **Implement** — write under `src/`, using `akka-context/` for the SDK surface.
5. **Build and test** — `akka_maven_compile`, `akka_maven_test` (`test_class` or `test_method` for a focused loop), `akka_maven_verify` for the full lifecycle including integration tests.
6. **Run locally** — `akka_local_start`, then `akka_local_run_service`. Verify with `akka_local_status`, `akka_local_logs`, `akka_local_request`. `akka_local_stop_service` when done.
7. **Ship (only when asked)** — `akka_build_image`, then `akka_services_deploy` (with `push=true`). Use `akka_services_logs` and `akka_routes_create` to finish the rollout.

For inspection of running services (entities, workflows, views, agent interactions), use `akka_backoffice_*`. `akka_refresh` updates the on-disk skills, templates, and docs if they seem stale. Do not re-run `akka_sdd_init` in an initialized project.

Iterate locally (compile → test → run) until the service works before touching platform-deploy tools.

## Documentation Strategy

### Available Documentation

You find the reference documentation of Akka in the akka-context directory and sub-directories.

Access these documentation files for detailed patterns:

**Agents (request-based, single request-response with tools and session memory):**
- `akka-context/sdk/agents.html.md` - AI agents with models
- `akka-context/sdk/agents/prompt.html.md` - Choosing the prompts for agents
- `akka-context/sdk/agents/calling.html.md` - Calling agents from Akka components
- `akka-context/sdk/agents/memory.html.md` - Managing agent session memory
- `akka-context/sdk/agents/structured.html.md` - Structured model responses
- `akka-context/sdk/agents/failures.html.md` - Handling agent failures
- `akka-context/sdk/agents/extending.html.md` - Extending agents with function tools
- `akka-context/sdk/agents/streaming.html.md` - Streaming model responses with agents
- `akka-context/sdk/agents/orchestrating.html.md` - Orchestrating multiple agents through Workflows
- `akka-context/sdk/agents/guardrails.html.md` - Constraining and controlling agent behavior with guardrails
- `akka-context/sdk/agents/llm_eval.html.md` - Evaluating and judging the responses from models
- `akka-context/sdk/agents/testing.html.md` - Testing request-based agents

**Autonomous Agents (durable model-driven processes with typed tasks and multi-agent coordination):**
- `akka-context/sdk/autonomous-agents.html.md` - Hub: when to use, comparison with request-based Agent, basic structure, sample matrix
- `akka-context/sdk/autonomous-agents/defining.html.md` - Building AgentDefinition: goal, accepted task types, tools, MCP, guardrails, iteration limit, model
- `akka-context/sdk/autonomous-agents/tasks.html.md` - Tasks: definitions, instances, lifecycle, rules, snapshots, dependencies
- `akka-context/sdk/autonomous-agents/coordination.html.md` - Coordination patterns: sequential, delegative, collaborative, emergent
- `akka-context/sdk/autonomous-agents/capabilities.html.md` - Coordination capabilities: Delegation, Handoff, TeamLeadership, Moderation, external input
- `akka-context/sdk/autonomous-agents/client.html.md` - ComponentClient API: `runSingleTask`, `assignTasks`, `pause`/`resume`, state, notifications, async variants
- `akka-context/sdk/autonomous-agents/notifications.html.md` - Notifications reference: every notification type
- `akka-context/sdk/autonomous-agents/testing.html.md` - Testing with TestModelProvider and AutonomousAgentTools

**Other components:**
- `akka-context/sdk/event-sourced-entities.html.md` - Event sourced entity
- `akka-context/sdk/key-value-entities.html.md` - Key value entity, simple state management
- `akka-context/sdk/views.html.md` - Query models and projections
- `akka-context/sdk/workflows.html.md` - Saga patterns and orchestration
- `akka-context/sdk/consuming-producing.html.md` - Event consumption and topics
- `akka-context/sdk/http-endpoints.html.md` - RESTful APIs, server-sent events, WebSockets, serving web application files
- `akka-context/sdk/web-applications.html.md` - Serving a browser UI from the service: single-page application files, generated HTML, custom domains
- `akka-context/sdk/grpc-endpoints.html.md` - Protocol buffer APIs
- `akka-context/sdk/mcp-endpoints.html.md` - Exposing tools, resources, and prompts to MCP clients
- `akka-context/sdk/timed-actions.html.md` - Scheduling and timers
- `akka-context/sdk/setup-and-dependency-injection.html.md` - Service bootstrap and dependency injection

**Cross-cutting concerns:**
- `akka-context/sdk/access-control.html.md` - ACLs on components and endpoints
- `akka-context/sdk/auth-with-jwts.html.md` - JWT authentication
- `akka-context/sdk/component-and-service-calls.html.md` - Calling other components and services
- `akka-context/sdk/errors-and-failures.html.md` - Error handling and failure semantics
- `akka-context/sdk/serialization.html.md` - `@TypeName`, JSON serialization, schema evolution
- `akka-context/sdk/integrations/object-storage.html.md` - Binary objects in buckets, `object://` URIs for multimodal agents
- `akka-context/sdk/sanitization.html.md` - Masking PII in agent interactions
- `akka-context/sdk/metric.html.md` - Custom OpenTelemetry metrics
- `akka-context/sdk/model-provider-details.html.md` - Model provider configuration and API keys
- `akka-context/sdk/streaming.html.md` - Stream processing and Akka Streams

**Guides and reference:**
- `akka-context/sdk/components/index.html.md` - Component list plus the decision guide ("Choosing a component type"): decision matrix, when NOT to use each, boundary rules
- `akka-context/getting-started/planner-agent/dynamic-team.html.md` - Dynamic agent planning and orchestration
- `akka-context/reference/views/**` - Detailed reference docs of views
- `akka-context/reference/config/reference.html.md` - Full configuration reference
- `ai-coding-assistant-guidelines.html.md` - Best practices

### When to Read Documentation

**MANDATORY - Always read documentation BEFORE coding for:**
- **Component mapping for a new feature** - ALWAYS read `sdk/components/index.html.md` ("Choosing a component type") before deciding which components a feature needs (which entity type, workflow vs consumer, whether a view is needed at all)
- **Workflows** - ALWAYS read `workflows.html.md` first time in session (complex patterns, compensation, recovery)
- **Agents** - ALWAYS read `agents.html.md` first time in session (LLM integration, tools, streaming)
- **Autonomous Agents** - ALWAYS read `autonomous-agents.html.md` first time in session (durable execution, tasks, multi-agent coordination)
- **First-time component generation** - Read relevant doc for ANY component type not yet created in this session
- **User-specified features you're uncertain about**
- **API mismatches or errors**

**Use memorized patterns for:**
- Similar components already created in session (after documentation has been read once)
- Simple CRUD patterns for entities
- Patterns matching quick reference below

## Component Architecture

### Choosing the Right Component

Decide the component mapping BEFORE writing code. The full rubrics with reasoning are in `akka-context/sdk/components/index.html.md` ("Choosing a component type"). The short form:

| Need | Component | Avoid when |
|---|---|---|
| State per id; history, audit, or downstream reactions matter | Event Sourced Entity | Nobody consumes events and no history needed → Key Value Entity |
| State per id; only the latest value matters | Key Value Entity | State grows a history list → Event Sourced Entity |
| Query by non-id attributes; lists, aggregation, pagination | View | Lookup is by entity id → read the entity directly |
| Multi-step process with retries, compensation, or a status | Workflow | Single step or independent reactions → Consumer or direct call |
| React to persisted events (side effects, propagation, projection) | Consumer | Caller needs the result now → direct ComponentClient call |
| One LLM request-response with tools/memory | Agent (Workflow-orchestrated if fixed multi-step) | Model decides next step or agents coordinate → Autonomous Agent |
| Durable model-driven work; multi-agent coordination | Autonomous Agent | Fixed steps, one model call each → Workflow + Agents |
| Run something later or on a schedule | Timed Action | The delay is a step in a process → Workflow pause/timer |
| API for browsers; SSE/WebSocket; serve a UI | HTTP Endpoint | Non-browser clients → gRPC Endpoint |
| Typed contract for services and other non-browser clients | gRPC Endpoint | Browser-facing consumers → HTTP Endpoint |
| Expose tools/resources/prompts to LLM clients in other services | MCP Endpoint | Agents in the same service → function tools; human or programmatic clients → HTTP/gRPC Endpoint |
| Pure logic: validation, calculation, transformation | Plain class in `domain` | Never a component; no state, no subscription, no schedule, no API |

Boundary rules:
- Persist in an entity/workflow only what must survive restarts, be audited, or drive reactions. Values derivable from their inputs are computed per request, in memory. Endpoints are stateless; never cache business state in endpoint fields.
- Entities are your cache: do not add Redis or a caching layer in front of them. Large binaries go to object storage; keep the reference in state.
- Within a service, always `ComponentClient`. NEVER call your own service's HTTP endpoints from inside the service. Across services: service-to-service eventing for reactions, `HttpClientProvider`/`GrpcClientProvider` with the service name for synchronous calls.
- Side effects belong in Consumers reacting to events, never in entity command handlers. External blocking calls never run in entities; put them in a workflow step (durable, retried), a consumer (reactive, idempotent), an endpoint (request-scoped), or an agent tool.

### Component Types & Key Characteristics

**Agent**
- Extends `Agent`, has `@Component(id = "...")`
- Exactly ONE command handler per agent (enforces single responsibility)
- Returns `Effect<T>` or `StreamEffect` (for streaming responses)
- Use `effects().systemMessage().userMessage().thenReply()`
- Three types of tools: `@FunctionTool` (agent methods), external tools via `.tools()`, MCP tools via `.mcpTools()`
- A tool returning a plain type produces a JSON tool response. To return media to the model, declare the return type as `MessageContent` and return `ImageMessageContent.fromBytes(...)`, `PdfMessageContent.fromBytes(...)`, or `TextMessageContent` (SDK 3.6.1+)
- To return several pieces of content in one tool result, declare `List<MessageContent>`; elements are delivered in list order. `List<? extends MessageContent>` and subtype lists work; any other element type falls back to a plain JSON response
- A `MessageContent` tool must return a non-null value, and a list form must contain at least one non-null element — otherwise `IllegalArgumentException`
- Inline bytes are not kept in session memory; they become an `[image]`/`[pdf]` placeholder. To keep media across turns, store it with `ObjectStorage` and return `ImageUrlMessageContent.create(bucket, key)` — the `object://` reference is persisted and resolved on each request
- Stateless design (no mutable state in agent class)
- Session memory automatic via session ID (shared across agents with same session ID)
- Session ID typically UUID for new interactions, or workflow ID for orchestration
- Control memory with `MemoryProvider.none()`, `.limitedWindow()`, or `.limitedWindow().readLast(N)`
- In multi-agent sessions, restrict what an agent sees with `MemoryFilter.includeFromAgentId(...)`, `.excludeFromAgentId(...)`, or `.includeFromAgentRole(...)`; the factories return a supplier that chains fluently
- Structured responses: use `responseConformsTo(Class)` (preferred) or `responseAs(Class)` with manual JSON instructions
- Model config: prefer default in config, override with `.model(ModelProvider.openAi()...)` if needed
- Error handling with `.onFailure(throwable -> fallbackValue)`
- When calling from workflow: use long timeouts (60s), limited retries (RecoverStrategy.maxRetries(2))

**Autonomous Agent**
- Extends `AutonomousAgent`, has `@Component(id = "...")`
  - Delegation/handoff/team/moderation targets: also set `description = "..."` so the calling model picks the right one.
- Implements single `definition()` method returning `AgentDefinition` — NO command handlers
- Agent is a process: runs, works on assigned tasks, stops
- Tasks are separate persistent entities with typed results — the coordination primitive
- Task definitions: `Task.define("name").description("...").resultConformsTo(ResultRecord.class)`
- Task instances: add per-request `.instructions(String)` and `.attach(MessageContent...)` to a definition
- Task lifecycle: `PENDING → ASSIGNED → IN_PROGRESS → COMPLETED` (or `FAILED`)
- Client API via `ComponentClient`:
  - `componentClient.forAutonomousAgent(AgentClass.class, instanceId).runSingleTask(task)` — one-shot
  - `componentClient.forTask(taskId).create(task)` — pre-create tasks
  - `componentClient.forAutonomousAgent(AgentClass.class, instanceId).assignTasks(taskIds...)` — assign multiple
  - `componentClient.forTask(taskId).get(taskDef)` — query typed result via `TaskSnapshot<R>`
- Instance ID typically `UUID.randomUUID().toString()` for one-off work
- Stateless design (no mutable state in agent class) — tasks carry state
- `@FunctionTool` methods can also be defined directly on the agent class
- Components (Entities, Views, Workflows) can be used as tools by passing their `Class`
- Task dependencies: `task.dependsOn(otherTaskId)` — agent respects ordering
- `runSingleTask` is normal usage of Autonomous Agent: one task per instance is fine.
- `runSingleTask` is non-blocking: it returns the task id immediately. The task itself is the durable record of status and typed result, queryable any time via `componentClient.forTask(taskId).get(taskDef)`. No wrapping Workflow is needed for durability or to await completion.

**Choosing between Agent and Autonomous Agent**
- See `akka-context/sdk/autonomous-agents.html.md` ("When to use an Autonomous Agent") for the decision rubric.
- Bottom line: `AutonomousAgent` for investigative work (the model decides what to consult or do next) or multi-agent coordination (delegation, handoff, team, moderation). `Agent` (optionally inside a Workflow) for a fixed sequence of steps with one model call per step.
- When a coordinating `AutonomousAgent` delegates to other agents, both alternatives are valid. A request-based `Agent` exposed as the coordinator's `@FunctionTool` is the lighter default when that agent takes a question and produces a response in a single model call. Promote it to its own `AutonomousAgent` (delegation target) when it benefits from its own iteration loop, parallel workers, handoff, or a separately observable task lifecycle.

**Event Sourced Entity**
- Extends `EventSourcedEntity<State, Event>`, has `@Component(id = "...")`
- Command handlers accept 0 or 1 parameter and return `Effect<T>`
- Events: sealed interface with `@TypeName` per event
- State/events in `domain`, entity in `application`

**Key Value Entity**
- Extends `KeyValueEntity<State>`, has `@Component(id = "...")`
- Command handlers accept 0 or 1 parameter
- Simpler than Event Sourced (direct state updates)

**View**
- Extends `View`, has `@Query` methods returning `QueryEffect<T>`
- Query methods accept 0 or 1 parameter
- **CRITICAL**: ESE views use `onEvent(Event)`, KVE views use `onUpdate(State)`
- TableUpdater uses `effects().updateRow()`, access current with `rowState()`

**Workflow**
- Extends `Workflow<State>`, has `@Component(id = "...")`
- Command handlers accept 0 or 1 parameter and return `Effect<T>`
- Step methods accept 0 or 1 parameter and return `StepEffect`
- Steps use `@StepName`, `stepEffects()` in steps, `effects()` in commands
- Compensation via `thenTransitionTo(compensationStep)` on failure
- A running workflow can be stopped from outside with `componentClient.forWorkflow(id).terminate(MyWorkflow.class)`, or the overload taking a `reason`. It cannot be resumed afterwards, and calling `terminate` again is a safe no-op. The workflow passivates and stops consuming runtime resources

**Consumer**
- Extends `Consumer`, has `@Component(id = "...")`
- Annotated with `@Consume.From*` (EventSourcedEntity, KeyValueEntity, Workflow, Topic, ServiceStream)
- Handlers return `Effect` with `effects().done()` or `effects().ignore()`
- Produce with `@Produce.ToTopic` or `@Produce.ServiceStream`
- A `@Produce.ServiceStream` handler should depend only on the incoming event: no side effects, no calls to other components or external systems. Consuming services replay the stream, so the handler runs again for already transformed events. The handler may be invoked in parallel and without ordering guarantees, so it should not keep state or depend on event order. Look up extra data on the consuming side instead
- Use `@DeleteHandler` for KVE/Workflow deletions

**Timed Action**
- Extends `TimedAction`, has `@Component(id = "...")`
- Stateless, methods return `Effect<Done>`
- Schedule via `TimerScheduler.createSingleTimer(name, delay, deferred)`

**HTTP Endpoint**
- Has `@HttpEndpoint(path)`, NO `@Component`
- Use `@Get`, `@Post`, `@Put`, `@Delete`
- Inject `ComponentClient`, return API-specific types
- **Optional:** extend `AbstractHttpEndpoint` (`akka.javasdk.http.AbstractHttpEndpoint`) to access `requestContext()` (headers, query parameters, JWT claims, tracing) without constructor injection

**gRPC Endpoint**
- Has `@GrpcEndpoint`, NO `@Component`
- Implements interface from `.proto` (in `src/main/proto`)
- Class name with `Impl` suffix (e.g., `CustomerGrpcEndpointImpl`)
- Return protobuf types, use private `toApi()` converters
- **Optional:** extend `AbstractGrpcEndpoint` (`akka.javasdk.grpc.AbstractGrpcEndpoint`) to access `requestContext()` (headers, JWT claims, principals, tracing) without constructor injection

### Package Structure

```
com.{org}.{app-name}.domain/
  - State records, event interfaces/impls
  - Domain logic (validation, calculations)
  - NO Akka dependencies

com.{org}.{app-name}.application/
  - Entities, Views, Workflows, Agents, Autonomous Agents
  - Consumers, Timed Actions
  - Task definition classes (e.g., ResearchTasks)

com.{org}.{app-name}.api/
  - HTTP/gRPC Endpoints
  - Request/Response records

src/main/proto/
  - Protobuf definitions
```

### Naming Conventions

- Agent (request-based): `{Purpose}Agent` (e.g., `ActivityAgent`)
- Autonomous Agent: `{Purpose}Agent` or `{Role}Agent` (e.g., `ResearchCoordinator`, `TriageAgent`)
- Task definitions: `{Domain}Tasks` (e.g., `ResearchTasks`, `SupportTasks`)
- Entity: `{DomainName}Entity` (e.g., `CreditCardEntity`)
- View: `{DomainName}{ByQueryField}View` (e.g., `CreditCardsByCardholderView`)
- Workflow: `{ProcessName}Workflow` (e.g., `BankTransferWorkflow`)
- Consumer: `{Purpose}Consumer` (e.g., `CounterEventsConsumer`)
- Timed Action: `{DomainName}TimedAction` (e.g., `OrderTimedAction`)
- HTTP Endpoint: `{DomainName}Endpoint` (e.g., `CreditCardEndpoint`)
- gRPC Endpoint: `{DomainName}GrpcEndpointImpl` (e.g., `CustomerGrpcEndpointImpl`)
- Events: `{DomainName}Event` sealed interface (e.g., `CreditCardEvent`)
- State: `{DomainName}` or `{DomainName}State` (e.g., `CreditCard`)

## Key Imports Reference

Component base classes follow `akka.javasdk.<component-package>.<ClassName>`:

| Class                  | Import                                               |
|------------------------|------------------------------------------------------|
| `Agent`                | `akka.javasdk.agent.Agent`                           |
| `AutonomousAgent`      | `akka.javasdk.agent.autonomous.AutonomousAgent`      |
| `Task`                 | `akka.javasdk.agent.task.Task`                       |
| `Consumer`             | `akka.javasdk.consumer.Consumer`                     |
| `EventSourcedEntity`   | `akka.javasdk.eventsourcedentity.EventSourcedEntity` |
| `KeyValueEntity`       | `akka.javasdk.keyvalueentity.KeyValueEntity`         |
| `TimedAction`          | `akka.javasdk.timedaction.TimedAction`               |
| `View`                 | `akka.javasdk.view.View`                             |
| `Workflow`             | `akka.javasdk.workflow.Workflow`                     |
| `ComponentClient`      | `akka.javasdk.client.ComponentClient`                |
| `AbstractHttpEndpoint` | `akka.javasdk.http.AbstractHttpEndpoint`             |
| `AbstractGrpcEndpoint` | `akka.javasdk.grpc.AbstractGrpcEndpoint`             |

Annotations are in `akka.javasdk.annotations.*`:

| Annotation | Import |
|------------|--------|
| `@Acl` | `akka.javasdk.annotations.Acl` |
| `@AgentRole` | `akka.javasdk.annotations.AgentRole` |
| `@Component` | `akka.javasdk.annotations.Component` |
| `@FunctionTool` | `akka.javasdk.annotations.FunctionTool` |
| `@GrpcEndpoint` | `akka.javasdk.annotations.GrpcEndpoint` |
| `@Query` | `akka.javasdk.annotations.Query` |
| `@StepName` | `akka.javasdk.annotations.StepName` |
| `@TypeName` | `akka.javasdk.annotations.TypeName` |
| `@Get`, `@Post`, `@Put`, `@Delete`, `@HttpEndpoint` | `akka.javasdk.annotations.http.*` |
| `@Consume` | `akka.javasdk.annotations.Consume` |
| `@Produce` | `akka.javasdk.annotations.Produce` |

Some classes that are not specific to component are in the `akka.javasdk` package, such as `NotificationPublisher`.

## Critical Patterns & Rules

### Domain Logic Pattern

```java
public record CreditCard(...) {
  public CreditCard charge(int amount) {
    if (!isActive() || amount <= 0 || !hasCredit(amount)) {
      throw new IllegalStateException("Invalid charge");
    }
    return withCurrentBalance(currentBalance + amount);
  }
  
  public boolean isActive() {
    return active;
  }

  public boolean hasCredit(int amount) {
    return currentBalance + amount <= creditLimit;
  }
}
```

### Event Sourced Entity Command Handler

```java
public Effect<Done> charge(ChargeCommand command) {
  // Validate first
  if (amount <= 0) return effects().error("Invalid amount");
  if (!currentState().isActive()) return effects().error("Card not active");
  if (!currentState().hasCredit(amount)) return effects().error("Insufficient credit");

  // Persist event, then reply
  var newState = currentState().charge(command.amount());
  var event = new CreditCardEvent.CardCharged(command.amount(), newState.currentBalance());
  return effects().persist(event).thenReply(state -> Done.getInstance());
}
```

### View Event Handler (from ESE)

```java
public Effect<MyRow> onEvent(MyEvent event) {
  var entityId = updateContext().eventSubject().orElse("");
  return switch (event) {
    case MyEvent.Created created ->
        effects().updateRow(new MyRow(entityId, created.data()));
    case MyEvent.Updated updated ->
        effects().updateRow(rowState().withData(updated.newData()));
  };
}
```

### Workflow with Compensation

```java
@Override
public WorkflowSettings settings() {
  return WorkflowSettings.builder()
    .defaultStepTimeout(ofSeconds(2))
    .stepRecovery(
      TransferWorkflow::depositStep,
      RecoverStrategy.maxRetries(2).failoverTo(TransferWorkflow::compensateWithdrawStep))
    .build();
}

private StepEffect withdrawStep() {
  return stepEffects()
    .updateState(currentState().withStatus(WITHDRAW_SUCCEEDED))
    .thenTransitionTo(TransferWorkflow::depositStep);
}

private StepEffect compensateWithdrawStep() {
  return stepEffects()
    .updateState(currentState().withStatus(COMPENSATION_COMPLETED))
    .thenEnd();
}
```

### Agent with Tools

```java
@Component(id = "activity-agent")
public class ActivityAgent extends Agent {
  public Effect<String> query(String message) {
    return effects()
        .systemMessage("You are an activity agent...")
        .userMessage(message)
        .thenReply();
  }

  @FunctionTool(description = "Return current date in yyyy-MM-dd format")
  private String getCurrentDate() {
    return LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
  }
}
```

### Autonomous Agent (basic)

```java
@Component(
    id = "question-answerer",
    description = "Answers questions clearly and concisely")
public class QuestionAnswerer extends AutonomousAgent {

  @Override
  public AgentDefinition definition() {
    return define()
        .capability(TaskAcceptance.of(QuestionTasks.ANSWER).maxIterationsPerTask(3));
  }

  @FunctionTool(description = "Look up an authoritative source for a topic")
  public String lookupSource(String topic) {
    return "Source for " + topic;
  }
}
```

### Autonomous Agent with Combined Capabilities

```java
@Component(
    id = "research-coordinator",
    description = "Produces research briefs by synthesizing specialist findings")
public class ResearchCoordinator extends AutonomousAgent {

  @Override
  public AgentDefinition definition() {
    return define()
        .tools(new ResearchTools())
        .capability(
            TaskAcceptance.of(ResearchTasks.BRIEF)
                .maxIterationsPerTask(10)
                .canHandoffTo(SeniorAnalyst.class))
        .capability(Delegation.to(Researcher.class, Analyst.class).maxParallelWorkers(3));
  }
}
```

### Autonomous Agent Task Definition

```java
public class ResearchTasks {
  public static final Task<ResearchBrief> BRIEF = Task
      .define("Brief")
      .description("Produce a research brief on a given topic")
      .resultConformsTo(ResearchBrief.class);

  public static final Task<ResearchFindings> FINDINGS = Task
      .define("Findings")
      .description("Research a topic and produce factual findings")
      .resultConformsTo(ResearchFindings.class)
      .rules(ResearchFindingsRule.class); // optional validation rule
}

public record ResearchBrief(String title, String summary, List<String> keyFindings) {}
public record ResearchFindings(String topic, List<String> facts, List<String> sources) {}

public class ResearchFindingsRule implements TaskRule<ResearchFindings> {
  @Override
  public Result onComplete(ResearchFindings findings) {
    if (findings.sources() == null || findings.sources().isEmpty()) {
      return new Result.Rejected("research findings must cite sources");
    }
    return new Result.Accepted();
  }
}
```

### Endpoint Driving an Autonomous Agent

```java
@HttpEndpoint
@Acl(allow = @Acl.Matcher(principal = Acl.Principal.INTERNET))
public class ResearchEndpoint {

  public record Request(String topic) {}

  private final ComponentClient componentClient;

  public ResearchEndpoint(ComponentClient componentClient) {
    this.componentClient = componentClient;
  }

  @Post("/research")
  public HttpResponse start(Request request) {
    var taskId = componentClient
        .forAutonomousAgent(ResearchCoordinator.class, UUID.randomUUID().toString())
        .runSingleTask(ResearchTasks.BRIEF.instructions(request.topic())); // returns task id immediately
    return HttpResponses.created(taskId, "/research/" + taskId);
  }

  @Get("/research/{taskId}")
  public HttpResponse get(String taskId) {
    var snapshot = componentClient.forTask(taskId).get(ResearchTasks.BRIEF); // typed result
    return snapshot.result()
        .<HttpResponse>map(HttpResponses::ok)
        .orElseGet(() -> HttpResponses.notFound("Not ready"));
  }
}
```

### Workflow Orchestrating Multiple Agents (Static)

```java
@Component(id = "agent-team")
public class AgentTeamWorkflow extends Workflow<AgentTeamWorkflow.State> {

  public record State(String query, String weatherForecast, String answer) {
    State withWeatherForecast(String f) { return new State(query, f, answer); }
    State withAnswer(String a) { return new State(query, weatherForecast, a); }
  }

  private final ComponentClient componentClient;

  public AgentTeamWorkflow(ComponentClient componentClient) {
    this.componentClient = componentClient;
  }

  public Effect<Done> start(String query) {
    return effects()
      .updateState(new State(query, "", ""))
      .transitionTo(AgentTeamWorkflow::askWeather)
      .thenReply(Done.getInstance());
  }

  public Effect<String> getAnswer() {
    if (currentState() == null || currentState().answer.isEmpty()) {
      return effects().error("Workflow not completed");
    }
    return effects().reply(currentState().answer);
  }

  @Override
  public WorkflowSettings settings() {
    return WorkflowSettings.builder()
      .stepTimeout(AgentTeamWorkflow::askWeather, ofSeconds(60)) // Long timeout for AI
      .defaultStepRecovery(RecoverStrategy.maxRetries(2).failoverTo(AgentTeamWorkflow::errorStep))
      .build();
  }

  @StepName("weather")
  private StepEffect askWeather() {
    var forecast = componentClient
      .forAgent()
      .inSession(sessionId()) // Shared session for context
      .method(WeatherAgent::query)
      .invoke(currentState().query);

    return stepEffects()
      .updateState(currentState().withWeatherForecast(forecast))
      .thenTransitionTo(AgentTeamWorkflow::suggestActivities);
  }

  @StepName("activities")
  private StepEffect suggestActivities() {
    var request = currentState().query + "\nWeather: " + currentState().weatherForecast;
    var suggestion = componentClient
      .forAgent()
      .inSession(sessionId())
      .method(ActivityAgent::query)
      .invoke(request);

    return stepEffects()
      .updateState(currentState().withAnswer(suggestion))
      .thenEnd();
  }

  private StepEffect errorStep() {
    return stepEffects().thenEnd();
  }

  private String sessionId() {
    return commandContext().workflowId(); // Workflow ID = Session ID
  }
}
```

### Autonomous Agent Orchestrating Multiple Agents (Dynamic)

```java
public class ActivityTasks {
  public static final Task<String> SUGGEST_ACTIVITIES = Task.name("SuggestActivities")
      .description("Suggest activities, taking weather and preferences into account.");
}

// Model decides which workers to call. WeatherAgent and ActivityAgent are
// unchanged request-based Agents.
@Component(
    id = "activity-coordinator",
    description = "Suggests activities by consulting the weather and/or activity agents.")
public class ActivityCoordinator extends AutonomousAgent {

  @Override
  public AgentDefinition definition() {
    return define()
        .capability(TaskAcceptance.of(ActivityTasks.SUGGEST_ACTIVITIES).maxIterationsPerTask(5))
        .capability(Delegation.to(WeatherAgent.class, ActivityAgent.class));
  }
}
```

### Consumer Producing to Topic

```java
@Component(id = "counter-to-topic")
@Consume.FromEventSourcedEntity(CounterEntity.class)
@Produce.ToTopic("counter-events")
public class CounterToTopicConsumer extends Consumer {
  public Effect onEvent(CounterEvent event) {
    var counterId = messageContext().eventSubject().get();
    Metadata metadata = Metadata.EMPTY.add("ce-subject", counterId);
    return effects().produce(event, metadata);
  }
}
```
### HTTP Endpoints

Favor endpoint APIs that follow REST principles. 

When an HTTP method returns an `akka.http.javadsl.model.HttpResponse` instead of a custom type and it can return errors, avoid throwing exceptions. Instead, use HTTP error response methods such as `akka.javasdk.http.HttpResponses.badRequest` or `akka.javasdk.http.HttpResponses.notFound`.

### MCP Endpoints

Use an MCP endpoint to expose capabilities to MCP clients. This is the reverse direction from
`.mcpTools()` on an agent, which *consumes* a remote MCP server.

```java
@Acl(allow = @Acl.Matcher(principal = Acl.Principal.ALL))
@McpEndpoint(serverName = "my-service-mcp", serverVersion = "0.0.1")
public class MyMcpEndpoint {

  @McpTool(name = "add", description = "Add two numbers")
  public String add(@Description("The first number") int n1, @Description("The second number") int n2) {
    return String.valueOf(n1 + n2);
  }
}
```

- Served at `/mcp` by default.
- Three member kinds: `@McpTool` (callable), `@McpResource` (fetchable content), `@McpPrompt`.
- Descriptions matter — the calling LLM relies on them. Use `@Description` on every parameter.
- Tool input classes must use primitives, boxed primitives, or `String`. All fields are required
  by default; make a parameter optional by typing it `Optional<T>`.
- See `akka-context/sdk/mcp-endpoints.html.md`.

### Object storage

For binary data (images, PDFs, documents), inject `ObjectStorageProvider` and call `forBucket`.
Do not put large binaries in entity state.

```java
public class ImageEndpoint {
  private final ObjectStorage bucket;

  public ImageEndpoint(ObjectStorageProvider provider) {
    this.bucket = provider.forBucket("images");
  }
}
```

- `put`, `get`, `getMetadata`, `delete`, `list` for small to medium payloads.
- `putStreamAsync`, `getStreamAsync`, `streamList` for large objects — prefer these over `list()`
  on large buckets.
- Objects are reachable by agents as multimodal content via `ImageUrlMessageContent.create(bucket, key)`
  and `PdfUrlMessageContent.create(bucket, key)`, which produce `object://` URIs the SDK resolves.
- Dev mode uses a local filesystem backend with no configuration; any bucket name is accepted.
- `TestKitSupport` provides an in-memory backend, isolated per test class.
- See `akka-context/sdk/integrations/object-storage.html.md`.

### Endpoint with web UI

A service can serve its own browser UI. Put the files in `src/main/resources/static-resources`
and return them from an endpoint method with `HttpResponses.staticResource`.

For a single-page application, map one method to a `**` subtree and strip the prefix. Do not
write one `@Get` per file:

```java
@HttpEndpoint
@Acl(allow = @Acl.Matcher(principal = Acl.Principal.ALL)) // required for browser access
public class UiEndpoint {

  @Get("/ui/**")
  public HttpResponse assets(HttpRequest request) {
    return HttpResponses.staticResource(request, "/ui/");
  }
}
```

`GET /ui/app.css` serves `static-resources/app.css`. When the remaining path is empty or ends
with `/`, `index.html` from that directory is served, so `GET /ui/` returns the application shell.

Content types are set from the file extension.

Use `HttpResponses.of(StatusCodes.OK, ContentTypes.TEXT_HTML_UTF8, bytes)` when the page is
generated at request time rather than read from a packaged file.

To push updates into an open page, use server-sent events or a `@WebSocket` method rather than
polling from the browser.

See "Serving web application assets" in `akka-context/sdk/http-endpoints.html.md` and the full
guide in `akka-context/sdk/web-applications.html.md`.
If the user gives no style preferences, you should use something similar to the CSS in `akka-context/ui/default-akka-style.css`

### Agent Testing Pattern

```java
public class MyAgentTest extends TestKitSupport {

  private final TestModelProvider agentModel = new TestModelProvider();

  @Override
  protected TestKit.Settings testKitSettings() {
    return TestKit.Settings.DEFAULT
        .withModelProvider(MyAgent.class, agentModel);
  }

  @Test
  public void testAgent() {
    var mockResponse = new MyAgent.Response("mocked result");
    agentModel.fixedResponse(JsonSupport.encodeToString(mockResponse));

    var result = componentClient
        .forAgent()
        .inSession("test-session-id")
        .method(MyAgent::myMethod)
        .invoke(request);

    assertThat(result).isEqualTo(mockResponse);
  }
}
```

**Key points:**
- Create `TestModelProvider` instance as field
- Register in `testKitSettings()` with `.withModelProvider(AgentClass.class, modelProvider)`
- Use `.fixedResponse()` with `JsonSupport.encodeToString()` for structured responses
- Always use `.inSession(sessionId)` when calling agents from tests
- Use `.whenMessage(predicate).reply(response)` for conditional responses

### Entity Unit Tests

```java
var testKit = EventSourcedTestKit.of("entity-id", MyEntity::new);
var result = testKit.method(MyEntity::myCommand).invoke(command);
assertThat(result.isReply()).isTrue();
assertThat(testKit.getState()).satisfies(...);
```

### View Integration Tests

```java
public class MyViewIntegrationTest extends TestKitSupport {
  @Override
  protected TestKit.Settings testKitSettings() {
    return TestKit.Settings.DEFAULT
        .withEventSourcedEntityIncomingMessages(MyEntity.class);
  }

  @Test
  public void testView() {
    var events = testKit.getEventSourcedEntityIncomingMessages(MyEntity.class);
    events.publish(myEvent, "entity-id");

    Awaitility.await()
        .atMost(10, TimeUnit.SECONDS)
        .untilAsserted(() -> {
          var result = componentClient.forView()
              .method(MyView::query)
              .invoke(queryParam);
          assertThat(result).isNotNull();
        });
  }
}
```

### Endpoint Integration Tests

```java
public class MyEndpointIntegrationTest extends TestKitSupport {
  @Test
  public void testEndpoint() {
    var response = httpClient // Use httpClient, NOT componentClient
        .POST("/counter/" + counterId + "/increase")
        .withRequestBody(request)
        .responseBodyAs(Counter.class)
        .invoke();

    assertThat(response.status().isSuccess()).isTrue();
    assertThat(response.status()).isEqualTo(akka.http.javadsl.model.StatusCodes.CREATED);
    assertThat(response.body().value).isEqualTo(3);
  }
}
```

## Critical Gotchas - Memorize These!

### Common Mistakes to Avoid

❌ **DON'T:**
- Use `io.akka.*` imports → use `akka.*`
- Put Akka dependencies in domain package
- Use `onUpdate(State)` for ESE views → use `onEvent(Event)`
- Use `componentClient` in endpoint integration tests → use `httpClient`
- Return domain objects/records from endpoints → create API-specific types
- Put business logic in entities → put in domain objects
- Use try-catch for validation in command handlers → use explicit validation checks returning `effects().error()`
- Use `commandContext().entityId()` in `emptyState()` → inject context
- Return `QueryEffect<List<Row>>` → wrap in record with `List<Row> items`
- Use `SELECT *` for multi-row → use `SELECT * AS items`
- Put `@Consume` on View class → put on TableUpdater subclass
- Return `CompletionStage` from endpoints → use synchronous style
- Use `.invokeAsync()` → use `.invoke()`
- Omit `@Acl` on endpoints
- Use `definition()` in Workflow → use `settings()` + step methods
- Use string step names → use method references (`::`)
- Create a `Main` class for bootstrapping → use a `Bootstrap` class that implements `ServiceSetup`
- Inject `ComponentClient` into Entities and Views → `ComponentClient` is only allowed in ServiceSetup, Endpoints, Agents, Consumers, TimedActions, and Workflows
- Create empty command record classes without fields → causes serialization errors; if no fields needed, make the command handler method parameterless
- Return `null` in the event handler → Only the `emptyState()` method is allowed to return `null`; Add a method to the State record class to model an empty or deleted state instead
- Perform side effects in `.thenReply()` in Entities → use a Consumer to react to events for side effects
- Add `@Component` to HTTP/gRPC endpoints
- Inject `RequestContext` or `GrpcRequestContext` as constructor parameters when extending `AbstractHttpEndpoint` / `AbstractGrpcEndpoint` → use `requestContext()` method instead
- Use deprecated `testKit.call`  -> use `testKit.method(...).invoke(...)`
- Create multiple command handlers in Agent
- Add command handlers to AutonomousAgent → it only has `definition()`
- Use `Agent` base class for autonomous agents → use `AutonomousAgent`
- Use `componentClient.forAgent()` for autonomous agents → use `componentClient.forAutonomousAgent()`
- Create task instances without instructions → always add `.instructions()` for per-request context
- Wrap `runSingleTask` in a Workflow for durability or to "wait" for the result → the task is already durable and queryable via `componentClient.forTask(taskId).get(taskDef)`
- Use `definition()` in request-based Agent → use `effects()` chain; `definition()` is for AutonomousAgent only
- Return protobuf types from domain layer
- Import `WorkflowSettings` -> WorkflowSettings is an inner class of Workflow, so no additional import is needed
- Static import `maxRetries` -> use `RecoverStrategy.maxRetries()` (import `Workflow.RecoverStrategy`)
- Write one `@Get` per file when serving a web UI → map a `**` subtree and strip the prefix with `HttpResponses.staticResource(request, prefix)`
- Put web UI files directly in `src/main/resources` → they must be in `src/main/resources/static-resources`
- Store large binaries in entity state → put them in a bucket via `ObjectStorageProvider`
- Return raw bytes from a `@FunctionTool` expecting the model to see an image → declare the return type as `MessageContent` and use `ImageMessageContent.fromBytes(...)`
- Expect inline tool image/PDF bytes to persist in session memory → they become an `[image]`/`[pdf]` placeholder; store in a bucket and return `ImageUrlMessageContent.create(bucket, key)` to keep them
- Use `@McpTool` parameter types other than primitives, boxed primitives, or `String` → unsupported; mark optional parameters `Optional<T>`

✅ **DO:**
- Use Java records for immutable data
- Add `@TypeName` to all events
- Validate in domain objects, return effects in entities
- Use `with*` methods for immutable updates
- Inject `EventSourcedEntityContext` if accessing entity ID in `emptyState()`
- Use `Awaitility.await()` for view tests
- Follow package structure strictly
- Use `TestModelProvider` to mock AI in agent and autonomous agent tests
- Define task types as `static final` constants in a `{Domain}Tasks` class
- Use `UUID.randomUUID().toString()` for one-off autonomous agent instance IDs
- Add `ce-subject` metadata when producing to topics
- Handle errors in Timed Actions to avoid infinite rescheduling
- Define `.proto` files in `src/main/proto` for gRPC
- Use private `toApi()` converters in gRPC endpoints

## Self-Review Checklist

Before presenting code, verify:

**Component choice**
- [ ] Component mapping follows `sdk/components/index.html.md` ("Choosing a component type"); each component needs its guarantees (durable state, subscription, schedule, process, API surface)
- [ ] No Key Value Entity with a hand-maintained history list (use Event Sourced); no Event Sourced Entity with a single whole-state `StateChanged` event (use Key Value)
- [ ] No View whose only query is by entity id; no read-your-own-write through a View in the same request
- [ ] No single-step Workflow (use a Consumer or direct call); no consumer chain that hides a multi-step process (use a Workflow)
- [ ] Side effects live in Consumers, not in entity command handlers or `.thenReply()`
- [ ] Nothing is a component that could be a plain domain class

**Imports**
- [ ] Using `akka.*` not `io.akka.*`
- [ ] Using `akka.javasdk.*`

**Agent**
- [ ] Only ONE command handler
- [ ] Rich descriptions in `@FunctionTool`
- [ ] Use `responseConformsTo()` for structured responses (not `responseAs()`)
- [ ] Handle errors from JSON parsing, tool calls, or model with `.onFailure()`
- [ ] Session ID strategy defined (UUID, workflow ID, etc.)

**Autonomous Agent**
- [ ] **STOP: Did you read `autonomous-agents.html.md` BEFORE writing any code?** (Required for first autonomous agent in session)
- [ ] Extends `AutonomousAgent`, NOT `Agent`
- [ ] Has `@Component(id = "...", description = "...")` annotation with a non-empty description (mandatory)
- [ ] `@Component` description captures the agent's purpose and expected outcome: used by coordinators, injected into the system message
- [ ] Implements `definition()` method, NO command handlers
- [ ] Optional `.instructions(...)` for tone, persona, domain rules, or procedural guidance to the model; not multi-agent orchestration mechanics (those belong in capabilities)
- [ ] Declares accepted task types with `.capability(TaskAcceptance.of(...))`
- [ ] Task definitions are `static final` constants with `.resultConformsTo()`
- [ ] Result types are Java records
- [ ] `maxIterationsPerTask()` set appropriately for task complexity
- [ ] Rich descriptions in `@FunctionTool` methods
- [ ] Coordination capabilities match the pattern needed (delegation vs handoff vs both)
- [ ] Agent class is stateless (no mutable fields)

**Events & State**
- [ ] Events have `@TypeName` annotations
- [ ] State uses immutable records

**Entity**
- [ ] Inject `EventSourcedEntityContext` if needed, `emptyState()` uses injected context

**View**
- [ ] `@Consume` on TableUpdater, not View class
- [ ] Multi-row queries use wrapper record with `AS` clause
- [ ] ESE views use `onEvent()` not `onUpdate()`

**Workflow**
- [ ] **STOP: Did you read `workflows.html.md` BEFORE writing any code?** (Required for first workflow in session)
- [ ] Uses `settings()` with `WorkflowSettings` (NOT `definition()`)
- [ ] Command handlers accept 0 or 1 parameter and return `Effect<T>`
- [ ] Step methods accept 0 or 1 parameter and return `StepEffect` (NOT `Effect`)
- [ ] Uses method references for step names (e.g., `TransferWorkflow::withdrawStep`)
- [ ] Uses `stepEffects()` in steps, `effects()` in command handlers

**Endpoint**
- [ ] Has `@Acl` annotation
- [ ] Synchronous style, uses `.invoke()`
- [ ] Returns API-specific types

**Tests**
- [ ] Entity tests use `EventSourcedTestKit`
- [ ] View tests use event publishing + `Awaitility`
- [ ] Endpoint tests use `httpClient` not `componentClient`
- [ ] Agent tests use `TestModelProvider` with `.fixedResponse()` or `.whenMessage()`
