Files
paseo/public-docs/hub/configuration/hub-yml.md
T
Mohamed Boudra c54f20e53e feat(website): show Hub's Free and Pro plans, and drop trial wording (#5138)
Hosted Hub replaces its automatic trial with a real Free plan, so the
pricing section becomes three columns: Self-hosted, Free, and Pro. Both
hosted columns render entirely from `GET /api/billing/plans` — name,
price, the `included` figures, and the catalog's feature prose — because
those figures are derived from the entitlement template the instance
enforces, so nothing on this page can drift from the limit a customer
actually gets.

The parser requires both slugs and the new `included` object and throws
on anything else. The page already degrades to "temporarily unavailable"
when the loader throws, so a strict boundary costs a fallback we have
rather than a wrong number we would ship. This is also why the change
must not merge before the Hub side deploys: against today's API the
section renders that fallback.

Public docs follow the two Hub changes: Free replaces the trial and
points at /hub for the figures Stripe metadata now owns; sign-in lands on
Home with its four-step checklist; `hub.execute` gets the grant command
it needs; and trigger authoring documents that the agent is validated
against the target daemon at save, which needs that daemon connected and
accepts Claude, Codex, and OpenCode only.
2026-09-28 15:51:12 +01:00

18 KiB
Raw Blame History

title, description, nav, order, category
title description nav order category
Hub configuration reference Canonical Hub resource, workflow, agent, expression, and prompt fields. Configuration reference 71 Hub

Hub configuration reference

Hub accepts YAML in this layout:

.paseo/
├── hub.yml
└── workflows/
    ├── <workflow>.yml
    └── partials/
        └── <partial>.md

Only direct .yml children of .paseo/workflows/ are workflows. Each file contains one trigger and its ordered steps. There is no manifest, includes, uses, reusable step, workflow call, or inheritance.

hub.yml

.paseo/hub.yml contains named project resources. Names are map keys and are not repeated inside each object.

environments:
  paseo:
    kind: daemon
    daemon: laptop
    cwd: /Users/you/code/paseo
  hub:
    kind: daemon
    daemon: devbox
    cwd: /workspace/hub

agents:
  codex-safe:
    provider: codex
    model: gpt-5.5
    thinkingOptionId: xhigh
    options:
      sandbox_workspace_write:
        writable_roots: [/var/cache/npm]
        network_access: false
  claude:
    provider: claude
    mode: bypassPermissions

The only top-level keys are environments and agents. A triggers key is rejected with a migration error.

Environments

Field Required Notes
kind yes daemon, fly, or docker; workflow steps must select a daemon environment.
daemon daemon only Registered daemon slug, resolved when the revision activates.
cwd daemon only Absolute working directory on the daemon.
image fly/docker Image name.
worktree no branch-off, checkout-branch, or checkout-pr target.

For worktree, use newBranch and optional base with branch-off, branch with checkout-branch, or positive prNumber with checkout-pr.

environments:
  review:
    kind: daemon
    daemon: build-server
    cwd: /workspace/project
    worktree:
      mode: branch-off
      newBranch: trigger-${{ paseo.execution.id }}
      base: origin/main

newBranch is a branch-name string. Embed ${{ paseo.execution.id }}, which renders the execution's UUID, so every execution branches off base on its own branch and keeps it when Hub retries or recovers that execution.

One execution is one step run, so two steps selecting the same environment get separate branches.

${{ paseo.execution.id }} is the only expression newBranch accepts. paseo.prompt, paseo.context, paseo.inputs.*, values.*, steps.<id>.outputs.*, and provider event fields are unavailable here, and each one fails bundle activation at the authored field, such as .paseo/hub.yml.environments.review.worktree.newBranch.

${{ paseo.execution.id }} fails activation the same way anywhere else in a bundle. branch and prNumber take literal values.

An environment is a complete named object. A step selects its name; objects are not inherited, merged, or partially overridden.

Named agents

Each agent is one complete provider configuration:

Field Required Notes
provider yes Provider ID. Hub runs unattended, so claude, codex, or opencode.
model no Provider model ID.
mode no Paseo mode ID.
thinkingOptionId no Provider thinking option.
options no JSON-safe provider-native options, preserving names and nesting.

A named selection preserves the complete object, including structured options. Named agents have no parent, patch, or per-step override.

Hub passes model, mode, thinkingOptionId, and options to the Paseo daemon without renaming or flattening provider fields. The selected daemon validates them against its current provider schema when the trigger is saved or deployed, so a value it does not offer is refused then rather than at the first run; Hub does not translate provider-native options. See Saving checks the agent against the daemon.

Workflow files

.paseo/workflows/review.yml:

name: review
on: manual.run
max_runtime: 2h
filters:
  from_users: [automation]
inputs:
  repo:
    type: string
    required: true
    choices: [paseo, hub]
steps:
  - id: inspect
    environment: ${{ paseo.inputs.repo }}
    max_runtime: 30m
    idle_timeout: 5m
    agent: codex-safe
    prompt:
      - text: ${{ paseo.prompt }}
Field Required Notes
name yes Workflow name, unique across the bundle.
on yes Provider event such as manual.run or discord.mention.
max_runtime yes Hard limit for the complete run, up to 24h.
filters yes Provider resource filters and the sender allowlist.
inputs no Typed invocation headers.
values no Named expressions.
steps yes One or more ordered inline steps.

GitHub events and filters

Use one of these semantic event names for new GitHub workflows:

on Matches
github.issue_created An issues delivery whose action is opened.
github.pull_request_created A pull_request delivery whose action is opened.
github.issue_comment_created An issue_comment delivery whose action is created, on an issue.
github.pull_request_comment_created An issue_comment delivery whose action is created, on a pull request.
github.issue_label_added An issues delivery whose action is labeled.
github.pull_request_label_added A pull_request delivery whose action is labeled.

Existing configurations may continue to use github.issues, github.issue_comment, github.pull_request_review, github.pull_request_review_comment, and github.push. These legacy events retain their existing behavior.

filters supports these GitHub fields. from_users must be non-empty for every externally sourced workflow. All supplied filters compose with AND.

Field Type Applies to Meaning
from_users non-empty list of strings all GitHub events GitHub logins allowed to start the workflow.
repo non-empty string all GitHub events Repository in owner/name form.
connection string all GitHub events GitHub connection slug.
contains string issue, pull-request, and comment events Substring in the issue or pull-request title plus body, or in the comment body.
pattern string issue, pull-request, and comment events Start of that same text.
label non-empty string github.issue_label_added, github.pull_request_label_added The label added by the delivery.
labels non-empty list of non-empty strings issue, pull-request, and comment events Every listed label must be currently present on the issue or pull request.

label and labels match GitHub labels case-insensitively. label checks the one changed label; labels checks the full current label set and requires every entry. For example, labels: [bug, backend] requires both bug and backend.

Use label only with a label-added event. It has no match on other events. Use labels to require the item state, including when a comment starts the workflow.

See GitHub triggers for complete triage, pull-request review, and ready-for-agent workflows.

Inputs and values

Inputs have type: string | number | boolean, plus optional required, default, and choices. required and default cannot be combined. Finite choices are required when an input can choose authority such as an environment or named agent.

Values bind expressions:

values:
  selected_environment: ${{ steps.classify.outputs.environment }}
  selected_agent: ${{ steps.classify.outputs.agent }}

Expressions may read declared paseo.inputs, earlier steps.<id>.outputs, and values. The grammar supports paths, JSON literals, parentheses, !, ==, !=, &&, ||, and ??.

An environment or dynamic named-agent expression must have a finite set of possible string results at activation. Every result must name a configured resource. Runtime selection never falls back to another environment or agent.

Steps

Field Required Notes
id yes Unique within the workflow.
environment yes Literal environment name or finite expression resolving to one.
max_runtime yes Step hard limit.
idle_timeout yes Idle limit no longer than max_runtime.
startup_timeout no Step startup waiting budget. See startup timeout for defaults and limits.
agent yes Named agent, finite expression selecting a named agent, or complete static inline agent.
prompt yes Ordered text and include blocks.
if no Expression deciding whether the step runs.
env no Environment variables from connection values.
output.schema no JSON Schema for structured step output.
allow_outputs no Provider output capabilities with optional max and required.
auto_archive no Archive the agent after the step ends.
github no Explicit GitHub authority for this step.

An inline agent is static and complete:

agent:
  provider: codex
  model: gpt-5.5
  options:
    approval_policy: never
    sandbox_mode: read-only

An expression-valued agent selects a named agent. Dynamic provider fields inside an inline object are rejected.

Prompt semantics

prompt:
  - include: partials/review.md
  - text: |
      <user-prompt>
      ${{ paseo.prompt }}
      </user-prompt>

${{ paseo.prompt }} is the normalized request after the provider marker and declared leading key=value inputs are removed. It is not rewritten or augmented with event context.

${{ paseo.context }} opts that step into provider context materialization and renders the result as JSON in the prompt. It is available only in prompt text. Hub does not inject it unless the workflow authors that expression.

Includes resolve relative to .paseo/workflows/, so shared partials use partials/<name>.md. Missing files, absolute or traversing paths, symlinks, content mismatches, and files outside the partial tree are rejected.

Output capabilities

Authority stays on the step that uses it:

allow_outputs:
  - type: discord.reply
    max: 1
    required: true

Slack workflows use slack.reply; Discord workflows use discord.reply. The declaration grants hub.reply, and the prompt must tell the agent to call it. GitHub has no reply output; use an explicit github block.

Every step receives hub.finish_execution. The prompt must tell the agent when to call it; Hub does not append completion or reply instructions. If output.schema is present, hub.finish_execution requires an output value that matches the schema. If an allow_outputs entry is required: true, the agent must emit that output before finishing. max defaults to 1.

Migrating a monolithic file

Keep environments in hub.yml, convert the environment list to a named map, and move each former trigger into its own .paseo/workflows/<name>.yml file. Move shared prompt files to .paseo/workflows/partials/. Define complete named agent configurations under agents and replace dynamic provider fields with finite named-agent selection.

Hub does not read TOML or a monolithic triggers section, and the CLI does not rewrite either format.

See Workflows for complete routing examples.

Agent continuation

Self-contained dashboard trigger documents accept run.continuation:

Value Behavior
{mode: conversation} Default. Reuse the project's agent for the event's conversation; create a new agent when the event has no conversation.
{mode: key, key: "support-${{ paseo.inputs.ticket }}"} Reuse the project's agent for the evaluated custom key.
{mode: new} Create a new agent for each arrival.

Keys use the existing expression syntax and must resolve to a non-empty string of at most 512 characters. Custom keys and provider conversation identities occupy separate namespaces. The same key in different projects does not share an agent.

An existing session keeps its daemon, agent configuration, target, environment, and tool contracts. Changing those settings for the same key fails with an explanation; choose a different key or New agent. Prompts and output destinations belong to each arrival and may change. A worktree branch is chosen when the session is first created and reused on later arrivals.

A follow-up steers the active agent without extending its runtime deadline or credential expiry. With a run.github grant or connection token in run.env, follow-ups share the active agent’s credentials. Once all requests finish, Hub revokes leased tokens; the next arrival starts a new agent with fresh credentials. Agents without temporary credentials can be reused after completion.

Upgrading

Upgrade the connected Paseo daemons before enabling the new Hub version. Hub requires the daemon's ordinary agent RPC and request receipt capabilities; an older host produces an actionable dispatch error.

Hub's database migration adds sessions and nullable execution associations. Existing executions retain their saved launch contract and execution-specific MCP endpoint until they finish. New arrivals for existing self-contained trigger documents use the conversation default. Historical agents are not backfilled into sessions.

Legacy multi-step workflow bundles keep their existing behavior. Converting one to a self-contained trigger writes mode: new explicitly; change it in the editor when ready to reuse agents.