Skip to content
Learn Kiro.

Recipes · Chapter 42 of 69

Write Your First Workflow Recipe

Write a Kiro workflow recipe in .kiro/workflows/ that implements a change, reviews it with two parallel agents, and loops until a JSON verdict says APPROVED. Validate it, run it in the IDE and CLI, and fix the usual problems.

All levels 7 min read last reviewed 2026-10-04

◎ Learning objective

Save a small implement-review-loop recipe under .kiro/workflows/, validate it, launch it from the IDE or CLI, and read the run's evidence when it finishes.

A recipe is a small JSON or YAML file that tells Kiro’s runtime which agents to run, in what order, and when to stop. This one implements a change, has two reviewers look at it independently, merges their findings into a verdict, and repeats until the verdict is APPROVED or three attempts are used up.

When to use this

Use this when a change is big enough to deserve a separate reviewer but you do not want to supervise the review yourself, and when you want to learn the recipe format with something that exercises repeat, parallel, artifacts, and a stop condition in one file. It is not for a one-line fix; a loop with four agent steps per iteration costs more credits than a chat session, so start with a small task.

The recipe uses only agents Kiro ships for workflows. Swap in your own custom agent once you want tighter tools or a different model for a step.

Steps

  1. Turn workflows on in the client you will use. IDE: in Agent Focus, Workspace Configuration → Workflows → enable (kiroAgent.workflows.enabled), then start a new chat. CLI V3: /settings → Features → Workflows, then exit and restart the CLI. Web: Settings → Workflows → Enable workflows. If the option is missing, the feature is not available for your account yet.

  2. Save the recipe. The file must sit in .kiro/workflows/ and end in .workflow.json (or .workflow.yaml / .workflow.yml).

    .kiro/workflows/implement-and-review.workflow.json

    {
      "name": "implement-and-review",
      "description": "Implement a change, review it twice independently, loop until approved",
      "inputs": {
        "task": "prompt"
      },
      "steps": [
        {
          "type": "repeat",
          "id": "review-loop",
          "maxIterations": 3,
          "onMaxIterations": "pause",
          "stopCondition": {
            "fileCheck": {
              "path": ".kiro/workflow-output/review.json",
              "jsonPath": "verdict",
              "value": "APPROVED"
            }
          },
          "steps": [
            {
              "type": "step",
              "id": "implement",
              "agent": "wf-coder",
              "artifacts": {
                "summary": ".kiro/workflow-output/summary.md"
              },
              "prompt": "Implement this change in the current workspace: {{task}}\n\nIf .kiro/workflow-output/review.json exists and its verdict is REVISE, address its findings first. Run the relevant tests. Do not commit. Write .kiro/workflow-output/summary.md listing changed files, tests run, and remaining risks, then finish with send_message severity success."
            },
            {
              "type": "parallel",
              "id": "reviews",
              "joinPolicy": "all",
              "branches": [
                {
                  "type": "step",
                  "id": "review-correctness",
                  "agent": "semantic_reviewer",
                  "artifacts": {
                    "review_correctness": ".kiro/workflow-output/review-correctness.md"
                  },
                  "prompt": "Review the uncommitted changes for correctness and missing tests, using {{artifacts.summary}} as your map. Do not edit code. Write your findings to .kiro/workflow-output/review-correctness.md."
                },
                {
                  "type": "step",
                  "id": "review-safety",
                  "agent": "semantic_reviewer",
                  "artifacts": {
                    "review_safety": ".kiro/workflow-output/review-safety.md"
                  },
                  "prompt": "Review the uncommitted changes for security and error handling, using {{artifacts.summary}} as your map. Do not edit code. Write your findings to .kiro/workflow-output/review-safety.md."
                }
              ]
            },
            {
              "type": "step",
              "id": "aggregate",
              "agent": "wf-review-aggregator",
              "artifacts": {
                "review": ".kiro/workflow-output/review.json"
              },
              "prompt": "Read {{artifacts.review_correctness}} and {{artifacts.review_safety}}. Write .kiro/workflow-output/review.json with a verdict field of APPROVED or REVISE and a findings array, deduplicated, with corroborated issues first."
            }
          ]
        }
      ]
    }
  3. Read the recipe against the rules before you run it, because every one of them is checked:

    • task is declared under inputs, so {{task}} resolves. An undeclared bare variable stays as literal text and only warns.
    • Each node has a unique id. The repeat has a finite maxIterations, a stopCondition, and an onMaxIterations of pause, so a stuck loop hands you a decision instead of spending indefinitely.
    • The reviewers are inside parallel, so they read {{artifacts.summary}} from the earlier implement step rather than {{previous.output}}, which is not allowed in a branch. Files cross step boundaries as artifacts; relative paths resolve from the workspace root.
    • aggregate reads both review artifacts and writes the JSON the fileCheck reads. Kiro evaluates the condition after each iteration, so the loop always runs at least once.
    • .kiro/workflow-output/ is just a folder inside the workspace, the one the docs’ own examples use. Any workspace path works; one outside every workspace root fails the node.
  4. Validate it. Ask Kiro in the chat:

    Run validate_workflow on .kiro/workflows/implement-and-review.workflow.json.
    Report every error and warning, and do not launch the workflow.

    Fix anything it reports. A pass means the file is well formed, not that the run can start: the validator does not check agent names or watch handlers. Kiro checks those when it creates the run.

  5. Launch it with a small, real task.

    IDE. Ask in the parent chat: “Run the implement-and-review recipe. Task: add input validation to the signup form’s email field.” Kiro launches the run in the background and the chat stays free.

    CLI V3.

    /workflow run implement-and-review --task "add input validation to the signup form's email field"

    Omit --task and Kiro opens a form for it.

    Web. Upload the file with Upload workflow (one recipe per upload) under Settings → Workflows, then ask Kiro in a cloud session to run it and describe the task.

  6. Follow the run. In the IDE, open Workflows above the parent chat, expand the run, and select a step to open its Workflow step tab with the agent’s session and a Message this step’s agent field. In the CLI, the full-screen monitor shows the step tree and active-step output; /workflow opens history if you leave it, and /workflow status <workflowId> prints the status of a run you know. In Web, open Workflows beside the chat and select a step.

  7. If a step pauses with a question (it called send_message with severity warning), answer in that step’s own session: the Workflow step tab in the IDE, or select the step and press s in the CLI monitor. A plain message in the parent chat is a conversation with the main agent, not a reply to the step, unless you ask the main agent to pass it on.

Check it worked

Three things should be true when the run reports completed. The run’s status is completed, not paused at the iteration cap. .kiro/workflow-output/review.json exists and its verdict is APPROVED, which is what ended the loop. And the parent chat has the handoff: ask the main agent to summarise the run if it has not already, and it can name the workflow ID, the steps and loop iterations completed, the files changed, and what was verified. Then run git status: the implementation is in your working tree and uncommitted, because the prompt said so.

To see the loop actually loop, give it a task a reviewer is likely to reject, such as a change with no tests, and watch iteration two of implement pick up the findings from review.json.

Common problems

  • The recipe does not appear, or /workflow run does not know the name. Check the folder and suffix: .kiro/workflows/ and .workflow.json. In the CLI, workflow commands are set when the process starts, so restart after enabling. In the IDE, an untrusted workspace does not load recipes until you trust it. If two files share a stem with different suffixes, the JSON one wins and the other is reported as a conflict.
  • A prompt shows a literal {{task}}. The input was not declared, or not supplied at launch.
  • A step fails on an artifact or output template. The producer must run before the consumer: never reference a later sibling or another parallel branch, and never use {{previous.output}} as the first node of a container or inside a branch.
  • The loop reaches the cap every time. Open review.json. The fileCheck needs valid JSON, the exact key verdict, and the exact value APPROVED; anything else, including a missing file, counts as no match. Tighten the aggregate prompt if the agent is writing a different shape.
  • Resume pauses again immediately. A repeat paused at its cap has spent its budget; Resume does not add iterations. Stop the run, raise the cap or fix the stop condition, and launch again.
  • Validation passed but the run would not start. Check the agent names and your model access; those are runtime checks the standalone validator cannot do.
  • You stopped the run and files are half changed. Stop does not undo edits. Inspect the workspace and revert with git before relaunching.
  • The reviewers took as long as running them one after another. Expected. parallel buys isolation and a join policy, not a shorter wall clock.
  • Workflows explains the five ideas behind a recipe and how to enable the feature per client.
  • Build a read-only reviewer agent is a good replacement for semantic_reviewer when you want to control the reviewer’s tools yourself.
  • Create a custom agent makes any step agent you like, with its own model and tool set.

Frequently asked questions

How do I write a Kiro workflow recipe?

Create a file under .kiro/workflows/ ending in .workflow.json or .workflow.yaml. Give it a name, declare any inputs your prompts use as template variables, and fill the steps array with nodes. A step names an agent and a prompt; repeat loops a group with a maxIterations cap; parallel runs branches with a join policy. Ask Kiro to run validate_workflow on the file, then launch it.

How do I run a workflow in Kiro CLI?

Enable Workflows under /settings → Features and restart the CLI. Then run /workflow run <recipe-name> --task "what to do". If you leave out a declared input, Kiro opens a form to collect it. Follow the run in the monitor, or open /workflow later to find it in history.

Which agents can a workflow step use?

A workflow-capable agent: one of the agents Kiro bundles for workflows (wf-planner, wf-coder, wf-design, wf-design-reviewer, wf-review-aggregator, wf-pr-submitter, wf-pr-responder, wf-auto-researcher, semantic_reviewer) or a custom agent defined in .kiro/agents/. A built-in sub-agent is not valid as a step agent.

Why does my workflow loop stop at the cap even though the work looks done?

The stop condition did not match. For a fileCheck, Kiro reads the JSON file at the path, compares the value at jsonPath with the expected value, and treats a missing file, invalid JSON, missing path, or mismatch as not matched. Open the file and check the exact key and value the producing step wrote.

☰ Chapter summary

  • A recipe is a JSON or YAML file in .kiro/workflows/ named *.workflow.json, *.workflow.yaml, or *.workflow.yml, with a name, optional inputs, and a steps tree.
  • Node types are step, sequence, repeat, parallel, and watch; a step needs id, agent, and prompt, and the agent must be workflow-capable such as wf-coder or a custom agent in .kiro/agents/.
  • Pass files between steps as artifacts and short text as captured output; inside a parallel branch never use previous.output.
  • Give every repeat a finite maxIterations, a machine-readable stopCondition such as a fileCheck on a JSON verdict, and a deliberate onMaxIterations.
  • Ask Kiro to run validate_workflow on the file before launching; validation cannot check agent names or watch handlers, which Kiro checks when the run is created.
  • Launch by asking Kiro in the IDE chat, or with /workflow run <name> --task "..." in CLI V3; follow the run in the Workflows area or the CLI monitor.

All chapter summaries are collected on the revision page.

Was this chapter helpful?