Customization Guide

Pulse is your source code. Here's where to look for the most common tweaks, and how to brief Claude Code on the rest.

Repo layout

src/
  components/         # UI components
  features/           # Feature modules (standups, surveys, polls, reminders)
  lib/                # Utilities (supabase client, timezone, slack, rrule)
  pages/              # Top-level routes
  theme.css           # Tokens
supabase/
  schema.sql          # Schema
  functions/          # Edge Functions

Common customizations

Change brand colors

File: src/theme.css

:root {
  --pulse-accent: #8b5cf6;
  --pulse-accent-contrast: #1a0d3b;
  --pulse-bg: #0b0f1a;
}

Add a question type

Question types are registered in:

File: src/features/questions/registry.ts

export const questionTypes = {
  short_text: shortTextType,
  long_text: longTextType,
  scale: scaleType,
  // add:
  slider: {
    label: "Slider",
    schema: z.object({ min: z.number(), max: z.number(), step: z.number() }),
    renderComposer: (props) => <SliderComposer {...props} />,
    renderAnswer: (props) => <SliderInput {...props} />,
    renderDigest: (resp) => <SliderBar value={resp.value} />,
  },
};

Also add Slack/email renderers in src/lib/slack/blocks.ts and src/lib/email/templates.ts so the new type works across every delivery channel.

Add a survey template

File: src/features/surveys/templates.ts

Each template is a plain JSON object — add a new entry and it shows up in the template gallery.

Change the default digest format

File: src/features/digests/default-template.ts

Edit the markdown template. Variable substitutions:

  • {{team.name}}
  • {{date}}
  • {{responses}} (iterable)
  • {{blockers}} (filtered list)

Add a delivery channel

Three pieces to add:

  1. Channel config under src/features/channels/{name}.ts.
  2. Sender implementation under supabase/functions/pulse-{name}-sender/.
  3. Response ingestion route under src/pages/api/{name}/events.ts.

Copy the Slack implementation as a starting point.

Change default CRON parsing

Pulse uses rrule under the hood. To adjust:

File: src/lib/rrule.ts

Tips for working with AI

Pulse has tight coupling to scheduled jobs. When asking Claude Code for changes:

  • Timezones are everywhere — always mention "honor the participant's timezone" when changing anything schedule-related.
  • Slack signature verification is non-negotiable. Any change that adds a new Slack endpoint must verify signatures first.
  • Respect anonymity — if you're touching survey code, tell Claude "maintain the anonymity invariant: no user_id on anonymous responses."
  • Edge functions are Deno, not Node — Claude sometimes writes Node-only imports. Remind it to stay within the Deno standard library and Supabase helpers.

Example prompts

Add a "mood emoji" question type to standups. Users pick from a palette of 12 emoji. The digest renders the emoji grid grouped by person. Update the Slack block renderer to use a select menu.

Add a "weekly summary" digest kind: aggregates every standup response from Mon–Fri into a single digest posted Friday at 5 PM team-local time. Add a toggle in the standup editor.

Extract the scheduler logic from pulse-scheduler into a pure-function library so we can unit-test it. Keep the function's entry point and the runtime semantics the same.