# user.message vs user.define_outcome: Event Types in Anthropic Managed Agents

> Understand the difference between user.message and user.define_outcome events in Anthropic Managed Agents. Learn how to trigger responses and enable iteration loops for your agents.

- Repository: [Anthropic/cwc-workshops](https://github.com/anthropics/cwc-workshops)
- Tags: deep-dive
- Published: 2026-07-18

---

**The `user.message` event sends conversational input to trigger standard agent responses, while `user.define_outcome` declares a desired final state with evaluation criteria to enable automated iteration loops.**

When building applications with Anthropic Managed Agents using the `anthropics/cwc-workshops` reference implementation, developers must choose between two distinct event types for client-to-agent communication. Understanding the difference between `user.message` and `user.define_outcome` is critical for controlling whether a session operates in standard chat mode or outcome-driven evaluation mode.

## Core Functional Differences

**`user.message`** serves as the standard mechanism for conversational interaction. According to the source code in [`research-desk/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/src/lib/sessions.ts), this event type triggers normal agent responses through the `sendUserMessage()` function, allowing users to ask questions, provide instructions, or continue dialogue threads.

**`user.define_outcome`** initiates a structured evaluation loop. As implemented in [`research-desk/solutions/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/solutions/src/lib/sessions.ts), the `defineOutcome()` function sends this event to declare what "done" looks like, supply a grading rubric, and optionally set iteration limits. This switches the session into outcome-driven mode where the platform automatically evaluates agent outputs against defined criteria.

## Implementation in the Source Code

### Sending Standard Messages with sendUserMessage()

In [`research-desk/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/src/lib/sessions.ts) (lines 53-57), the `sendUserMessage()` function constructs and transmits a `user.message` event:

```typescript
// research-desk/src/lib/sessions.ts
export async function sendUserMessage(
  client: Anthropic,
  sessionId: string,
  text: string,
) {
  await client.beta.sessions.events.send(sessionId, {
    events: [{ type: "user.message", content: [{ type: "text", text }] }],
  });
}

```

This pattern appears consistently across the codebase, including in `production-ready-agent/solution/app/api/steer/[id]/route.ts` (lines 17-18), where the same event structure forwards user text to the session.

### Defining Outcomes with defineOutcome()

The solution implementation in [`research-desk/solutions/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/solutions/src/lib/sessions.ts) (lines 66-78) provides the full `defineOutcome()` function that sends a `user.define_outcome` event:

```typescript
// research-desk/solutions/src/lib/sessions.ts (implemented version)
export async function defineOutcome(
  client: Anthropic,
  sessionId: string,
  description: string,
  rubric: string,
  maxIterations = 2,
) {
  await client.beta.sessions.events.send(sessionId, {
    events: [
      {
        type: "user.define_outcome",
        description,
        rubric: { type: "text", content: rubric },
        max_iterations: maxIterations,
      },
    ],
  });
}

```

Note that the main repository contains only a stub implementation that throws a TODO error, while the solutions directory provides this complete working version.

## Payload Structure and Schema

The JSON structures for these events differ significantly:

**user.message payload:**

```json
{
  "type": "user.message",
  "content": [{ "type": "text", "text": "Your prompt here" }]
}

```

**user.define_outcome payload:**

```json
{
  "type": "user.define_outcome",
  "description": "What 'done' looks like",
  "rubric": {
    "type": "text",
    "content": "Evaluation criteria for the grader"
  },
  "max_iterations": 2
}

```

The `user.define_outcome` event requires `description` and `rubric` fields, with `max_iterations` as an optional parameter that defaults to 2 in the reference implementation.

## Session Behavior and Routing

When you send a **`user.message`** event, the orchestrator processes it as a normal chat event and streams back `agent.message` responses. This creates the standard interactive back-and-forth typical of conversational AI applications.

Sending a **`user.define_outcome`** event triggers the platform's grader evaluation loop. The system watches agent outputs, compares them against the provided rubric, and may request additional iterations until the rubric is satisfied or `max_iterations` is reached. This generates `span.outcome_evaluation_end` events that indicate the grader's verdict on whether the outcome requirements were met.

## UI Rendering Differences

The [`production-ready-agent/starter/lib/chat.ts`](https://github.com/anthropics/cwc-workshops/blob/main/production-ready-agent/starter/lib/chat.ts) file (lines 40-49) demonstrates how the UI distinguishes between these events in its `toChatMessages()` function:

```typescript
// production-ready-agent/starter/lib/chat.ts
if (e.type === "user.message") {
  out.push({ id: e.id, role: "user", text: textOf(e) });
} else if (e.type === "user.define_outcome") {
  out.push({
    id: e.id,
    role: "user",
    text: "",
    outcome: {
      result: "defined",
      explanation: (e as { description?: string }).description,
    },
  });
}

```

While `user.message` renders as a standard text chat bubble, `user.define_outcome` produces a special outcome marker that displays the defined objective to the user, creating a visual distinction between conversational turns and evaluation setup.

## Dynamic Selection in API Endpoints

The steering endpoint in `production-ready-agent/solution/app/api/steer/[id]/route.ts` (lines 10-20) illustrates how applications can dynamically select between these event types based on request parameters:

```typescript
// production-ready-agent/solution/app/api/steer/[id]/route.ts
const event =
  kind === "outcome"
    ? {
        type: "user.define_outcome",
        description: text,
        rubric: { type: "text", content: text },
      }
    : { type: "user.message", content: [{ type: "text", text }] };
await client.beta.sessions.events.send(id, { events: [event] });

```

This pattern allows a single API route to handle both standard messaging and outcome definition by checking the request kind and constructing the appropriate event payload.

## Summary

- **`user.message`** sends standard conversational input that triggers immediate agent responses, suitable for interactive chat flows.
- **`user.define_outcome`** declares a target state with evaluation criteria, enabling the platform to automatically iterate and grade agent outputs against a rubric.
- **Source implementations** reside in [`research-desk/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/src/lib/sessions.ts) for messages and [`research-desk/solutions/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/solutions/src/lib/sessions.ts) for outcomes, with UI handling in [`production-ready-agent/starter/lib/chat.ts`](https://github.com/anthropics/cwc-workshops/blob/main/production-ready-agent/starter/lib/chat.ts).
- **Payload requirements** differ: messages require only text content, while outcomes require description, rubric, and optionally `max_iterations`.
- **Session effects** vary significantly: standard messaging creates a simple request-response loop, whereas outcome events trigger the grader's evaluation cycle with potential for multiple iterations.

## Frequently Asked Questions

### Can I mix user.message and user.define_outcome events in the same session?

Yes, you can send `user.message` events for standard conversational turns and later send a `user.define_outcome` event to switch the session into outcome-driven evaluation mode. However, once the outcome is defined, subsequent interactions typically focus on achieving that outcome rather than casual conversation, as the grader will evaluate all agent outputs against the established rubric.

### What happens if the rubric is never satisfied within max_iterations?

According to the implementation in [`research-desk/solutions/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/solutions/src/lib/sessions.ts), the platform will stop iterating once `max_iterations` is reached, even if the rubric criteria remain unmet. The session generates a final `span.outcome_evaluation_end` event indicating the result, which the UI renders as a completed outcome bubble, allowing the application to handle the incomplete status programmatically.

### Is the max_iterations parameter required for user.define_outcome?

No, `max_iterations` is optional. The reference implementation in [`research-desk/solutions/src/lib/sessions.ts`](https://github.com/anthropics/cwc-workshops/blob/main/research-desk/solutions/src/lib/sessions.ts) sets a default value of 2 if not specified. This parameter controls the maximum number of revision cycles the grader will attempt before concluding the evaluation, preventing infinite loops when the rubric cannot be satisfied.

### How does the grader evaluate agent outputs against the rubric?

The platform's grader automatically compares agent outputs to the `rubric.content` field provided in the `user.define_outcome` event. As implemented in the `anthropics/cwc-workshops` codebase, this evaluation generates `span.outcome_evaluation_end` events that indicate whether the agent's work meets the defined criteria. The UI then renders these verdicts through the conversion logic in [`production-ready-agent/starter/lib/chat.ts`](https://github.com/anthropics/cwc-workshops/blob/main/production-ready-agent/starter/lib/chat.ts) (lines 40-49), displaying the evaluation results alongside the conversation history.