docs(hub): align public docs with v0.3 (#3152)
* docs(hub): align public docs with v0.3 Bring the public workflow, API, authority, activity, and self-hosting guidance in line with the released Hub contracts. Clarify the public HTTPS boundary required by provider events while keeping Hub and PostgreSQL private. * docs(hub): clarify daemon logout scope * docs(hub): restore Compose path and simplify TLS guidance * docs(hub): link the single-repo-team-bot example
This commit is contained in:
+11
-17
@@ -12,34 +12,28 @@ Every event Hub accepts is recorded, whether or not it ran anything. That record
|
|||||||
|
|
||||||
## Where to look
|
## Where to look
|
||||||
|
|
||||||
**Project → Activity** lists the events routed to that project: the event, its source, the result, and when it arrived.
|
**Project → Activity** lists routed trigger runs and their execution state.
|
||||||
|
|
||||||
The result column says what happened:
|
**Connections → Known unrouted events** is the organization-level view of accepted provider events that did not start a configured trigger. Hub records one of four bounded reasons:
|
||||||
|
|
||||||
| Result | Meaning |
|
| Reason | Meaning |
|
||||||
| --------------------- | ----------------------------------------------------------------- |
|
| --------------------------- | ------------------------------------------------------------ |
|
||||||
| A trigger name | The event matched that trigger and dispatched |
|
| `no_project_route` | No project route is configured for the event |
|
||||||
| A lifecycle state | The execution is in progress or finished |
|
| `no_trigger_for_source` | No configured trigger handles that event source |
|
||||||
| `no_matching_trigger` | The event reached the project, but no trigger's filters matched |
|
| `trigger_filters_rejected` | A trigger handles the source, but its filters rejected it |
|
||||||
| `provider_unrouted` | No project route existed for the resource that produced the event |
|
| `configuration_unavailable` | A relevant configuration or connection could not be resolved |
|
||||||
|
|
||||||
**Project → Executions** lists the runs: which trigger, which configuration revision, which daemon, duration, and outcome.
|
|
||||||
|
|
||||||
**Connections → Known unrouted events** is the organization-level view. It holds events whose credential belongs to your organization but which no project's configuration claimed. A repository you connected but never named in a trigger lands here.
|
|
||||||
|
|
||||||
Those two are different problems. `no_matching_trigger` means your filters are wrong. An unrouted event means no configuration mentions that repository, workspace, or guild at all.
|
|
||||||
|
|
||||||
## Nothing happened when I mentioned the bot
|
## Nothing happened when I mentioned the bot
|
||||||
|
|
||||||
Work down this list.
|
Work down this list.
|
||||||
|
|
||||||
1. **Is the event in the project's Activity?** If not, check **Connections → Known unrouted events**. If it is there, no trigger names that resource. Add `filters.repo`, `filters.workspace`, or `filters.guild` and push.
|
1. **Is the event in the project's Activity?** If not, check **Connections → Known unrouted events** and use its reason to distinguish routing, source, filter, and configuration failures.
|
||||||
2. **Is the event anywhere at all?** If not, the event never reached Hub. Check the provider's own delivery log: GitHub's App → Advanced → Recent Deliveries, or Slack's Event Subscriptions page. Then check that the app is subscribed to that event type.
|
2. **Is the event anywhere at all?** If not, the event never reached Hub. Check the provider's own delivery log: GitHub's App → Advanced → Recent Deliveries, or Slack's Event Subscriptions page. Then check that the app is subscribed to that event type.
|
||||||
3. **Is your user in `from_users`?** This is the most common cause. GitHub uses your login; Slack and Discord use the user ID, not the display name.
|
3. **Is your user in `from_users`?** This is the most common cause. GitHub uses your login; Slack and Discord use the user ID, not the display name.
|
||||||
4. **Did the mention match?** On GitHub, `contains` must appear in the comment body. On Slack and Discord the bot must actually be mentioned, and `pattern` matches only at the start of the text after the mention.
|
4. **Did the invocation match?** On GitHub, `contains` must appear in the comment body. On Slack and Discord the bot must be mentioned, and `pattern` or its legacy `contains` alias must prefix the text after the mention.
|
||||||
5. **Is the configuration you think is active actually active?** The Configuration tab shows the active revision and the last sync attempt. A failed push leaves the old revision serving.
|
5. **Is the configuration you think is active actually active?** The Configuration tab shows the active revision and the last sync attempt. A failed push leaves the old revision serving.
|
||||||
6. **Is the daemon connected?** An offline daemon fails dispatch with `daemon_not_connected`.
|
6. **Is the daemon connected?** An offline daemon fails dispatch with `daemon_not_connected`.
|
||||||
7. **Did it run and stop early?** Check the execution. An agent that never reports back is ended by `idle_timeout` after 5 minutes by default, or `timeout` after an hour.
|
7. **Did it run and stop early?** Compare the execution with the step's authored `idle_timeout` and `max_runtime`, and the workflow's `max_runtime`. All three limits are explicit in the workflow.
|
||||||
8. **Did it run, but deliver nothing?** Check the step's prompt. An agent that is not told to call `hub.reply` and `hub.finish_execution` can answer in its own transcript and never report back. See [Tell the agent which tool to call](/docs/hub/workflows#tell-the-agent-which-tool-to-call).
|
8. **Did it run, but deliver nothing?** Check the step's prompt. An agent that is not told to call `hub.reply` and `hub.finish_execution` can answer in its own transcript and never report back. See [Tell the agent which tool to call](/docs/hub/workflows#tell-the-agent-which-tool-to-call).
|
||||||
|
|
||||||
## Sync failures
|
## Sync failures
|
||||||
|
|||||||
+19
-23
@@ -54,10 +54,12 @@ API failures use RFC 9457 problem details. Missing, invalid, or revoked credenti
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "https://hub.example.com/problems/unauthorized",
|
"type": "https://paseo.sh/problems/unauthorized",
|
||||||
"title": "Unauthorized",
|
"title": "Authentication required",
|
||||||
"status": 401,
|
"status": 401,
|
||||||
"detail": "Provide a valid organization API key."
|
"detail": "Provide an active Paseo organization credential in the Authorization: Bearer header.",
|
||||||
|
"code": "unauthorized",
|
||||||
|
"requestId": "5e967c44-fc22-4f6d-8fc5-1bbff33121af"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -130,7 +132,8 @@ Limits:
|
|||||||
|
|
||||||
- Bundle: at most 100 files.
|
- Bundle: at most 100 files.
|
||||||
- File path: at most 512 characters.
|
- File path: at most 512 characters.
|
||||||
- File content: at most 1,000,000 characters; partial byte limits are enforced during compilation.
|
- File content: at most 1,000,000 characters.
|
||||||
|
- Prompt partials: at most 1,000,000 bytes each and 5,000,000 bytes in total.
|
||||||
|
|
||||||
On success, Hub returns `201`:
|
On success, Hub returns `201`:
|
||||||
|
|
||||||
@@ -163,7 +166,7 @@ The trigger must exist in the active configuration, and `actor` must be listed
|
|||||||
in that trigger's `filters.from_users` allowlist.
|
in that trigger's `filters.from_users` allowlist.
|
||||||
|
|
||||||
```http
|
```http
|
||||||
POST /api/manual-runs
|
POST /api/v1/manual-runs
|
||||||
```
|
```
|
||||||
|
|
||||||
Request body:
|
Request body:
|
||||||
@@ -181,32 +184,27 @@ Request body:
|
|||||||
|
|
||||||
- `expectedVersionId` is optional. When supplied, Hub rejects the dispatch if that revision is no longer active.
|
- `expectedVersionId` is optional. When supplied, Hub rejects the dispatch if that revision is no longer active.
|
||||||
- `input` is the same string a provider message uses: leading `key=value` tokens are parsed as declared inputs, and the remainder becomes `${{ paseo.prompt }}`.
|
- `input` is the same string a provider message uses: leading `key=value` tokens are parsed as declared inputs, and the remainder becomes `${{ paseo.prompt }}`.
|
||||||
- `deliveryKey` should be unique and stable per dispatch. Reusing one resolves to the existing trigger instead of starting a duplicate run.
|
- `deliveryKey` should be unique and stable per dispatch. Hub uses it for durable deduplication, but does not promise exactly-once dispatch or replay of an earlier response.
|
||||||
|
|
||||||
On success, Hub returns `200`:
|
On success, Hub returns `200`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"deliveryKey": "deploy-2026-08-04-001",
|
"deliveryKey": "deploy-2026-08-04-001",
|
||||||
"triggerId": "00000000-0000-4000-8000-000000000000",
|
"providerEventReceiptId": "00000000-0000-4000-8000-000000000000",
|
||||||
"executionId": "00000000-0000-4000-8000-000000000000",
|
"triggerRunId": "00000000-0000-4000-8000-000000000000",
|
||||||
"status": "spawning",
|
"configuredTriggerName": "deploy",
|
||||||
"daemonId": "00000000-0000-4000-8000-000000000000",
|
"workflowStatus": "running"
|
||||||
"agentId": "agent-id"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Common responses are `400 {"error":"invalid_request"}`, `404` for an
|
Common responses are `400` for an invalid request, `403` when the actor is not allowed by the trigger, `404` for an unknown project, configuration, or trigger, and `409` when the daemon is offline, the expected configuration is no longer current, or dispatch conflicts. Each uses the problem-details shape above.
|
||||||
unknown project, missing configuration, or missing trigger, `403
|
|
||||||
{"error":"actor_forbidden"}` when the actor is not allowed by the trigger,
|
|
||||||
and `409` when the daemon is offline, the expected configuration is no longer
|
|
||||||
current, or the run could not be dispatched.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --fail-with-body -sS -X POST "$HUB_URL/api/manual-runs" \
|
curl --fail-with-body -sS -X POST "$PASEO_HUB_URL/api/v1/manual-runs" \
|
||||||
-H "Authorization: Bearer $PASEO_API_KEY" \
|
-H "Authorization: Bearer $PASEO_HUB_API_KEY" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
--data '{
|
--data '{
|
||||||
"projectSlug": "my-project",
|
"projectSlug": "my-project",
|
||||||
@@ -230,7 +228,7 @@ be used as one.
|
|||||||
POST /api/v1/daemons/enrollment-tokens
|
POST /api/v1/daemons/enrollment-tokens
|
||||||
```
|
```
|
||||||
|
|
||||||
Send an empty JSON object as the request body. On success, Hub returns `201`:
|
No request body is required. On success, Hub returns `201`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -245,10 +243,8 @@ The token expires after 10 minutes and is consumed when the daemon enrolls.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --fail-with-body -sS -X POST \
|
curl --fail-with-body -sS -X POST \
|
||||||
"$HUB_URL/api/v1/daemons/enrollment-tokens" \
|
"$PASEO_HUB_URL/api/v1/daemons/enrollment-tokens" \
|
||||||
-H "Authorization: Bearer $PASEO_API_KEY" \
|
-H "Authorization: Bearer $PASEO_HUB_API_KEY"
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
--data '{}'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Direct API consumers can pass the returned token to the daemon enrollment protocol. The Paseo CLI intentionally does not accept raw enrollment tokens; `connect` owns the authenticated single-flow exchange.
|
Direct API consumers can pass the returned token to the daemon enrollment protocol. The Paseo CLI intentionally does not accept raw enrollment tokens; `connect` owns the authenticated single-flow exchange.
|
||||||
|
|||||||
@@ -64,6 +64,18 @@ The only top-level keys are `environments` and `agents`. A `triggers` key is rej
|
|||||||
|
|
||||||
For `worktree`, use `newBranch` and optional `base` with `branch-off`, `branch` with `checkout-branch`, or positive `prNumber` with `checkout-pr`.
|
For `worktree`, use `newBranch` and optional `base` with `branch-off`, `branch` with `checkout-branch`, or positive `prNumber` with `checkout-pr`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environments:
|
||||||
|
review:
|
||||||
|
kind: daemon
|
||||||
|
daemon: build-server
|
||||||
|
cwd: /workspace/project
|
||||||
|
worktree:
|
||||||
|
mode: branch-off
|
||||||
|
newBranch: paseo/review
|
||||||
|
base: origin/main
|
||||||
|
```
|
||||||
|
|
||||||
An environment is a complete named object. A step selects its name; objects are not inherited, merged, or partially overridden.
|
An environment is a complete named object. A step selects its name; objects are not inherited, merged, or partially overridden.
|
||||||
|
|
||||||
### Named agents
|
### Named agents
|
||||||
@@ -80,6 +92,8 @@ Each agent is one complete provider configuration:
|
|||||||
|
|
||||||
A named selection preserves the complete object, including structured options. Named agents have no parent, patch, or per-step override.
|
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; Hub does not translate provider-native options.
|
||||||
|
|
||||||
## Workflow files
|
## Workflow files
|
||||||
|
|
||||||
`.paseo/workflows/review.yml`:
|
`.paseo/workflows/review.yml`:
|
||||||
@@ -88,6 +102,8 @@ A named selection preserves the complete object, including structured options. N
|
|||||||
name: review
|
name: review
|
||||||
on: manual.run
|
on: manual.run
|
||||||
max_runtime: 2h
|
max_runtime: 2h
|
||||||
|
filters:
|
||||||
|
from_users: [automation]
|
||||||
inputs:
|
inputs:
|
||||||
repo:
|
repo:
|
||||||
type: string
|
type: string
|
||||||
@@ -103,15 +119,15 @@ steps:
|
|||||||
- text: ${{ paseo.prompt }}
|
- text: ${{ paseo.prompt }}
|
||||||
```
|
```
|
||||||
|
|
||||||
| Field | Required | Notes |
|
| Field | Required | Notes |
|
||||||
| ------------- | ------------------ | --------------------------------------------------------- |
|
| ------------- | -------- | --------------------------------------------------------- |
|
||||||
| `name` | yes | Workflow name, unique across the bundle. |
|
| `name` | yes | Workflow name, unique across the bundle. |
|
||||||
| `on` | yes | Provider event such as `manual.run` or `discord.mention`. |
|
| `on` | yes | Provider event such as `manual.run` or `discord.mention`. |
|
||||||
| `max_runtime` | yes | Hard limit for the complete run, up to 24h. |
|
| `max_runtime` | yes | Hard limit for the complete run, up to 24h. |
|
||||||
| `filters` | provider-dependent | Provider resource and sender allowlists. |
|
| `filters` | yes | Provider resource filters and the sender allowlist. |
|
||||||
| `inputs` | no | Typed invocation headers. |
|
| `inputs` | no | Typed invocation headers. |
|
||||||
| `values` | no | Named expressions. |
|
| `values` | no | Named expressions. |
|
||||||
| `steps` | yes | One or more ordered inline steps. |
|
| `steps` | yes | One or more ordered inline steps. |
|
||||||
|
|
||||||
### Inputs and values
|
### Inputs and values
|
||||||
|
|
||||||
@@ -176,7 +192,7 @@ prompt:
|
|||||||
|
|
||||||
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.
|
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 authority
|
### Output capabilities
|
||||||
|
|
||||||
Authority stays on the step that uses it:
|
Authority stays on the step that uses it:
|
||||||
|
|
||||||
@@ -189,6 +205,8 @@ allow_outputs:
|
|||||||
|
|
||||||
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).
|
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).
|
||||||
|
|
||||||
|
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
|
## 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.
|
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.
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ A project configuration is one versioned bundle:
|
|||||||
|
|
||||||
`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.
|
`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.
|
||||||
|
|
||||||
|
[single-repo-team-bot](https://github.com/getpaseo/hub/tree/main/examples/single-repo-team-bot) is a complete bundle in this shape: Discord, Slack, and GitHub workflows running a classifier and a worker on shared partials. Copy `.paseo/` into your repository and replace the placeholders its README lists.
|
||||||
|
|
||||||
## Sources
|
## Sources
|
||||||
|
|
||||||
A configuration comes from one source:
|
A configuration comes from one source:
|
||||||
|
|||||||
@@ -46,18 +46,21 @@ The agent can use `git` and `gh` within the declared repositories and permission
|
|||||||
| `connection` | Project GitHub connection slug. |
|
| `connection` | Project GitHub connection slug. |
|
||||||
| `repositories` | Repositories the token can reach. On a GitHub-triggered run, this defaults to the triggering repository. Required for other providers. |
|
| `repositories` | Repositories the token can reach. On a GitHub-triggered run, this defaults to the triggering repository. Required for other providers. |
|
||||||
| `permissions` | Installation-token permissions such as `contents`, `pull_requests`, and `issues`. Defaults to `contents: read`. |
|
| `permissions` | Installation-token permissions such as `contents`, `pull_requests`, and `issues`. Defaults to `contents: read`. |
|
||||||
| `duration` | Token lifetime. Defaults to `1h`, GitHub's maximum. |
|
| `duration` | Positive token lifetime up to `1h`. Defaults to `1h`, GitHub's maximum. |
|
||||||
|
|
||||||
Requested authority cannot exceed the GitHub App installation. Activation and dispatch fail clearly when the connection, repository, or permissions cannot be resolved.
|
Requested authority cannot exceed the GitHub App installation. Activation and dispatch fail clearly when the connection, repository, or permissions cannot be resolved.
|
||||||
|
|
||||||
## Agent environment
|
## Agent environment
|
||||||
|
|
||||||
Hub supplies `GH_TOKEN` and git configuration through environment variables:
|
Hub supplies `GH_TOKEN` and process-scoped git configuration through environment variables:
|
||||||
|
|
||||||
- Commits use the App bot identity.
|
- Commits use the App bot login as `user.name` and `<app-id>+<bot-login>@users.noreply.github.com` as `user.email`.
|
||||||
- `git@github.com` remotes are rewritten to HTTPS.
|
- `git@github.com:` and `ssh://git@github.com/` remotes are rewritten to HTTPS.
|
||||||
- Global and system git configuration are ignored.
|
- `gh auth git-credential` handles GitHub credentials for the step.
|
||||||
- The daemon host's git credentials are not used or changed.
|
- User-global and system git configuration are ignored, and terminal credential prompts are disabled.
|
||||||
|
- The daemon host's git identity and credentials are not read or changed.
|
||||||
|
|
||||||
|
`GH_TOKEN` and Hub's git configuration variables are reserved when a step has a `github` block; workflow `env` cannot replace them.
|
||||||
|
|
||||||
## Keep authority on the worker
|
## Keep authority on the worker
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Hosted Hub
|
title: Hosted Hub
|
||||||
description: The managed Paseo Hub, not available yet.
|
description: Sign in to the managed Paseo Hub or self-host the same service.
|
||||||
nav: Hosted
|
nav: Hosted
|
||||||
order: 73
|
order: 73
|
||||||
category: Hub
|
category: Hub
|
||||||
@@ -8,6 +8,6 @@ category: Hub
|
|||||||
|
|
||||||
# Hosted Hub
|
# Hosted Hub
|
||||||
|
|
||||||
Not available yet. For now, see [self-hosting](/docs/hub/self-hosting).
|
[Paseo Hub](https://hub.paseo.sh) is the managed service. Existing accounts can sign in; new account registration is currently closed.
|
||||||
|
|
||||||
When it ships, Paseo owns the GitHub App, Slack app, and Discord application, so connecting a provider is one click rather than a console walkthrough. Projects, configuration, triggers, daemons, and activity work the same way on both.
|
Paseo owns the hosted GitHub App, Slack app, and Discord application. Projects, configuration, triggers, daemons, and activity work the same way when you [self-host](/docs/hub/self-hosting).
|
||||||
|
|||||||
@@ -8,20 +8,21 @@ category: Hub
|
|||||||
|
|
||||||
# Hub quickstart
|
# Hub quickstart
|
||||||
|
|
||||||
## 1. Connect GitHub and a daemon
|
## 1. Create a project
|
||||||
|
|
||||||
Open **Connections** in Hub and connect the GitHub account or organization whose repositories you use. On the machine that will run agents:
|
Open **Connections** in Hub and connect the GitHub account or organization whose repositories you use. Then open **Projects → New project** and create a project.
|
||||||
|
|
||||||
|
## 2. Log in and connect a daemon
|
||||||
|
|
||||||
|
On the machine that will run agents:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
paseo hub login https://your-hub.example.com
|
paseo hub login https://your-hub.example.com
|
||||||
|
paseo hub projects
|
||||||
paseo hub connect
|
paseo hub connect
|
||||||
```
|
```
|
||||||
|
|
||||||
Approve the browser login. See [Daemons](/docs/hub/daemons) for the separation between your CLI login and the daemon relationship.
|
Approve the browser login. `projects` shows the slug needed by `deploy`. See [Daemons](/docs/hub/daemons) for the separation between your CLI login and the daemon relationship.
|
||||||
|
|
||||||
## 2. Create a project
|
|
||||||
|
|
||||||
Open **Projects → New project**. In **Configuration**, choose the repository that will hold the configuration and select **Use for configuration**.
|
|
||||||
|
|
||||||
## 3. Add the bundle
|
## 3. Add the bundle
|
||||||
|
|
||||||
@@ -79,9 +80,7 @@ Workflow files are discovered as direct `.yml` children of `.paseo/workflows/`.
|
|||||||
|
|
||||||
## 4. Validate and deploy
|
## 4. Validate and deploy
|
||||||
|
|
||||||
Push the files to the configuration repository's default branch. Hub fetches the complete bundle at that commit, validates it, and activates a revision. A failed sync leaves the previous revision active.
|
From the project root:
|
||||||
|
|
||||||
You can validate or deploy the same local bundle from its project root:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
paseo hub deploy -p your-project --dry-run
|
paseo hub deploy -p your-project --dry-run
|
||||||
@@ -101,3 +100,15 @@ Comment from the account in `from_users`:
|
|||||||
Open the project's **Activity** tab to see routing and execution. If nothing runs, use the [Activity checklist](/docs/hub/activity).
|
Open the project's **Activity** tab to see routing and execution. If nothing runs, use the [Activity checklist](/docs/hub/activity).
|
||||||
|
|
||||||
Before widening the allowlist or granting write authority, read [Hub security](/docs/hub/security).
|
Before widening the allowlist or granting write authority, read [Hub security](/docs/hub/security).
|
||||||
|
|
||||||
|
When you no longer need the local CLI login:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
paseo hub logout
|
||||||
|
```
|
||||||
|
|
||||||
|
Logging out does not disconnect the daemon. When the daemon is connected to the same Hub as the active CLI login, use `paseo hub logout --disconnect-daemon` to remove both relationships.
|
||||||
|
|
||||||
|
## Next
|
||||||
|
|
||||||
|
[single-repo-team-bot](https://github.com/getpaseo/hub/tree/main/examples/single-repo-team-bot) is a complete bundle covering all three providers, with a classifier, a worker, and shared prompt partials.
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ Go to **Settings → Developer settings → GitHub Apps → New GitHub App** on
|
|||||||
|
|
||||||
Replace `hub.example.com` with your `PASEO_HUB_APP_URL`.
|
Replace `hub.example.com` with your `PASEO_HUB_APP_URL`.
|
||||||
|
|
||||||
|
The webhook URL must be reachable from GitHub. Keep GitHub's default SSL verification enabled; see [Provider URLs](/docs/hub/self-hosting#provider-urls).
|
||||||
|
|
||||||
| Setting | Value |
|
| Setting | Value |
|
||||||
| ------------------ | ---------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------- |
|
||||||
| Homepage URL | `https://hub.example.com` |
|
| Homepage URL | `https://hub.example.com` |
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ Migrations run automatically at startup. Hub does not start listening when a mig
|
|||||||
|
|
||||||
Hub has one public URL and one persistent application secret:
|
Hub has one public URL and one persistent application secret:
|
||||||
|
|
||||||
| Variable | Purpose |
|
| Variable | Purpose |
|
||||||
| ----------------------- | ------------------------------------------------------------------ |
|
| ----------------------- | ---------------------------------------------------------------------------- |
|
||||||
| `PASEO_HUB_APP_URL` | Public origin used by the dashboard, authentication, and callbacks |
|
| `PASEO_HUB_APP_URL` | Public origin used by the dashboard, authentication, callbacks, and webhooks |
|
||||||
| `PASEO_HUB_AUTH_SECRET` | Protects browser sessions and derives execution credentials |
|
| `PASEO_HUB_AUTH_SECRET` | Protects browser sessions and derives execution credentials |
|
||||||
| `DATABASE_URL` | PostgreSQL connection string |
|
| `DATABASE_URL` | PostgreSQL connection string |
|
||||||
|
|
||||||
Generate `PASEO_HUB_AUTH_SECRET` once and keep it across restarts:
|
Generate `PASEO_HUB_AUTH_SECRET` once and keep it across restarts:
|
||||||
|
|
||||||
@@ -89,7 +89,26 @@ docker compose up -d
|
|||||||
|
|
||||||
The stack publishes Hub on port `3000` and stores PostgreSQL data in a named volume. The Hub image is `ghcr.io/getpaseo/hub:latest`.
|
The stack publishes Hub on port `3000` and stores PostgreSQL data in a named volume. The Hub image is `ghcr.io/getpaseo/hub:latest`.
|
||||||
|
|
||||||
When a reverse proxy terminates HTTPS, set `PASEO_HUB_TRUSTED_CLIENT_IP_HEADER` to the header carrying the original client IP.
|
### HTTPS with Caddy
|
||||||
|
|
||||||
|
Compose serves plain HTTP on port `3000`. Run Caddy on the same host to terminate TLS:
|
||||||
|
|
||||||
|
```caddyfile
|
||||||
|
hub.example.com {
|
||||||
|
reverse_proxy 127.0.0.1:3000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Point `hub.example.com` at the host and open ports 80 and 443. Caddy [obtains and renews the certificate](https://caddyserver.com/docs/automatic-https).
|
||||||
|
|
||||||
|
Then set in `.env`:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
PASEO_HUB_APP_URL=https://hub.example.com
|
||||||
|
PASEO_HUB_TRUSTED_CLIENT_IP_HEADER=x-forwarded-for
|
||||||
|
```
|
||||||
|
|
||||||
|
To keep port `3000` off the public interface, change the `hub` port in `compose.yml` to `"127.0.0.1:3000:3000"`.
|
||||||
|
|
||||||
## Fly
|
## Fly
|
||||||
|
|
||||||
@@ -122,6 +141,23 @@ fly deploy -a your-hub \
|
|||||||
|
|
||||||
Keep one machine running. Hub holds the Discord gateway connection and dispatches events to daemons, so a stopped machine misses events.
|
Keep one machine running. Hub holds the Discord gateway connection and dispatches events to daemons, so a stopped machine misses events.
|
||||||
|
|
||||||
|
## Provider URLs
|
||||||
|
|
||||||
|
Slack and GitHub call Hub at `PASEO_HUB_APP_URL`:
|
||||||
|
|
||||||
|
| Provider setting | URL |
|
||||||
|
| ---------------------------- | ------------------------------------------------------ |
|
||||||
|
| GitHub webhook | `<PASEO_HUB_APP_URL>/webhook` |
|
||||||
|
| GitHub OAuth callback | `<PASEO_HUB_APP_URL>/api/integrations/github/callback` |
|
||||||
|
| Slack Events API request URL | `<PASEO_HUB_APP_URL>/api/integrations/slack/events` |
|
||||||
|
| Slack OAuth callback | `<PASEO_HUB_APP_URL>/api/integrations/slack/callback` |
|
||||||
|
|
||||||
|
Slack requires the Events API request URL to be publicly reachable over HTTPS with a valid certificate, and its [OAuth redirect URL](https://docs.slack.dev/authentication/installing-with-oauth/) must use HTTPS. See Slack's [HTTP request URL](https://docs.slack.dev/apis/events-api/using-http-request-urls/) requirements.
|
||||||
|
|
||||||
|
GitHub must reach the webhook URL and [verifies SSL certificates](https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks#use-https-and-ssl-verification) by default.
|
||||||
|
|
||||||
|
A Hub on `localhost` or a LAN address still runs manual and daemon workflows, but Slack and GitHub cannot reach it. To test provider setup locally, point `PASEO_HUB_APP_URL` at an HTTPS tunnel before starting Hub. A changed tunnel origin requires updated provider settings and a Hub restart.
|
||||||
|
|
||||||
## Upgrades
|
## Upgrades
|
||||||
|
|
||||||
Pull the new image or source and deploy it. Migrations are forward-only. Back up PostgreSQL first; it contains configuration revisions, connections, and execution history.
|
Pull the new image or source and deploy it. Migrations are forward-only. Back up PostgreSQL first; it contains configuration revisions, connections, and execution history.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ category: Hub
|
|||||||
|
|
||||||
# Slack for Hub
|
# Slack for Hub
|
||||||
|
|
||||||
Hub receives Slack mentions over the Events API. Socket Mode is not used, so your Hub must be reachable from Slack.
|
Hub receives Slack mentions over the Events API. Socket Mode is not used, so your Hub needs a publicly reachable HTTPS origin with a valid certificate. See [Provider URLs](/docs/hub/self-hosting#provider-urls).
|
||||||
|
|
||||||
## Create the app
|
## Create the app
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ steps:
|
|||||||
- { type: discord.reply, max: 1, required: true }
|
- { type: discord.reply, max: 1, required: true }
|
||||||
```
|
```
|
||||||
|
|
||||||
Turn on Discord Developer Mode to copy IDs. `from_users` matches the author; `guild` and `channels` constrain where the mention arrived. All filters must pass.
|
Turn on Discord Developer Mode to copy IDs. `from_users` matches the author; `guild` and `channels` constrain where the mention arrived. `pattern` is a required prefix after the mention; `contains` is its legacy alias and has the same prefix behavior. All filters must pass.
|
||||||
|
|
||||||
The reply posts in the triggering thread or channel. `discord.reply` grants `hub.reply`, but does not rewrite the prompt. A Discord trigger grants no GitHub credential; add a [`github` block](/docs/hub/github) to the step that needs one.
|
The reply posts in the triggering thread or channel. `discord.reply` grants `hub.reply`, but does not rewrite the prompt. A Discord trigger grants no GitHub credential; add a [`github` block](/docs/hub/github) to the step that needs one.
|
||||||
|
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ An allowlist is one layer of defense. It does not make a permitted account trust
|
|||||||
| `workspace` | Slack | Team id, `T01234567` |
|
| `workspace` | Slack | Team id, `T01234567` |
|
||||||
| `guild` | Discord | Guild id |
|
| `guild` | Discord | Guild id |
|
||||||
| `channels` | Slack, Discord | Channel ids |
|
| `channels` | Slack, Discord | Channel ids |
|
||||||
| `contains` | all | Substring of the message text |
|
| `contains` | all | GitHub substring; Slack and Discord invocation prefix |
|
||||||
| `pattern` | all | Prefix of the message text |
|
| `pattern` | all | Invocation prefix |
|
||||||
| `connection` | all | A connection slug, when the organization has several |
|
| `connection` | all | A connection slug, when the organization has several |
|
||||||
|
|
||||||
All conditions must pass. There is no `any` mode.
|
All conditions must pass. There is no `any` mode.
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ steps:
|
|||||||
- { type: slack.reply, max: 1, required: true }
|
- { type: slack.reply, max: 1, required: true }
|
||||||
```
|
```
|
||||||
|
|
||||||
Slack filters use IDs, not display names. `from_users` matches the author, `workspace` the team, and `channels` the channel. `pattern` checks the beginning of text after the mention; `contains` checks a substring. All filters must pass.
|
Slack filters use IDs, not display names. `from_users` matches the author, `workspace` the team, and `channels` the channel. `pattern` is a required prefix after the mention; `contains` is its legacy alias and has the same prefix behavior. All filters must pass.
|
||||||
|
|
||||||
The reply posts in the triggering thread. A root message gets a thread; a threaded message stays there. `slack.reply` grants `hub.reply`, but does not add reply instructions to the prompt.
|
The reply posts in the triggering thread. A root message gets a thread; a threaded message stays there. `slack.reply` grants `hub.reply`, but does not add reply instructions to the prompt.
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: Hub workflows
|
title: Hub workflows
|
||||||
description: Build ordered Hub workflows with prompts, routing, outputs, and provider authority.
|
description: Build ordered Hub workflows with prompts, routing, outputs, and provider authority.
|
||||||
nav: Workflows
|
nav: Workflows
|
||||||
order: 65
|
order: 64
|
||||||
category: Hub
|
category: Hub
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -55,6 +55,8 @@ A finite input can select among complete named environments:
|
|||||||
name: route-repository
|
name: route-repository
|
||||||
on: manual.run
|
on: manual.run
|
||||||
max_runtime: 1h
|
max_runtime: 1h
|
||||||
|
filters:
|
||||||
|
from_users: [automation]
|
||||||
inputs:
|
inputs:
|
||||||
repo:
|
repo:
|
||||||
type: string
|
type: string
|
||||||
@@ -94,6 +96,8 @@ For dynamic routing, select complete named agents from a finite expression:
|
|||||||
name: route-agent
|
name: route-agent
|
||||||
on: manual.run
|
on: manual.run
|
||||||
max_runtime: 1h
|
max_runtime: 1h
|
||||||
|
filters:
|
||||||
|
from_users: [automation]
|
||||||
inputs:
|
inputs:
|
||||||
agent:
|
agent:
|
||||||
type: string
|
type: string
|
||||||
@@ -192,6 +196,8 @@ Steps run in file order. `if` may read inputs, values, and prior step output:
|
|||||||
name: conditional-review
|
name: conditional-review
|
||||||
on: manual.run
|
on: manual.run
|
||||||
max_runtime: 1h
|
max_runtime: 1h
|
||||||
|
filters:
|
||||||
|
from_users: [automation]
|
||||||
steps:
|
steps:
|
||||||
- id: inspect
|
- id: inspect
|
||||||
environment: paseo
|
environment: paseo
|
||||||
|
|||||||
Reference in New Issue
Block a user