reliant-labs/reliant/workflow-builder

Claude Code and agent skill by reliant-labs/reliant

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Build a bot or agent that runs on a schedule or event (cron, webhook, twice a day, daily digest, monitor, triage); also multi-agent Reliant workflows. Use to create, edit, test or debug any workflow.

Install

npx vskill@latest install reliant-labs/reliant/workflow-builder

SKILL.md

Workflow Builder

You build Reliant workflows. Your goal: create working workflows that solve the user's problem.

Threading, context, loops, parallelization, inputs, prompts, error handling and composition have their own do's-and-don'ts reference: skill(action="load", path="workflow-builder/design-patterns"). Load it before designing a workflow's control flow.

When to use

  • Building an agent or automation that runs on its own: on a schedule ("every morning", "twice a day", cron), on a webhook or an app event — a bot, monitor, digest or triage job, even when it sounds like "just a script"
  • Creating a new Reliant workflow from scratch
  • Editing or extending an existing workflow
  • Debugging workflow execution issues
  • Writing scenario tests for workflows
  • Understanding workflow patterns and best practices

Approach

Every workflow tool that targets an existing workflow (get_workflow, edit_workflow, write_workflow, and the scenario tools) requires an explicit id — a UUID, slug, or name. Nothing binds this chat to a workflow, so there is no "current workflow"; any chat can work on any workflow.

Starting from scratch? Call create_workflow first — it returns the new draft's id, name, and slug. Pass that id to every subsequent call. Omit both name and content to get a random name and the default agent template; pass content with complete workflow YAML to start from a specific design.

Editing an existing workflow? Find it with list_workflows and pass its id or slug. If the user's message names a workflow (e.g. "Workflow swift-fox-a1b2: ..."), use that as the id.

Follow this process:

  1. Setup — New workflow: call create_workflow. Existing workflow: call get_workflow with its id to see current content.
  2. Understand — Ask clarifying questions about the user's goal
  3. Learn — Use list_workflows to see examples and patterns, list_presets/get_preset to see what

agent presets exist before inventing a system prompt from scratch. Calling an external service? search_integrations finds the action ref and get_integration_schema its params before you write the node

  1. Explore — Read the user's codebase (test commands, code patterns). Note: references to "workflows" and "nodes" in user code are unlikely to be Reliant-specific.
  2. Build — Use edit_workflow for small changes, write_workflow for larger rewrites
  3. Test — Create and run scenarios (aim for 3+ covering positive, negative, and edge cases). Try to break your workflow. It's frustrating for users to run a workflow for an hour and hit a bug at the end—scenarios catch this early.

Working in a chat that isn't running this preset? These tools are still reachable: load_tool(name="tag:workflow") loads all of them on demand.

Key concepts

Workflows are DAGs

Every workflow must be a directed acyclic graph. You cannot create cycles in the graph structure. Use loop nodes (with while conditions) for iterative behavior.

CEL expressions

Two syntax modes:

  • `condition` / `while` fields: Pure CEL — no {{}} wrapping

``yaml condition: "nodes.llm.stop_reason == 'tool_use'" while: "outputs.stop_reason in ['tool_use', 'incomplete', 'truncated', 'interrupted'] && iter.iteration < 50" ``

  • All other fields: Template interpolation with {{}}

``yaml model: "{{inputs.model}}" system_prompt: "You are helping with {{inputs.task}}" ``

Always use has() or safe navigation (object.?field) before accessing optional fields.

Template rules. A {{ }} is read as CEL, so a brace inside a string literal is data ({{ x.startsWith('{') }} works) and a newline inside it is whitespace (a folded >- scalar is fine). A {{ that never closes, an empty {{ }} and an expression that does not parse are validation errors with the field path and line/column, never literal text; write a literal {{ as {{ '{{' }}. Raw-CEL fields (condition, while, a trigger filter) take no {{ }}. Inside an inline type: workflow body, templates are evaluated in the BODY's scope when it runs (its own inputs and nodes), not the parent's.

Deterministic logic belongs in the workflow, not a script. Use a type: compute node (below) for labels, size buckets, lease expiry, id validation and parsing a node's JSON stdout. Expressions have Strings, Lists, Sets, Math, Encoders, Bindings, Regex, optional types, timestamps and durations, and json.decode(s) (tolerant: an optional, .?status.orValue('error')) beside the strict parseJson(s). Evaluation is cost-bounded (a runaway expression fails with cost limit exceeded). The CEL reference has a table of worked helper expressions. Test an expression with `cel_eval` before writing it into a workflow.

Compute node

type: compute computes named outputs from CEL in the workflow: no model, no shell, no worker, no mock needed in a scenario. outputs: maps a name to a value; a value that is exactly one {{ }} keeps its type, text around it makes a string, a non-string is a literal. Read them as nodes.<id>.<name> (validation checks the names; values are dyn, so compare a boolean output in a condition: nodes.facts.ready == true). Outputs cannot read each other: chain two compute nodes. A failing expression fails the node.

yaml
- id: facts
type: compute
outputs:
size: "{{ inputs.adds + inputs.dels < 60 ? 'size:S' : 'size:M' }}"
ready: "{{ 'agent:ready' in inputs.labels }}"
status: "{{ json.decode(nodes.start.stdout).?status.orValue('error') }}"
Publishing a branch

type: git_publish commits a worktree's changes and pushes them to a feature branch with no shell ever holding a credential. Pair it with credentials: none on the editing shell.

yaml
- id: publish
type: git_publish
args:
worktree: "{{ nodes.wt.path }}"
repo: "{{ inputs.repo }}" # owner/name
branch: "autopilot/issue-{{ inputs.issue }}" # or pr_head_of: "{{ inputs.pr }}"
allow: ["autopilot/*"] # optional
message: "{{ nodes.edit.commit_message }}"

Refused (the node completes with refused: true and a refusal, it does not fail): the default branch, protected branches, main, master, release/*, names that are not plain branches, branches outside allow, a pull request head in a fork. Never forces: a diverged remote is refused. No changes means pushed: false and no error. Outputs: pushed, sha, branch, base_sha, files_changed, insertions, deletions, refused, refusal. Route on them: condition: nodes.publish.pushed == true. The push is recorded in the write ledger with its sha, so its events carry trigger.origin. In a scenario, mock the node's outputs like any activity.

Shells without credentials

credentials: none removes GitHub, git, ssh and cloud credentials from a command's environment: no GH_TOKEN/GITHUB_TOKEN, no ssh agent, no cloud variables, no kubeconfig, git's credential helpers reset, GIT_TERMINAL_PROMPT=0, an empty GH_CONFIG_DIR. A git push or gh pr merge from it fails to authenticate at once and never prompts. Set it for an agent's shell with tools_config.tools.shell (bound, so the model is never shown it) and on a run node with credentials: none.

yaml
tools_config:
tools:
shell: {credentials: none}

On Linux (every Reliant cloud machine) the command also runs in a sandbox where the daemon's credential files are absent (~/.reliant/daemon.json, ~/.config/forge, ~/.git-credentials, ~/.ssh, ~/.config/gh, kubeconfig and cloud files, the container engine's socket), sees only its own processes, and has no capabilities. It shares the network and can write its working directory, and on macOS and Windows only the environment is scrubbed. Never tell an agent to look elsewhere for a token; publish with a git_publish node.

Threading

Modes: inherit (default), new, fork

  • inherit: Reuse parent thread (default)
  • new: Create a fresh thread
  • fork: Copy parent thread into a new one

Key rules:

  • Use memo in loops to reuse the same thread across iterations
  • Use inject to prepend a message when entering a sub-workflow
  • Never run parallel agents on the same thread simultaneously
Edge routing
  • Multiple cases on one edge = exactly 1 executes (first match wins)
  • All cases require a condition — use default for the fallback
  • For parallelism: create multiple edges from the same source node, OR use default: [node-a, node-b]

Syntactic sugar

These shorthands compile to standard nodes/edges at parse time. They are not in the proto — purely YAML convenience.

sequence: sugar

A top-level workflow field (alongside name:, nodes:, edges:) that replaces the combination of entry:, nodes:, and sequential edges: for linear chains.

Rules:

  • Cannot coexist with entry: (it implies entry from the first node)
  • CAN coexist with nodes: and edges: for mixed patterns (e.g., linear main flow with extra branches)
  • Compiles to standard entry: + nodes: + edges: at parse time

Before (explicit):

yaml
entry: [research]
nodes:
- id: research
type: workflow
ref: builtin://agent
- id: implement
type: workflow
ref: builtin://agent
- id: review
type: workflow
ref: builtin://structured-agent
edges:
- from: research
default: implement
- from: implement
default: review

After (sugar):

yaml
sequence:
- id: research
type: workflow
ref: builtin://agent
- id: implement
type: workflow
ref: builtin://agent
- id: review
type: workflow
ref: builtin://structured-agent
type: parallel sugar

A node type used inside nodes: that desugars into branch nodes + a join node + fan-out/fan-in edges.

Rules:

  • Must have id: and branches: fields
  • branches: is a list of regular node definitions
  • The parallel node's id becomes the join node's id (so downstream edges referencing it still work)
  • Join uses condition: all (all branches must complete)
  • Incoming edges targeting the parallel node get rewritten to fan-out to all branches

Before (explicit):

yaml
nodes:
- id: research
type: workflow
ref: builtin://agent
- id: design
type: workflow
ref: builtin://agent
- id: explore
type: join
condition: all
edges:
- from: trigger
default: [research, design]
- from: research
default: explore
- from: design
default: explore

After (sugar):

yaml
nodes:
- id: explore
type: parallel
branches:
- id: research
type: workflow
ref: builtin://agent
- id: design
type: workflow
ref: builtin://agent
edges:
- from: trigger
default: explore

Triggers: when a workflow runs

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
60
Repository forks
5
7-day trend score
21

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/reliant-labs/reliant/workflow-builder/badge)](https://verified-skill.com/skills/reliant-labs/reliant/workflow-builder)

Something wrong with this skill or its page? Tell us.