---
title: Vibes and Pulses | Vibecodr Docs
description: Get a clear mental model for VXBE client runtimes, artifact-scoped playback, same-origin Pulse routes, and when each architecture is best.
canonical: https://vibecodr.space/docs/vibes-pulses
---

# Vibes and Pulses

This is the core architecture split for Vibecodr: editable source lives in the capsule, published Vibes handle interactive client runtime on VXBE hosts, and Pulses own trusted backend operations on same-origin /api routes.

Marker: Authoritative client-versus-edge execution model for Vibecodr.

## Implementation focus

Use this boundary first. It prevents accidental secret exposure and keeps user-facing surfaces fast and remixable.

## Expected outcomes

- Decide correctly between client runtime and server-side execution.
- Understand where capsules end, artifacts begin, and why public playback uses artifact-scoped launch contracts.
- Avoid coupling public UI behavior to trusted credentials.
- Scale safely by moving only trust-requiring logic into Pulses.

## Understanding Vibes & Pulses

A capsule can hold browser code, backend code, or both. Vibecodr keeps those jobs separate on purpose: the interface runs in the browser, trusted backend work runs on the edge, and the two talk over normal HTTP.

For the full browser-runtime contract, including WebAssembly, workers, import shape, and source-only projects, read [What Can Be a Vibe?](/docs/vibe-runtime).

- Vibe: browser-executable runtime artifact. It can include local assets, canvas/WebGL, and browser-safe WebAssembly, but no direct secrets or trusted database authority.

- Pulse: server-side endpoints from `src/server/` (or `server/`) files.

- Combo: both in one capsule (UI + endpoints), using one deployment slot.

Pulse deployment rule: all serverless compute that should run as backend code belongs in `src/server/` (preferred) or `server/`. Those files are deployed as Pulse endpoints and exposed as same-origin `/api/*` routes. In other words, `src/server/` is the folder you author in, but callers still hit `/api/*`, not `/server/*`.

## How Pulse State helps Pulses coordinate work

A Pulse is the backend function you write. Pulse State gives that function a small, platform-managed memory for operation keys, so repeated calls can agree on what is new, already running, completed, failed, or safe to retry.

### A Pulse runs your backend code

Use a Pulse for server-side routes, webhooks, schedules, provider calls, secrets, connected accounts, and other trusted backend behavior.

### Pulse State coordinates repeated calls

Use Pulse State when retries, duplicate deliveries, manual lifecycles, or guarded side effects need to share one stable operation key across calls.

### How `runOnce()` chooses the operation

`runOnce()` protects one trusted operation key inside one named Pulse State resource. The key, not the browser tab or a single invocation, defines “same work.” Choose a stable key from the thing being protected, such as a verified Stripe event id, scheduled window key, normalized runtime/social event identity, or an idempotency token from a form submission.

Same key means same coordinated operation

```typescript
const event = await env.webhooks.verify("stripe", {
  secret: "STRIPE_WEBHOOK_SECRET",
});
const key = `stripe:event:${event.id}`;

return env.state.webhookDedupe.runOnce(key, async () => {
  await env.fetch("https://api.example.com/fulfill", {
    method: "POST",
    auth: env.secrets.bearer("PROVIDER_API_KEY"),
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ eventId: event.id }),
  });

  return { accepted: true };
});
```

- Same Pulse, same state resource, same key: coordinated as the same operation.

- Same Pulse, same state resource, different key: a new operation.

- Different Pulse or different owner: separate coordination scope.

- Pulse State is focused on operation lifecycle. Use a real data surface or connected service for application records that need querying, editing, or long-term storage.

### Vibes

Client-side code

- Runs in the user's browser

- HTML, CSS, JavaScript, React, assets, canvas/WebGL, and browser-safe WASM

- Cannot access secrets or trusted databases directly; use a Pulse for that

- Sandboxed iframe for security

- Does not consume a deployment slot

Files: index.html, src/*.tsx, styles.css

### Pulses

Managed backend endpoints

- Publishes as a managed backend endpoint without manual deploy wiring

- Write TypeScript or JavaScript; Vibecodr packages the runtime path

- `env.pulse`, Pulse Secrets, policy fetch, and structured logs are built in

- Shows up on same-origin `/api/*` routes

- Uses 1 deployment slot (plan limits apply)

Files: src/server/*.ts (preferred), server/*.ts (also supported)

If you need advanced SQL compatibility, `env.db` is available inside pulse or combo handlers on eligible plans. Treat it as an advanced surface rather than the default Pulse backend model, and inspect that data from [Operating Center](/pulses?tab=database).

## Node.js compatibility in Pulses

Pulses are built to feel familiar if you already know modern JavaScript backend tooling. Many Node-style imports work, but they still run inside Vibecodr's managed backend environment with the usual safety boundaries around storage, secrets, and network access.

### Virtual filesystem (node:fs)

`node:fs` works through a temporary virtual filesystem. It is useful for scratch files and libraries that expect `fs`, but it is not long-term storage. Use a durable backend surface or connected service when the data needs to last.

### HTTP clients (node:http / node:https)

Node's `http` and `https` client APIs are available for compatibility, but most new code can use `fetch()`.

Using node:fs in a Pulse (temp files)

```typescript
import fs from "node:fs";

export default async function run() {
  // Virtual, ephemeral filesystem (not persistent storage).
  const file = `hello-${Date.now()}.txt`;
  fs.writeFileSync(file, "hello from a pulse");

  const text = fs.readFileSync(file, "utf8");
  return { file, readBack: text };
}
```

Note: this is for compatibility and temp workflows. Don't use it as an application database or long-term storage.

## When to Use Each

Use Case

Use

Why

Interactive game or demo

Vibe

Everything runs in browser, no server needed

WASM compiler, emulator, or simulation

Vibe

Compiled engine runs as browser compute from artifact assets

Call third-party APIs with keys

Pulse

Secrets must stay server-side

Store user data persistently

Pulse

Keep durable state and private integrations on the backend side

Send emails or webhooks

Pulse

Keep keys safe; talk to APIs or send webhooks

Static visualization

Vibe

No backend logic needed

Game with leaderboard

Combo

Vibe for game, Pulse for scores

Node CLI, Express server, or VS Code extension

Adapt

Needs adaptation; the browser player cannot run local/server processes as-is

## Runtime Isolation

Published vibes run in an isolated runtime frame, separate from the main Vibecodr app. That split keeps creator-authored code away from Vibecodr cookies and local storage.

### Published runtime

The player loads the published artifact in a dedicated runtime frame. Viewers use the player, embed, or vanity URL; they do not need the internal launch URL.

### Studio and Composer previews

Previews use the same isolation model where possible. If a preview cannot use the normal runtime host, Vibecodr falls back to a stricter browser sandbox.

Runtime isolation is a browser boundary, not a replacement for app-level authorization in Pulses.

## Runtime bridge (vibecodrBridge)

Vibes run inside a sandboxed iframe. The runtime bridge is the public browser API for readiness signals, safe logs, lightweight stats, and host-mediated capability requests.

Bridge usage

```typescript
async function boot() {
  const bridge = window.vibecodrBridge;

  bridge.ready({ capabilities: { popups: true } });
  bridge.log("info", "vibe ready");
  bridge.stats({ fps: 60 });

  const result = await bridge.runPulse("pls_abc123", { city: "SF" });
  console.log(result.status, result.body);

  const allowed = await bridge.requestCapability(
    ["clipboard-write"],
    "Copy result to clipboard",
    { type: "clipboard-write", text: "Hello" }
  );

  if (allowed) {
    bridge.log("info", "Clipboard write approved");
  }
}
```

- `ready({ capabilities })` reports readiness and optional capability intent.

- `log(level, message, extra)` and `error(err, extra)` send structured runtime logs.

- `stats(data)` reports performance signals (FPS, timings, counters).

- `listen(handlers)` subscribes to host messages and returns an unsubscribe function.

- `runPulse(pulseId, payload)` calls a pulse and resolves `{ status, body }`.

- `requestCapability(capabilities, reason, action)` asks for gated actions and resolves `true` or `false`.

## Runtime capability gating

Capabilities are host-mediated. Some map to iframe permissions (camera, mic, location); action-based capabilities use `requestCapability()`.

### Capability names

- camera

- microphone

- geolocation

- clipboard-write

- popups

- downloads

- payment (prompted)

- usb (never allowed)

### Action types

- popup

- download

- clipboard-write

Action requests include a payload (URL, filename, or clipboard text) and may be approved or denied by the viewer.

requestCapability example

```typescript
const allowed = await window.vibecodrBridge.requestCapability(
  ["downloads"],
  "Export report CSV",
  { type: "download", url: "/exports/report.csv", fileName: "report.csv" }
);

if (allowed) {
  console.log("Download approved");
}
```

## Vanity URLs (vxbe.space)

Vanity subdomains serve published vibes at `https://{slug}.vxbe.space`. Direct-serve is available for client-only runners (`client-static`, `webcontainer`).

- If your manifest entry is HTML-like (`.html`, `.htm`), the entry file is served directly.

- Otherwise, a runtime host loads the published artifact for the capsule.

- Runtime hosts on `vxbe.space` are execution-only. They should not rely on platform cookies or ambient first-party auth.

- Published vibes can still call ordinary public `https://` / `wss://` endpoints, but direct browser requests to Vibecodr infrastructure and sibling runtime hosts stay blocked.

- Responses cache briefly at the edge (~5 minutes) for performance.

- All plans can reserve vanity subdomains. Plan limits control how many you can hold, and only Creator and Pro can disable the hosted watermark.

Plan

Max Vanity Subdomains

Free

50

Creator

100

Pro

250

## Automation Trigger Kinds

Automations start from a moment that wakes a Pulse:

- `runtime_event` - emit events from a vibe or browser. Filter by event types, capsule IDs, and post IDs. Example types: `vibe.view`, `vibe.run`, `capsule.run`, `capsule.error`, `pulse.run.failed`, `social.comment.created`.

- `http_webhook` - receive inbound webhooks at `/t/:triggerId` (Creator+). For `pulse_script` actions, the webhook JSON arrives as `input` to your pulse. Verify first; body event ids are hints until the caller is trusted. Then use Pulse State for Run once per event.

- `cron` - run on a schedule using a standard cron expression (Creator+). Scheduled Pulses receive a stable scheduled window key.

- `manual` - click Run in the UI to fire immediately. Manual tests usually Run every time unless your Pulse opts into replay.

### Emit runtime events

Use Vibecodr's event and trigger controls to grant the vibe permission to emit events, then filter those events to the smallest set your automation needs. Product controls keep event grants scoped to the right public work instead of asking creators to hand-build platform requests.

Event types are lowercased and must match `[a-z0-9._-]` (max 64 chars). `internal.*` namespaces are rejected.

### Inbound webhook signature options

These automation-event receiver formats are separate from Pulse provider helpers: Pulse ships Stripe as the first certified helper, while other signed webhooks use `env.secrets.verifyHmac(...)` until fixture-backed helpers exist.

- shared: HMAC SHA-256 hex in `X-Vibecodr-Signature` (also accepts `x-signature-sha256` or `x-hub-signature-256`).

- github: validates `x-hub-signature-256` (or `x-hub-signature`).

- stripe: validates `stripe-signature` with `t=` and `v1=` parts (tolerance default 300s).

- none: no signature verification.

- Non-JSON bodies are accepted and wrapped as `{ raw:... }`.

## Automation Action Types

When a trigger fires, it can run one supported action:

- `webhook` - HTTP POST to a URL you control. Optional headers and shared secret.

- `discord_webhook` - Send a message to a Discord channel via webhook URL.

- `email` - Not implemented yet (reserved action type; UI hides it for now).

- `pulse_script` - Run a server-side pulse by `serverActionId` with an optional payload template. The Pulse also receives a Pulse State memory hint for duplicate protection.

Action examples

```text
Webhook: send a POST to a URL you control.
Discord webhook: send a templated message to a Discord webhook.
Pulse: wake one of your Pulse handlers with a moment payload and Pulse State memory hint.
```

Configure actions from the Pulse Operating Center or Studio automation UI. Use the product UI so auth, plan checks, secret handling, and trigger ownership stay on the supported path.

## Cron Scheduling Rules

Cron uses 5 fields: `minute hour day month weekday`.

- Supports wildcards (`*`), lists (`1,15,30`), ranges (`9-17`), and steps (`*/5`).

- Day-of-month and weekday follow standard cron rules: when both are set (not `*`), the schedule runs when either matches.

- Timezone defaults to UTC; set a timezone in the trigger config to shift schedules.

- Example: `0 0 1 * 0` runs at midnight on the 1st of each month and every Sunday.

- Schedules use one-minute resolution.

- Vibecodr avoids overlapping runs for the same scheduled trigger.

- Scheduled Pulses can use `cron:triggerId:scheduledAt` as the Run once per event key.

- Per-user fairness: max 10 cron triggers fire per minute per user. If you have more than 10 due at once, the rest fire in subsequent minutes. This ensures no single user can monopolize scheduler capacity.

- Long gaps work too (monthly 31st, yearly, leap-day) - we search years ahead for the next match.

## Plan limits for Pulses

Each plan sets a clear ceiling for how many Pulses you can keep deployed and how much backend traffic they can handle each month. Monthly runtime headroom also scales by plan; Vibecodr shows that as in-product usage guidance instead of publishing CPU-hour promises that would make the platform harder to tune safely.

Plan

Max pulses

Runs / month

Max runtime

Secrets

Advanced SQL

Free

3

1,500

5s

No

Creator

15

150,000

15s

Yes

No

Pro

50

1,000,000

30s

Yes

## Calling Pulses from Your UI

Pulses are normal HTTP endpoints. In a combo app, call the Pulse route your app exposes and keep the request body small, explicit, and shaped around the action the viewer is taking.

Call a Pulse from React

```typescript
async function callWeatherPulse() {
  const res = await fetch("/api/weather", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ city: "San Francisco" }),
  });

  if (!res.ok) {
    throw new Error(`Pulse failed with status ${res.status}`);
  }

  const data = await res.json();
  console.log(data); // e.g. { temp: 68, conditions: "sunny" }
}
```

Pulse Handler

```typescript
// Pulse code (server-side). Default export is your handler.
// Enhanced style: (input, env) => result
export default async function handler(input, env) {
  const { city } = input;

  // Call weather API with a policy-bound secret capability
  const response = await env.fetch(`https://api.weather.com/v1/forecast?city=${city}`, {
    auth: env.secrets.query("WEATHER_API_KEY", "apikey"),
  });

  const forecast = await response.json();
  return { city, forecast };
}
```

Deployed pulse source stays owner-only, but the HTTP endpoint is public by default. Add signed requests or owner-authored checks only when the pulse's own behavior should be restricted.

### Auth planes in plain English

- `Authorization` is for your app's auth when it reaches pulse code through a runtime call.

- Signed-in API runs use top-level `Authorization` only at Vibecodr's API boundary; that bearer is not forwarded to pulse code.

- Programmatic runtime authorization should go through Vibecodr client helpers, not hand-written platform headers.

- Secret and connection access uses platform-managed runtime authorization that callers cannot supply.

- Platform-owned runtime request headers are stripped before your handler sees `env.request`.

For external systems, prefer a webhook trigger or a product-provided caller token flow instead of copying platform headers. Keep your own `Authorization` header for the app or partner protocol your Pulse code validates.

## Structured route body

### Client and trusted execution

Vibes run in the browser as sandboxed client experiences. Pulses run as trusted backend endpoints on the platform-managed edge. The distinction protects creators and viewers by keeping credentials and privileged operations away from client-visible code.

A Combo is a project that uses both sides: the vibe owns interactive UI while Pulses own backend work such as secrets, schedules, webhooks, storage, or third-party APIs.

- Use vibes for UI, graphics, interaction, and public browser behavior.
- Use Pulses for secrets, OAuth/token work, provider calls, schedules, and durable side effects.
- Do not put private API keys, platform grants, or owner-only operational metadata in browser code.

### Same-origin backend shape

Pulse endpoints are called through same-origin /api routes so the browser app can talk to backend behavior without hardcoding a separate service host. That does not make the endpoint private by itself.

If endpoint behavior should be restricted, implement request validation and authorization in the Pulse handler.

- Public endpoint availability is separate from private source visibility.
- The platform mediates secrets and grants; the application still owns its business rules.
- Keep response bodies viewer-safe.

### How Pulse State helps Pulses coordinate work

A Pulse is creator-authored backend code. Pulse State gives that code a small, platform-managed memory for operation keys, so repeated calls can agree on what is new, already running, completed, failed, or safe to retry.

runOnce() coordinates one named Pulse State resource plus one trusted key inside the Pulse owner/deployment scope. The key defines the operation being protected, so stable keys such as verified webhook event ids, scheduled window keys, or form idempotency tokens are the best fit.

- Same Pulse, same state resource, same key: coordinated as the same operation.
- Same Pulse, same state resource, different key: a new operation.
- Different Pulse or different owner: a separate coordination scope.
- Use Pulse State for operation lifecycle. Use a real data surface or connected service for application records that need querying, editing, or long-term storage.

#### Same key means same coordinated operation

```typescript
const event = await env.webhooks.verify("stripe", {
  secret: "STRIPE_WEBHOOK_SECRET",
});
const key = `stripe:event:${event.id}`;

return env.state.webhookDedupe.runOnce(key, async () => {
  await env.fetch("https://api.example.com/fulfill", {
    method: "POST",
    auth: env.secrets.bearer("PROVIDER_API_KEY"),
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ eventId: event.id }),
  });

  return { accepted: true };
});
```

### Example and read next

Example: a vibe needs to call OpenAI, Stripe, or GitHub. Keep the interactive UI in the browser, put the credential-backed provider call in a Pulse, and have the vibe call a same-origin /api route.

Use these related pages when you need the next layer of guidance. They point to the most likely follow-up tasks, not every page that happens to touch the same system.

- Read next: [Vibe Runtime](/docs/vibe-runtime)
- Read next: [/blueprints](/blueprints)
- Read next: [Pulse SDK & Handlers](/docs/handlers)
- Read next: [Secrets & APIs](/docs/secrets)
- Read next: [Calling Pulses](/docs/calling-pulses)

## Related documentation

- [/docs/vibe-runtime](https://vibecodr.space/docs/vibe-runtime/index.md)
- [/blueprints](https://vibecodr.space/blueprints)
- [/docs/handlers](https://vibecodr.space/docs/handlers/index.md)
- [/docs/secrets](https://vibecodr.space/docs/secrets/index.md)
- [/docs/calling-pulses](https://vibecodr.space/docs/calling-pulses/index.md)