Deploy multi-file Hub workflows (#3128)
* feat(hub): deploy canonical workflow bundles Keep CLI deployment aligned with Hub's authored bundle boundary so validation and activation receive the same deterministic source files. Public documentation now teaches that boundary as the only configuration format. * test(hub): assert validation diagnostics directly * refactor(hub): deepen HTTP client module * feat(hub): validate named agent configurations * docs(hub): align Claude mode example
This commit is contained in:
@@ -1,143 +1,184 @@
|
||||
---
|
||||
title: hub.yml reference
|
||||
description: The authored Hub configuration: environments, triggers, typed inputs, workflow steps, routing, and prompt partials.
|
||||
nav: hub.yml reference
|
||||
title: Hub configuration reference
|
||||
description: Canonical Hub resource, workflow, agent, expression, and prompt fields.
|
||||
nav: Configuration reference
|
||||
order: 71
|
||||
category: Hub
|
||||
---
|
||||
|
||||
# `hub.yml` reference
|
||||
# Hub configuration reference
|
||||
|
||||
A configuration has `environments` and `triggers`. It may also include top-level `project` deployment metadata for `paseo hub deploy`. Execution fields belong to each trigger's `steps`.
|
||||
Hub accepts YAML in this layout:
|
||||
|
||||
```yaml
|
||||
project: my-project
|
||||
|
||||
environments:
|
||||
- name: development
|
||||
kind: daemon
|
||||
daemon: my-macbook
|
||||
cwd: /Users/you/code/project
|
||||
|
||||
triggers:
|
||||
- name: request
|
||||
on: manual.run
|
||||
max_runtime: 2h
|
||||
filters:
|
||||
from_users: [automation]
|
||||
steps:
|
||||
- id: work
|
||||
environment: development
|
||||
max_runtime: 90m
|
||||
idle_timeout: 10m
|
||||
agent:
|
||||
provider: codex
|
||||
mode: full-access
|
||||
prompt:
|
||||
- text: Call hub.finish_execution when the step is complete.
|
||||
- text: |
|
||||
<user-prompt>
|
||||
${{ paseo.prompt }}
|
||||
</user-prompt>
|
||||
```text
|
||||
.paseo/
|
||||
├── hub.yml
|
||||
└── workflows/
|
||||
├── <workflow>.yml
|
||||
└── partials/
|
||||
└── <partial>.md
|
||||
```
|
||||
|
||||
`project` is an optional bare project slug. The deploy CLI uses it to choose the target project when `-p, --project` is absent. The flag takes precedence over this metadata without rewriting the YAML. `project` is not available to triggers, expressions, or agents.
|
||||
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.
|
||||
|
||||
## Environments
|
||||
## `hub.yml`
|
||||
|
||||
| Field | Required | Notes |
|
||||
| ---------- | ----------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | yes | Lowercase identifier referenced by a step. |
|
||||
| `kind` | yes | `daemon`, `fly`, or `docker` in the authored schema; workflow steps must resolve to a daemon environment. |
|
||||
| `daemon` | daemon only | Friendly daemon slug, resolved to its immutable ID when the revision activates. |
|
||||
| `cwd` | daemon only | Absolute path on the daemon. |
|
||||
| `image` | fly/docker | Image name. |
|
||||
| `worktree` | no | `branch-off`, `checkout-branch`, or `checkout-pr` target. |
|
||||
|
||||
The `worktree` object is part of the environment. Its fields are exact authored names: `newBranch` and optional `base` for `branch-off`, `branch` for `checkout-branch`, and positive integer `prNumber` for `checkout-pr`. Give `base` a remote-tracking ref such as `origin/main`; see [Git worktrees](/docs/worktrees#create-a-worktree-backed-workspace).
|
||||
|
||||
## Triggers
|
||||
|
||||
| Field | Required | Notes |
|
||||
| ------------- | ------------ | ----------------------------------------------------------------------------------------------- |
|
||||
| `name` | yes | Lowercase identifier, unique in the configuration. |
|
||||
| `on` | yes | `provider.event`, such as `slack.mention` or `manual.run`. |
|
||||
| `max_runtime` | yes | Positive duration for the complete trigger run, up to 24h. |
|
||||
| `filters` | no in schema | Provider filters; externally sourced triggers still require a non-empty `from_users` allowlist. |
|
||||
| `inputs` | no | Typed leading `key=value` invocation headers. |
|
||||
| `values` | no | Derived expressions. |
|
||||
| `steps` | yes | One or more ordered steps. |
|
||||
|
||||
### Inputs
|
||||
|
||||
Each input has:
|
||||
`.paseo/hub.yml` contains named project resources. Names are map keys and are not repeated inside each object.
|
||||
|
||||
```yaml
|
||||
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`.
|
||||
|
||||
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. |
|
||||
| `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.
|
||||
|
||||
## Workflow files
|
||||
|
||||
`.paseo/workflows/review.yml`:
|
||||
|
||||
```yaml
|
||||
name: review
|
||||
on: manual.run
|
||||
max_runtime: 2h
|
||||
inputs:
|
||||
repo:
|
||||
type: string
|
||||
required: false
|
||||
choices: [project, paseo]
|
||||
agent:
|
||||
type: string
|
||||
default: codex
|
||||
choices: [codex, claude]
|
||||
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 }}
|
||||
```
|
||||
|
||||
`type` is `string`, `number`, or `boolean`. `required`, `default`, and `choices` are optional. `required` and `default` cannot be combined. Defaults and choices must match the declared type; a default must be one of the choices.
|
||||
| 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` | provider-dependent | Provider resource and sender allowlists. |
|
||||
| `inputs` | no | Typed invocation headers. |
|
||||
| `values` | no | Named expressions. |
|
||||
| `steps` | yes | One or more ordered inline steps. |
|
||||
|
||||
Inputs may be referenced as `${{ paseo.inputs.name }}`. A dynamic authority-bearing field such as a provider, model, mode, or environment requires finite `choices` at activation. A prompt cannot supply authority.
|
||||
### Inputs and values
|
||||
|
||||
### 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 under their own namespace:
|
||||
Values bind expressions:
|
||||
|
||||
```yaml
|
||||
values:
|
||||
selected_repo: ${{ paseo.inputs.repo ?? steps.classify.outputs.repo }}
|
||||
selected_environment: ${{ steps.classify.outputs.environment }}
|
||||
selected_agent: ${{ steps.classify.outputs.agent }}
|
||||
```
|
||||
|
||||
The grammar supports paths, JSON literals, parentheses, `!`, `==`, `!=`, `&&`, `||`, and `??`. It does not support function calls, JavaScript, arithmetic, mutation, or implicit string coercion. Referenced steps must exist and value dependencies cannot cycle.
|
||||
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 | Lowercase step identifier, unique within the trigger. |
|
||||
| `environment` | yes | Environment name or a finite input expression resolving to one. |
|
||||
| `max_runtime` | yes | Positive step hard limit, up to 24h. |
|
||||
| `idle_timeout` | yes | Positive idle limit, no longer than the step hard limit. |
|
||||
| `agent` | yes | `provider`, optional `model`, `mode`, `thinkingOptionId`, and provider-native `options`. |
|
||||
| `prompt` | yes | Non-empty list of `text` and GitHub-only `include` blocks. |
|
||||
| `if` | no | Expression deciding whether this ordered step runs. |
|
||||
| `env` | no | Environment variables populated from connection values. See [GitHub access](/docs/hub/github#other-integrations). |
|
||||
| `output` | no | `{ schema: <JSON Schema> }` for the structured result the agent passes to `hub.finish_execution`. |
|
||||
| `allow_outputs` | no | Registered output capabilities such as `slack.reply` or `discord.reply`, each with optional `max` and `required`. |
|
||||
| `auto_archive` | no | Archives the step's agent when it ends. |
|
||||
| `github` | no | Scoped GitHub token and git setup for this step. See [GitHub access](/docs/hub/github). |
|
||||
| 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`. |
|
||||
| `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. |
|
||||
|
||||
Prompt blocks are objects, not a scalar prompt:
|
||||
An inline agent is static and complete:
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```yaml
|
||||
prompt:
|
||||
- include: developer.md
|
||||
- include: partials/review.md
|
||||
- text: |
|
||||
<user-prompt>
|
||||
${{ paseo.prompt }}
|
||||
</user-prompt>
|
||||
```
|
||||
|
||||
Keep the triggering message in its own final block, wrapped in `<user-prompt>` tags, as [the first workflow](/docs/hub/workflows#your-first-workflow) does.
|
||||
`${{ 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.
|
||||
|
||||
Use `${{ paseo.prompt }}`, `${{ paseo.inputs.* }}`, `${{ steps.*.outputs.* }}`, and `${{ values.* }}` in prompts, conditions, and agent selection fields. Provider event payloads are not part of this workflow expression namespace; provider adapters put the normalized request into the prompt and preserve the raw event as evidence.
|
||||
`${{ 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.
|
||||
|
||||
`agent.options` carries JSON-safe options using the selected provider's native names and nesting. Paseo validates them with that provider's strict schema before starting the session. See [Hub security](/docs/hub/security) for the trust boundary and copyable provider examples.
|
||||
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.
|
||||
|
||||
`mode` names a Paseo agent mode ID, which is a separate surface from these options. Some modes keep the provider's interactive approval flow, and that stalls an unattended step, so set the provider's own approval and sandbox settings in `options` instead.
|
||||
### Output authority
|
||||
|
||||
#### Output capabilities
|
||||
|
||||
`allow_outputs` separates permission from obligation. `max` limits how many times a capability may be emitted and defaults to `1`. Set `required: true` when the step must emit that capability at least once before it can finish successfully:
|
||||
Authority stays on the step that uses it:
|
||||
|
||||
```yaml
|
||||
allow_outputs:
|
||||
@@ -146,55 +187,12 @@ allow_outputs:
|
||||
required: true
|
||||
```
|
||||
|
||||
`required: true` means the step must actually emit the capability. Assistant text does not count.
|
||||
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](/docs/hub/github).
|
||||
|
||||
- A required output must resolve to a registered, available capability for the execution, or dispatch rejects the step.
|
||||
- A required output needs an effective `max` of at least `1`, or activation rejects the configuration.
|
||||
- Failed delivery is retryable. An agent that tries to finish first is told the concrete output tool to call, then `hub.finish_execution` is retried.
|
||||
## Migrating a monolithic file
|
||||
|
||||
Omitting `required` keeps the output optional. GitHub has no reply capability; a step acts through the `gh` CLI with the token its [`github` block](/docs/hub/github) grants.
|
||||
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.
|
||||
|
||||
A declaration grants the tool. The step's prompt still has to tell the agent to call `hub.reply`, and to call `hub.finish_execution` when it is done. See [Tell the agent which tool to call](/docs/hub/workflows#tell-the-agent-which-tool-to-call).
|
||||
Hub does not read TOML or a monolithic `triggers` section, and the CLI does not rewrite either format.
|
||||
|
||||
## Prompt partials
|
||||
|
||||
`include` paths are relative to `.paseo/partials/`.
|
||||
|
||||
- GitHub configuration: Hub reads each file at the exact configuration commit and stores the resolved content and SHA-256 hash in the immutable revision.
|
||||
- `paseo hub deploy`: the CLI reads the referenced files from the local project root and sends them in the optional `partials` bundle. The bundle path omits the `.paseo/partials/` prefix.
|
||||
- Missing files, unsafe paths, symlinks, submodules, directories, duplicate or unexpected bundle entries, and nested includes are rejected.
|
||||
- Manual configurations cannot use repository partials.
|
||||
|
||||
## Deadlines
|
||||
|
||||
The trigger's `max_runtime` is the hard limit for the complete workflow run. Each step also has `max_runtime` and `idle_timeout`:
|
||||
|
||||
```yaml
|
||||
max_runtime: 2h
|
||||
steps:
|
||||
- id: classify
|
||||
max_runtime: 2m
|
||||
idle_timeout: 30s
|
||||
|
||||
- id: implement
|
||||
max_runtime: 90m
|
||||
idle_timeout: 10m
|
||||
```
|
||||
|
||||
The effective step hard and idle deadlines are capped by the remaining trigger deadline. Meaningful daemon activity refreshes idle time, but cannot extend a hard deadline. Hub persists absolute deadlines, so a restart or deployment does not reset them. A step timeout fails the run; a trigger timeout stops later steps and interrupts a live agent.
|
||||
|
||||
## Provider invocation
|
||||
|
||||
The provider removes its mention or marker before Hub parses leading declared input tokens. Slack and Discord place the inputs immediately after the bot mention. GitHub places them after the configured marker. Manual runs send the same string as the API `input`:
|
||||
|
||||
```text
|
||||
@Paseo repo=project investigate the failed sync
|
||||
```
|
||||
|
||||
The first token that is not a declared input begins the prompt. The clean prompt is available as `${{ paseo.prompt }}`. The raw provider message remains separate Activity evidence. See [provider triggers](/docs/hub/triggers) for provider-specific marker and filter behavior.
|
||||
|
||||
## Removed fields
|
||||
|
||||
Do not put execution fields directly on a trigger. `environment`, `agent`, `prompt`, `timeout`, `idle_timeout`, `auto_archive`, and `allow_outputs` are step fields now. The duration field is `max_runtime`; `timeout` is not an alias.
|
||||
|
||||
Next: [Hub workflows](/docs/hub/workflows) for routing patterns and copyable configurations.
|
||||
See [Workflows](/docs/hub/workflows) for complete routing examples.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Hub configuration
|
||||
description: Where a project's configuration comes from, how GitHub sync works, and how revisions activate and roll back.
|
||||
description: Configuration bundles, GitHub sync, CLI deployment, and revisions.
|
||||
nav: Configuration
|
||||
order: 70
|
||||
category: Hub
|
||||
@@ -8,94 +8,75 @@ category: Hub
|
||||
|
||||
# Hub configuration
|
||||
|
||||
A project is configured by one versioned document. The project's **Configuration** tab shows the active revision, its source, and the last synchronization attempt.
|
||||
A project configuration is one versioned bundle:
|
||||
|
||||
```text
|
||||
.paseo/
|
||||
├── hub.yml
|
||||
└── workflows/
|
||||
├── <workflow>.yml
|
||||
└── partials/
|
||||
└── <partial>.md
|
||||
```
|
||||
|
||||
`hub.yml` owns named environments and agents. Each direct-child workflow file owns one trigger and its ordered inline steps. Prompt partials referenced by those workflows live below `workflows/partials/`. Workflow discovery is fixed by convention; there is no manifest or include list.
|
||||
|
||||
## Sources
|
||||
|
||||
A configuration comes from exactly one source:
|
||||
A configuration comes from one source:
|
||||
|
||||
- **GitHub source**: one repository, the file `.paseo/hub.yml`, on the repository's current default branch.
|
||||
- **Manual source**: edited in the dashboard and saved with **Save and activate**.
|
||||
- **CLI/API install**: YAML sent explicitly with an organization API key.
|
||||
- **GitHub source**: the complete `.paseo` bundle on the repository's default branch.
|
||||
- **Manual source**: source files edited and activated in the dashboard.
|
||||
- **CLI/API install**: a complete bundle sent with organization authority.
|
||||
|
||||
Pick a GitHub source by choosing a repository and clicking **Use for configuration**. That syncs immediately and enables automatic deployment.
|
||||
|
||||
The path and the branch are fixed. There is no setting for either.
|
||||
The **Configuration** tab shows the active revision, source files, and latest synchronization attempt.
|
||||
|
||||
## Deploy from the CLI
|
||||
|
||||
From a project checkout, add the target project slug as optional deployment metadata:
|
||||
|
||||
```yaml
|
||||
project: my-project
|
||||
```
|
||||
|
||||
Then deploy:
|
||||
Run from the project root:
|
||||
|
||||
```sh
|
||||
paseo hub login https://hub.example.com
|
||||
paseo hub deploy --dry-run
|
||||
paseo hub deploy
|
||||
paseo hub deploy -p my-project --dry-run
|
||||
paseo hub deploy -p my-project
|
||||
```
|
||||
|
||||
Deploy reads exactly `.paseo/hub.yml` in the current directory; it does not search parent directories. Partials are read from `.paseo/partials/` under the same directory.
|
||||
Both commands discover `.paseo/hub.yml`, every direct `.paseo/workflows/*.yml` file, and each referenced file below `.paseo/workflows/partials/`. Files are sent in deterministic path order through the same bundle request. Dry-run calls server-side validation and does not create or activate a revision.
|
||||
|
||||
- `paseo hub deploy path/to/config.yml` deploys another file. The bundle root stays the current directory.
|
||||
- `-p, --project <slug>` overrides the file's `project` value without changing the YAML sent to Hub.
|
||||
- `--dry-run` sends the identical resolved YAML, project slug, and partial bundle to Hub's validator. Nothing is recorded or activated.
|
||||
|
||||
For each prompt `include`, the CLI sends one `{ path, content }` entry whose path is relative to `.paseo/partials/`. Only files referenced by the main YAML are sent; include-looking text inside a partial is not scanned. Missing, unsafe, duplicate, unreadable, non-file, or oversized inputs fail locally, and a configuration with only inline prompt blocks sends no `partials` field.
|
||||
The CLI rejects missing resource or workflow files, `.yaml` workflow extensions, nested workflow files, unsafe partial paths, symlinked bundle paths, and unreadable files before contacting Hub. Errors name paths but never print file contents or credentials.
|
||||
|
||||
Origin precedence:
|
||||
|
||||
1. `--hub`
|
||||
2. `PASEO_HUB_URL`
|
||||
3. The active stored login
|
||||
3. Active stored login
|
||||
4. `https://hub.paseo.sh`
|
||||
|
||||
Credential precedence:
|
||||
|
||||
1. `--api-key`
|
||||
2. `PASEO_HUB_API_KEY`
|
||||
3. An exact-origin stored login
|
||||
3. Stored login for the exact resolved origin
|
||||
|
||||
Keys passed by flag or environment are not stored, and a stored credential is never reused for a different Hub origin. Deploy and dry-run print the normalized destination before sending anything.
|
||||
Flags and environment keys are not stored. Endpoint and credential behavior is unchanged between deploy and dry-run.
|
||||
|
||||
## Sync
|
||||
## GitHub sync
|
||||
|
||||
A push to the default branch of the configuration repository triggers a sync:
|
||||
A push to the configuration repository's default branch starts a sync:
|
||||
|
||||
1. Hub fetches `.paseo/hub.yml` at that exact commit.
|
||||
2. It validates the document and resolves every repository, workspace, guild, and daemon it names.
|
||||
3. On success the revision becomes active.
|
||||
1. Hub discovers the canonical bundle at that exact commit.
|
||||
2. It parses every source file and resolves prompt partials.
|
||||
3. It validates named resources, expressions, connections, and daemon availability.
|
||||
4. On success, the new immutable revision becomes active.
|
||||
|
||||
**Sync now** does the same on demand.
|
||||
**Sync now** performs the same operation on demand. Failures retain their source path and authored field. A failed sync never replaces the active revision.
|
||||
|
||||
Every attempt is recorded, including failures. The outcomes you will see:
|
||||
## Revisions and source changes
|
||||
|
||||
| Outcome | What happened |
|
||||
| ----------------------- | ------------------------------------------------------------------------------- |
|
||||
| Activated | Valid document, everything resolved, now serving events. |
|
||||
| Invalid | The document failed validation or named something the organization can't reach. |
|
||||
| Fetch failed | The file is missing, or GitHub could not be read. |
|
||||
| Superseded push ignored | A newer commit already moved the branch head. |
|
||||
Revisions retain the exact authored files needed to inspect or redeploy them. Rolling back activates an earlier revision. The next valid GitHub push activates a new revision again.
|
||||
|
||||
A failed sync never replaces the active revision. A repository with a broken `hub.yml` keeps serving the last good one.
|
||||
GitHub-backed configuration is read-only in the dashboard. Switching to manual preserves source documents; it does not collapse the bundle into one generated file.
|
||||
|
||||
## Revisions
|
||||
The configuration repository may differ from repositories named by `filters.repo`. Protect it because changing the bundle can select connections, daemons, working directories, agents, and outputs. See [Hub security](/docs/hub/security).
|
||||
|
||||
Revisions are immutable and numbered per project. Rolling back selects an earlier revision and recompiles its routes. The next valid push activates again, so rollback holds only until the next push.
|
||||
|
||||
## Switching source
|
||||
|
||||
Switching from GitHub to manual copies the active revision into the editor and stops syncing. Switching back means choosing a repository again.
|
||||
|
||||
While a project uses a GitHub source, the dashboard editor is read-only. The repository is the source of truth.
|
||||
|
||||
## The configuration repository does not have to be the repository you watch
|
||||
|
||||
`filters.repo` can name any repository the organization has a connection for. Keeping `hub.yml` in a private repository while triggers watch several public ones is a common setup, because push access to the configuration repository grants access to the organization's connections.
|
||||
|
||||
Treat the configuration repository as part of the security boundary. [Hub security](/docs/hub/security) covers what a changed configuration can authorize and how to limit the resulting agent process.
|
||||
|
||||
Next: [Hub workflows](/docs/hub/workflows), then the [`hub.yml` reference](/docs/hub/configuration/hub-yml).
|
||||
Next: the [configuration reference](/docs/hub/configuration/hub-yml) and [workflow examples](/docs/hub/workflows).
|
||||
|
||||
Reference in New Issue
Block a user