Skip to content

Commit e1663c4

Browse files
authored
Clarify AgentTask documentation
1 parent 0641bde commit e1663c4

11 files changed

Lines changed: 287 additions & 80 deletions

File tree

README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ programs. The canonical workflow stays inside your repository beside the code
4040
and dependencies it uses. Generated `SKILL.md` files only help coding agents
4141
discover it.
4242

43+
Write the workflow in code. Use `AgentTask` only where a bounded step needs
44+
coding-agent judgment, then continue with structured data in normal code.
45+
4346
Verified with Cursor, Codex, and Claude Code. Registry-backed project paths are
4447
available for 73 more coding agents.
4548

@@ -81,7 +84,9 @@ A release skill often starts as prose:
8184
> Run the tests. Review the release. Stop if the review finds a critical issue.
8285
> Ask me before publishing. Publish the package, then verify the registry.
8386
84-
Yield makes the order and stopping rules executable:
87+
Yield makes the order and stopping rules executable. The coding agent reviews
88+
what the deterministic check may miss; the program still owns the gate,
89+
approval, publish, and verification steps:
8590

8691
<!-- release-example:start -->
8792

@@ -101,7 +106,7 @@ defineSkill((ctx) => {
101106
// coding agent's response at runtime before this workflow can continue.
102107
const review = ctx.agentTask<Review>(
103108
"review-release",
104-
"Review this release. Report critical findings and a short summary.",
109+
"Review this release for correctness problems that the test command may miss. Report critical findings and a short summary.",
105110
{ stdout: tests.stdout, stderr: tests.stderr },
106111
{
107112
type: "object",
@@ -267,13 +272,13 @@ The agent follows the generated adapter, runs the canonical workflow in
267272
If replay produces a different operation, the run fails instead of silently
268273
forking. Every side effect crosses one of these primitives:
269274

270-
| Primitive | Purpose |
271-
| --------------------- | ------------------------------------------------------ |
272-
| `runCommand` | Execute a command and record its exit code and output. |
273-
| `agentTask` | Ask the coding agent for schema-valid JSON. |
274-
| `askUser` | Request an explicit human decision. |
275-
| `require` | Bind a required claim to recorded evidence. |
276-
| `blocked` / `refused` | Stop honestly when work cannot or must not continue. |
275+
| Primitive | Purpose |
276+
| --------------------- | ----------------------------------------------------------------------- |
277+
| `runCommand` | Execute a command and record its exit code and output. |
278+
| `agentTask` | Delegate one bounded judgment; an optional schema validates the result. |
279+
| `askUser` | Request an explicit human decision. |
280+
| `require` | Bind a required claim to recorded evidence. |
281+
| `blocked` / `refused` | Stop honestly when work cannot or must not continue. |
277282

278283
See the [primitive guides](https://github.com/operatorstack/yield/blob/main/docs/primitives/README.md) and
279284
[runtime reference](https://github.com/operatorstack/yield/blob/main/docs/reference/cli.md) for the full contract.

docs/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ code. The coding agent still investigates, reviews, edits, and explains. Your
1818
program decides which operation comes next, what evidence must exist, and when
1919
the run is finished.
2020

21+
When one step needs judgment, call the coding agent with `AgentTask`, receive
22+
structured data, then continue in normal code.
23+
2124
A **skill workflow** is a portable, executable process that combines agent
2225
skills with deterministic code, state, and verification. The canonical
2326
workflow is the source you edit. Generated adapters let coding agents discover

docs/primitives/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
Yield has a deliberately small API. Each primitive has one clear owner.
44

5-
| Primitive | What it does | Who performs it |
6-
| ------------------------------ | ---------------------------------------------------- | --------------------- |
7-
| [`RunCommand`](run-command.md) | Runs a command and records its real output | `yskill` |
8-
| [`AgentTask`](agent-task.md) | Requests model judgment with an optional JSON schema | coding agent |
9-
| [`AskUser`](ask-user.md) | Pauses for a human answer | coding agent and user |
10-
| [`Require`](require.md) | Prevents completion unless a claim passes | skill workflow |
11-
| [Outcomes](outcomes.md) | Completes, blocks, or refuses with a recorded reason | skill workflow |
5+
| Primitive | What it does | Who performs it |
6+
| ------------------------------ | ----------------------------------------------------------------------- | --------------------- |
7+
| [`RunCommand`](run-command.md) | Runs a command and records its real output | `yskill` |
8+
| [`AgentTask`](agent-task.md) | Delegates one bounded judgment; an optional schema validates the result | coding agent |
9+
| [`AskUser`](ask-user.md) | Pauses for a human answer | coding agent and user |
10+
| [`Require`](require.md) | Prevents completion unless a claim passes | skill workflow |
11+
| [Outcomes](outcomes.md) | Completes, blocks, or refuses with a recorded reason | skill workflow |
1212

1313
Ordinary language features provide the rest. Use `if` for choices, `for` or
1414
`while` for bounded retries, functions for reusable flows, and your language's

docs/primitives/agent-task.md

Lines changed: 122 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,130 @@
1-
# `AgentTask`: keep judgment with the model
2-
3-
Use `AgentTask` for work that needs interpretation: reviewing a diff,
4-
diagnosing a failure, comparing designs, extracting a policy, or proposing a
5-
fix.
6-
7-
```ts
8-
type Diagnosis = { cause: string; confidence: number }
9-
10-
const diagnosis = ctx.agentTask<Diagnosis>(
11-
"diagnose",
12-
"Find the most likely cause of this test failure.",
13-
{ stdout: test.stdout, stderr: test.stderr },
14-
{
15-
type: "object",
16-
required: ["cause", "confidence"],
17-
properties: {
18-
cause: { type: "string" },
19-
confidence: { type: "number" },
1+
# AgentTask
2+
3+
Use the coding agent as a typed judgment step inside your workflow.
4+
5+
The agent interprets. With a JSON Schema, Yield checks the returned shape. Your
6+
program still owns what happens next.
7+
8+
```text
9+
workflow code
10+
11+
AgentTask
12+
13+
coding-agent judgment
14+
15+
JSON result, schema-validated when requested
16+
17+
workflow code continues
18+
```
19+
20+
Use `AgentTask` when one step needs interpretation: review what a check may
21+
have missed, diagnose captured output, compare designs against criteria, or
22+
extract structured information from repository material.
23+
24+
## One workflow, three roles
25+
26+
| Role | Primitive | Responsibility |
27+
| ------------------ | -------------------------- | ------------------------------------------------------ |
28+
| deterministic work | `RunCommand` and `Require` | run commands and enforce requirements |
29+
| agent judgment | `AgentTask` | interpret a bounded request and return structured data |
30+
| human authority | `AskUser` | make a decision before a protected effect |
31+
32+
Not every workflow needs all three. Yield lets them work together without
33+
asking the coding agent to rediscover order, retry limits, or completion rules
34+
on every run.
35+
36+
## Example: check, review, approve, publish
37+
38+
This tested workflow runs a deterministic check, asks the coding agent to
39+
review what that check may miss, requires a safe review result, then asks a
40+
person before publishing.
41+
42+
<!-- release-example:start -->
43+
44+
```typescript
45+
import { defineSkill } from "@operatorstack/yield"
46+
47+
type Review = { critical: number; summary: string }
48+
49+
defineSkill((ctx) => {
50+
// Yield runs commands itself and records their output and exit status.
51+
const tests = ctx.runCommand("test", "echo tests-ok", 300)
52+
53+
// A failed requirement stops the workflow and keeps its evidence.
54+
ctx.require(tests.exit_code === 0, "the test command succeeds", tests)
55+
56+
// Review gives TypeScript its compile-time type. The JSON schema checks the
57+
// coding agent's response at runtime before this workflow can continue.
58+
const review = ctx.agentTask<Review>(
59+
"review-release",
60+
"Review this release for correctness problems that the test command may miss. Report critical findings and a short summary.",
61+
{ stdout: tests.stdout, stderr: tests.stderr },
62+
{
63+
type: "object",
64+
required: ["critical", "summary"],
65+
properties: {
66+
critical: { type: "integer", minimum: 0 },
67+
summary: { type: "string", minLength: 1 },
68+
},
2069
},
21-
},
22-
)
70+
)
71+
ctx.require(review.critical === 0, "the review has no critical findings", review)
72+
73+
// Yield emits these fixed choices. A supported host may show native controls;
74+
// otherwise the coding agent asks through its normal interface.
75+
const approval = ctx.askUser("approve-publish", "Publish this package?", [
76+
{ value: "yes", label: "Publish" },
77+
{ value: "no", label: "Stop" },
78+
])
79+
if (approval !== "yes") ctx.refused("the operator declined publication")
80+
81+
// Publishing cannot start before approval. Verification is a separate step,
82+
// so completion requires evidence that the registry contains the release.
83+
const publish = ctx.runCommand("publish", "echo publish-ok", 600)
84+
ctx.require(publish.exit_code === 0, "the publish command succeeds", publish)
85+
86+
const registry = ctx.runCommand("verify-registry", "echo registry-ok", 300)
87+
ctx.require(registry.exit_code === 0, "the registry contains the release", registry)
88+
89+
return { published: true, summary: review.summary }
90+
})
2391
```
2492

25-
The arguments are:
93+
<!-- release-example:end -->
94+
95+
## Give the task the evidence it needs
96+
97+
The third argument is explicit workflow context. Pass the result that the
98+
judgment depends on, such as command output, a diff summary, or a previous
99+
structured result. Explicit context is easier to understand, test, and replay.
100+
101+
Yield sends the instruction and explicit context in the request. It does not
102+
promise access to a complete conversation, the repository, or any hidden host
103+
context. A coding agent may have additional working capabilities in its host,
104+
but those capabilities are host-dependent.
105+
106+
Cursor, Codex, and Claude Code are verified integrations. The host still owns
107+
the UI and working capabilities available to the agent.
108+
109+
## What schema validation proves
110+
111+
When you provide a JSON Schema, Yield validates the returned JSON before the
112+
workflow continues. It proves that required fields and declared structural
113+
constraints are present. It does not prove that the analysis is correct, files
114+
were inspected, or the requested work happened.
115+
116+
Use `RunCommand` for machine-observed output, `Require` to control
117+
continuation, and `AskUser` for human authority. Another `AgentTask` can offer
118+
another judgment, but it is still model judgment.
119+
120+
## Test the surrounding workflow
26121

27-
1. a stable operation ID;
28-
2. the instruction;
29-
3. optional structured context;
30-
4. an optional JSON Schema for the response.
122+
In production, `AgentTask` waits for the coding agent. In a test,
123+
`yskill test` reads a deterministic fixture response instead. The same
124+
surrounding workflow logic still runs, including commands and requirements.
31125

32-
The Yield CLI validates the response schema before accepting it. Schema-valid
33-
does not mean true; use `RunCommand`, human approval, or another explicit check
34-
when the workflow needs stronger evidence.
126+
See [testing fixtures](../testing-fixtures.md) for
127+
`fixtures/responses.json` and test-only effects.
35128

36129
## Common mistake
37130

docs/tutorials/code-review.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ ctx.require(check.exit_code === 0, "typecheck passes", check)
1313

1414
const review = ctx.agentTask<Review>(
1515
"review",
16-
"Review the branch for correctness, security, and data-loss risks.",
17-
undefined,
16+
"Review the branch for correctness, security, and data-loss risks that the typecheck may miss.",
17+
{ exit_code: check.exit_code, stdout: check.stdout, stderr: check.stderr },
1818
reviewSchema,
1919
)
2020

evals/results/latest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"schema_version": 2,
33
"methodology_version": "1.1",
4-
"generated_at": "2026-08-08T20:17:45.135Z",
5-
"source_digest": "a5e563abbe348dc60c3e8643beb2778acec8382d880c1cc08504158f8a5cb244",
4+
"generated_at": "2026-08-08T21:45:59.521Z",
5+
"source_digest": "f064d931095318d00a02d4b407f8b784dd6a0a24d190f2260f4158e50187515a",
66
"status": "passed",
77
"workflow_conformance": {
88
"passed": 40,

examples/release-checklist/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ defineSkill((ctx) => {
1616
// coding agent's response at runtime before this workflow can continue.
1717
const review = ctx.agentTask<Review>(
1818
"review-release",
19-
"Review this release. Report critical findings and a short summary.",
19+
"Review this release for correctness problems that the test command may miss. Report critical findings and a short summary.",
2020
{ stdout: tests.stdout, stderr: tests.stderr },
2121
{
2222
type: "object",

scripts/readme.test.mjs

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,105 @@ async function text(path) {
1010
}
1111

1212
test("README release example matches the tested TypeScript source", async () => {
13-
const [readme, source] = await Promise.all([
13+
const [readme, agentTaskDocs, source] = await Promise.all([
1414
text("README.md"),
15+
text("docs/primitives/agent-task.md"),
1516
text("examples/release-checklist/main.ts"),
1617
])
1718

18-
const readmeMatch = readme.match(
19-
/<!-- release-example:start -->\s*```typescript\n([\s\S]*?)\n```\s*<!-- release-example:end -->/,
20-
)
21-
assert.ok(readmeMatch, "README release example markers are missing")
19+
const example =
20+
/<!-- release-example:start -->\s*```typescript\n([\s\S]*?)\n```\s*<!-- release-example:end -->/
2221

2322
const sourceMatch = source.match(/\/\/ README_EXAMPLE_START\n([\s\S]*?)\n\/\/ README_EXAMPLE_END/)
2423
assert.ok(sourceMatch, "TypeScript release example markers are missing")
2524

26-
const readmeProgram = readmeMatch[1]
27-
.replace(/^import \{ defineSkill \} from "@operatorstack\/yield";?\n+/, "")
28-
.trim()
29-
assert.equal(readmeProgram, sourceMatch[1].trim())
25+
for (const [name, document] of [
26+
["README", readme],
27+
["AgentTask guide", agentTaskDocs],
28+
]) {
29+
const match = document.match(example)
30+
assert.ok(match, `${name} release example markers are missing`)
31+
const program = match[1]
32+
.replace(/^import \{ defineSkill \} from "@operatorstack\/yield";?\n+/, "")
33+
.trim()
34+
assert.equal(program, sourceMatch[1].trim())
35+
}
36+
})
37+
38+
test("AgentTask documentation preserves the typed judgment boundary", async () => {
39+
const [
40+
agentTask,
41+
primitiveIndex,
42+
docsIndex,
43+
tutorial,
44+
readme,
45+
pythonReadme,
46+
goReadme,
47+
rustReadme,
48+
] = await Promise.all([
49+
text("docs/primitives/agent-task.md"),
50+
text("docs/primitives/README.md"),
51+
text("docs/README.md"),
52+
text("docs/tutorials/code-review.md"),
53+
text("README.md"),
54+
text("sdk/python/README.md"),
55+
text("sdk/yield/README.md"),
56+
text("sdk/rust/README.md"),
57+
])
58+
59+
const normalized = (document) => document.replace(/\s+/g, " ")
60+
const normalizedAgentTask = normalized(agentTask)
61+
assert.match(
62+
normalizedAgentTask,
63+
/Use the coding agent as a typed judgment step inside your workflow\./,
64+
)
65+
assert.match(
66+
normalizedAgentTask,
67+
/The agent interprets\. With a JSON Schema, Yield checks the returned shape\./,
68+
)
69+
assert.match(
70+
normalizedAgentTask,
71+
/It does not prove that the analysis is correct, files were inspected, or the requested work happened\./,
72+
)
73+
assert.match(
74+
normalizedAgentTask,
75+
/does not promise access to a complete conversation, the repository, or any hidden host context/,
76+
)
77+
assert.match(normalizedAgentTask, /Cursor, Codex, and Claude Code are verified integrations/)
78+
assert.match(normalizedAgentTask, /`yskill test` reads a deterministic fixture response instead/)
79+
assert.match(
80+
primitiveIndex,
81+
/Delegates one bounded judgment; an optional schema validates the result/,
82+
)
83+
assert.match(
84+
normalized(docsIndex),
85+
/call the coding agent with `AgentTask`, receive structured data, then continue in normal code/,
86+
)
87+
assert.match(
88+
tutorial,
89+
/\{ exit_code: check\.exit_code, stdout: check\.stdout, stderr: check\.stderr \}/,
90+
)
91+
assert.match(
92+
normalized(readme),
93+
/Use `AgentTask` only where a bounded step needs coding-agent judgment/,
94+
)
95+
96+
for (const [name, document] of [
97+
["Python", pythonReadme],
98+
["Go", goReadme],
99+
["Rust", rustReadme],
100+
]) {
101+
const normalizedDocument = normalized(document)
102+
assert.match(
103+
normalizedDocument,
104+
/Delegate one bounded judgment; an optional schema validates the result/,
105+
)
106+
assert.match(normalizedDocument, /Host workspace and conversation access are host-dependent\./)
107+
assert.match(
108+
normalizedDocument,
109+
/With its schema, Yield checks the returned JSON shape before the workflow continues/,
110+
)
111+
}
30112
})
31113

32114
test("Python README example matches the tested environment doctor", async () => {

0 commit comments

Comments
 (0)