hobhob
Core Features

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

ScopeLocationShared with team?
Shared.hob/workflows/ in your repoYes
PrivatePer-project personal configNo
GlobalAvailable in every projectNo

Creating a workflow

  1. Open the Workflows panel
  2. Click +
  3. Fill in a name and command, choose a scope (shared, private, or global)
  4. Save

Each saved workflow is a single YAML file:

.hob/workflows/build.yaml
version: 1
id: dce7771f-5949-4c98-b8d5-81088c4062f5
name: Build & Test
shell: sh
command: npm run build && npm test
category: CI/CD

For 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 commandStep fields
npm run testexec: npm, args: [run, test]
pnpm run testexec: pnpm, args: [run, test]
yarn run testexec: yarn, args: [run, test]
bun run testexec: bun, args: [run, test]
make buildexec: make, args: [build]
just checkexec: just, args: [check]
task releaseexec: 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: tools

has 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: url

A 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:

.hob/workflows/release.yaml
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 typeWhat it does
runExecute a shell command; foreground runs use a PTY with full color output, while detach: true launches in the background and moves on
agentSend a prompt to an agent pane — pick backend, model, effort, permission mode
renderOpen a file in a render pane (reports, previews)
workflowCall 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: true

Steps 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: bool

Input 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:

.hob/workflows/dev-server.yaml
version: 1
id: 7ecc791b-f9be-45aa-9594-2b5feb7ae2a5
name: dev-server
restart: unless-stopped
shell: sh
command: npm run dev

Declaring 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.

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:

.hob/workflows/feedback-viewer.yaml
version: 1
id: f7ad01a5-b5f6-45af-88fc-b3ad9fc913fe
name: Run Feedback Viewer
restart: unless-stopped
surface: url
shell: sh
command: hob feedback viewer

For 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: 5m

Top-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: latest

There 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: true

With 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.sh

How scheduling behaves:

  • Scheduled workflows fire only while the project is open in hob — there is no background daemon
  • every is nominal start-to-start spacing. Elapsed values include 2s, 5m, 1h30m, and 24h; the minimum is one second
  • Integer d, w, and mo values are calendar recurrences. 24h is elapsed time; 1d follows the effective local wall clock
  • Calendar counts are limited to 120. m means minutes while mo means months, so 1m and 1mo are intentionally very different
  • Daily schedules require at, weekly schedules require weekday and at, and monthly schedules require day and at
  • Selectors establish the first occurrence and its phase: every: 2w with weekday: thu means the first matching Thursday, then every two weeks from that persisted anchor
  • Monthly day is 1 through 31 or last; missing numbered dates are skipped, while last follows the actual end of each month
  • timezone defaults to the host's local timezone; specify an IANA name such as America/Chicago or UTC to pin it
  • dst defaults to compatible: spring-forward gaps move forward and fall-back repeats run once at the earlier occurrence; advanced policies are earlier, later, and skip
  • Selector fields are strict: weekday works only with w, day only with mo, and calendar selectors are rejected on elapsed intervals
  • missed-run: skip resumes at the next occurrence; run-once performs at most one catch-up run
  • overlap is optional and derives from workflow concurrency; when written, it must match that policy
  • Scheduled queue retains 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-output

Shell 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.

How is this guide?

On this page