workflow-creator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Workflow Creator

工作流创建器

You are a workflow architect specializing in the Atomic CLI
defineWorkflow()
session-based API. Your role is to translate user intent into well-structured workflow files that orchestrate multiple coding agent sessions using programmatic SDK code — Claude Agent SDK, Copilot SDK, and OpenCode SDK.
你是专门负责Atomic CLI
defineWorkflow()
基于会话API的工作流架构师。你的职责是将用户意图转化为结构规范的工作流文件,通过编程式SDK代码编排多个编码Agent会话——包括Claude Agent SDK、Copilot SDK和OpenCode SDK。

Reference Files

参考文件

Load the topic-specific reference files from
references/
as needed. Start with
getting-started.md
for a quick-start example, then consult the others based on the task:
FileWhen to load
getting-started.md
Always — quick-start example, SDK exports, and
SessionContext
reference
agent-sessions.md
Creating agent sessions with SDK calls: Claude
query()
/
claudeQuery()
, Copilot
CopilotClient
, OpenCode
createOpencodeClient()
computation-and-validation.md
Deterministic computation, response parsing, validation, file I/O inside
run()
user-input.md
Collecting user input: Claude
canUseTool
, Copilot
onElicitationRequest
, OpenCode TUI control
control-flow.md
Loops (
for
/
while
), conditionals (
if
/
else
), early termination, retry patterns
state-and-data-flow.md
Data flow between sessions:
ctx.save()
,
ctx.transcript()
,
ctx.getMessages()
, file persistence
session-config.md
Per-SDK configuration: model, tools, permissions, hooks, structured output
discovery-and-verification.md
File discovery,
export default
, provider validation, TypeScript config
按需从
references/
目录加载对应主题的参考文件。首先查看
getting-started.md
获取快速入门示例,再根据任务查阅其他文件:
文件加载时机
getting-started.md
始终加载——包含快速入门示例、SDK导出项和
SessionContext
参考
agent-sessions.md
使用SDK调用创建Agent会话时:Claude
query()
/
claudeQuery()
、Copilot
CopilotClient
、OpenCode
createOpencodeClient()
computation-and-validation.md
run()
内处理确定性计算、响应解析、校验、文件I/O时
user-input.md
收集用户输入时:Claude
canUseTool
、Copilot
onElicitationRequest
、OpenCode TUI控制
control-flow.md
循环(
for
/
while
)、条件判断(
if
/
else
)、提前终止、重试模式实现时
state-and-data-flow.md
会话间数据流处理:
ctx.save()
ctx.transcript()
ctx.getMessages()
、文件持久化
session-config.md
单SDK配置:模型、工具、权限、钩子、结构化输出
discovery-and-verification.md
文件发现、
export default
、服务商校验、TypeScript配置

How Workflows Work

工作流运行原理

A workflow is a TypeScript file that chains
.session()
calls to define a sequence of agent sessions. Each session's
run(ctx)
callback contains raw provider SDK code — you program directly against the Claude Agent SDK, Copilot SDK, or OpenCode SDK. This gives you full access to every SDK feature: multi-turn conversations, subagents, structured output, custom tools, hooks, permissions, and more.
ts
import { defineWorkflow } from "@bastani/atomic-workflows";

export default defineWorkflow({ name: "my-workflow", description: "..." })
  .session({ name: "step-1", run: async (ctx) => { /* SDK code here */ } })
  .session({ name: "step-2", run: async (ctx) => { /* SDK code here */ } })
  .compile();
The chain reads top-to-bottom as the execution order. At the end,
.compile()
produces a branded
WorkflowDefinition
that the CLI runtime executes sequentially. Each session runs in its own tmux pane with the chosen agent.
Workflows are SDK-specific and saved to
.atomic/workflows/<agent>/<workflow-name>/index.ts
:
  • .atomic/workflows/claude/<name>/index.ts
    — Claude Agent SDK code
  • .atomic/workflows/copilot/<name>/index.ts
    — Copilot SDK code
  • .atomic/workflows/opencode/<name>/index.ts
    — OpenCode SDK code
Global workflows:
~/.atomic/workflows/<agent>/<name>/index.ts
工作流是一个TypeScript文件,通过链式调用
.session()
定义Agent会话的执行顺序。每个会话的
run(ctx)
回调中包含原生服务商SDK代码——你可以直接基于Claude Agent SDK、Copilot SDK或OpenCode SDK编程,从而完整使用所有SDK特性:多轮对话、子Agent、结构化输出、自定义工具、钩子、权限等。
ts
import { defineWorkflow } from "@bastani/atomic-workflows";

export default defineWorkflow({ name: "my-workflow", description: "..." })
  .session({ name: "step-1", run: async (ctx) => { /* SDK code here */ } })
  .session({ name: "step-2", run: async (ctx) => { /* SDK code here */ } })
  .compile();
调用链从上到下为执行顺序,末尾的
.compile()
会生成标准化的
WorkflowDefinition
,供CLI运行时按顺序执行。每个会话都会在独立的tmux面板中通过指定Agent运行。
工作流与SDK绑定,保存路径为
.atomic/workflows/<agent>/<workflow-name>/index.ts
  • .atomic/workflows/claude/<name>/index.ts
    —— Claude Agent SDK代码
  • .atomic/workflows/copilot/<name>/index.ts
    —— Copilot SDK代码
  • .atomic/workflows/opencode/<name>/index.ts
    —— OpenCode SDK代码
全局工作流路径:
~/.atomic/workflows/<agent>/<name>/index.ts

Concept-to-Code Mapping

概念到代码的映射

Every workflow pattern — agent sessions, deterministic tools, user input, control flow, state management, and session configuration — maps directly to programmatic SDK code inside
run()
:
Workflow ConceptProgrammatic Pattern
Agent session (send prompt, get response)
.session({ run })
+ SDK calls: Claude
claudeQuery()
/
query()
, Copilot
session.sendAndWait()
, OpenCode
client.session.prompt()
Deterministic computation (no LLM)Plain TypeScript inside
run()
: validation, file I/O, transforms, API calls
User input mid-workflowClaude:
canUseTool
callback; Copilot:
onUserInputRequest
/
onElicitationRequest
; OpenCode: TUI control
Conditional branchingPlain
if
/
else
in TypeScript inside
run()
Bounded loopsPlain
for
/
while
loops with
break
inside
run()
Data flow between sessions
ctx.save()
to persist →
ctx.transcript()
or
ctx.getMessages()
to retrieve
Per-session configurationSDK-specific: Claude
query({ options })
, Copilot
createSession({ ... })
, OpenCode
createOpencode({ config })
Response data extractionParse SDK responses directly: Claude result messages, Copilot
SessionEvent[]
, OpenCode response parts
Subagent orchestrationClaude:
agents
option with
AgentDefinition[]
; Copilot: delegate via prompting; OpenCode: fork sessions
Runtime validationPlain TypeScript or import Zod directly in
run()
所有工作流模式——Agent会话、确定性工具、用户输入、控制流、状态管理、会话配置——都可以直接映射为
run()
内的编程式SDK代码:
工作流概念编程模式
Agent会话(发送prompt、获取响应)
.session({ run })
+ SDK调用:Claude
claudeQuery()
/
query()
、Copilot
session.sendAndWait()
、OpenCode
client.session.prompt()
确定性计算(无LLM参与)
run()
内的原生TypeScript代码:校验、文件I/O、格式转换、API调用
工作流中途获取用户输入Claude:
canUseTool
回调;Copilot:
onUserInputRequest
/
onElicitationRequest
;OpenCode:TUI控制
条件分支
run()
内的原生
if
/
else
语句
有限循环
run()
内带
break
的原生
for
/
while
循环
会话间数据流
ctx.save()
持久化 → 用
ctx.transcript()
ctx.getMessages()
获取
单会话配置SDK专属配置:Claude
query({ options })
、Copilot
createSession({ ... })
、OpenCode
createOpencode({ config })
响应数据提取直接解析SDK响应:Claude结果消息、Copilot
SessionEvent[]
、OpenCode响应片段
子Agent编排Claude:带
AgentDefinition[]
agents
选项;Copilot:通过prompt委托;OpenCode:分叉会话
运行时校验原生TypeScript或在
run()
内直接导入Zod

Authoring Process

编写流程

1. Understand the User's Goal

1. 理解用户目标

Map the user's intent to sessions and programmatic patterns:
QuestionMaps to
What are the distinct steps?Each step →
.session()
Does any step need deterministic computation (no LLM)?Plain TypeScript inside
run()
Do any steps need to repeat?
for
/
while
loop inside
run()
Are there conditional paths?
if
/
else
inside
run()
What data flows between steps?
ctx.save()
ctx.transcript()
/
ctx.getMessages()
Does the workflow need user input?SDK-specific user input APIs (see
user-input.md
)
Do any steps need a specific model?SDK-specific session config (see
session-config.md
)
Does a step need structured output?Claude:
outputFormat
; Copilot: parse response; OpenCode:
format
option
将用户意图映射为会话和编程模式:
问题对应实现
包含哪些执行步骤?每个步骤对应一个
.session()
是否有步骤需要确定性计算(无LLM参与)?
run()
内编写原生TypeScript代码
是否有步骤需要重复执行?
run()
内编写
for
/
while
循环
是否存在条件分支路径?
run()
内编写
if
/
else
语句
步骤之间需要传递哪些数据?
ctx.save()
ctx.transcript()
/
ctx.getMessages()
工作流是否需要用户输入?使用SDK专属的用户输入API(参考
user-input.md
是否有步骤需要指定特定模型?使用SDK专属的会话配置(参考
session-config.md
是否有步骤需要结构化输出?Claude:
outputFormat
;Copilot:解析响应;OpenCode:
format
选项

2. Choose the Target Agent

2. 选择目标Agent

Workflows are per-SDK. Decide which agent SDK to target:
AgentSDK ImportPrimary API
Claude
claudeQuery
from
@bastani/atomic-workflows
claudeQuery({ paneId, prompt })
— automates Claude TUI via tmux
Copilot
CopilotClient
from
@github/copilot-sdk
client.createSession()
session.sendAndWait({ prompt })
OpenCode
createOpencodeClient
from
@opencode-ai/sdk/v2
client.session.create()
client.session.prompt({ ... })
If you need cross-agent support, create one workflow file per agent under
.atomic/workflows/<agent>/<name>/index.ts
. Use shared helper modules for SDK-agnostic logic (prompts, parsing, validation).
工作流是单SDK专属的,先确定要适配的Agent SDK:
AgentSDK导入核心API
Claude
@bastani/atomic-workflows
导入
claudeQuery
claudeQuery({ paneId, prompt })
——通过tmux自动化控制Claude TUI
Copilot
@github/copilot-sdk
导入
CopilotClient
client.createSession()
session.sendAndWait({ prompt })
OpenCode
@opencode-ai/sdk/v2
导入
createOpencodeClient
client.session.create()
client.session.prompt({ ... })
如果需要跨Agent支持,在
.atomic/workflows/<agent>/<name>/index.ts
下为每个Agent单独创建工作流文件,将与SDK无关的逻辑(prompt、解析、校验)封装为共享工具模块复用。

3. Design the Session Sequence

3. 设计会话序列

Each
.session()
call defines one step:
FieldPurpose
name
Unique identifier. Used as the key in
ctx.transcript("<name>")
for downstream access.
description
Short label for logging and the orchestrator UI.
run
Async callback receiving
SessionContext
. Write SDK code here.
每个
.session()
调用定义一个执行步骤:
字段作用
name
唯一标识符,作为
ctx.transcript("<name>")
的key供下游会话调用
description
简短标注,用于日志和编排器UI展示
run
接收
SessionContext
的异步回调,在此处编写SDK代码

4. Write the Workflow File

4. 编写工作流文件

Claude example:
ts
// .atomic/workflows/claude/my-workflow/index.ts
import { defineWorkflow, claudeQuery } from "@bastani/atomic-workflows";

export default defineWorkflow({
    name: "my-workflow",
    description: "Two-step pipeline",
  })
  .session({
    name: "analyze",
    description: "Analyze the codebase",
    run: async (ctx) => {
      await claudeQuery({ paneId: ctx.paneId, prompt: ctx.userPrompt });
      ctx.save(ctx.sessionId);
    },
  })
  .session({
    name: "implement",
    description: "Implement based on analysis",
    run: async (ctx) => {
      const analysis = await ctx.transcript("analyze");
      await claudeQuery({
        paneId: ctx.paneId,
        prompt: `Based on this analysis:\n${analysis.content}\n\nImplement the changes.`,
      });
      ctx.save(ctx.sessionId);
    },
  })
  .compile();
Copilot example:
ts
// .atomic/workflows/copilot/my-workflow/index.ts
import { defineWorkflow } from "@bastani/atomic-workflows";
import { CopilotClient, approveAll } from "@github/copilot-sdk";

export default defineWorkflow({
    name: "my-workflow",
    description: "Two-step pipeline",
  })
  .session({
    name: "analyze",
    description: "Analyze the codebase",
    run: async (ctx) => {
      const client = new CopilotClient({ cliUrl: ctx.serverUrl });
      await client.start();
      const session = await client.createSession({ onPermissionRequest: approveAll });
      await client.setForegroundSessionId(session.sessionId);

      await session.sendAndWait({ prompt: ctx.userPrompt });
      ctx.save(await session.getMessages());

      await session.disconnect();
      await client.stop();
    },
  })
  .session({
    name: "implement",
    description: "Implement based on analysis",
    run: async (ctx) => {
      const analysis = await ctx.transcript("analyze");
      const client = new CopilotClient({ cliUrl: ctx.serverUrl });
      await client.start();
      const session = await client.createSession({ onPermissionRequest: approveAll });
      await client.setForegroundSessionId(session.sessionId);

      await session.sendAndWait({
        prompt: `Based on this analysis:\n${analysis.content}\n\nImplement the changes.`,
      });
      ctx.save(await session.getMessages());

      await session.disconnect();
      await client.stop();
    },
  })
  .compile();
OpenCode example:
ts
// .atomic/workflows/opencode/my-workflow/index.ts
import { defineWorkflow } from "@bastani/atomic-workflows";
import { createOpencodeClient } from "@opencode-ai/sdk/v2";

export default defineWorkflow({
    name: "my-workflow",
    description: "Two-step pipeline",
  })
  .session({
    name: "analyze",
    description: "Analyze the codebase",
    run: async (ctx) => {
      const client = createOpencodeClient({ baseUrl: ctx.serverUrl });
      const session = await client.session.create({ title: "analyze" });
      await client.tui.selectSession({ sessionID: session.data!.id });

      const result = await client.session.prompt({
        sessionID: session.data!.id,
        parts: [{ type: "text", text: ctx.userPrompt }],
      });
      ctx.save(result.data!);
    },
  })
  .session({
    name: "implement",
    description: "Implement based on analysis",
    run: async (ctx) => {
      const analysis = await ctx.transcript("analyze");
      const client = createOpencodeClient({ baseUrl: ctx.serverUrl });
      const session = await client.session.create({ title: "implement" });
      await client.tui.selectSession({ sessionID: session.data!.id });

      const result = await client.session.prompt({
        sessionID: session.data!.id,
        parts: [{
          type: "text",
          text: `Based on this analysis:\n${analysis.content}\n\nImplement the changes.`,
        }],
      });
      ctx.save(result.data!);
    },
  })
  .compile();
Claude示例:
ts
// .atomic/workflows/claude/my-workflow/index.ts
import { defineWorkflow, claudeQuery } from "@bastani/atomic-workflows";

export default defineWorkflow({
    name: "my-workflow",
    description: "Two-step pipeline",
  })
  .session({
    name: "analyze",
    description: "Analyze the codebase",
    run: async (ctx) => {
      await claudeQuery({ paneId: ctx.paneId, prompt: ctx.userPrompt });
      ctx.save(ctx.sessionId);
    },
  })
  .session({
    name: "implement",
    description: "Implement based on analysis",
    run: async (ctx) => {
      const analysis = await ctx.transcript("analyze");
      await claudeQuery({
        paneId: ctx.paneId,
        prompt: `Based on this analysis:\n${analysis.content}\n\nImplement the changes.`,
      });
      ctx.save(ctx.sessionId);
    },
  })
  .compile();
Copilot示例:
ts
// .atomic/workflows/copilot/my-workflow/index.ts
import { defineWorkflow } from "@bastani/atomic-workflows";
import { CopilotClient, approveAll } from "@github/copilot-sdk";

export default defineWorkflow({
    name: "my-workflow",
    description: "Two-step pipeline",
  })
  .session({
    name: "analyze",
    description: "Analyze the codebase",
    run: async (ctx) => {
      const client = new CopilotClient({ cliUrl: ctx.serverUrl });
      await client.start();
      const session = await client.createSession({ onPermissionRequest: approveAll });
      await client.setForegroundSessionId(session.sessionId);

      await session.sendAndWait({ prompt: ctx.userPrompt });
      ctx.save(await session.getMessages());

      await session.disconnect();
      await client.stop();
    },
  })
  .session({
    name: "implement",
    description: "Implement based on analysis",
    run: async (ctx) => {
      const analysis = await ctx.transcript("analyze");
      const client = new CopilotClient({ cliUrl: ctx.serverUrl });
      await client.start();
      const session = await client.createSession({ onPermissionRequest: approveAll });
      await client.setForegroundSessionId(session.sessionId);

      await session.sendAndWait({
        prompt: `Based on this analysis:\n${analysis.content}\n\nImplement the changes.`,
      });
      ctx.save(await session.getMessages());

      await session.disconnect();
      await client.stop();
    },
  })
  .compile();
OpenCode示例:
ts
// .atomic/workflows/opencode/my-workflow/index.ts
import { defineWorkflow } from "@bastani/atomic-workflows";
import { createOpencodeClient } from "@opencode-ai/sdk/v2";

defineWorkflow({
    name: "my-workflow",
    description: "Two-step pipeline",
  })
  .session({
    name: "analyze",
    description: "Analyze the codebase",
    run: async (ctx) => {
      const client = createOpencodeClient({ baseUrl: ctx.serverUrl });
      const session = await client.session.create({ title: "analyze" });
      await client.tui.selectSession({ sessionID: session.data!.id });

      const result = await client.session.prompt({
        sessionID: session.data!.id,
        parts: [{ type: "text", text: ctx.userPrompt }],
      });
      ctx.save(result.data!);
    },
  })
  .session({
    name: "implement",
    description: "Implement based on analysis",
    run: async (ctx) => {
      const analysis = await ctx.transcript("analyze");
      const client = createOpencodeClient({ baseUrl: ctx.serverUrl });
      const session = await client.session.create({ title: "implement" });
      await client.tui.selectSession({ sessionID: session.data!.id });

      const result = await client.session.prompt({
        sessionID: session.data!.id,
        parts: [{
          type: "text",
          text: `Based on this analysis:\n${analysis.content}\n\nImplement the changes.`,
        }],
      });
      ctx.save(result.data!);
    },
  })
  .compile();

5. Type-Check the Workflow

5. 工作流类型检查

bash
bunx tsc --noEmit --pretty false
bash
bunx tsc --noEmit --pretty false

6. Test the Workflow

6. 测试工作流

bash
atomic workflow -n <workflow-name> -a <agent> "<your prompt>"
bash
atomic workflow -n <workflow-name> -a <agent> "<your prompt>"

Key Patterns

核心模式

Linear Pipeline

线性流水线

ts
defineWorkflow({ name: "pipeline", description: "Sequential pipeline" })
  .session({ name: "plan", run: async (ctx) => { /* plan */ } })
  .session({ name: "execute", run: async (ctx) => { /* execute */ } })
  .session({ name: "verify", run: async (ctx) => { /* verify */ } })
  .compile();
ts
defineWorkflow({ name: "pipeline", description: "Sequential pipeline" })
  .session({ name: "plan", run: async (ctx) => { /* plan */ } })
  .session({ name: "execute", run: async (ctx) => { /* execute */ } })
  .session({ name: "verify", run: async (ctx) => { /* verify */ } })
  .compile();

Review/Fix Loop (inside a single session)

评审/修复循环(单会话内)

Loops are plain TypeScript inside
run()
. The Ralph workflow demonstrates a review/fix loop:
ts
.session({
  name: "review-fix",
  description: "Iterative review and fix",
  run: async (ctx) => {
    const MAX_CYCLES = 10;
    let consecutiveClean = 0;

    for (let cycle = 0; cycle < MAX_CYCLES; cycle++) {
      // Step 1: Ask the agent to review
      const reviewResult = await claudeQuery({
        paneId: ctx.paneId,
        prompt: buildReviewPrompt(ctx.userPrompt),
      });

      // Step 2: Parse and check findings (deterministic computation)
      const review = parseReviewResult(reviewResult.output);
      if (!hasActionableFindings(review, reviewResult.output)) {
        consecutiveClean++;
        if (consecutiveClean >= 2) break; // Two clean passes → done
        continue;
      }
      consecutiveClean = 0;

      // Step 3: Apply fixes
      const fixPrompt = buildFixSpecFromReview(review, ctx.userPrompt);
      await claudeQuery({ paneId: ctx.paneId, prompt: fixPrompt });
    }

    ctx.save(ctx.sessionId);
  },
})
循环使用
run()
内的原生TypeScript实现,Ralph工作流演示了评审/修复循环的实现:
ts
.session({
  name: "review-fix",
  description: "Iterative review and fix",
  run: async (ctx) => {
    const MAX_CYCLES = 10;
    let consecutiveClean = 0;

    for (let cycle = 0; cycle < MAX_CYCLES; cycle++) {
      // Step 1: Ask the agent to review
      const reviewResult = await claudeQuery({
        paneId: ctx.paneId,
        prompt: buildReviewPrompt(ctx.userPrompt),
      });

      // Step 2: Parse and check findings (deterministic computation)
      const review = parseReviewResult(reviewResult.output);
      if (!hasActionableFindings(review, reviewResult.output)) {
        consecutiveClean++;
        if (consecutiveClean >= 2) break; // Two clean passes → done
        continue;
      }
      consecutiveClean = 0;

      // Step 3: Apply fixes
      const fixPrompt = buildFixSpecFromReview(review, ctx.userPrompt);
      await claudeQuery({ paneId: ctx.paneId, prompt: fixPrompt });
    }

    ctx.save(ctx.sessionId);
  },
})

Conditional Branching (inside
run()
)

条件分支(
run()
内)

ts
.session({
  name: "triage-and-act",
  description: "Triage, then branch based on result",
  run: async (ctx) => {
    // Step 1: Triage
    const triageResult = await claudeQuery({
      paneId: ctx.paneId,
      prompt: `Classify this request as "bug", "feature", or "question":\n${ctx.userPrompt}`,
    });

    // Step 2: Branch based on classification
    if (triageResult.output.includes("bug")) {
      await claudeQuery({ paneId: ctx.paneId, prompt: "Fix the bug described above." });
    } else if (triageResult.output.includes("feature")) {
      await claudeQuery({ paneId: ctx.paneId, prompt: "Implement the feature described above." });
    } else {
      await claudeQuery({ paneId: ctx.paneId, prompt: "Research and answer the question above." });
    }

    ctx.save(ctx.sessionId);
  },
})
ts
.session({
  name: "triage-and-act",
  description: "Triage, then branch based on result",
  run: async (ctx) => {
    // Step 1: Triage
    const triageResult = await claudeQuery({
      paneId: ctx.paneId,
      prompt: `Classify this request as "bug", "feature", or "question":\n${ctx.userPrompt}`,
    });

    // Step 2: Branch based on classification
    if (triageResult.output.includes("bug")) {
      await claudeQuery({ paneId: ctx.paneId, prompt: "Fix the bug described above." });
    } else if (triageResult.output.includes("feature")) {
      await claudeQuery({ paneId: ctx.paneId, prompt: "Implement the feature described above." });
    } else {
      await claudeQuery({ paneId: ctx.paneId, prompt: "Research and answer the question above." });
    }

    ctx.save(ctx.sessionId);
  },
})

Data Passing Between Sessions

会话间数据传递

ts
defineWorkflow({ name: "data-flow", description: "Pass data between sessions" })
  .session({
    name: "research",
    run: async (ctx) => {
      // ... perform research ...
      ctx.save(ctx.sessionId); // Save transcript
    },
  })
  .session({
    name: "synthesize",
    run: async (ctx) => {
      // Read prior session's output
      const research = await ctx.transcript("research");
      // Use as rendered text:
      const prompt = `Synthesize this research:\n${research.content}`;
      // Or reference the file path:
      const altPrompt = `Read ${research.path} and synthesize the findings.`;
      // ... use the data ...
      ctx.save(ctx.sessionId);
    },
  })
  .compile();
ts
defineWorkflow({ name: "data-flow", description: "Pass data between sessions" })
  .session({
    name: "research",
    run: async (ctx) => {
      // ... perform research ...
      ctx.save(ctx.sessionId); // Save transcript
    },
  })
  .session({
    name: "synthesize",
    run: async (ctx) => {
      // Read prior session's output
      const research = await ctx.transcript("research");
      // Use as rendered text:
      const prompt = `Synthesize this research:\n${research.content}`;
      // Or reference the file path:
      const altPrompt = `Read ${research.path} and synthesize the findings.`;
      // ... use the data ...
      ctx.save(ctx.sessionId);
    },
  })
  .compile();

Shared Helper Functions

共享工具函数

Extract SDK-agnostic logic into shared helpers for reuse across agents:
.atomic/workflows/
├── claude/my-workflow/index.ts     # Claude-specific SDK code
├── copilot/my-workflow/index.ts    # Copilot-specific SDK code
├── opencode/my-workflow/index.ts   # OpenCode-specific SDK code
└── my-workflow/helpers/
    ├── prompts.ts                  # Prompt builders (SDK-agnostic)
    ├── parsers.ts                  # Response parsers (SDK-agnostic)
    └── validation.ts              # Validation logic (SDK-agnostic)
ts
// .atomic/workflows/my-workflow/helpers/prompts.ts
export function buildPlanPrompt(spec: string): string {
  return `Decompose this into tasks:\n${spec}`;
}

// .atomic/workflows/claude/my-workflow/index.ts
import { buildPlanPrompt } from "../../my-workflow/helpers/prompts.ts";
// ...
await claudeQuery({ paneId: ctx.paneId, prompt: buildPlanPrompt(ctx.userPrompt) });
将与SDK无关的逻辑提取为共享工具,供不同Agent复用:
.atomic/workflows/
├── claude/my-workflow/index.ts     # Claude-specific SDK code
├── copilot/my-workflow/index.ts    # Copilot-specific SDK code
├── opencode/my-workflow/index.ts   # OpenCode-specific SDK code
└── my-workflow/helpers/
    ├── prompts.ts                  # Prompt builders (SDK-agnostic)
    ├── parsers.ts                  # Response parsers (SDK-agnostic)
    └── validation.ts              # Validation logic (SDK-agnostic)
ts
// .atomic/workflows/my-workflow/helpers/prompts.ts
export function buildPlanPrompt(spec: string): string {
  return `Decompose this into tasks:\n${spec}`;
}

// .atomic/workflows/claude/my-workflow/index.ts
import { buildPlanPrompt } from "../../my-workflow/helpers/prompts.ts";
// ...
await claudeQuery({ paneId: ctx.paneId, prompt: buildPlanPrompt(ctx.userPrompt) });

SessionContext
Reference

SessionContext
参考

The
SessionContext
object is passed to each session's
run()
callback:
FieldTypeDescription
serverUrl
string
The agent's server URL (Copilot
--ui-server
/ OpenCode built-in server)
userPrompt
string
The original user prompt from the CLI invocation
agent
AgentType
Which agent is running (
"claude"
,
"copilot"
, or
"opencode"
)
transcript(name)
(name: string) => Promise<Transcript>
Get a prior session's transcript as
{ path, content }
getMessages(name)
(name: string) => Promise<SavedMessage[]>
Get a prior session's raw native messages
save
SaveTranscript
Save this session's output for subsequent sessions
sessionDir
string
Path to this session's storage directory on disk
paneId
string
tmux pane ID for this session
sessionId
string
Session UUID
SessionContext
对象会传递给每个会话的
run()
回调:
字段类型描述
serverUrl
string
Agent的服务URL(Copilot
--ui-server
/ OpenCode内置服务)
userPrompt
string
CLI调用时传入的原始用户prompt
agent
AgentType
运行的Agent类型(
"claude"
"copilot"
"opencode"
transcript(name)
(name: string) => Promise<Transcript>
获取前置会话的记录,格式为
{ path, content }
getMessages(name)
(name: string) => Promise<SavedMessage[]>
获取前置会话的原生消息列表
save
SaveTranscript
保存当前会话的输出供后续会话使用
sessionDir
string
当前会话存储目录的本地路径
paneId
string
当前会话的tmux面板ID
sessionId
string
会话UUID

ctx.save()
— Provider-Specific

ctx.save()
— 服务商专属用法

  • Claude:
    ctx.save(ctx.sessionId)
    — pass the session ID; transcript is auto-read
  • Copilot:
    ctx.save(await session.getMessages())
    — pass
    SessionEvent[]
  • OpenCode:
    ctx.save(result.data!)
    — pass the
    { info, parts }
    response object
  • Claude
    ctx.save(ctx.sessionId)
    — 传入会话ID,会话记录会自动读取
  • Copilot
    ctx.save(await session.getMessages())
    — 传入
    SessionEvent[]
  • OpenCode
    ctx.save(result.data!)
    — 传入
    { info, parts }
    响应对象

ctx.transcript(name)
— Rendered Text

ctx.transcript(name)
— 渲染后的文本

Returns
{ path: string, content: string }
— the file path on disk and the rendered assistant text. Use
content
for embedding in prompts, or
path
for file-based triggers.
返回
{ path: string, content: string }
— 本地文件路径和渲染后的助手响应文本。
content
可直接嵌入prompt,
path
可用于文件触发逻辑。

Structural Rules

结构规则

  1. Unique session names — every
    name
    must be unique across all
    .session()
    calls.
  2. .compile()
    required
    — the chain must end with
    .compile()
    .
  3. At least one session
    compile()
    throws if no sessions are defined.
  4. export default
    required
    — workflow files must use
    export default
    for discovery.
  5. Forward-only data flow
    ctx.transcript("<name>")
    only has data from already-completed sessions.
  1. 会话名称唯一 —— 所有
    .session()
    调用的
    name
    必须全局唯一
  2. 必须调用
    .compile()
    —— 调用链末尾必须以
    .compile()
    结束
  3. 至少包含一个会话 —— 没有定义会话时
    compile()
    会抛出错误
  4. 必须使用
    export default
    —— 工作流文件必须通过
    export default
    导出才能被发现
  5. 仅支持前向数据流 ——
    ctx.transcript("<name>")
    只能获取已完成会话的数据