browser-flow のすべての名詞には定義が1つだけあります。このページは、残りのドキュメントが前提にするグロッサリです。データ型は Zod スキーマ(このプロジェクトの標準形式)として示します。Fooz.infer<typeof FooSchema> を表します。

0. 共有スキーマ語彙

4つの小さなスキーマが全体で参照されます。ここで一度だけ定義します。
import { z } from "zod";

/**
 * 小さな JSON Schema(Draft 2020-12)のサブセット: tool/flow の I/O slot が
 * 取り得る型。スカラー、配列、オブジェクトを扱えるため、入力は単なる
 * スカラーに限定されません(tool はオブジェクト body や配列などを宣言できます)。
 */
export type JsonSchema =
  | { type: "string" | "number" | "boolean" | "null" }
  | { type: "array"; items: JsonSchema }
  | {
      type: "object";
      properties: Record<string, JsonSchema>;
      required?: string[];
      additionalProperties?: boolean;
    };

export const JsonSchemaSchema: z.ZodType<JsonSchema> = z.lazy(() =>
  z.union([
    z.object({ type: z.enum(["string", "number", "boolean", "null"]) }).strict(),
    z.object({ type: z.literal("array"), items: JsonSchemaSchema }).strict(),
    z
      .object({
        type: z.literal("object"),
        properties: z.record(z.string(), JsonSchemaSchema),
        required: z.array(z.string()).optional(),
        additionalProperties: z.boolean().optional(),
      })
      .strict(),
  ]),
);

/**
 * 式: `${{ … }}` の内側(またはリテラル)に現れるソーステキスト。
 * コンパイラが生の文字列と、解析・検証済みの式を区別できるよう
 * branded されています。Grammar: [02 — Authoring](02-authoring.md#expression-language)。
 */
export const ExprSchema = z.string().brand<"Expr">();
export type Expr = z.infer<typeof ExprSchema>;

/** Step ごとの retry policy。デフォルトは tool の `kind` から導かれます([04 §4](04-execution.md#4-retries-timeouts-idempotency))。 */
export const RetryPolicySchema = z
  .object({
    max: z.number().int().nonnegative(),
    backoff: z.enum(["exp", "fixed"]),
    base_ms: z.number().int().positive(),
    jitter: z.boolean(),
  })
  .strict();
export type RetryPolicy = z.infer<typeof RetryPolicySchema>;

/**
 * pin された tool dependency: 正確な `name@version` ref と、解決済みの
 * contract digest。これにより flow の identity は version label だけでなく
 * tool の *behavior* まで閉じます([03 §5](03-ir.md#5-the-digest))。
 */
export const RequireSchema = z
  .object({ ref: z.string().min(1), contract_digest: z.string().min(1) })
  .strict();
export type Require = z.infer<typeof RequireSchema>;

1. 7つの名詞

名詞ひと言で作成者存在する場所
Tool型付き I/O contract を持つ決定論的な作業単位pack authorPack
StepFlow 内での Tool の1回の呼び出しと、その配線flow authorFlow
FlowSteps の DAG、つまりワークフローflow author(SDK または YAML)Pack / ファイル
FlowSpecFlow がコンパイルされる、正規化された content-addressed IRコンパイラregistry / .flow.json
RunFlowSpec の1回の実行。Journal を伴うRider(engine)Store
PackTools + Flows の、バージョン付きかつ content-addressed な bundle(“SDK”)pack authorRegistry
RegistryPacks が公開、バージョン管理、複製される場所サービスself-host / cloud
さらに2つの役割があります。Rider(実行エンジン)と、Rider を駆動するホストである Launcher(CLI、REST、MCP、cron など)です。

2. Tool — 最小単位

Tool は、Step が呼び出せる最小の再利用可能な単位です。Tool は contract によって定義されます。contract には、名前、version、型付き input、型付き output、宣言された capabilities、そして run 関数が含まれます。重要なのは、Tool が 入力と記録済み effect が与えられれば決定論的であることです。Tool は判断せず、実行します。 contract はこのプロジェクト内で一から定義されています。input は、型付きで、任意に secret にできる slot として宣言されます。
import { z } from "zod";

/**
 * tool 上で宣言される1つの input slot。tool の caller と body の間の contract です。
 * tool は input を名前と `schema` で読み取り、`secret: true` の slot は run boundary
 * (§7)を決して出ません。`schema` は slot の JSON-Schema-subset 型です。
 * スカラー **だけでなく** object/array も扱えるため、tool はたとえば object request body
 * を宣言できます。YAML surface は `type: string|number|boolean` という shorthand を受け付け、
 * canonicalization 中に `{ "type": … }` へ展開します
 * ([02 §3](02-authoring.md#3-the-same-flow-three-ways))。
 */
export const InputDeclSchema = z
  .object({
    name: z.string().min(1),
    schema: JsonSchemaSchema,
    secret: z.boolean(),
  })
  .strict();

export type InputDecl = z.infer<typeof InputDeclSchema>;

/**
 * tool の interface contract。`inputs`/`output` は型付けされるため、配線は
 * author time にチェックされ、run time に検証されます。`capabilities` は tool が
 * 使用を許可された effect を列挙します(T2: permission による effects)。
 * Rider はそれらだけを注入し、それ以上は注入しません。`provenance.source_digest` は
 * tool body を作成したもの(例: 記録済み browser session)の content-addressed
 * fingerprint なので、tool は pin でき、監査できます。
 */
export const ToolContractSchema = z
  .object({
    schema_version: z.literal("1.0"),
    name: z.string().min(1),
    version: z.string().min(1), // semver
    kind: z.enum(["browser", "http", "shell", "transform", "code", "model", "composite"]),
    description: z.string().min(1),
    inputs: z.array(InputDeclSchema),
    output: JsonSchemaSchema, // 小さな JSON Schema(Draft 2020-12)のサブセット
    capabilities: z.array(z.enum(["net", "fs", "browser", "clock", "random", "env", "spawn", "secrets"])),
    provenance: z
      .object({ source_digest: z.string().optional(), pack: z.string().optional() })
      .strict(),
  })
  .strict();

export type ToolContract = z.infer<typeof ToolContractSchema>;
Tool の kind は標準 Pack に含まれます(Tools & Packs を参照)。
一度記録され、モデルなしでリプレイされる決定論的な Playwright オートメーション。これが代表的な tool kind です。
HTTP リクエストを発行する tool kind です。
shell コマンドを実行する tool kind です。
純粋な JSON→JSON 関数です。
capability によって sandbox される escape hatch です。
宣言され、記録された LLM 呼び出しです。author-time の利便性であり、runtime decision ではありません。
Tool として再公開された Flow です。flow を入れ子にする仕組みです。
composite tool は内側の flow から contract を継承します。その際、入れ子構造を正直に保つ2つのルールがあります。宣言される capabilities は、内側の flow が呼び出すすべての tool の capabilities の union です。入れ子は effect を隠しません。また、外側の composite の secret: true input は、内側の flow で対応する secret input への reference として渡され、最も内側の secrets capability を持つ tool でのみ解決されます。そのため、どの深さの入れ子でも boundary(§7)は維持されます。

3. Step — 1回の呼び出し

Step は Tool を Flow 内の位置に結び付けます。呼び出しに id を与え、Flow のデータを Tool の inputswith)へ map し、依存関係を宣言し、必要に応じて retry / timeout / conditional policy を付与します。
export const StepSchema = z
  .object({
    id: z.string().min(1), // flow 内で一意。編集をまたいで stable
    use: z.string().min(1), // "browser:search-price@1.2.0" | "http.post" | "flow:sub@2"
    with: z.record(z.string(), ExprSchema).optional(), // input bindings(expression の場合があります)
    needs: z.array(z.string()).optional(), // explicit deps。なければ refs から推論
    when: ExprSchema.optional(), // これが truthy に評価された場合のみ run
    retry: RetryPolicySchema.optional(),
    timeout_ms: z.number().int().positive().optional(),
    foreach: ExprSchema.optional(), // array に fan out(map)
    output_as: z.string().optional(), // downstream references 用の alias
  })
  .strict();

export type Step = z.infer<typeof StepSchema>;
データは expression 内の references を通じて Step 間を流れます。
${{ steps.lookup.output.price }}
${{ input.query }}
${{ env.REGION }}
コンパイラはこれらの references を読んで依存関係の edge を構築するため、needs は通常、手で書かれずに推論されます。expression language については Authoring を、references が graph edges になる仕組みについては FlowSpec IR を参照してください。

4. Flow — ワークフロー

Flow は、型付き input contract と型付き output projection を持つ、名前付きの Steps の DAG です。control flow は宣言的に表現されます。
  • branch — condition によって steps の sub-list を選ぶ(when field、または fluent な .branch())。
  • foreach — step(または sub-flow)を array に対して fan out し、結果を集める。
  • parallel — edge のない独立した steps は、デフォルトで同時に実行される。concurrency は launcher によって制限される。
  • nesting — Flow は composite Tool として公開し、別の Flow 内の1つの Step として呼び出せるため、大きな process も読みやすく保てる。
Flow は作成対象そのものです。Flow は FlowSpec にコンパイルされます。

5. FlowSpec — 正規 IR

FlowSpec は、browser-flow において Trailbrowser-flow に対して持つ関係と同じもの、つまり 単一の中間表現 です。どちらの authoring surface も FlowSpec を生成し、FlowSpec は YAML へ round-trip できます。FlowSpec は canonicalized(key の sort、expression の normalize、tool version の resolve)され、sha256 digest に hashed されます。この digest が、cache、pinning、replication における flow の identity です。
export const FlowSpecSchema = z
  .object({
    schema_version: z.literal("1.0"),
    name: z.string().min(1),
    description: z.string().optional(),
    inputs: z.array(InputDeclSchema),
    output: ExprSchema.optional(),
    steps: z.array(StepSchema),
    requires: z.array(RequireSchema), // pinned tool ref + resolved contract digest
    digest: z.string().optional(), // canonical form の sha256(compiler が埋める)
  })
  .strict();

export type FlowSpec = z.infer<typeof FlowSpecSchema>;
canonicalization rules、digest algorithm、graph derivation の詳しい説明は FlowSpec IR にあります。

6. Run — 1回の実行

Run は、Rider が具体的な inputs に対して FlowSpec を実行することです。Run は Journal を生成します。Journal は、step lifecycle events(started、output、failed、retried、skipped)に加え、解決済み inputs と最終 output を含む、append-only で順序付きの log です。
export const RunSchema = z
  .object({
    id: z.string().min(1), // uuidv4
    flow_digest: z.string().min(1), // 実行された FlowSpec を正確に示す
    status: z.enum(["pending", "running", "succeeded", "failed", "canceled"]),
    started_at: z.string(), // ISO-8601
    finished_at: z.string().optional(),
    journal: z.array(JournalEntrySchema),
    output: z.unknown().optional(),
  })
  .strict();

export type Run = z.infer<typeof RunSchema>;
Journal によって、Run は 再開可能(完了済み steps を再実行せず log から replay する)かつ inspectable(CLI または UI で run を time-travel する)になります。Execution を参照してください。

7. Secrets — 境界

Secrets は、flow 全体にまたがる value ではなく boundary です。secret: true の input slot は次の性質を持ちます。
  • FlowSpec、Journal、log line、公開済み Pack のいずれにも現れません。
  • secrets capability を持つ Tool が注入された Secrets provider を通じて解決する瞬間まで、reference{ slot, refers_to })としてのみ運ばれます。
  • そうでなければ leak し得るすべての場所で maskInputs によって masked されます。
flow author は ${{ secret.WEBHOOK_URL }} と書きます。その value が実体化するのは、secrets capability を宣言した step の内部だけ、かつ run time だけです。

taint rule(静的に強制)

secret. reference は opaque です。これは、変換されていない全体のまま、tool input への argument としてのみ bind できます。そして、その tool が secrets capability を宣言している場合に限られます。secret reference は次のことができません。
  • operator、member access、built-in function のいずれも通過できません。secret.x + yjson(secret.x)default(secret.x, z)secret.x.foo はすべて拒否されます。
  • secrets を宣言していない tool へ bind できません。
  • output のどこにも現れることはできません。
各違反は secret_leak diagnostic であり、compile time の single-pass taint check によって証明されます(FlowSpec IR §7)。得られる効果は機械的です。secret は expression layer を通過しないため、その value が URL、header、browser field に組み込まれるのは、解決する tool の 内部 だけです。そして、そこは effect を記録する layer そのものなので、Journal に到達する前に secret を redact できる layer でもあります(Execution §5a)。

8. Pack — デプロイ可能な SDK

Pack は、Tools と Flows のバージョン付きかつ content-addressed な bundle です。Pack は deployment(“deploy SDKs”)、versioning(semver + digest)、replication(“services to replicate them”)の単位です。Pack の manifest には、その tools(それぞれ自身の contract digest を持つ)と flows(それぞれ FlowSpec digest を持つ)が列挙されます。そのため Pack は全体として再現可能です。一度取得し、すべての digest を検証すれば、永久に offline で実行できます。
export const PackManifestSchema = z
  .object({
    schema_version: z.literal("1.0"),
    name: z.string().min(1), // "@acme/pricing"
    version: z.string().min(1), // semver
    tools: z.array(z.object({ ref: z.string(), contract_digest: z.string() }).strict()),
    flows: z.array(z.object({ name: z.string(), flow_digest: z.string() }).strict()),
    dependencies: z.array(z.string()), // 他の packs。pinned
    digest: z.string(), // canonical manifest の sha256
  })
  .strict();

export type PackManifest = z.infer<typeof PackManifestSchema>;
Packs と Registry の詳細は Tools & PacksControl Plane にあります。

9. Registry、Rider、Launcher — runtime cast

  • Registry — Packs が公開され、そこから解決される場所です。local registry は directory であり、team registry は control plane です。Registries は互いに(push / pull / scheduled で)replicate し、digest によって検証されます。そのため、ある environment で作成された Pack は、pin され完全性を保ったまま、別の environment に現れます。
  • Rider — 実行エンジンです。FlowSpec + inputs + 注入された capabilities の set を受け取り、Run を生成します。何かを実行する 唯一 の component であり、model を実行しません
  • Launcher — environment 向けの capabilities を構築して Rider を呼び出す薄い host です。browserflow run(CLI)、HTTP route(REST)、MCP tool(agents)、cron tick、CI step などです。同じ FlowSpec が、どの Launcher の下でも変更なしに実行されます。Launchers を参照してください。

10. すべての組み合わせ

オーサリング: SDK & YAML

TypeScript SDK と YAML surface の両方で同じ flow を書きます。

FlowSpec IR

正規化ルール、digest algorithm、graph derivation。