> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lyzr.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SkillsFlow

> Compose skills into multi-step workflows with branching, loops, and parallel execution.

SkillsFlow is GitAgent's workflow engine. It lets you define deterministic multi-step sequences that call skills in a specific order — with branching, loops, and parallel execution — without relying on the LLM to sequence every step.

## When to use SkillsFlow

**Use the LLM to sequence skills (default)** when the agent needs to reason about which skills to call and in what order based on the user's request.

**Use SkillsFlow** when the sequence is known in advance: "always fetch data, then clean it, then summarize it." SkillsFlow gives you predictability, lower token usage, and easier testing.

## Defining a flow

Flows are YAML files in the `flows/` directory:

```yaml theme={null}
# flows/research_report.yaml
name: research-report
description: "Research a topic and write a formatted report"

input:
  topic:
    type: string
    description: "The topic to research"

steps:
  - id: search
    skill: search_web
    input:
      query: "{{ input.topic }} recent developments 2024"
      num_results: 10

  - id: fetch_articles
    skill: fetch_url
    foreach: "{{ steps.search.output }}"   # loop over search results
    input:
      url: "{{ item.url }}"

  - id: summarize
    skill: summarize_text
    input:
      texts: "{{ steps.fetch_articles.output | map('content') }}"
      max_length: 500

  - id: write_report
    skill: write_document
    input:
      title: "{{ input.topic }}"
      sections: "{{ steps.summarize.output }}"

output: "{{ steps.write_report.output }}"
```

## Running a flow

```bash theme={null}
# Run a flow directly
gitagent flow run research-report --input '{"topic": "quantum computing"}'

# Run via the agent (agent decides when to use it)
gitagent run "Write a report on quantum computing"
```

Flows are automatically discovered by the agent and exposed as skills. The agent can choose to invoke a flow the same way it invokes a single skill.

## Step types

### Skill step

```yaml theme={null}
- id: my_step
  skill: skill_name
  input:
    arg1: "{{ expression }}"
```

### Parallel step

Run multiple skills simultaneously:

```yaml theme={null}
- id: parallel_research
  parallel:
    - skill: search_web
      input:
        query: "{{ input.topic }} news"
    - skill: search_web
      input:
        query: "{{ input.topic }} papers"
    - skill: fetch_url
      input:
        url: "https://wikipedia.org/wiki/{{ input.topic }}"
  # output: list of results from all parallel branches
```

### Conditional step

```yaml theme={null}
- id: check_length
  condition: "{{ steps.fetch.output.length > 1000 }}"
  then:
    skill: summarize_text
    input:
      text: "{{ steps.fetch.output }}"
  else:
    skill: passthrough
    input:
      value: "{{ steps.fetch.output }}"
```

### Loop step

```yaml theme={null}
- id: process_items
  foreach: "{{ steps.list_files.output }}"
  skill: process_file
  input:
    path: "{{ item.path }}"
  # output: list of results, one per item
```

Limit concurrent iterations:

```yaml theme={null}
- id: process_items
  foreach: "{{ steps.list_files.output }}"
  concurrency: 3        # process 3 files at a time
  skill: process_file
  input:
    path: "{{ item.path }}"
```

### Sub-flow step

```yaml theme={null}
- id: run_sub_workflow
  flow: another-flow    # references flows/another-flow.yaml
  input:
    param: "{{ steps.previous.output }}"
```

## Expressions

Expressions use Jinja2 syntax inside `{{ }}`:

```yaml theme={null}
# Access flow input
"{{ input.topic }}"

# Access a previous step's output
"{{ steps.search.output }}"

# Access a field of the output
"{{ steps.search.output.results[0].url }}"

# Apply filters
"{{ steps.text.output | upper }}"
"{{ steps.items.output | length }}"
"{{ steps.items.output | map('title') | join(', ') }}"

# Conditional expression
"{{ steps.result.output if steps.result.output else 'No result' }}"
```

## Error handling

```yaml theme={null}
steps:
  - id: fetch_data
    skill: fetch_url
    input:
      url: "{{ input.url }}"
    on_error:
      action: continue     # continue | stop | retry
      fallback: "Failed to fetch"

  - id: parse
    skill: parse_json
    input:
      text: "{{ steps.fetch_data.output }}"
    retry:
      max_attempts: 3
      delay_seconds: 2
```

## Testing flows

```bash theme={null}
gitagent flow test research-report \
  --input '{"topic": "AI safety"}' \
  --mock-skills              # mock skill calls, test the routing logic only
```

Test with real skills:

```bash theme={null}
gitagent flow run research-report \
  --input '{"topic": "AI safety"}' \
  --dry-run                  # print what would be called without calling
```

## Flow as LLM tool

The agent exposes each flow as a skill to the LLM. The flow's `name` and `description` determine when the LLM chooses to invoke it — the same rules as individual skills apply.

To prevent a flow from being exposed to the LLM (run only via `gitagent flow run`):

```yaml theme={null}
# flows/internal-batch.yaml
name: internal-batch
expose_as_skill: false
```
