Backend Dev Guidelines
langfuse/langfuse
Build or review Langfuse backend code. An agent skill from langfuse/langfuse.
Work inside the Databuddy monorepo for internal implementation, debugging, review, and refactoring.
$ npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install databuddy-analytics/Databuddy databuddy-internal --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/databuddy-analytics/Databuddy.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/databuddy-internal .claude/skills/databuddy-internal && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "databuddy-internal" agent skill from https://github.com/databuddy-analytics/Databuddy/tree/main/.agents/skills/databuddy-internal into .claude/skills/databuddy-internal/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "databuddy-internal", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/databuddy-analytics/Databuddy/tree/main/.agents/skills/databuddy-internalType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install databuddy-analytics/Databuddy databuddy-internal --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/databuddy-analytics/Databuddy.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/databuddy-internal .agents/skills/databuddy-internal && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "databuddy-internal" agent skill from https://github.com/databuddy-analytics/Databuddy/tree/main/.agents/skills/databuddy-internal into .agents/skills/databuddy-internal/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "databuddy-internal", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install databuddy-analytics/Databuddy databuddy-internal --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/databuddy-analytics/Databuddy.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/databuddy-internal .cursor/skills/databuddy-internal && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "databuddy-internal" agent skill from https://github.com/databuddy-analytics/Databuddy/tree/main/.agents/skills/databuddy-internal into .cursor/skills/databuddy-internal/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "databuddy-internal", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/databuddy-analytics/Databuddy.git --path .agents/skills/databuddy-internal--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install databuddy-analytics/Databuddy databuddy-internal --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/databuddy-analytics/Databuddy.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/databuddy-internal .gemini/skills/databuddy-internal && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "databuddy-internal" agent skill from https://github.com/databuddy-analytics/Databuddy/tree/main/.agents/skills/databuddy-internal into .gemini/skills/databuddy-internal/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "databuddy-internal", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install databuddy-analytics/Databuddy databuddy-internalInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/databuddy-analytics/Databuddy.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/databuddy-internal .github/skills/databuddy-internal && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "databuddy-internal" agent skill from https://github.com/databuddy-analytics/Databuddy/tree/main/.agents/skills/databuddy-internal into .github/skills/databuddy-internal/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "databuddy-internal", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install databuddy-analytics/Databuddy databuddy-internal --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/databuddy-analytics/Databuddy.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/databuddy-internal .opencode/skills/databuddy-internal && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "databuddy-internal" agent skill from https://github.com/databuddy-analytics/Databuddy/tree/main/.agents/skills/databuddy-internal into .opencode/skills/databuddy-internal/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "databuddy-internal", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
databuddy-internalWork inside the Databuddy monorepo for internal implementation, debugging, review, and refactoring.
Databuddy Internal is an agent skill from databuddy-analytics/Databuddy. Work inside the Databuddy monorepo for internal implementation, debugging, review, and refactoring. Use only for repository code changes across dashboard, api, basket, links, docs, uptime, SDK, tracker, auth, RPC, database schema, ClickHouse, or shared packages. Do not use for external SDK, API, CDN, feature flag, or LLM observability integration guidance; use databuddy instead.
Its SKILL.md is about 11k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including reference files (for example `references/codebase-map.md`).
It sits in Development, covering Monorepo tooling, Data warehousing and Database schema design. It works with ClickHouse. The repository describes itself as: Open-source product analytics for startups: track visitors, events, funnels, and goals without cookies, and ask Databunny, the built-in AI analyst. Uptime, feature flags, and… The licence is AGPL-3.0.
6 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit fc7eb6b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
bunrgbashdockerclickhouseFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
ai-sdk.devFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
AUTUMN_SECRET_KEYAI_GATEWAY_API_KEYCONTEXT_DEV_API_KEYDATABUDDY_E2E_TEST_KEYAXIOM_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Databuddy Internal loads about 11k tokens when it runs, and up to ~14k if it reads all its reference files. Until then it costs about 100 tokens; SKILL.md has 5,447 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
- The local `.env` sets `NODE_ENV=development`; override it with `NODE_ENV=production` when verifying `next build`, or rThe Slack package scripts read the root `.env`.the exact `.env.example` template; real `.env`, `.env.*`, key, and credential files should still be blocked.lags API local dev** requires `dotenv -e .env` from repo root to pick up `REDIS_URL`, `DATABASE_URL`, etc.Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from databuddy-analytics/Databuddy at commit fc7eb6b, republished under its AGPL-3.0 licence (© databuddy-analytics). 5,447 words, ~10,791 tokens.
.claude/skills/databuddy-internal/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Databuddy is a Bun + Turborepo TypeScript monorepo. Start by locating the user request in one product surface, then trace its shared dependencies before editing.
For external integrations (SDK, CDN, public APIs), use the databuddy skill; this skill is for this repository.
When a mistake could have been avoided with better repo context (wrong app, package, port, or pattern), or when the user corrects you or asks you to fix something you got wrong, update this skill (SKILL.md or references/codebase-map.md) in the same turn when practical.
Keep additions minimal: one bullet, a new rg hint, or a routing note—enough that the next session does not repeat it. If the lesson is for SDK/API customers, add it under .agents/skills/databuddy/ instead.
.agents/skills is versioned project guidance. Put new personal or experimental agent skills under /Users/iza/.agents/skills unless the user explicitly wants the skill committed with Databuddy.Work directly in the local staging checkout by default. Task branches, worktrees, and PRs require an explicit user request; preserve existing local edits.
Self-host changes must preserve hosted behavior with SELFHOST unset or false, including auth cookies/email, generated snippets, CSP, and image publication. Compare to the pre-change path; import guard-only helpers from @databuddy/env/boolean so checking the mode does not initialize unrelated URL config.
Before any PR merge, follow the AGENTS.md review-feedback gate: wait for configured reviewers on the final head, read all comment/review/thread pages, address each finding with evidence, and re-fetch to verify no unresolved feedback. Review bots can finish several minutes after a draft becomes ready; green CI does not establish completed review.
Prod infrastructure repo is local at /Users/iza/Documents/GitHub/databuddy-infra (databuddy-analytics/infra); ClickHouse cluster inventory is clickhouse/ansible/inventory.yml, not /Users/iza/Dev/Databuddy/infra or DatabuddyOPS.
Never use production/customer data as tests, fixtures, snapshots, examples, or copied output. Tests must use placeholders/mocks only (example.com, example IDs). If production ClickHouse is queried for investigation, summarize anonymized aggregates and do not paste customer domains, client IDs, emails, or other identifiers into code or responses.
@databuddy/test/env targets local databuddy_test unless CI=true, so a normal db:push may update a different database; sync that test database explicitly before debugging removed-column failures.
apps/dashboard: Next.js app on port 3000 (per-website agent chat: @ai-sdk/react useChat via contexts/chat-context.tsx — not the separate chat-sdk package; overlapping sends while streaming are queued client-side to mirror a “queue latest” strategy.)
Dashboard Playwright webServer commands run under CI PATH from setup-bun; avoid bash -lc because login shells can drop Bun from PATH. Build dist-only workspace packages such as @databuddy/sdk and @databuddy/devtools before starting the API/dashboard. Client NEXT_PUBLIC_* flags must use direct env access so Next can inline them. readBooleanEnv only treats the literal string "true" as enabled, so CI E2E booleans must use "true"/"false", not "1"/"0".
Dashboard pages that call useSearchParams() must keep that call inside a Suspense-rendered child; run the production dashboard build after adding URL-driven onboarding state.
Business context loads through OrganizationProvider before its page query and generation-access check; keep all three states on the same page/card geometry and test their transitions with delayed requests on desktop and mobile.
Business-context generation runs in the API; verify AI_GATEWAY_API_KEY, CONTEXT_DEV_API_KEY, and hosted AUTUMN_SECRET_KEY on the serving API deployment. Worker credentials and a green /health do not establish feature readiness.
Failed business-context generations survive refresh; dismiss them through the existing generation-ID-scoped cancel mutation while preserving unsaved editor drafts. Hiding the message in component state is not durable.
Playwright launched through Bun still uses the Node on PATH. CI installs Node 24; local Node 20 lacks Promise.withResolvers, so keep deferred E2E requests on portable Promise constructors.
The local .env sets NODE_ENV=development; override it with NODE_ENV=production when verifying next build, or root-error prerender behavior can produce a misleading local failure.
Local dashboard E2E tests that need /api/test/e2e/* should start the API/dashboard directly (or through Playwright's webServer command), not via bun run dev:dashboard; Turbo runs in strict env mode and drops DATABUDDY_E2E_MODE/DATABUDDY_E2E_TEST_KEY unless they are added to turbo.json globalEnv.
Dashboard Playwright public/demo analytics specs call API /v1/query anonymously from the browser; keep DATABUDDY_E2E_MODE query behavior isolated from production rate limits so CI retries do not exhaust anon:unknown.
apps/api: Elysia API on port 3001
API tests use Vitest through bun run test inside apps/api; use Vitest test imports rather than bun:test in that package.
Public REST docs live in apps/api/src/rpc/openapi.ts: /spec.json is the generated spec, / is the reference UI, and hiding a router there also makes its top-level REST paths return 404 because /* uses the same filtered docs router.
apps/slack: Slack agent adapter; Slack installs resolve through org-scoped DB integration records, not a single env bot token/default website. Agent calls use the org-scoped internal principal synthesized from the active integration in slack/installations.ts, never a global internal secret.
Slack OAuth lives in apps/api, but slash commands/events require apps/slack to be running too; local bun run dev:dashboard runs dashboard + API only, so use bun run dev:slack when working on Slack. The Slack package scripts read the root .env.
Run Slack tests through bun run test inside apps/slack; the package script supplies only the inert Redis URL needed by eager shared imports.
Inspect root package.json overrides before interpreting Slack dependency manifest versions or apparent lockfile drift; the effective @slack/web-api version may be pinned there.
Slack routing is organization-scoped: OAuth binds a Slack workspace to a Databuddy organization, app mentions from the installed workspace auto-bind channels including Slack Connect, and /bind is now a manual fallback for unknown/unapproved channels. DMs/assistant threads work after workspace install. Analytics questions should go through app mentions/DMs using MCP-style website discovery inside the installed organization, never by fanning out across the message sender's user memberships. Slack emits evlog events under apps/slack/.evlog/logs in development/SLACK_EVLOG_FS=1; Axiom uses AXIOM_TOKEN and the slack dataset; reactions need the reactions:write bot scope.
Model evaluations should use the user’s agreed quality, latency, and cost tradeoff; an explicitly accepted accuracy regression is not an adoption veto. Keep authorization and execution validation deterministic, and report fresh held-out results with failures and model overhead included.
Slack scope changes require reinstalling/reauthorizing the workspace; updating the local/remote manifest alone does not grant newly-added bot scopes to an existing installation.
Slack agent billing flows through an org-scoped automation API key; existing keys may have userId: null, so the agent billing resolver must fall back to the organization owner when an API key has organizationId.
Slack memory is separate from billing/auth: pass a Slack-scoped memoryUserId such as slack-{team}-{user} plus current-speaker context so one Slack user's saved name/preferences do not bleed into another user's replies.
Slack agent tools use the scopes on the internal principal in slack/installations.ts; changing those Databuddy scopes applies without Slack reauthorization. Only changes to Slack OAuth scopes require reconnecting the workspace.
Shared agent integrations should call @databuddy/ai/agent (askDatabuddyAgent / streamDatabuddyAgent) instead of importing internal MCP run/history helpers directly.
Keep the Jev evaluation request in its owning classifier; do not add a provider-wrapper file for a single call. Slack message types already live in ai/mcp/slack-context.ts.
The shared conversational MCP runner (including Slack) uses native goal/link tools through createMcpAgentTools; the external MCP server has separate wrappers in mcp/workspace-tools.ts.
First-party ads attribution work should start by preserving UTMs into registration and signup events only; do not add RPC plumbing, conversion destinations, env hooks, tables, workers, or UI until explicitly needed.
Organization business-context drafting is an active streaming request owned by apps/api/src/ai/organization-business-context.ts, injected into oRPC by the API host. Its request abort cancels only the matching generation; consumed usage settlement stays independent. Investigation generation stays in apps/insights.
Insights generation logic belongs in apps/insights and should reuse @databuddy/ai; apps/api should only read insight data or queue runs, not own prompts, model calls, tool loops, validation, or persistence orchestration.
SPEC.md is the intelligence product contract. insight_observations is the readable Insights history; analytics_insights is the durable investigation projection. The agent outcome owns brief publication and act/ask promotion; do not replace either with frontend heuristics or collapse the feed into cases. Do not add a parallel agent, evidence API, fixed query choreography, or action-specific lifecycle.
Insights quality reviews must compare fresh baseline/candidate outputs and lead with the product verdict and concrete examples. Score usefulness, noise, reading effort, and retained useful findings separately from code tests and contract passes; preserve interrupted attempts instead of reporting retries as an uninterrupted pass rate.
Insights RPC helpers that take { context, ...input } must strip context before parsing a .strict() Zod input schema (same pattern as appendInvestigationReply / applyInsightGoalAction); otherwise CI fails with Unrecognized key: "context".
insights.history / MCP list_investigations hide cases while analysis or verification is queued/running; included clarifications use saved evidence and must not hide or mutate the case.
When reporting what an organization can see in Insights, follow the insights.brief/history visibility rules instead of counting analytics_insights; the projection can contain legacy rows without a readable or published insight_observations turn.
Production insight shadows must freeze --reference-time, retain a tool-name trace, and pass available GitHub context before supporting quality claims. Postgres and ClickHouse are read-only, but connector token refreshes or cache writes can still occur; never describe the whole run as zero-write.
Automatic investigations have one organization-wide schedule (off, daily, or weekly) and one organization-wide delivery set; website selection is only for manual runs. Do not reintroduce per-website overrides, hourly/custom cadence, or cron input.
A manual insight run is a deliberate recheck: it bypasses automatic cooldown only for currently detected signals, while retaining detector thresholds and normal signal ranking. Otherwise “Run now” can complete without producing an evaluable result.
Insight run items are execution metadata, not rendered insight content; previews should use run status/counts or query real insights, never infer titles or bodies from run items.
Insight Slack delivery must resolve each channel binding to its active same-organization integration; never choose an arbitrary organization bot token.
Replies beneath delivered Slack investigations must resolve the delivery and enter the existing durable reply/resume path; never route them through generic Slack chat or relevance scoring.
One-off insight previews must preserve the real signal entity and use customer-facing product output. Never hand-write Slack copy from eval metadata or expose evaluation and suppression mechanics.
Agent ClickHouse SQL must use the canonical analytics.events schema: client_id, time, path, event_name, and pageviews as event_name = 'screen_view'; never website_id, created_at, page_path, event_type, or pageview.
Agent get_data filters select rows; do not expose SQL CTE target or having as generic event/error scopes. Query discovery supplies accepted selectors, and result row counts describe the query output rather than a complete population.
Slack agent expected stops such as exhausted Databunny credits should throw DatabuddyAgentUserError from @databuddy/ai/agent/errors; Slack surfaces those messages directly and reserves the generic reconnect copy for real infrastructure failures.
Slack Docker builds use bun build --compile --bytecode; keep apps/slack/src/index.ts bootstrapping inside an async main() instead of top-level await, which can fail during compile even when typecheck passes.
Insights Docker builds also use bun build --compile --bytecode; keep apps/insights/src/index.ts startup work inside async functions instead of top-level await.
After Slack Docker changes, verify the full pruned image with docker build --progress=plain -f slack.Dockerfile -t databuddy-slack:test .; the inner Bun compile is not enough because prune can miss dependency build outputs and package exports.
Slack-reachable shared packages (@databuddy/ai, @databuddy/rpc) must not import evlog/elysia; use host-injected request logger providers from the API and plain evlog fallbacks elsewhere.
AI link tools must assign link folders by existing folder id or slug only; folder names are display text and must not be used for routing or dedupe.
apps/basket: ingest and LLM tracking service, Elysia app on port 4000
Basket tests use Vitest; run them through bun run test inside apps/basket, not bun test directly.
apps/docs: Next.js + Fumadocs docs app on port 3005
When a user drops a prototype, remove only prototype-specific wiring and preserve the existing product surfaces it temporarily reused.
apps/links: redirect/link service
apps/uptime: uptime monitoring service
apps/uptime BullMQ worker concurrency defaults high for Bun async I/O; do not lower it just because 10_000 looks large. Verify downstream saturation or lock/timeout evidence first.
Public status pages render from apps/status; apps/dashboard owns status-page management/config UI only. When cleaning public status UX, update shared @databuddy/ui/uptime pieces or apps/status wrappers instead of redesigning dashboard-only route remnants.
packages/db: Drizzle Postgres schema, client, and ClickHouse helpers
Keep Bun-only DQL provisioning code off the @databuddy/db/clickhouse barrel; dashboard Next routes run under Node and import the shared ClickHouse surface.
packages/rpc: shared oRPC router, procedures, auth-aware server context
packages/rpc must declare drizzle-orm: "catalog:" before importing drizzle-orm/* helpers such as drizzle-orm/zod; otherwise TypeScript can resolve a different Drizzle instance than @databuddy/db and reject table-derived schemas.
packages/auth: Better Auth setup, permissions, organization access
packages/env: shared URL, public, and boolean environment helpers
packages/shared: shared types, flags, analytics schemas, utilities
Analytics query builders live in packages/ai/src/query; there is no standalone packages/query directory. Tests are excluded from root Biome checks, so format changed test blocks explicitly.
apps/insights uses the ES2022 TypeScript library; Bun supporting findLast or newer Set methods does not make those APIs typecheck here. Check the package TS library before choosing newer built-ins.
packages/sdk: published analytics SDK for React, Vue, and Node
packages/tracker: internal tracker script build and release package
packages/encryption, packages/notifications, packages/cache, packages/redis, packages/services, packages/validation, packages/api-keys: shared infra and domain packages
Knip is configured in root knip.json (run bun run knip); per-workspace test globs are required because the root test:watch (bun test --watch ./apps) script shadows the Bun plugin's per-workspace script parsing; apps/cron is ignored (standalone scripts, no package.json)
Read codebase-map.md when you need deeper routing guidance.
package.json, entrypoint, and direct dependencies before changing code.dashboard -> apps/dashboard/lib/orpc.ts -> packages/rpc -> apps/apipackages/sdk or packages/tracker -> apps/basket -> packages/db / ClickHousepackages/auth and packages/rpc together.bun@databuddy/db; a root-level Bun eval cannot resolve workspace or transitive dependencies directly.bun install --lockfile-only, preserve lockfile sync for pre-existing package.json changes instead of reverting them as unrelated.turbobun run check-types --filter=… from the workspace root; inside a package, its local script invokes tsc directly and treats those flags as TypeScript options.bun run format, bun run lintstaging, verify HEAD, the intended commit set, and upstream divergence on that branch before declaring the work complete.no-secrets guard intentionally ignores the exact .env.example template; real .env, .env.*, key, and credential files should still be blocked.bun run devbun run dev:dashboard./apps: bun run testpackages/ai broadly mocks @databuddy/redis, keep the mock export surface in sync with runtime imports from shared RPC/tool code.Tool<Input, Output>; do not cast mixed tool inputs to never to suppress union errors. AI package tests are excluded from its normal type check, so check changed test types explicitly.packages/dbpackages/envBULLMQ_REDIS_URL; generic Redis cache/pubsub code uses REDIS_URL.apps/dashboardorganizations/components/general-settings.tsx: the same max-w-2xl column, shared Card headers/content, compact fields, and TopBar.Actions for Save. Compare actual neighboring pages visually before claiming design consistency; shared inputs alone are not enough.components/layout/navigation/navigation-config.tsx, components/ui/command-search.tsx, and local PageNavigation layouts under app/**/layout.tsx before calling a page orphaned.apps/dashboard/components/events/custom-events; keep many-series legends outside the Recharts plot, use compact controls for property-summary event selection, and avoid separate event-count chip/list sections.app/(main)/websites/[id]/funnels instead of adding separate summary-card chrome.Button, not only on List.Row, so the visible row surface is clickable without nesting buttons.overageLimit is additional feature units, not USD. Use the native databunny_chat flag to hide legacy credit purchases and guards for included-chat accounts; an investigation balance alone does not establish chat terms.apps/dashboard/app/globals.css. --border is intentionally subtle; do not crank it darker for “contrast” unless iza asks—prefer text tokens or layout for readability.filters URL param in app/(main)/websites/[id]/layout.tsx; guard URL-driven atom writes from echoing stale atom state back into nuqs, or adding a filter can lock the page during form submit.iconPath, render it through a shared logo tile with bg-secondary/60, border-border/70, text-foreground, and fill="currentColor", then use brand color only as a small accent bar (accent or accentClassName: "bg-foreground/70" for black/near-black brands). Avoid raw brand-black icons or mixed line/filled icon sets that disappear in dark mode.packages/ai/src/ai/mcp/tools.ts: default to read:data, then expose explicit action bundles for workspace actions, feature flags, and short links with their required scopes and confirmation behavior.packages/ui/src/components and are consumed through @databuddy/ui (@databuddy/ui/client for client-only components); the old apps/dashboard/components/ds/README.md path no longer exists. Read the corresponding shared component implementation before extending UI. Dashboard UI must use these shared primitives exactly; feature code must not use raw form/control elements (button, input, select, textarea, native dialogs), Base UI/Radix primitives, or ad hoc styled controls directly. If a variant is missing, add or extend the DS component first. For menu-style folder/status/filter/sort/action pickers, use components/ds/dropdown-menu.tsx; use Select only when the established pattern is explicitly a select/combobox. Inspect the shared component APIs in packages/ui/src/components before creating new dashboard UI.DropdownMenu.GroupLabel must be rendered inside DropdownMenu.Group; Base UI throws MenuGroupRootContext is missing when labels are placed directly under DropdownMenu.Content.app/(main)/websites/[id]/flags/_components/flags-list.tsx) are clickable containers with nested controls; mark nested controls with data-row-interactive="true" and have the row ignore those targets instead of relying on broad cell-level stopPropagation.<button> on dashboard rows. If a row has actions/menus, make the main row content a sibling Button and keep action buttons as separate siblings; do not use a div with click/key handlers as a fake button.apps/dashboard/lib/orpc.ts and the corresponding hooks/componentsapps/api/src/routes/query.ts; public website access is controlled by per-query-builder publicAccess, not only oRPC metadata.packages/rpcapps/api/srcpackages/rpcpackages/rpc rather than duplicating validation in the dashboardapps/insights; RPC only reads cases and accepts durable replies. Case identity is websiteId|subjectKey, where the backend owns the subject key. New analysis appends an observation; a clarification stores its answer on the reply and reads the originating observation's saved evidence without changing case state. The stored changePercent is already signed.apps/basket/srcBusiness includes 100 investigations/month and Scale 500, then $1 per extra. Lead pricing cards with these allowances; keep investigation definitions in one short FAQ. A pushed config is not an active offer: verify the serving deployment and native Autumn plan version before claiming the change is live.
Billing-control read/modify/write must use a strict native client and verify the customer ID before merging settings. SDK getOrCreate can fail open with empty controls, causing a later successful update to erase unrelated saved limits.
Autumn owns all investigation allowances, charges, reservations, prices, and invoicing. Do not store investigation billing state in Postgres tables, fields, or a billing outbox. Use existing product identities and completion state for provider retry references. Verify deployed entitlement support before syncing live plans.
Autumn catalog updates must send complete mutable plan fields, including explicit addOn, autoEnable, price, and description: omitted provider fields can reset flags, erase descriptions, or create a free new version. Preserve live legacy economics and verify exact before/after provider readback; passing SDK/CLI validation does not establish provider defaults. Do not overwrite unrelated live credit-schema drift during a pricing sync.
Retried insight jobs must persist immutable external delivery effects (currently Slack) before calling providers and reuse the effect ID as the provider idempotency key. An insight observation is product memory, not a delivery checkpoint.
Investigation plans use monthly counts from INVESTIGATION_ALLOWANCES and $1 per additional completed result through Autumn investigation_runs; never market token credits or an access gate as an investigation allowance. Render the actual attached allowance/reset separately from prepaid balances, and verify catalog, customer subscription, pricing cards, billing, and machine-readable docs together. Clarifications and repair verification are included. Validate explicit analysis consent at the API boundary and reserve one unit in Autumn before analysis; settle only after a readable complete result is persisted, reusing product identity on retries. Existing customers without the entitlement retain legacy agent_credits terms; do not convert their balances implicitly.
Transactional billing email identity has three separate concepts: Autumn customer/billing owner, organization, and actual to recipient. Only personalize from the actual recipient record; if it is unavailable, omit the greeting rather than using the owner name. Distinguish fixed-price investigations from legacy credits in billing copy.
autumn-js v1.2.2+ — import autumnHandler from autumn-js/fetch (NOT autumn-js/elysia, that export was removed in v1.0)
For Elysia, mount with .mount(autumnHandler(...)) — NOT .use()
identify callback receives (request: Request) directly, not ({ request })
Webhook event types: balances.limit_reached (replaces old customer.threshold_reached), customer.products.updated, balances.usage_alert_triggered
balances.limit_reached payload is flat: { customer_id, feature_id, entity_id?, limit_type } — no full customer object
SDK Customer type uses camelCase (balances, subscriptions, overageAllowed), but webhook payloads are snake_case and use old field names (features, products, included_usage, overage_allowed) — do NOT use the SDK Customer type for webhooks
SDK class is new Autumn() (reads AUTUMN_SECRET_KEY from env); methods use camelCase: customerId, featureId, sendEvent
autumn-js catalog version is in root package.json — update it when bumping
Storage and schema concerns usually continue into packages/db
evlog → Axiom: never use top-level error as a string on log.error({ ... }) (e.g. process handlers); it overwrites structured error.message on the wide event. Use error_message instead. Basket/API drains run normalizeWideEventForAxiom before ingest; 4xx EvlogError rows are emitted as level: "warn" with client_http_error: true so Axiom “errors” are not inflated by expected client failures.
packages/db/src/drizzle/schema/ (index.ts barrel)packages/db/src/drizzle/relations.tspackages/db/src/client.tsDATABASE_URL may already target PgBouncer; inspect both the process pool and PgBouncer queues before attributing API timeouts to PostgreSQL.pg.Pool already grows lazily from zero to its configured max; do not replace it with one Client to address acquisition timeouts, because that serializes queries. Keep a bounded pool, tune its acquisition timeout, and monitor waitingCount.packages/db/src/clickhouse/*ch:check is package-scoped; run cd packages/db && bun run ch:check, not the root script runner.packages/db db:push through init.Dockerfile; register new schema files in packages/db/drizzle.config.ts. packages/migrate transforms SDK source and is not a database migration runner.CREATE ... IF NOT EXISTS does not migrate
deployed tables, and Keeper-path or sort-key changes need a shadow-table
exchange.packages/auth/src/auth.tspackages/auth/src/client/auth-client.tsclient_name, not name.db.select().from(oauthConsent) and schema columns rather than db.query.oauthConsent.packages/rpcpackages/sdk/srcpackages/tracker/srcanonymizeVisitorIds (true/omitted = anonymized, false = raw IDs, "auto" = raw only in Databuddy's conservative country allowlist).apps/basketbun run dev:dashboardcd apps/api && bun run testcd packages/sdk && bun testcd packages/tracker && bun run test:unit:online model suffix is a Perplexity-only convention (e.g. perplexity/sonar-pro). Never add :online to non-Perplexity models.apps/api/src/ai/config/models.ts use gateway-style names (e.g. anthropic/claude-sonnet-4.5), not OpenRouter catalog strings.idleTimeout is 10 seconds; agent streams can look idle during slow tools. apps/api/src/index.ts exports idleTimeout on the server (Bun caps at 255 seconds).useChat) does not document automatic HTTP retries on DefaultChatTransport—retry UX is regenerate() + error (chatbot error state, error handling). maxRetries on streamText/generateText is server-side model calls, not the browser chat fetch. Mid-stream disconnect: resumeStream() (useChat).type: "data-*" (for example data-usage or data-aiComponent); injecting arbitrary chunk types such as usage makes DefaultChatTransport reject the stream.packages/ai/src/ai/agents/analytics.ts; otherwise the model may call an unavailable tool and then apologize instead of rendering the intended UI.@databuddy/shared just to sync the AI tool with dashboard routes.@elysiajs/cors with origin: true sets Vary: *, killing CDN caching. Override with set.headers.vary = "Origin" on cacheable public endpoints.applyAuthWideEvent in apps/api/src/index.ts runs a session DB lookup on every request including anonymous /public/ routes. Skip it for public endpoints via URL check in onBeforeHandle.client_id) is enforced programmatically in validateAgentSQL + requiresTenantFilter from @databuddy/db. Never rely solely on system-prompt instructions for data isolation. Every SQL tool entry point (API, RPC, etc.) must use the shared validation from packages/db/src/clickhouse/sql-validation.ts.analytics.* tables only. system.*, information_schema.* are blocked. Add new allowed prefixes in sql-validation.ts if new databases are added.dotenv -e .env from repo root to pick up REDIS_URL, DATABASE_URL, etc.createServerFlagsManager (not createFlagsManager). Call waitForInit() before use.flags.userId is set) via getCachedFlagsForUser and merges them with client/org-scoped flags. Client-scoped cache is shared; user-scoped cache is keyed per userId.flex bars at min-h-10/py-2.5 (40px) — not <dl> grids with large padding. Heights must be multiples of 10px to align with sidebar item sizing. Status uses a colored dot + text, not Badge.parseReferrers should return canonical name, referrer, source, domain, and referrer_type; dashboard tables should render/filter from those fields instead of reparsing source labels.ReferrerSourceCell must also parse URL/domain-looking source, referrer, or name values, because cached/legacy query rows may reach the table before all builders return canonical fields.apps/docs marketing copy: Do not explain pages as “keyword-focused,” “programmatic,” “intent,” or “meta” in UI—users care about tasks (compare tools, replace X, migrate). Keep internal SEO rationale out of hero and body copy.rg "createRPCContext|appRouter|sessionProcedure" packages/rpc apps/apirg "NEXT_PUBLIC_API_URL|createConfig|publicConfig|readBooleanEnv" packages/env apps/dashboardrg "clickHouse|ClickHouse|TABLE_NAMES" packages/db apps/basket apps/apirg "betterAuth|drizzleAdapter|organization" packages/auth packages/rpc apps/dashboardrg "trackRoute|basketRouter|llmRouter|structured-errors" apps/basketrg "signalKey|subjectKey|insightDedupeKey" apps/insights packages/rpc packages/shared© databuddy-analytics, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file (references) in .agents/skills/databuddy-internal of databuddy-analytics/Databuddy.
Open the folder on GitHubat commit fc7eb6b
Databuddy Internal next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Databuddy Internal this skilldatabuddy-analytics/Databuddy | 1.2k | — | ~11k | Automated safety check: Notes | AGPL-3.0 | |
| Backend Dev Guidelineslangfuse/langfuse | 35k | — | ~1.9k | Automated safety check: Pass | Custom licence | |
| Modelersidequery/sidemantic | 129 | — | ~4.2k | Automated safety check: Pass | Apache-2.0 | |
| Seed Test Datalangfuse/langfuse | 35k | — | ~5.7k | Automated safety check: Pass | Custom licence | |
| Schema Design Advisorchmonitor/chmonitor | 298 | — | ~2.2k | Automated safety check: Pass | GPL-3.0 | |
| Write Doc ExamplesClickHouse/clickhouse-java | 1.6k | — | ~3.1k | Automated safety check: Pass | Apache-2.0 |
langfuse/langfuse
Build or review Langfuse backend code. An agent skill from langfuse/langfuse.
sidequery/sidemantic
Build, validate, and manage semantic models using Sidemantic.
langfuse/langfuse
Seed reproducible local Langfuse data in ClickHouse and Postgres.
chmonitor/chmonitor
Recommend table ORDER BY keys, partition strategies, column data-type right-sizing, codecs, skip indexes, and projections for ClickHouse tables.
ClickHouse/clickhouse-java
Write, rewrite, and format documentation code snippets into reusable, production-ready methods with necessary library imports and clean linting.
mattiacerutti/supernova
Write idiomatic Effect v4 TypeScript following official best practices from effect-solutions and the Effect source.
databuddy-analytics/Databuddy
Integrate Databuddy analytics using the SDK, REST API, or MCP.
databuddy-analytics/Databuddy
Build multi-platform chat bots with Chat SDK (chat npm package).
databuddy-analytics/Databuddy
Help external users integrate Databuddy into their own apps.
databuddy-analytics/Databuddy
Build or review Bun fullstack TypeScript code with Drizzle-backed SQL.
databuddy-analytics/Databuddy
Design, implement, and review software using vertical slices (feature-first architecture) instead of horizontal layers.
databuddy-analytics/Databuddy
A skill your agent uses whenever the Databuddy MCP server is available and the user wants analytics, errors, vitals, investigations, flags, links, annotations, funnels, or goals queried or changed.
Works with
Categories
Work inside the Databuddy monorepo for internal implementation, debugging, review, and refactoring. Databuddy Internal is an agent skill from databuddy-analytics/Databuddy. Work inside the Databuddy monorepo for internal implementation, debugging, review, and refactoring.
Databuddy Internal fits situations like: LLM observability integration guidance; use databuddy instead.
Run `npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a claude-code`. Or copy the skill folder (.agents/skills/databuddy-internal in databuddy-analytics/Databuddy) into .claude/skills/databuddy-internal in your project. Claude Code loads it when a task matches its description.
Run `npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a codex`. Or copy the skill folder (.agents/skills/databuddy-internal in databuddy-analytics/Databuddy) into .agents/skills/databuddy-internal in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add databuddy-analytics/Databuddy --skill databuddy-internal -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/databuddy-internal, .gemini/skills/databuddy-internal, .github/skills/databuddy-internal and .opencode/skills/databuddy-internal in your project.
Going by SKILL.md and its folder, Databuddy Internal needs the command-line tools its instructions call (bun, rg, bash, docker and clickhouse) and credentials named AUTUMN_SECRET_KEY, AI_GATEWAY_API_KEY, CONTEXT_DEV_API_KEY and DATABUDDY_E2E_TEST_KEY. Our summary lists: A credential in AI_GATEWAY_API_KEY; A credential in CONTEXT_DEV_API_KEY.
SKILL.md names 1 domain. As links in the text: ai-sdk.dev. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Databuddy Internal is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 11k tokens (SKILL.md is roughly 43k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 3k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Databuddy Internal: Backend Dev Guidelines (langfuse/langfuse, 35k stars), Modeler (sidequery/sidemantic, 129 stars), Seed Test Data (langfuse/langfuse, 35k stars) and Schema Design Advisor (chmonitor/chmonitor, 298 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
databuddy-analytics (a GitHub organization) maintains it in databuddy-analytics/Databuddy, which has 1,176 GitHub stars. The repository holds 8 skills in this directory. The repository was last updated on October 7, 2026.
Source: databuddy-analytics/Databuddy on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.