The Burrow: features, how they function, and backend config
What it is
The Burrow is Hedgehog Marketing's client portal: AI-powered marketing tools for clients, powered by Claude and the Hedgehog skill library. Each client gets access to 35 marketing tools across 5 categories, persistent conversations, deliverables, tasks, and autopilot approvals.
Repo: teddi-coder/hedgehog-client-portal. Live at theburrow.hedgehogmarketing.com.au.
Stack: Next.js 16 (App Router) + React 19 + TypeScript, Supabase (Auth, Postgres, RLS; project zfmraowvqigcagscdive), Anthropic Claude (claude-sonnet-4) with streaming, Tailwind with HH brand colours, deployed on Vercel. AI chat proxies to nearly-headless-hilda (NHH) on Fly.io.
Surfaces
| Surface | Route | Auth | Purpose |
|---|---|---|---|
| Public demo | /preview/burrow/* |
None | Sales/demo surface using Klaylife fixtures. Never break; shown to prospects. |
| Authenticated portal | /burrow/* |
Supabase session | Each client sees their own RLS-constrained data. Internal users get a client picker. |
| Login | /login |
n/a | Email + password. Accepts full email or business-name slug (e.g. klaylife). |
| Admin | /admin/* and /burrow/admin/* |
Internal only | Per-client access controls, SoT review. |
| Legacy | /dashboard, /advisor, /tools/[slug], /channels/* |
Mixed | Pre-Burrow pages. Don't touch without reason. |
Features and how they function
Hilda chat
The chat page calls /api/hilda/chat, which calls Anthropic directly with MCP tools wired into the portal route (Phase 3b decision, 6 Jun 2026). There is no NHH proxy in the path. A context block built by hildaClientContext() is sent on the first message of each thread only: client name and slug, connector IDs (Google Ads, GA4, Meta, GSC, GBP, Slack, WhatConverts, Shopify), and strategy/plan/report sections for the demo client only. Drive and Sheets tools are excluded from the portal's tool set. /api/hilda/status probes connectivity.
35 config-driven tools
All tools share one chat UI and API route. The tool registry (src/lib/tools/registry.ts) plus SKILL.md files under /skills/ define the differences. System prompt layering: Identity, then Client Brief, then Skill Instructions, then Behavioural Rules. Adding a tool means one skill folder plus one registry entry; the chat page, sidebar, and dashboard pick it up automatically.
Tool-chat MCP integration
Separate from Hilda chat: when CHAT_MCP_ENABLED=true, the tool chat handler loads read-only tools from the hedgehog-google-ads and hedgehog-semrush MCP servers (Fly.io, Streamable HTTP). Every call goes through withClientScope(), which enforces the active client's account IDs to prevent cross-client data access. CHAT_MCP_CLIENT_ALLOWLIST limits which client slugs get MCP access.
Conversations
Message-per-row Postgres storage. When history exceeds 50 messages, older messages are summarised to manage tokens. Responses stream via ReadableStream. Agent portraits render in AgentBubble; messages carry an agent_id column.
Deliverables
The deliverables table holds typed deliverables rendered by per-type renderers in src/components/deliverables/renderers/: monthly reports, quarterly plans, a 13-section zod-schema audit renderer, prose types (campaign_build, content_piece), and creative_asset (iframe-style preview, copy panel, brief metadata, Download PNG via html2canvas). The deliverables folder is unified: all types appear in one view with type labels. Unique constraint on (client_id, type, period_label); all inserts must use INSERT ... ON CONFLICT ... DO UPDATE SET content = EXCLUDED.content, updated_at = NOW().
Creative Studio
AI-generated ad creatives via the generate-creative Supabase edge function (v4). Logo URL auto-populates from SoT brand data into the generation prompt. "Save to Burrow" stores outputs as creative_asset deliverables.
Source of Truth (SoT) review
Brand voice and persona data for all HH and MM clients across three tables: clients (core fields plus sot_completeness_pct, strategic_context, key_decisions), client_brand_voice (one row per client), and client_personas (multiple rows per client). Every record has hilda_confidence: draft then reviewed then approved. The review UI at /burrow/admin/sot-review (internal only) shows completeness bars, pending counts, and one-click approval. The index page is a server component calling createAdminSupabaseClient() directly; SUPABASE_SERVICE_ROLE_KEY must be set in Vercel or it silently shows 0 clients.
Autopilot approvals
Pending Google Ads and Meta Ads autopilot actions surface in the Burrow; clients approve or reject via /api/autopilot routes, with badge counts on the sidebar nav.
ClickUp tasks
/api/tasks fetches from multiple ClickUp lists in parallel (per-client clickup_list_ids), deduplicates, and groups team vs client tasks with list-name pills. Card-based layout with status bands and overdue de-emphasis. Internal users get an inline status dropdown backed by a PATCH route (/api/clickup/tasks/[taskId]) with optimistic UI updates. Client to-dos are checkable; HH internal tasks are read-only for clients.
Inbox
/api/inbox builds a unified notification feed from four Supabase tables, rendered at /burrow/inbox with skeleton loading and empty states.
Onboarding and welcome emails
Self-serve 4-step onboarding wizard, token-gated, firing an NHH webhook on completion, with an admin link generator. Completion triggers a transactional welcome email via Resend (sending domain hedgehogmarketing.com.au, must be verified in Resend; emails silently skip if RESEND_API_KEY is unset).
Auth and client scoping
Supabase email and password; slug logins map to <slug>@burrow.hedgehogmarketing.com.au. /burrow/layout.tsx calls resolveBurrowBootstrap() server-side, then BurrowClientBootstrap picks the active client from ?client=<slug> and provides it via useBurrowClient(). Internal users switch clients; clients are locked to their own profile (URL-hacking ?client= does nothing for them). Every internal link must use useBurrowHref() to preserve the slug across navigation. Only Klaylife is the demo client; isDemoClient() gates all fixture content so non-Klaylife clients never see Klaylife data. Password reset flows live at /auth/callback and /auth/reset-password. Internal users also get a "Preview mode" toggle in the sidebar.
Report ingest
- Monthly planning reports are converted to Burrow-ready JSON and inserted into Supabase project
zfmraowvqigcagscdivevia theburrow-report-ingestworkflow. - The
deliverablestable has a unique constraint on(client_id, type, period_label). - All inserts MUST use
INSERT ... ON CONFLICT ... DO UPDATE SET content = EXCLUDED.content, updated_at = NOW()— re-ingesting is always safe and never duplicates. - Renderer types are documented on /burrow-components.
Client ID resolution
- HH and MM internal client workspaces resolve via hardcoded overrides in NHH
burrow-proposals.js(BURROW_CLIENT_ID_OVERRIDES, PR #125): HH →c63e6cc5-333e-4033-af9f-4be578e9e26a, MM →858637a4-7e23-4a73-9b72-5e5ea983f493. - All other clients resolve dynamically from the database.
Hilda chat architecture (June 2026)
- The portal's
/api/hilda/chatcalls Anthropic directly — there is NO NHH proxy in the path. - MCP tools are wired directly into the portal route (Phase 3b decision, 6 Jun 2026). Two-stack parity with NHH is accepted.
- Drive and Sheets tools are excluded from the portal's tool set.
- Orphaned code on the cleanup list: NHH
/api/chatand the portal'sstreamHilda().
Backend config
Core env vars (required)
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, ANTHROPIC_API_KEY, ADMIN_EMAILS.
Email (optional)
RESEND_API_KEY.
MCP tool-use (optional)
CHAT_MCP_ENABLED, CHAT_MCP_CLIENT_ALLOWLIST, NHH_AUTH_TOKEN, NHH_URL (defaults to https://nearly-headless-hilda.fly.dev), MCP_TOKEN_PRIMARY + MCP_SERVER_HEDGEHOG_GOOGLE_ADS_URL, MCP_TOKEN_SEMRUSH + MCP_SERVER_HEDGEHOG_SEMRUSH_URL.
All values live in Vercel → hedgehog-client-portal → Settings → Environment Variables. Vercel's VERCEL_GIT_COMMIT_SHA feeds the /burrow/* build banner; a mismatched SHA means the deploy hasn't landed.
Seeding
npm run seed:clients upserts the client roster from the ClickUp HH Client Tasks folder (id 90160957776); each client list contains a Client Config task holding platform IDs. npm run seed:admin creates the internal admin user. Runbook: docs/client-auth-seeding.md.
Git and deploy
Never commit to main (pre-commit hook plus Vercel rejection). Feature branches named feature/burrow-iter-N-<desc>, committed as teddi-coder; Teddi merges and Vercel auto-deploys from main.
Known limitations (June 2026)
- MCP tools are now wired directly into the portal route (Phase 3b, Jun 2026). NHH's
/api/chatis orphaned and on the cleanup list. - Passwords equal slugs. Preview-grade; harden with magic links or forced reset before real client onboarding.
- Deliverables are empty for most non-Klaylife clients until the pipeline populates them.
- 22 ClickUp clients have no Config task and aren't seeded (likely inactive).
/api/burrow/metrics/[slug]/snapshotreturns stored data only; live-fetch blocks are stubbed asnot-connected.- NHH's
/api/onboardingendpoint isn't built yet; the wizard webhook graceful-fails.