Workflows
Save commands and multi-step processes — shell, agent, and render steps with inputs, secrets, schedules, and artifacts.
Workflows let you save commands, scripts, and multi-step processes and run them without rebuilding the same setup every time. Think of them as a task runner that lives next to your agents — with agent steps as a first-class citizen.
Opening the Workflows panel
Press Cmd/Ctrl+Shift+X to open the Workflows panel.
Where workflows live
| Scope | Location | Shared with team? |
|---|---|---|
| Shared | .hob/workflows/ in your repo | Yes |
| Private | Per-project personal config | No |
| Global | Available in every project | No |
Creating a workflow
- Open the Workflows panel
- Click
+ - Fill in a name and command, choose a scope (shared, private, or global)
- Save
Each saved workflow is a single YAML file:
version: 1
id: dce7771f-5949-4c98-b8d5-81088c4062f5
name: Build & Test
shell: sh
command: npm run build && npm test
category: CI/CDFor advanced workflows, open the YAML editor and edit the full definition directly. Workflow files reload automatically when they change on disk.
Create shortcuts for existing scripts
hob does not automatically turn package-manager scripts or build-tool targets into workflows. Every panel entry is an intentional version 1 workflow file, so its identity, trust decision, history, and capabilities are explicit.
Create a workflow with +, then use an exec step to wrap the command you want:
version: 1
id: 7a91f7d4-c130-4fcb-9261-342e8a6a4834
name: Test
category: development
steps:
- id: test
name: Test
exec: npm
args: [run, test]exec passes arguments without shell interpolation, making simple shortcuts portable and
predictable:
| Existing command | Step fields |
|---|---|
npm run test | exec: npm, args: [run, test] |
pnpm run test | exec: pnpm, args: [run, test] |
yarn run test | exec: yarn, args: [run, test] |
bun run test | exec: bun, args: [run, test] |
make build | exec: make, args: [build] |
just check | exec: just, args: [check] |
task release | exec: task, args: [release] |
Use a run step with an explicit shell only when you need shell syntax such as pipes,
redirects, or command chaining. A wrapped shortcut can opt into inputs, surfaces, health checks,
scheduling, or lifecycle restart like any other workflow.
One execution model
Every workflow executes as a step plan. command is concise authoring syntax for the common
one-command case; hob compiles it in memory to an implicit foreground run step with id: main.
For example:
version: 1
id: 5af1c74e-f97a-4db8-9eca-e76b9ed5afe3
name: Feedback Viewer
shell: sh
command: hob feedback viewer
surface: url
cwd: toolshas the same execution plan as:
version: 1
id: 5af1c74e-f97a-4db8-9eca-e76b9ed5afe3
name: Feedback Viewer
cwd: tools
steps:
- id: main
name: Feedback Viewer
shell: sh
run: hob feedback viewer
surface: urlA definition must contain exactly one of command or steps. hob preserves the concise source
form in the YAML editor; normalization does not rewrite the file. Workflow-level context and
lifecycle settings stay at the top level. Use explicit steps for more than one action or when you
need step identity, retries, error policy, timeout, detach, or a non-shell step. workflow: is a
child-workflow step and is unrelated to command shorthand.
Multi-step workflows
Use steps instead of command. Steps run in sequence — shell commands, agent prompts, file
renders, or calls to other workflows:
version: 1
id: e87eb1a2-1978-4567-aeaf-e63886839305
name: Release
inputs:
target:
description: Deploy target
type: choice
options: [staging, production]
default: staging
steps:
- id: build
name: Build
shell: sh
run: npm run build
- id: review
name: Review
agent:
prompt: Review the diff for release blockers
permission-mode: ask
- id: deploy
name: Deploy
exec: ./scripts/deploy.sh
args: ["${{ inputs.target }}"]| Step type | What it does |
|---|---|
run | Execute a shell command; foreground runs use a PTY with full color output, while detach: true launches in the background and moves on |
agent | Send a prompt to an agent pane — pick backend, model, effort, permission mode |
render | Open a file in a render pane (reports, previews) |
workflow | Call another saved workflow as a child run |
detach is a boolean attribute of run, not a separate step type. Set it to true when a process
should keep running while the workflow moves to the next step:
version: 1
id: ad957cce-8e0a-457a-b553-06121a95386d
name: Preview server
steps:
- id: preview
name: Start preview server
shell: sh
run: npm run dev
detach: trueSteps can pass data forward — ${{ steps.build.outputs.tag }}, ${{ steps.test.exit-code }} —
and gate on conditions with if:. Failures stop the run unless a step sets
on-error: continue or on-error: retry.
Inputs
The focused YAML snippets below are fragments to place inside a complete workflow with
version: 1, a UUID id, and a name. Every shown run step still declares its own id and
shell.
Declare inputs and hob prompts for them before the run starts:
inputs:
tag:
description: Version tag
type: text
confirm:
description: Really deploy?
type: boolInput types are text (default), textarea, choice (pick from options), bool,
number, integer, date, time, datetime, file, and directory. Mark an input
secret: true for a password-style field that is scrubbed from logs and history.
Secrets
Secrets are encrypted at rest, scrubbed from workflow output and history, and never expanded
in agent prompts. Manage them in the Workflows panel. Every secret a workflow may use must also
be declared in its top-level secrets list, which makes credential access explicit and reviewable:
secrets: [DEPLOY_TOKEN]
steps:
- id: push
name: Push
shell: sh
run: ./deploy.sh
env:
TOKEN: "${{ secrets.DEPLOY_TOKEN }}"Resolution order is project secret first, then global. Keep secret-bearing actions in run
steps and pass only scrubbed outputs back to agents.
Start a workflow with the project
Use the Docker-style restart policy for a long-running development loop that should live for as
long as the project is open:
version: 1
id: 7ecc791b-f9be-45aa-9594-2b5feb7ae2a5
name: dev-server
restart: unless-stopped
shell: sh
command: npm run devDeclaring unless-stopped makes a workflow eligible for lifecycle management, but does not start it.
The first manual Run activates the policy. From then on, hob starts it through a short,
staggered queue on project load and restarts it after a brief delay if the command exits. Choosing
Stop deactivates it, so it stays stopped on later project loads until another manual Run.
If restart: unless-stopped is added to a workflow that is already running from a manual Run, hob
adopts that run without starting a second copy. Restart-managed workflows do not block project or
window close by default. Set block-on-exit: true to opt back in.
Only non-interactive workflows can use restart: they cannot declare inputs: or
pty: { input: true }. Omit restart (or use restart: no) for normal manually run workflows.
Trusting shared workflows
The first run of a shared workflow from .hob/workflows/ requires confirmation in the hob UI,
regardless of whether a person, agent, CLI call, schedule, or parent workflow requested it. Trust
is stored locally against a hash of the canonical execution definition. Rewriting command
shorthand into its exact explicit-step equivalent therefore does not revoke trust. If a trusted
definition is edited directly in hob's workflow editor, hob carries that trust—and its
automatic-run choice—to
the saved version. A repository update or edit made outside hob produces a new untrusted hash and
requires review again. The confirmation distinguishes a clean repository update from an
uncommitted working-tree edit.
A shared workflow that declares restart: unless-stopped still cannot start automatically from
YAML alone. Its trust confirmation includes a separate, default-off Allow automatic runs
choice for that exact definition. The same two gates permit shared schedules: a schedule cannot
become the first execution, and it remains disabled until both exact-hash trust and automatic-run
authorization have been granted by the human UI.
Surface a live value or link
A long-running workflow can keep one useful line directly beneath its entry in the Running
section. The url shortcut extracts the last HTTP(S) URL from output and makes it a one-click
link. Links open in a hob web pane, keeping host-local URLs such as 127.0.0.1 on the host side
even when the workflows panel is viewed through a browser client:
version: 1
id: f7ad01a5-b5f6-45af-88fc-b3ad9fc913fe
name: Run Feedback Viewer
restart: unless-stopped
surface: url
shell: sh
command: hob feedback viewerFor precise output, use a regular expression. If group is omitted, hob uses the first capture
group (or the complete match when there are no groups):
surface:
regex: 'hob feedback viewer:\s+(https?://\S+)'
label: Open feedback viewer
search-timeout: 5mTop-level surface is available only with command shorthand and becomes part of its implicit
main step. In an explicit plan, put it on the run step that owns the value. Commands publish
named values through the temporary $HOB_OUTPUT file:
steps:
- id: viewer
name: Start feedback viewer
shell: sh
run: |
url="$(start-feedback-viewer)"
printf 'viewer_url=%s\n' "$url" >> "$HOB_OUTPUT"
wait
surface:
value: ${{ outputs.viewer_url }}
label: Open feedback viewer$HOB_OUTPUT accepts NAME=value records and delimiter-based multiline records. The file is
private to the current command or run step, watched while it runs, and its values also become
ordinary step outputs for later ${{ steps.name.outputs.key }} expressions. This avoids treating
arbitrary subprocess logs as control commands.
URL and regular-expression extraction watch only a bounded recent-output buffer. Checks back off
from 100 milliseconds to at most two seconds, run only when new complete output lines arrive, and
stop permanently after the first match. Named-output surfaces are event-driven and do not poll.
The search window defaults to five minutes; override it with search-timeout.
For a changing status or progress value, opt into live replacement:
surface:
regex: '^Progress:\s+(.+)$'
group: 1
update: latestThere is no polling or authored refresh interval. hob evaluates only newly completed output lines,
including carriage-return terminal progress, and publishes only when the extracted surface changes.
search-timeout bounds finding the first value; after that, updates continue until the process exits.
Terminal status is opt-in. Add pty: true to a foreground run or exec step to show its latest
terminal line as read-only status in the workflows panel. To additionally forward keyboard input,
use the mapping form:
pty:
input: trueWith command shorthand, top-level pty is moved onto the implicit main step. With explicit
steps, put pty beside the individual run or exec. Omit it for no terminal status line.
Scheduling
Workflows can run on a schedule with human-readable interval rules:
version: 1
id: d43ea588-a01b-48ec-9854-fee88b9db39b
name: health-check
concurrency: forbid
on:
schedule:
- every: 2s
overlap: forbid
missed-run: skip
- every: 1d
at: "09:00"
timezone: America/Chicago
overlap: forbid
missed-run: skip
- every: 2w
weekday: tue
at: "09:00"
overlap: forbid
missed-run: skip
- every: 1mo
day: last
at: "09:00"
overlap: forbid
missed-run: skip
steps:
- id: check
name: Check
shell: sh
run: ./scripts/health-check.shHow scheduling behaves:
- Scheduled workflows fire only while the project is open in hob — there is no background daemon
everyis nominal start-to-start spacing. Elapsed values include2s,5m,1h30m, and24h; the minimum is one second- Integer
d,w, andmovalues are calendar recurrences.24his elapsed time;1dfollows the effective local wall clock - Calendar counts are limited to 120.
mmeans minutes whilemomeans months, so1mand1moare intentionally very different - Daily schedules require
at, weekly schedules requireweekdayandat, and monthly schedules requiredayandat - Selectors establish the first occurrence and its phase:
every: 2wwithweekday: thumeans the first matching Thursday, then every two weeks from that persisted anchor - Monthly
dayis1through31orlast; missing numbered dates are skipped, whilelastfollows the actual end of each month timezonedefaults to the host's local timezone; specify an IANA name such asAmerica/ChicagoorUTCto pin itdstdefaults tocompatible: spring-forward gaps move forward and fall-back repeats run once at the earlier occurrence; advanced policies areearlier,later, andskip- Selector fields are strict:
weekdayworks only withw,dayonly withmo, and calendar selectors are rejected on elapsed intervals missed-run: skipresumes at the next occurrence;run-onceperforms at most one catch-up runoverlapis optional and derives from workflowconcurrency; when written, it must match that policy- Scheduled
queueretains at most one pending run and coalesces further occurrences - Two entries cannot declare the same cadence with different policies; hob rejects them as semantic duplicates
- Elapsed schedules skip missed ticks rather than generating catch-up bursts
- hob persists the initial cadence anchor before the first run, so project close or scheduler handoff does not reset the clock
- With the same project open in multiple windows, exactly one window owns the scheduler — no duplicate runs
Scheduled workflows must be non-interactive: no inputs: and no pty: { input: true }.
Artifacts
Record files or directories alongside a run — build outputs, reports, coverage:
artifacts:
- path: dist/
name: build-outputShell steps can also declare them at run time with
step-level artifacts: entries. hob never interprets stdout as a workflow command; dynamic named
values use the private $HOB_OUTPUT file, while artifact paths remain explicit executable
configuration reviewed before a shared workflow runs.
Run history
Every run is recorded. The Workflows panel shows recent runs; multi-step runs show per-step status, duration, outputs, and artifacts. Runs appear in Activity unless you mute a workflow there. Completed visible history is retained for 90 days and the newest 500 top-level runs per workflow; active and explicitly trashed runs are excluded from automatic retention.