DCF Model Rubric
managed-agents/define-outcomes
History
managed-agents/define-outcomes Changed · +7 / -11 lines
``` ```php PHP - // The PHP SDK exposes the Files API under the beta namespace; field names can differ from other SDKs. use Anthropic\Client; use Anthropic\Core\FileParam;
MD; file_put_contents('/tmp/rubric.md', $rubricText); - $rubric = $client->beta->files->upload( + $rubric = $client->files->upload( file: FileParam::fromResource(fopen('/tmp/rubric.md', 'r'), contentType: 'text/markdown'), ); echo "Uploaded rubric: {$rubric->id}\n";
--transform id --raw-output) # Define the outcome — agent starts working on receipt - ant beta:sessions:events send \ - --session-id "$SESSION_ID" <<YAML + ant beta:sessions:events send --session-id "$SESSION_ID" <<YAML events: - type: user.define_outcome description: Build a DCF model for Costco in .xlsx
## Retrieve deliverables -The agent writes output files to `/mnt/session/outputs/` inside the sandbox. Once the session is idle, fetch them through the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) scoped to the session. Filtering by `scope_id` requires the `managed-agents-2026-04-01` beta header on the list request, so the SDK and CLI examples make that call through the `beta` namespace and pass the header explicitly. +The agent writes output files to `/mnt/session/outputs/` inside the sandbox. To retrieve them, list files through the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) with the session ID as the `scope_id`, then download them by ID. Filtering by `scope_id` requires the `managed-agents-2026-04-01` beta header on the list request, so the SDK and CLI examples make that call through the `beta` namespace and pass the header explicitly. Files appear in the list shortly after the agent finishes writing them, sometimes a few seconds after the session goes idle. If a file you expect is not listed yet, list again after a short delay; once it appears in the list, its upload has finished. <CodeGroup> ```bash cURL
```bash CLI # List files produced by this session # scope_id filtering requires the managed-agents beta on the files request - ant beta:files list --scope-id "$SESSION_ID" \ - --beta managed-agents-2026-04-01 + ant beta:files list --scope-id "$SESSION_ID" --beta managed-agents-2026-04-01 # Download a file FILE_ID=$(ant beta:files list --scope-id "$SESSION_ID" \
``` ```php PHP - // The PHP SDK exposes the Files API under the beta namespace; field names can differ from other SDKs. // List files produced by this session // scope_id filtering requires the managed-agents beta on the files request $files = $client->beta->files->list(scopeID: $session->id, betas: ['managed-agents-2026-04-01']); - foreach ($files->data as $file) { + foreach ($files->getItems() as $file) { echo "{$file->id} {$file->filename}\n"; } // Download a file - if (count($files->data) > 0) { - $content = $client->beta->files->download($files->data[0]->id); + if (count($files->getItems()) > 0) { + $content = $client->files->download($files->getItems()[0]->id); file_put_contents('/tmp/output.txt', $content); } ```
managed-agents/define-outcomes Changed · +3 / -9 lines
Pass the rubric as inline text on `user.define_outcome` (see [Create a session with an outcome](https://platform.claude.com/docs/en/managed-agents/define-outcomes#create-a-session-with-an-outcome)), or upload it through the Files API for reuse across sessions. -<Note> - Uploading through the Files API doesn't require a beta header. The cURL example sends the `managed-agents-2026-04-01` header it uses throughout this walkthrough, which the Files API also accepts. -</Note> - <CodeGroup> ```bash cURL rubric=$(curl -fsSL https://api.anthropic.com/v1/files \
``` ```php PHP + // The PHP SDK exposes the Files API under the beta namespace; field names can differ from other SDKs. use Anthropic\Client; use Anthropic\Core\FileParam;
## Retrieve deliverables -The agent writes output files to `/mnt/session/outputs/` inside the sandbox. Once the session is idle, fetch them through the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) scoped to the session. +The agent writes output files to `/mnt/session/outputs/` inside the sandbox. Once the session is idle, fetch them through the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) scoped to the session. Filtering by `scope_id` requires the `managed-agents-2026-04-01` beta header on the list request, so the SDK and CLI examples make that call through the `beta` namespace and pass the header explicitly. -<Note> - Filtering by `scope_id` requires the `managed-agents-2026-04-01` beta header on the list request, so the SDK and CLI examples make that call through the `beta` namespace and pass the header explicitly. Downloading a file by ID needs no beta header. -</Note> - <CodeGroup> ```bash cURL # List files produced by this session
``` ```php PHP + // The PHP SDK exposes the Files API under the beta namespace; field names can differ from other SDKs. // List files produced by this session // scope_id filtering requires the managed-agents beta on the files request $files = $client->beta->files->list(scopeID: $session->id, betas: ['managed-agents-2026-04-01']);
managed-agents/define-outcomes Changed · +17 / -17 lines
``` ```bash CLI - RUBRIC_ID=$(ant beta:files upload \ + RUBRIC_ID=$(ant files upload \ --file /tmp/rubric.md \ --transform id --raw-output) ```
""" Path("/tmp/rubric.md").write_text(RUBRIC) - rubric = client.beta.files.upload(file=Path("/tmp/rubric.md")) + rubric = client.files.upload(file=Path("/tmp/rubric.md")) print(f"Uploaded rubric: {rubric.id}") ```
`; await writeFile("/tmp/rubric.md", RUBRIC); - const rubric = await client.beta.files.upload({ + const rubric = await client.files.upload({ file: await toFile(readFile("/tmp/rubric.md"), "/tmp/rubric.md"), }); console.log(`Uploaded rubric: ${rubric.id}`);
using Anthropic; using Anthropic.Models.Beta.Agents; using Anthropic.Models.Beta.Environments; - using Anthropic.Models.Beta.Files; using Anthropic.Models.Beta.Sessions; using Anthropic.Models.Beta.Sessions.Events; + using Anthropic.Models.Files; var client = new AnthropicClient();
"""; await File.WriteAllTextAsync("/tmp/rubric.md", Rubric); - var rubric = await client.Beta.Files.Upload(new() + var rubric = await client.Files.Upload(new() { File = File.OpenRead("/tmp/rubric.md"), });
panic(err) } - uploaded, err := client.Beta.Files.Upload(ctx, anthropic.BetaFileUploadParams{ + uploaded, err := client.Files.Upload(ctx, anthropic.FileUploadParams{ File: anthropic.File(f, "rubric.md", "text/markdown"), }) if err != nil {
import com.anthropic.models.beta.environments.BetaCloudConfigParams; import com.anthropic.models.beta.environments.EnvironmentCreateParams; import com.anthropic.models.beta.files.FileListParams; - import com.anthropic.models.beta.files.FileUploadParams; import com.anthropic.models.beta.sessions.SessionCreateParams; import com.anthropic.models.beta.sessions.events.BetaManagedAgentsTextRubricParams; import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserDefineOutcomeEventParams; import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserInterruptEventParams; import com.anthropic.models.beta.sessions.events.EventSendParams; + import com.anthropic.models.files.FileUploadParams; import java.io.InputStream; import java.nio.file.Files;
"""; Files.writeString(Path.of("/tmp/rubric.md"), RUBRIC); - var rubric = client.beta().files().upload( + var rubric = client.files().upload( FileUploadParams.builder() .file(Path.of("/tmp/rubric.md")) .build());
MD File.write("/tmp/rubric.md", RUBRIC) - rubric = client.beta.files.upload(file: Pathname.new("/tmp/rubric.md")) + rubric = client.files.upload(file: Pathname.new("/tmp/rubric.md")) puts "Uploaded rubric: #{rubric.id}" ``` </CodeGroup>
The agent writes output files to `/mnt/session/outputs/` inside the sandbox. Once the session is idle, fetch them through the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) scoped to the session. <Note> - Filtering by `scope_id` requires the `managed-agents-2026-04-01` beta header on the files request. The SDK files methods send only the files beta automatically, so the examples pass it explicitly. + Filtering by `scope_id` requires the `managed-agents-2026-04-01` beta header on the list request, so the SDK and CLI examples make that call through the `beta` namespace and pass the header explicitly. Downloading a file by ID needs no beta header. </Note> <CodeGroup>
--beta managed-agents-2026-04-01 \ --transform 'data[0].id' --raw-output) if [[ -n $FILE_ID ]]; then - ant beta:files download --file-id "$FILE_ID" --output /tmp/output.txt + ant files download --file-id "$FILE_ID" --output /tmp/output.txt fi ```
# Download a file if files.data: - content = client.beta.files.download(files.data[0].id) + content = client.files.download(files.data[0].id) content.write_to_file("/tmp/output.txt") ```
// Download a file if (files.data.length > 0) { - const content = await client.beta.files.download(files.data[0].id); + const content = await client.files.download(files.data[0].id); await writeFile("/tmp/output.txt", new Uint8Array(await content.arrayBuffer())); } ```
// Download a file if (files.Items.Count > 0) { - using var download = await client.Beta.Files.Download(files.Items[0].ID); + using var download = await client.Files.Download(files.Items[0].ID); await using var output = File.Create("/tmp/output.txt"); await (await download.ReadAsStream()).CopyToAsync(output); }
// Download a file if len(files.Data) > 0 { - resp, err := client.Beta.Files.Download(ctx, files.Data[0].ID, anthropic.BetaFileDownloadParams{}) + resp, err := client.Files.Download(ctx, files.Data[0].ID) if err != nil { panic(err) }
// Download a file if (!files.data().isEmpty()) { - try (HttpResponse response = client.beta().files().download(files.data().getFirst().id())) { + try (HttpResponse response = client.files().download(files.data().getFirst().id())) { try (InputStream body = response.body()) { Files.copy(body, Path.of("/tmp/output.txt"), StandardCopyOption.REPLACE_EXISTING); }
# Download a file if (first = files.data.first) - content = client.beta.files.download(first.id) + content = client.files.download(first.id) File.binwrite("/tmp/output.txt", content.read) end ```
managed-agents/define-outcomes Changed · +1 / -1 lines
Pass the rubric as inline text on `user.define_outcome` (see [Create a session with an outcome](https://platform.claude.com/docs/en/managed-agents/define-outcomes#create-a-session-with-an-outcome)), or upload it through the Files API for reuse across sessions. <Note> - Uploading through the Files API requires a beta header that grants Files API access. Your Managed Agents beta header grants this on its own, so you don't need to send `files-api-2025-04-14` alongside it. The curl example passes its headers explicitly. + Uploading through the Files API doesn't require a beta header. The cURL example sends the `managed-agents-2026-04-01` header it uses throughout this walkthrough, which the Files API also accepts. </Note> <CodeGroup>
managed-agents/define-outcomes First recorded · 910 lines, first recorded
## Create a rubric ## Create a session with an outcome ## Outcome events ### Define outcome user event ### Outcome evaluation start ### Outcome evaluation ongoing ### Outcome evaluation end ## Check outcome status ## Retrieve deliverables ## Next steps
The first capture of this source. The page was already there, and this is what it said.
---
title: Define outcomes
url: https://platform.claude.com/docs/en/managed-agents/define-outcomes
description: Tell the agent what 'done' looks like, and let it iterate until it gets there.
---
An outcome tells the session what the end result should look like and how to measure its quality. The agent works toward that target, self-evaluating and iterating until the outcome is met.
When you define an outcome, the harness automatically provisions a *grader* to evaluate the artifact against a rubric. The grader uses a separate context window to avoid being influenced by the main agent's implementation choices.
The grader returns an explanation summarizing which criteria passed or failed, or confirming that the artifact satisfies the rubric. That feedback is handed back to the agent for the next iteration.
<Note>
Managed Agents API requests require the `managed-agents-2026-04-01` beta header, except memory store endpoints, which use `agent-memory-2026-07-22` instead. The SDK sets the correct beta header automatically. See [Beta headers](https://platform.claude.com/docs/en/api/beta-headers#endpoint-specific-headers).
</Note>
## Create a rubric
A rubric is a markdown document describing per-criterion scoring. The rubric is required.
<Accordion title="Tips for writing effective rubrics">
Structure the rubric as explicit, gradeable criteria, such as "The CSV contains a price column with numeric values" rather than "The data looks good." The grader scores each criterion independently, so vague criteria produce noisy evaluations.
If you don't have a rubric on hand, try giving Claude an example of a known-good artifact and asking it to analyze what makes that content good, then turn that analysis into a rubric. This middle-ground approach often produces better results than writing criteria from scratch.
</Accordion>
Example rubric:
```markdown
# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
- Growth rate assumptions are explicitly stated and reasonable
## Cost Structure
- COGS and operating expenses are modeled separately
- Margins are consistent with historical trends or deviations are justified
## Discount Rate
- WACC is calculated with stated assumptions for cost of equity and cost of debt
- Beta, risk-free rate, and equity risk premium are sourced or justified
## Terminal Value
- Uses either perpetuity growth or exit multiple method (stated which)
- Terminal growth rate does not exceed long-term GDP growth
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
- Key assumptions are on a separate "Assumptions" sheet
- Sensitivity analysis on WACC and terminal growth rate is included
```
Pass the rubric as inline text on `user.define_outcome` (see [Create a session with an outcome](https://platform.claude.com/docs/en/managed-agents/define-outcomes#create-a-session-with-an-outcome)), or upload it through the Files API for reuse across sessions.
<Note>
Uploading through the Files API requires a beta header that grants Files API access. Your Managed Agents beta header grants this on its own, so you don't need to send `files-api-2025-04-14` alongside it. The curl example passes its headers explicitly.
</Note>
<CodeGroup>
```bash cURL
rubric=$(curl -fsSL https://api.anthropic.com/v1/files \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-F file=@/tmp/rubric.md)
rubric_id=$(jq -r '.id' <<<"$rubric")
printf 'Uploaded rubric: %s\n' "$rubric_id"
```
```bash CLI
RUBRIC_ID=$(ant beta:files upload \
--file /tmp/rubric.md \
--transform id --raw-output)
```
```python Python
import time
from pathlib import Path
from anthropic import Anthropic
client = Anthropic()
RUBRIC = """# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
"""
Path("/tmp/rubric.md").write_text(RUBRIC)
rubric = client.beta.files.upload(file=Path("/tmp/rubric.md"))
print(f"Uploaded rubric: {rubric.id}")
```
```typescript TypeScript
import { writeFile, readFile } from "node:fs/promises";
import Anthropic from "@anthropic-ai/sdk";
import { toFile } from "@anthropic-ai/sdk";
const client = new Anthropic();
const RUBRIC = `# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
`;
await writeFile("/tmp/rubric.md", RUBRIC);
const rubric = await client.beta.files.upload({
file: await toFile(readFile("/tmp/rubric.md"), "/tmp/rubric.md"),
});
console.log(`Uploaded rubric: ${rubric.id}`);
```
```csharp C#
using Anthropic;
using Anthropic.Models.Beta.Agents;
using Anthropic.Models.Beta.Environments;
using Anthropic.Models.Beta.Files;
using Anthropic.Models.Beta.Sessions;
using Anthropic.Models.Beta.Sessions.Events;
var client = new AnthropicClient();
const string Rubric = """
# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
""";
await File.WriteAllTextAsync("/tmp/rubric.md", Rubric);
var rubric = await client.Beta.Files.Upload(new()
{
File = File.OpenRead("/tmp/rubric.md"),
});
Console.WriteLine($"Uploaded rubric: {rubric.ID}");
```
```go Go
package main
import (
"context"
"fmt"
"io"
"os"
"time"
"github.com/anthropics/anthropic-sdk-go"
)
const rubric = `# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
`
func main() {
ctx := context.Background()
client := anthropic.NewClient()
if err := os.WriteFile("/tmp/rubric.md", []byte(rubric), 0o644); err != nil {
panic(err)
}
f, err := os.Open("/tmp/rubric.md")
if err != nil {
panic(err)
}
uploaded, err := client.Beta.Files.Upload(ctx, anthropic.BetaFileUploadParams{
File: anthropic.File(f, "rubric.md", "text/markdown"),
})
if err != nil {
panic(err)
}
fmt.Printf("Uploaded rubric: %s\n", uploaded.ID)
```
```java Java
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.http.HttpResponse;
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.beta.agents.AgentCreateParams;
import com.anthropic.models.beta.agents.BetaManagedAgentsAgentToolset20260401Params;
import com.anthropic.models.beta.agents.BetaManagedAgentsModel;
import com.anthropic.models.beta.environments.BetaCloudConfigParams;
import com.anthropic.models.beta.environments.EnvironmentCreateParams;
import com.anthropic.models.beta.files.FileListParams;
import com.anthropic.models.beta.files.FileUploadParams;
import com.anthropic.models.beta.sessions.SessionCreateParams;
import com.anthropic.models.beta.sessions.events.BetaManagedAgentsTextRubricParams;
import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserDefineOutcomeEventParams;
import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserInterruptEventParams;
import com.anthropic.models.beta.sessions.events.EventSendParams;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
void main() throws Exception {
var client = AnthropicOkHttpClient.fromEnv();
var RUBRIC = """
# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
""";
Files.writeString(Path.of("/tmp/rubric.md"), RUBRIC);
var rubric = client.beta().files().upload(
FileUploadParams.builder()
.file(Path.of("/tmp/rubric.md"))
.build());
IO.println("Uploaded rubric: " + rubric.id());
```
```php PHP
use Anthropic\Client;
use Anthropic\Core\FileParam;
$client = new Client();
$rubricText = <<<'MD'
# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
MD;
file_put_contents('/tmp/rubric.md', $rubricText);
$rubric = $client->beta->files->upload(
file: FileParam::fromResource(fopen('/tmp/rubric.md', 'r'), contentType: 'text/markdown'),
);
echo "Uploaded rubric: {$rubric->id}\n";
```
```ruby Ruby
require "anthropic"
require "pathname"
client = Anthropic::Client.new
RUBRIC = <<~MD
# DCF Model Rubric
## Revenue Projections
- Uses historical revenue data from the last 5 fiscal years
- Projects revenue for at least 5 years forward
## Output Quality
- All figures are in a single .xlsx file with clearly labeled sheets
MD
File.write("/tmp/rubric.md", RUBRIC)
rubric = client.beta.files.upload(file: Pathname.new("/tmp/rubric.md"))
puts "Uploaded rubric: #{rubric.id}"
```
</CodeGroup>
## Create a session with an outcome
The following examples create a [session](https://platform.claude.com/docs/en/managed-agents/sessions) for an existing [agent](https://platform.claude.com/docs/en/managed-agents/agent-setup) and [environment](https://platform.claude.com/docs/en/managed-agents/environments) (both created separately), then send a `user.define_outcome` event. The agent begins work immediately. No additional user message event is required.
<CodeGroup>
```bash cURL
# Create a session
session=$(curl -fsSL https://api.anthropic.com/v1/sessions \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
Cut at 300 lines.