VibeHost
Guides

Grants and visibility

How VibeHost decides who can see and act on an app. All gates AND-compose.

To do anything on an app, every active gate must pass. Hard Rule #8: gates AND-compose, never short-circuit. Adding a new gate is always ANDed in.

The four gates

        ┌─────────────┐    ┌──────────┐    ┌──────────────┐    ┌──────────────┐
        │  Visibility │ ∧  │  Grants  │ ∧  │   Password   │ ∧  │  Share link  │
        │ public/ws/  │    │ team or  │    │  (if set)    │    │  (if used)   │
        │  private    │    │ email    │    │              │    │              │
        └─────────────┘    └──────────┘    └──────────────┘    └──────────────┘
              │                 │                 │                  │
              └──────────── all four AND ─────────┴──────────────────┘


                            access granted

A viewer must satisfy all active gates. Disabling a gate (e.g. password clear) doesn't bypass the others — it just removes one term from the AND.

Visibility

Set per-app, decides who can hit the app at all:

VisibilityWho can request
publicAnyone on the internet (no auth required)
workspaceAny workspace member
privateOnly users with an explicit grant
vibehost app visibility public --app my-site
vibehost app visibility workspace --app my-site
vibehost app visibility private --app my-site

Visibility alone doesn't grant action permissions (deploy, settings) — those still need a grant.

Grants

Two grant tables: team-based and email-based. Both have the same role enum:

RoleCan do
viewerView deployments, see logs
deployerAbove + push new deploys, promote, rollback
adminAbove + manage grants, settings, custom domains

Grants are additive. If both your team and your email have grants, the effective role is the max (admin > deployer > viewer).

# Team grants (everyone in the team picks up the role)
vibehost app grants add-team web deployer --app my-site
vibehost app grants remove-team web --app my-site

# Email grants (one person, no team needed)
vibehost app grants add-email contractor@x.com viewer --app my-site
vibehost app grants remove-email contractor@x.com --app my-site

# List both axes
vibehost app grants ls --app my-site

# Grant yourself (for testing)
vibehost app grants self admin --app my-site

Email grants work before the invitee signs up. The grant row sits in app_email_grants with acceptedUserId = null; on first login with a matching email, the system resolves the user.

Password gate

Optional second factor on top of visibility + grants:

vibehost app password set <password> --app my-site
vibehost app password clear --app my-site
vibehost app password status --app my-site

Once set, anyone hitting the public URL sees a password prompt. After correct entry, a signed cookie remembers them for the session.

Use case: soft launches. "Public visibility, but only people I share the password with can see it."

Generate single-use cookie-issuing URLs:

vibehost app share-link create --app my-site
vibehost app share-link ls --app my-site

Each share link is a one-time URL like https://my-site.vibehost.space/_share/<token>. Visiting it sets a cookie tied to that share link; the cookie satisfies the share-link gate for that browser.

Use case: client previews. "Send this link to my client; revoke it next month."

How a request gets evaluated

When a viewer hits my-site.vibehost.space/index.html:

  1. Visibility check. Public → continue. Workspace → must be workspace member. Private → must have a grant.
  2. Grant check (for action endpoints). Read action → need viewer+. Deploy → need deployer+. Settings → need admin.
  3. Password check. If passwordHash IS NOT NULL and no valid vh_app_pw_<id> cookie → 401 password prompt.
  4. Share-link check. If any share links are active and no valid vh_share_<id> cookie → 401 password prompt (same UX as #3).

All four must pass. The dispatcher (apps/dispatcher/worker.js) runs these in order; the first failure short-circuits the response.

What this means in practice

SetupWho can view
public, no password, no share linksAnyone
public, password setAnyone who knows the password
workspace, no passwordWorkspace members only
private, no extrasUsers with explicit grants only
private + password + share linkGrant-holders who also know the password OR clicked the share link

The model is intentionally additive — every gate you turn on tightens, never loosens.

On this page