Prepare Hub guided self-hosting docs for the next release (#3342)

* docs(hub): drop the manual auth secret from self-hosting setup

Hub generates its authentication secret on first start and stores it in the
database it is already using, so self-hosters no longer run openssl or carry
PASEO_HUB_AUTH_SECRET between restarts. The variable stays as an override for
deployments that must supply the secret from a platform secret store; Hub uses
it without persisting it, so removing it resumes the stored value.

Also corrects a claim that predates this change: rotating the secret does not
invalidate execution credentials already issued. Hub verifies those against
persisted hashes rather than the secret, so only browser sessions end.

Documentation companion to https://github.com/getpaseo/hub/pull/50.

* docs(hub): lead with the local guided setup

* docs(hub): document XDG data directory

* docs: make Hub self-hosting the quickstart
This commit is contained in:
Mohamed Boudra
2026-08-20 14:16:01 +02:00
committed by GitHub
parent c6b04f302a
commit 9163aed3f1
9 changed files with 290 additions and 315 deletions
+1 -1
View File
@@ -60,7 +60,7 @@ ${agents}
- [Changelog](${SITE_URL}/changelog): Release notes for the Paseo daemon, CLI, desktop, and mobile apps.
- [Download](${SITE_URL}/download): Install Paseo on Mac, Windows, Linux, iOS, Android, or run the web app.
- [Paseo Hub](${SITE_URL}/hub): Optional service above your daemons that adds GitHub, Slack, and Discord triggers. Self-hosted, private beta.
- [Paseo Hub](${SITE_URL}/hub): Self-hosted service above your daemons that adds GitHub, Slack, and Discord triggers. A hosted version is planned.
- [Blog](${SITE_URL}/blog): Updates and technical posts from the Paseo team.
- [Privacy](${SITE_URL}/privacy): Privacy policy.
- [GitHub](https://github.com/getpaseo/paseo): Source code, issues, and releases.
+58 -18
View File
@@ -17,7 +17,7 @@ export const Route = createFileRoute("/hub")({
head: () =>
pageMeta(
"Paseo Hub - GitHub, Slack, and Discord triggers",
"An optional service above your Paseo daemons. Mention a bot in a GitHub issue and an agent runs on your own machine and opens a PR. Self-hosted first, private beta.",
"Run Paseo Hub yourself and start agents on your own machines from GitHub, Slack, and Discord.",
"/hub",
),
component: Hub,
@@ -34,9 +34,10 @@ function Hub() {
<p className="text-lg text-white/70 leading-relaxed max-w-2xl">
An optional service that sits above your daemons and gives them extra capabilities.
</p>
<p className="text-white/40 text-sm mt-3">Private beta. Self-hosted first.</p>
<p className="text-white/40 text-sm mt-3">Self-host now. Hosted version coming later.</p>
<div className="space-y-20 mt-16">
<QuickStart />
<Triggers />
<Agents />
<Shape />
@@ -47,6 +48,37 @@ function Hub() {
);
}
function QuickStart() {
return (
<section className="space-y-6">
<h2 className="text-xl font-medium">Run it yourself</h2>
<p className="text-white/70 leading-relaxed max-w-2xl">
Start with an embedded database and finish setup in the browser. No Docker, PostgreSQL, or
environment variables required.
</p>
<pre className="w-fit max-w-full overflow-x-auto rounded-xl border border-white/10 bg-white/[0.03] px-5 py-4 font-mono text-sm text-white/90">
<code>npx @getpaseo/hub</code>
</pre>
<div className="flex flex-wrap items-center gap-4 pt-2">
<a
href="/docs/hub/quickstart"
className="rounded-md bg-white text-black px-4 py-2 text-sm font-medium hover:bg-white/90 transition-colors"
>
Read the quickstart
</a>
<a
href="https://github.com/getpaseo/hub"
target="_blank"
rel="noopener noreferrer"
className={LINK_CLASS}
>
View the source
</a>
</div>
</section>
);
}
const TRIGGER_SURFACES = [
{ name: "GitHub", icon: <GitHubIcon className="h-6 w-6" />, body: "Issues, PRs, and reviews." },
{ name: "Slack", icon: <SlackIcon className="h-6 w-6" />, body: "Channels and threads." },
@@ -266,7 +298,7 @@ function Shape() {
<div className="w-full max-w-xs rounded-xl border border-white/20 bg-white/[0.06] px-6 py-5 text-center">
<p className="font-medium">Hub</p>
<p className="text-xs text-muted-foreground mt-1">Self-hosted, one per team</p>
<p className="text-xs text-muted-foreground mt-1">Self-hosted or managed</p>
</div>
<Connector label="the same RPCs the app and CLI use" />
@@ -357,10 +389,11 @@ function MachineIcon() {
function Access() {
return (
<section className="space-y-6">
<h2 className="text-xl font-medium">Getting access</h2>
<h2 className="text-xl font-medium">Hosted Hub</h2>
<p className="text-white/70 leading-relaxed max-w-2xl">
Join the Paseo Discord and DM me. I&apos;m looking for design partners who are comfortable
self-hosting.
The hosted version is not generally available yet. Join the Paseo Discord and watch the
<span className="font-mono text-white/80"> #paseo-hub</span> channel for the release
announcement.
</p>
<div className="flex items-center gap-4 pt-2">
<a
@@ -396,20 +429,26 @@ function FaqSection() {
a team, and run multi-tenant. None of that belongs in a single machine daemon.
</p>
</FAQItem>
<FAQItem question="Why self-hosted first?">
The Hub can trigger executions on the daemons connected to it, so it has to be trusted. I
am not comfortable having people connect their daemons to my infrastructure until the
daemon has stronger authorization primitives and sandboxing. That work is on the roadmap,
and it applies to every Paseo user.
<FAQItem question="Can I run it myself?">
Yes. Run <code>npx @getpaseo/hub</code> and complete setup in the browser. The source is
available on{" "}
<a href="https://github.com/getpaseo/hub" className={LINK_CLASS}>
GitHub
</a>
, and the{" "}
<a href="/docs/hub/self-hosting" className={LINK_CLASS}>
self-hosting guide
</a>{" "}
covers more involved deployments.
</FAQItem>
<FAQItem question="What do I need to run it?">
A single Node.js application and a Postgres database. You also bring your own GitHub App,
Slack app, and Discord bot credentials, which is the tedious part.
Node.js and a running Paseo daemon. Hub uses an embedded database by default and guides
you through connecting the provider apps you want. PostgreSQL, Docker, and environment
variables are optional deployment choices.
</FAQItem>
<FAQItem question="Will there be a hosted version?">
Planned, once the daemon has stronger authorization primitives and sandboxing. I already
run a Hub for my own repos, and I can walk you through a trial on it if you want to skip
the self-hosted setup. No SLA.
Yes. Join the Paseo Discord and watch the <code>#paseo-hub</code> channel. The hosted
release will be announced there.
</FAQItem>
<FAQItem question="What else is planned?">
<p>Not built yet, listed so you know where this is going.</p>
@@ -432,7 +471,7 @@ function FaqSection() {
triggers, and it&apos;s why access to the beta stays small and trusted.
</FAQItem>
<FAQItem question="How do I get access?">
Join the{" "}
You can self-host today. For the hosted version, join the{" "}
<a
href={DISCORD_INVITE_URL}
target="_blank"
@@ -441,7 +480,8 @@ function FaqSection() {
>
Paseo Discord
</a>{" "}
and DM @moboudra for an invite to the private Hub channel.
and wait for the release announcement in <code>#paseo-hub</code>. You do not need to
message anyone directly.
</FAQItem>
</div>
</section>
+4 -2
View File
@@ -8,6 +8,8 @@ category: Hub
# Hosted Hub
[Paseo Hub](https://hub.paseo.sh) is the managed service. Existing accounts can sign in; new account registration is currently closed.
[Paseo Hub](https://hub.paseo.sh) is the managed service. It is not generally available yet: existing accounts can sign in, but new account registration is closed.
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).
To start now, [run Hub yourself](/docs/hub/self-hosting). Projects, configuration, triggers, daemons, and activity use the same model in both forms. The managed service owns its GitHub App, Slack app, and Discord application; a self-hosted Hub uses apps you create and control.
For the hosted release, [join the Paseo Discord](https://discord.gg/jz8T2uahpH) and watch the `#paseo-hub` channel. The release will be announced there; you do not need to message anyone directly.
+15 -14
View File
@@ -26,9 +26,9 @@ What that gives you today:
Your daemons keep running agents where they always did. Hub decides when to ask them to.
## What you write
## What lives in your repository
One project resource file names environments and complete agent configurations. Each discovered workflow file keeps one trigger beside its ordered steps:
`paseo hub init` creates a project resource file for environments and agents, plus a safe starter workflow:
```text
.paseo/
@@ -39,22 +39,23 @@ One project resource file names environments and complete agent configurations.
└── answer.md
```
Push the bundle, mention the bot, and an agent starts on your machine. [Quickstart](/docs/hub/quickstart) builds the first bundle; [Workflows](/docs/hub/workflows) covers routing and provider-specific replies.
Deploy the bundle, mention the bot, and an agent starts on your machine. [Quickstart](/docs/hub/quickstart) runs the guided setup; [Workflows](/docs/hub/workflows) covers routing and provider-specific replies.
## Reading order
1. [How it works](/docs/hub/concepts)
2. [Daemons](/docs/hub/daemons)
3. [Triggers](/docs/hub/triggers)
4. [Workflows](/docs/hub/workflows)
5. [GitHub access](/docs/hub/github)
6. [Configuration](/docs/hub/configuration)
7. [Security](/docs/hub/security)
[Quickstart](/docs/hub/quickstart) goes end to end if you would rather start by doing.
1. [Quickstart](/docs/hub/quickstart)
2. [How it works](/docs/hub/concepts)
3. [Daemons](/docs/hub/daemons)
4. [Triggers](/docs/hub/triggers)
5. [Workflows](/docs/hub/workflows)
6. [GitHub access](/docs/hub/github)
7. [Configuration](/docs/hub/configuration)
8. [Security](/docs/hub/security)
If a workflow accepts requests from GitHub, Slack, Discord, or the API, read [Hub security](/docs/hub/security) before giving an agent access to a working directory or output capability.
## Where it runs
## Run Hub yourself
Everything on this page and the pages it links to works the same way on [hosted Hub](/docs/hub/hosted) and on a Hub you run yourself under [self-hosting](/docs/hub/self-hosting).
Start on your machine with the embedded database, then add PostgreSQL or a public deployment only when you need them. [Self-hosting](/docs/hub/self-hosting) covers each step.
[Hosted Hub](/docs/hub/hosted) uses the same projects, workflows, daemons, and activity model. New account registration is currently closed.
+32 -80
View File
@@ -1,6 +1,6 @@
---
title: Hub quickstart
description: Connect Hub, create a project, and run a workflow from a GitHub comment.
description: Run Hub locally and answer a Slack mention with an agent on your machine.
nav: Quickstart
order: 61
category: Hub
@@ -8,107 +8,59 @@ category: Hub
# Hub quickstart
## 1. Create a project
Run Hub locally, connect it to Slack without a public server, and answer a mention with an agent on your machine.
Open **Connections** in Hub and connect the GitHub account or organization whose repositories you use. Then open **Projects → New project** and create a project.
You need [Paseo installed and running](/docs), Node.js, and a Slack workspace where you can create an app.
## 2. Log in and connect a daemon
On the machine that will run agents:
## 1. Start Hub
```sh
paseo hub login https://your-hub.example.com
paseo hub projects
paseo hub connect
npx @getpaseo/hub
```
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.
Open <http://localhost:3000>. Hub uses an embedded database by default, so this first run needs no database, environment variables, or Docker.
## 3. Add the bundle
Create the operator account when Hub welcomes you.
Create these files:
## 2. Connect Slack
The next screen explains how to create the Slack app and gives you a manifest to paste into Slack. Keep **Socket Mode** selected. It connects out from Hub and does not need a public address or HTTPS.
Paste the App-level token and Bot token back into Hub, then choose **Connect Slack**. Invite the bot to the channel where you will use it:
```text
.paseo/
├── hub.yml
└── workflows/
└── github-help.yml
/invite @Paseo
```
`.paseo/hub.yml` names project-wide resources:
You can skip GitHub and Discord for now. Their setup remains available under **Apps**.
```yaml
environments:
dev:
kind: daemon
daemon: my-daemon
cwd: /Users/you/code/your-repo
agents:
codex:
provider: codex
mode: full-access
```
## 3. Initialize the project
`.paseo/workflows/github-help.yml` contains one trigger and its ordered steps:
```yaml
name: github-help
on: github.issue_comment
max_runtime: 2h
filters:
repo: yourname/your-repo
contains: "@paseo"
from_users: [your-github-login]
steps:
- id: work
environment: dev
max_runtime: 90m
idle_timeout: 10m
agent: codex
prompt:
- text: |
Complete this request and call hub.finish_execution when done.
<user-prompt>
${{ paseo.prompt }}
</user-prompt>
```
`daemon` is the daemon slug shown by Hub. `cwd` is a directory on that machine. `${{ paseo.prompt }}` is the normalized request text after the provider marker and declared input headers are removed.
Workflow files are discovered as direct `.yml` children of `.paseo/workflows/`. You do not list them in `hub.yml`.
## 4. Validate and deploy
From the project root:
From the repository where the agent should work:
```sh
paseo hub deploy -p your-project --dry-run
paseo hub deploy -p your-project
paseo hub init
```
Dry-run performs the same discovery and server-side validation without recording or activating a revision. See [Configuration](/docs/hub/configuration) for credentials, diagnostics, and GitHub sync.
Choose **Custom endpoint…** and enter `http://localhost:3000`, then choose Slack. The guided setup:
## 5. Trigger it
- signs you in through the browser;
- connects the local Paseo daemon;
- uses the default project created during first-run setup;
- selects the connected Slack workspace and asks for your Slack username;
- writes `.paseo/hub.yml` and `.paseo/workflows/slack-help.yml`;
- validates the generated bundle and offers to deploy it.
Comment from the account in `from_users`:
Accept the default **Deploy now?** choice. The generated workflow accepts mentions only from the username you entered.
## 4. Mention the bot
Mention the bot in the channel:
```text
@paseo have a look at this
@Paseo explain what this project does
```
Open the project's **Activity** tab to see routing and execution. If nothing runs, use the [Activity checklist](/docs/hub/activity).
Hub starts the agent on your daemon and posts its reply in the Slack thread. Open the project's **Activity** tab if nothing runs.
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.
Hub keeps its local state in your user data directory (normally `~/.local/share/paseo-hub`). [Self-hosting](/docs/hub/self-hosting) covers PostgreSQL, public URLs, environment-managed apps, Docker, and cloud deployment. [Configuration](/docs/hub/configuration) explains the generated files and manual deployment.
+16 -32
View File
@@ -1,6 +1,6 @@
---
title: Discord for Hub
description: Create the Discord application your Hub uses, connect a guild, and write Discord triggers.
description: Create the Discord application your Hub uses and connect a server.
nav: Discord app
order: 77
category: Hub
@@ -8,42 +8,26 @@ category: Hub
# Discord for Hub
Hub connects to Discord over the gateway with a bot you own. Unlike GitHub and Slack, Discord does not post to your Hub. Hub holds an outbound connection, so it needs no public webhook beyond the OAuth callback.
Hub connects out to Discord through the gateway. Discord does not send event webhooks to Hub, so the bot does not need a public inbound endpoint.
## Create the application
Open **Apps → Discord**. Hub gives you the redirect URL and the exact steps to create the application, enable its bot, and copy the Application ID, Client Secret, and Bot token.
Go to the [Discord developer portal](https://discord.com/developers/applications) → **New Application**.
Under **Bot → Privileged Gateway Intents**, enable **Message Content Intent**. Without it, the bot receives empty messages and no trigger can match. Server Members Intent is not needed.
Under **Bot**:
Paste the credentials into Hub and choose **Verify and save**. Then choose **Add to a Discord server** and authorize the server. Start the authorization from Hub so the server is bound to the active Hub organization.
- Add a bot and copy its token.
- Enable **Message Content Intent**. Without it the bot receives empty messages and no trigger can match.
- Server Members Intent is not needed.
One Discord application and gateway connection serves every organization and server connected to this Hub. Keep the Hub process running; events that arrive while it is stopped are missed.
Under **OAuth2**, add the redirect URL:
Now write a [Discord trigger](/docs/hub/triggers/discord).
```text
https://hub.example.com/api/integrations/discord/callback
## Configure from environment
Deployments that keep app secrets outside Hub can set:
```dotenv
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
DISCORD_BOT_TOKEN=
```
Replace `hub.example.com` with your `PASEO_HUB_APP_URL`.
## Configure Hub
| Value | Environment variable |
| -------------- | ----------------------- |
| Application ID | `DISCORD_CLIENT_ID` |
| Client Secret | `DISCORD_CLIENT_SECRET` |
| Bot token | `DISCORD_BOT_TOKEN` |
Restart Hub. Discord shows as **Ready** in Connections.
## Connect
Open **Connections → Discord → Connect**, choose the server, and authorize. Hub builds the invite with the permissions the bot needs, so you do not construct an invite URL yourself.
The connection appears with a slug derived from the guild name.
Because Hub holds one gateway connection for the whole deployment, one bot serves every organization and guild you connect.
Now write a trigger: [Discord triggers](/docs/hub/triggers/discord).
`DISCORD_CLIENT_ID` is the Application ID shown under **General Information**. Environment configuration takes precedence over a saved Discord application and appears as **Managed by environment** under **Apps**.
+35 -54
View File
@@ -1,6 +1,6 @@
---
title: GitHub for Hub
description: Create the GitHub App your Hub uses, install it, and connect it to an organization.
description: Create the GitHub App your Hub uses for repository access and event triggers.
nav: GitHub App
order: 75
category: Hub
@@ -8,75 +8,56 @@ category: Hub
# GitHub for Hub
Hub talks to GitHub through a GitHub App you own. One App serves your whole Hub; each account or organization that installs it becomes a connection.
Hub talks to GitHub through a GitHub App you create and own. One App serves the Hub; each account or organization that installs it becomes a connection.
## Create the App
Open **Apps → GitHub**. Hub gives you the current callback URLs, required repository permissions, subscribed events, and the fields to copy back from GitHub. It verifies the App before saving it.
Go to **Settings → Developer settings → GitHub Apps → New GitHub App** on the account that should own it.
## Public URL requirements
Replace `hub.example.com` with your `PASEO_HUB_APP_URL`.
Repository access and installation work without a GitHub webhook. GitHub event triggers and configuration sync do not: GitHub must be able to deliver events to a public HTTPS 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).
On a local HTTP Hub, the Apps guide lets you configure repository access and explains that event setup is unavailable. Reopen Hub at its public address after setting `PASEO_HUB_APP_URL` to add the webhook secret and events.
| Setting | Value |
| ------------------ | ---------------------------------------------------------- |
| Homepage URL | `https://hub.example.com` |
| Callback URL | `https://hub.example.com/api/integrations/github/callback` |
| Setup URL | `https://hub.example.com/api/integrations/github/setup` |
| Redirect on update | on |
| Webhook URL | `https://hub.example.com/webhook` |
| Webhook secret | a value you generate |
GitHub uses these Hub URLs:
Repository permissions:
| Setting | Hub URL |
| ------------ | ------------------------------------------------------ |
| Homepage URL | `<PASEO_HUB_APP_URL>` |
| Callback URL | `<PASEO_HUB_APP_URL>/api/integrations/github/callback` |
| Setup URL | `<PASEO_HUB_APP_URL>/api/integrations/github/setup` |
| Webhook URL | `<PASEO_HUB_APP_URL>/webhook` |
| Permission | Access | Why |
| ------------- | ------------ | ----------------------------------------- |
| Contents | Read & write | Read the `.paseo` bundle, let agents push |
| Issues | Read & write | Read comments, add reactions |
| Pull requests | Read & write | Read review comments, let agents open PRs |
| Metadata | Read | Required by GitHub |
Keep GitHub's SSL verification enabled.
Subscribe to events:
## Connect repositories
- Issue comment
- Issues
- Pull request review
- Pull request review comment
- Push
After Hub verifies the App, choose **Install on GitHub**. Select the account or organization and repositories the App may access.
Push is what makes configuration sync work. Without it, Hub never learns that the `.paseo` bundle changed.
Start from Hub rather than GitHub's own install button. The round trip binds the installation to the active Hub organization.
## Configure Hub
The connection appears with a slug derived from the account. An installation on `getpaseo`, for example, becomes `getpaseo-github`. Connect as many installations as the Hub organization needs.
From the App's settings page, collect:
## What the connection provides
| Value | Environment variable |
| ------------------------- | -------------------------- |
| App ID | `GITHUB_APP_ID` |
| The slug in the App's URL | `GITHUB_APP_SLUG` |
| Client ID | `GITHUB_APP_CLIENT_ID` |
| A generated client secret | `GITHUB_APP_CLIENT_SECRET` |
| A generated private key | `GITHUB_APP_PRIVATE_KEY` |
| The webhook secret | `GITHUB_WEBHOOK_SECRET` |
- **Events:** issues, comments, reviews, and pushes from repositories the installation can see. See [GitHub triggers](/docs/hub/triggers/github).
- **Configuration sync:** a repository can hold the canonical `.paseo` bundle. See [Configuration](/docs/hub/configuration).
- **Execution credentials:** Hub mints scoped GitHub App tokens for workflow steps that explicitly request GitHub authority.
The private key downloads as a PEM file. Pass its contents in `GITHUB_APP_PRIVATE_KEY`, or its path in `GITHUB_APP_PRIVATE_KEY_PATH`.
An authenticated `gh` CLI on the daemon does not configure Hub's GitHub integration. It can still serve agents outside Hub's scoped GitHub authority, subject to the daemon and provider's own environment and permission policy.
Restart Hub. GitHub should now show as **Ready** in Connections.
## Configure from environment
## Connect
Deployments that keep app secrets outside Hub can set:
Open **Connections → GitHub → Connect**. Hub sends you to GitHub to install the App, then binds the installation to your organization.
```dotenv
GITHUB_APP_ID=
GITHUB_APP_SLUG=
GITHUB_APP_CLIENT_ID=
GITHUB_APP_CLIENT_SECRET=
GITHUB_APP_PRIVATE_KEY=
GITHUB_WEBHOOK_SECRET=
```
Start from Hub, not from GitHub's own install button. GitHub only calls the setup URL when an installation is created or changed, so installing directly can leave you on a settings page with nothing bound.
The private key is the contents of GitHub's downloaded PEM file. Use `GITHUB_APP_PRIVATE_KEY_PATH` instead when the deployment mounts that file.
The connection appears with a slug derived from the account: an installation on `getpaseo` becomes `getpaseo-github`. That slug is how configuration names this connection.
Connect as many installations as you need. A personal account and several organizations can coexist in one Hub organization.
## What the connection gives you
- **Events.** Comments, issues, and reviews from every repository the installation can see. See [GitHub triggers](/docs/hub/triggers/github).
- **Configuration sync.** Any repository in the installation can hold the canonical `.paseo` bundle. See [Configuration](/docs/hub/configuration).
- **Tokens.** Scoped, per-execution GitHub credentials.
Which repositories the installation covers is a GitHub setting. Change it on GitHub, not in Paseo.
Environment configuration takes precedence over a saved GitHub App and appears as **Managed by environment** under **Apps**. A complete environment configuration includes the webhook secret and therefore expects a public webhook origin.
+71 -66
View File
@@ -1,6 +1,6 @@
---
title: Self-hosting Hub
description: Deploy Paseo Hub with PostgreSQL and a public HTTPS origin, using Docker Compose or Fly.
description: Run Hub locally with its embedded database, or deploy it with PostgreSQL.
nav: Self-hosting
order: 74
category: Hub
@@ -8,45 +8,60 @@ category: Hub
# Self-hosting Hub
Hub is a Node service backed by PostgreSQL. Connecting external providers requires a public HTTPS URL for their callbacks and webhooks.
1. Deploy Hub with [Docker Compose](#docker-compose) or [Fly](#fly).
2. Create the [GitHub App](/docs/hub/self-hosting/github-app), [Slack app](/docs/hub/self-hosting/slack-app), and [Discord app](/docs/hub/self-hosting/discord-app) you want.
3. Follow the [quickstart](/docs/hub/quickstart).
Migrations run automatically at startup. Hub does not start listening when a migration fails.
## Configuration
Hub has one public URL and one persistent application secret:
| Variable | Purpose |
| ----------------------- | ---------------------------------------------------------------------------- |
| `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 |
| `DATABASE_URL` | PostgreSQL connection string |
Generate `PASEO_HUB_AUTH_SECRET` once and keep it across restarts:
The shortest path is one command:
```sh
openssl rand -hex 32
npx @getpaseo/hub
```
Changing it signs everyone out and invalidates completion credentials for executions that are still running.
Open <http://localhost:3000>. A fresh Hub creates its embedded database and authentication secret, then guides you through creating the operator account and the GitHub, Slack, or Discord apps you want.
Bootstrap the first owner with:
Follow the [quickstart](/docs/hub/quickstart) to connect Slack over Socket Mode and run the first workflow without a public server.
```dotenv
PASEO_BOOTSTRAP_ORGANIZATION=My organization
PASEO_BOOTSTRAP_OWNER_EMAIL=me@example.com
PASEO_BOOTSTRAP_OWNER_PASSWORD=replace-with-a-temporary-password
## Local data
Without `DATABASE_URL`, Hub stores an embedded PGlite database and its generated authentication secret under `$XDG_DATA_HOME/paseo-hub`. If `XDG_DATA_HOME` is not set to an absolute path, Hub uses `~/.local/share/paseo-hub`. Both survive restarts.
Set a different location explicitly with:
```sh
PASEO_HUB_DATA_DIR=/path/to/paseo-hub-data npx @getpaseo/hub
```
The password must be at least 12 characters. Sign in with it once, replace it in the dashboard, then remove `PASEO_BOOTSTRAP_OWNER_PASSWORD` from the deployment. Hub keeps the account and organization.
Embedded mode supports one Hub process per data directory. It is intended for a personal or single-process Hub. Back up the whole data directory before upgrading or moving it.
### Providers
## Public addresses
Set the group for each provider you intend to connect. A provider with missing credentials shows as **Setup needed** in Connections.
Hub defaults to `http://localhost:3000`. That is enough for its dashboard, daemons, Slack Socket Mode, and providers that connect out from Hub.
GitHub event triggers use webhooks and need a public HTTPS address. Repository access can still work without the webhook. Slack's optional Webhooks transport also needs public HTTPS; Socket Mode does not.
When Hub is available at a stable public origin, set it before starting:
```sh
PASEO_HUB_APP_URL=https://hub.example.com npx @getpaseo/hub
```
Changing the public origin requires updating callback and webhook settings in the provider apps. The **Apps** page generates the URLs for the origin Hub is currently using.
## PostgreSQL
Set `DATABASE_URL` to use PostgreSQL instead of the embedded database:
```sh
DATABASE_URL=postgres://paseo:password@localhost:5432/paseo_hub \
npx @getpaseo/hub
```
Use PostgreSQL for a durable server deployment, more than one Hub process, or an existing database backup and operations setup. Migrations run automatically at startup. Hub does not start listening when a migration fails.
The database also stores Hub's generated authentication secret. Set `PASEO_HUB_AUTH_SECRET` only when the deployment must supply that secret from a platform secret store. While the override is set, Hub uses it without replacing the stored secret. Changing the effective secret signs everyone out of the dashboard; execution credentials already issued remain valid until their execution ends.
## App configuration
The operator configures GitHub, Slack, and Discord under **Apps**. Hub verifies the credentials before saving them in its database and starts the same provider runtime used by environment-configured deployments.
Environment variables remain available for deployments that manage secrets outside Hub. A complete environment configuration takes precedence over a saved application and appears as **Managed by environment** in the dashboard.
```sh
# GitHub
@@ -57,7 +72,13 @@ GITHUB_APP_CLIENT_SECRET=
GITHUB_APP_PRIVATE_KEY= # or GITHUB_APP_PRIVATE_KEY_PATH
GITHUB_WEBHOOK_SECRET=
# Slack
# Slack Socket Mode
SLACK_TRANSPORT=socket
SLACK_APP_ID=
SLACK_APP_TOKEN=
# Slack Webhooks instead of Socket Mode
SLACK_TRANSPORT=webhook
SLACK_APP_ID=
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
@@ -69,7 +90,19 @@ DISCORD_CLIENT_SECRET=
DISCORD_BOT_TOKEN=
```
See [GitHub](/docs/hub/self-hosting/github-app), [Slack](/docs/hub/self-hosting/slack-app), and [Discord](/docs/hub/self-hosting/discord-app) for where each value comes from.
See [GitHub](/docs/hub/self-hosting/github-app), [Slack](/docs/hub/self-hosting/slack-app), and [Discord](/docs/hub/self-hosting/discord-app) for provider behavior and connection steps.
## Bootstrap from environment
Browser setup is the default for a fresh database. An unattended deployment can create the first operator from environment variables instead:
```dotenv
PASEO_BOOTSTRAP_ORGANIZATION=My organization
PASEO_BOOTSTRAP_OWNER_EMAIL=me@example.com
PASEO_BOOTSTRAP_OWNER_PASSWORD=replace-with-a-temporary-password
```
The password must be at least 12 characters. Sign in once, replace it in the dashboard, then remove `PASEO_BOOTSTRAP_OWNER_PASSWORD`. Hub keeps the account and organization.
## Docker Compose
@@ -79,14 +112,11 @@ The repository contains Hub and PostgreSQL as one Compose stack:
git clone https://github.com/getpaseo/hub.git
cd hub
cp .env.example .env
```
Set `PASEO_HUB_APP_URL`, `PASEO_HUB_AUTH_SECRET`, and the three bootstrap values in `.env`, then run:
```sh
docker compose up -d
```
Open <http://localhost:3000> and complete browser setup. For a public deployment, set `PASEO_HUB_APP_URL` and any reverse-proxy settings in `.env` before starting the stack.
The stack publishes Hub on port `3000` and stores PostgreSQL data in a named volume. The Hub image is `ghcr.io/getpaseo/hub:latest`.
### HTTPS with Caddy
@@ -122,42 +152,17 @@ fly postgres create --name your-hub-db
fly postgres attach your-hub-db -a your-hub
```
Set the application secret and bootstrap account, along with credentials for the providers you use:
```sh
fly secrets set -a your-hub \
PASEO_HUB_AUTH_SECRET="$(openssl rand -hex 32)" \
PASEO_BOOTSTRAP_ORGANIZATION="My organization" \
PASEO_BOOTSTRAP_OWNER_EMAIL=me@example.com \
PASEO_BOOTSTRAP_OWNER_PASSWORD=replace-with-a-temporary-password
```
Deploy the Dockerfile from the repository:
Deploy the Dockerfile and give Hub its public origin:
```sh
fly deploy -a your-hub \
-e PASEO_HUB_APP_URL=https://your-hub.fly.dev
```
Keep one machine running. Hub holds the Discord gateway connection and dispatches events to daemons, so a stopped machine misses events.
Open that address and complete browser setup, or set the [bootstrap environment](#bootstrap-from-environment) before deploying.
## 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.
Keep one machine running. Hub holds Slack Socket Mode and Discord gateway connections and dispatches events to daemons, so a stopped machine misses events.
## 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 the embedded data directory or PostgreSQL database first; it contains accounts, app credentials, configuration revisions, connections, and execution history.
+58 -48
View File
@@ -1,6 +1,6 @@
---
title: Slack for Hub
description: Create the Slack app your Hub uses, connect a workspace, and write Slack triggers.
description: Connect Slack over Socket Mode, or use webhooks from a public Hub.
nav: Slack app
order: 76
category: Hub
@@ -8,62 +8,72 @@ category: Hub
# Slack for Hub
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).
Slack can reach Hub in two ways:
## Create the app
| Transport | Public HTTPS required | Best for |
| ----------- | --------------------- | --------------------------------------- |
| Socket Mode | No | Local, personal, and single-process Hub |
| Webhooks | Yes | Public server deployments |
Go to [api.slack.com/apps](https://api.slack.com/apps) → **Create New App → From a manifest**, and paste this after replacing `hub.example.com` with your `PASEO_HUB_APP_URL`:
Socket Mode is the default in browser setup. Both transports produce the same `slack.mention` triggers and thread replies.
```yaml
display_information:
name: Paseo
features:
bot_user:
display_name: Paseo
always_online: false
oauth_config:
redirect_urls:
- https://hub.example.com/api/integrations/slack/callback
scopes:
bot:
- app_mentions:read
- chat:write
- reactions:write
settings:
event_subscriptions:
request_url: https://hub.example.com/api/integrations/slack/events
bot_events:
- app_mention
interactivity:
is_enabled: false
org_deploy_enabled: false
socket_mode_enabled: false
token_rotation_enabled: false
```
## Set up Socket Mode
## Configure Hub
Open **Apps → Slack** in Hub and keep **Socket Mode** selected. Hub gives you the Slack manifest and the exact steps to:
From **Basic Information → App Credentials**, copy:
1. Create the Slack app from the manifest.
2. Generate an App-level token with `connections:write`.
3. Install the app and copy its Bot User OAuth Token.
| Value | Environment variable |
| -------------- | ---------------------- |
| App ID | `SLACK_APP_ID` |
| Client ID | `SLACK_CLIENT_ID` |
| Client Secret | `SLACK_CLIENT_SECRET` |
| Signing Secret | `SLACK_SIGNING_SECRET` |
Paste both tokens into Hub and choose **Connect Slack**. Hub verifies the installation, saves it for the active organization, and opens the outbound Socket Mode connection.
Restart Hub before Slack verifies the request URL. Hub needs the signing secret to answer the verification challenge.
## Connect
Open **Connections → Slack → Connect**, pick the workspace, and allow it.
Use Hub's button, not Slack's **Install to Workspace**. The install has to start from Hub so the workspace binds to your organization.
Then invite the bot to each channel it should watch:
Invite the bot to each channel it should watch:
```text
/invite @Paseo
```
Now write a trigger: [Slack triggers](/docs/hub/triggers/slack).
Now write a [Slack trigger](/docs/hub/triggers/slack).
Socket Mode holds one live connection in the Hub process. Run one Hub process for this transport and keep it running; events that arrive while it is stopped are missed.
## Use webhooks
Choose **Webhooks** when Slack should send events to a stable public Hub. Hub must be open at its public HTTPS address before setup so the generated redirect and request URLs are correct.
The Apps guide gives you a webhook manifest and asks for the App ID, Client ID, Client Secret, and Signing Secret. Saving continues to Slack so you can install the app into a workspace.
Slack calls:
| Provider setting | Hub URL |
| ---------------- | ----------------------------------------------------- |
| Redirect URL | `<PASEO_HUB_APP_URL>/api/integrations/slack/callback` |
| Request URL | `<PASEO_HUB_APP_URL>/api/integrations/slack/events` |
Start the installation from Hub. An installation started only from Slack is not bound to a Hub organization.
## Configure from environment
Deployments that keep app secrets outside Hub can use one complete transport configuration.
Socket Mode:
```dotenv
SLACK_TRANSPORT=socket
SLACK_APP_ID=A01234567
SLACK_APP_TOKEN=xapp-...
```
The Bot User OAuth Token remains attached to each saved Slack workspace connection; it is not part of the Socket Mode environment configuration.
Webhooks:
```dotenv
SLACK_TRANSPORT=webhook
SLACK_APP_ID=A01234567
SLACK_CLIENT_ID=...
SLACK_CLIENT_SECRET=...
SLACK_SIGNING_SECRET=...
```
Environment configuration takes precedence over a saved Slack app and appears as **Managed by environment** under **Apps**.