DEV Community

Cover image for I built a local automation runner - no cloud, no server, just YAML and Python
Ryszard Orlikowski
Ryszard Orlikowski

Posted on

I built a local automation runner - no cloud, no server, just YAML and Python

I built Stepyard - a local pipeline runner for automations that need persistent state, captured logs, and the ability to write custom steps in Python.

Stepyard:

  • flows are YAML files
  • each run is an isolated subprocess
  • logs are captured automatically
  • state is stored in SQLite
  • no cloud account or server required

Example: nightly backup

pip install stepyard
stepyard init my-automations
Enter fullscreen mode Exit fullscreen mode

flows/nightly_backup.yaml:

name: nightly_backup
trigger:
  uses: cron
  with:
    schedule: "0 3 * * *"

steps:
  - id: dump
    uses: shell.run
    with:
      command: pg_dump ${{ env.DATABASE_URL }} | gzip > /tmp/backup_$(date +%F).sql.gz

  - id: notify
    uses: http.request
    with:
      method: POST
      url: ${{ env.SLACK_WEBHOOK }}
      json_body:
        text: "Backup done: exit code ${{ steps.dump.output.code }}"
Enter fullscreen mode Exit fullscreen mode

Run the scheduler:

stepyard service start
Enter fullscreen mode Exit fullscreen mode

The Python escape hatch

If YAML is not enough, write a Python node:

from stepyard.sdk import node

@node(name="math.add")
def add(a: int, b: int) -> int:
    return a + b
Enter fullscreen mode Exit fullscreen mode

Then use it in YAML:

steps:
  - id: sum
    uses: math.add
    with:
      a: 2
      b: 3
Enter fullscreen mode Exit fullscreen mode

Plugins run in isolated virtualenvs - their dependencies never clash with Stepyard itself.

Built-in LLM step

Stepyard ships with a llm.generate step that supports OpenAI, Anthropic, Ollama, and any OpenAI-compatible endpoint:

steps:
  - id: summarize
    uses: llm.generate
    with:
      provider: ollama
      model: llama3
      prompt: "Summarize this log: ${{ steps.dump.output.stdout }}"
Enter fullscreen mode Exit fullscreen mode

Need structured output? Pass a JSON Schema and the response is validated automatically:

  - id: classify
    uses: llm.generate
    with:
      provider: openai
      model: gpt-4o-mini
      prompt: "Classify this error: ${{ steps.dump.output.stderr }}"
      schema:
        type: object
        properties:
          severity: { type: string, enum: [low, medium, high] }
          reason: { type: string }
        required: [severity, reason]
Enter fullscreen mode Exit fullscreen mode

No extra library needed - just add the step to your flow.

Try it

pip install stepyard
stepyard init my-automations && cd my-automations
stepyard run hello
Enter fullscreen mode Exit fullscreen mode

Top comments (0)