WhoDB is a source-first data management tool. The public GraphQL API and frontend
contract are built around SourceType, SourceContract, SourceObject,
SourceObjectRef, and SourceSessionMetadata. The current execution layer is
still powered mainly by database plugins under core/src/plugins/.
If the ee/ directory is present, read ee/CLAUDE.md for additional context. Do not add any code, comments, or references to ee/ in the CE codebase.
- Analyze before coding - Read relevant files and understand patterns before writing code. State assumptions explicitly, ask when requirements are ambiguous, and always check whether an existing pattern can be reused or adapted.
- GraphQL-first - All new API functionality via GraphQL. Never add HTTP resolvers unless explicitly needed (e.g., file downloads)
- No SQL injection - Never use
fmt.Sprintfwith user input for SQL. Use parameterized queries or GORM builders. See.claude/docs/sql-security.md - Plugin architecture - Never use
switch dbTypeorif dbType ==in shared code. All database-specific logic goes in plugins. See.claude/docs/plugin-architecture.md - Documentation requirements - All exported Go functions/types need doc comments. All exported TypeScript functions/components need JSDoc. See
.claude/docs/documentation.md - Localization requirements - All user-facing strings must use
t()with YAML keys. No fallback strings. No hardcoded UI text. See.claude/docs/localization.md - Verify before completing - For non-trivial tasks, define success criteria before editing. After finishing, verify: (1) type checks pass (
pnpm run build:cefor frontend,go build ./cmd/whodbfor backend), (2) no linting errors, (3) all added code is actually used (no dead code). See.claude/docs/verification.md - Fallback clarification - Do not include fallback logic UNLESS you were asked to. If you think the project could benefit from fallback logic, first ask and clarify
- Show proof - When making a claim about how something outside of our codebase works, for example a 3rd party library or function, always provide official documentation or the actual code to back that up. Check online if you have to.
- No defensive code - Do not program defensively. If there is an edge or use case that you think needs to be handled, first ask.
- Surgical changes - Touch only the files and lines required by the request. Do not refactor, reformat, rename, or "improve" adjacent code unless the task requires it.
- Simplicity first - Solve the requested problem with the smallest clear implementation. Do not add speculative abstractions, configurability, or features.
- Own your cleanup - Remove imports, variables, functions, files, and generated artifacts made unused by your own changes. Mention unrelated dead code or suspicious behavior instead of deleting it.
For non-trivial tasks, use a short goal-driven loop:
- Identify the expected behavior or failure path.
- Choose the smallest change that satisfies the request.
- Add or update focused tests when the behavior is testable and the risk justifies it.
- Run the relevant verification commands and inspect the diff before finishing.
If the task is unclear or has multiple valid interpretations, stop and ask instead of silently choosing. If the implementation grows beyond the request, pause and simplify before continuing.
core/ # Backend (Go)
cmd/whodb/main.go # Entry point — imports plugins and creates GraphQL schema
src/app/app.go # AppConfig + Run() — shared server logic
src/src.go # Engine initialization (collects from global plugin registry)
src/engine/registry.go # Global plugin registry (plugins self-register via init())
src/engine/plugin.go # PluginFunctions interface
src/source/ # Source-first public contract + connector/session interfaces
src/sourcecatalog/ # Public source catalog exposed to GraphQL/frontend
src/dbcatalog/ # Internal connectable-database catalog adapted into sourcecatalog
src/env/ # Environment variable declarations (pure, no log dependency)
src/envconfig/ # Config-loading functions that need both env and log
src/plugins/ # Database connectors (each has init() calling engine.RegisterPlugin)
# Includes: postgres, mysql, sqlite3, mongodb, redis, elasticsearch,
# clickhouse, duckdb, memcached (+ mariadb via mysql)
graph/schema.graphqls # GraphQL schema
graph/*.resolvers.go # GraphQL resolvers
frontend/ # React/TypeScript
src/index.tsx # Entry point
src/store/ # Redux Toolkit state
src/generated/ # GraphQL codegen output (@graphql alias)
cli/ # Interactive TUI CLI (Bubble Tea)
desktop-ce/ # Desktop app (Wails)
desktop-common/ # Shared desktop code
.github/workflows/ # CI/CD pipelines (release, build, deploy)
Additional docs: .claude/docs/cli.md (CLI), .claude/docs/desktop.md (desktop), .claude/docs/ci-cd.md (GitHub Actions), .claude/docs/testing.md (testing). For adding new data sources, follow DATA_SOURCE_GUIDE.md (EE-specific additions in ee/DATA_SOURCE_GUIDE_EE.md).
See .claude/docs/testing.md for comprehensive testing documentation including:
- Frontend Playwright E2E tests
- Docker container setup for test databases
- Go backend unit and integration tests
- CLI tests
Quick reference:
# Frontend Playwright E2E
cd frontend && pnpm e2e:ce:headless # Headless (all databases)
cd frontend && pnpm e2e:ce # Interactive (headed)
# Backend Go tests
bash dev/run-backend-tests.sh all # Unit + integration
# CLI tests
bash dev/run-cli-tests.sh # All CLI tests- Use
anyinstead ofinterface{}(Go 1.18+) - Use
plugins.WithConnection()for all database operations - handles connection lifecycle - SQL plugins should extend
GormPluginbase class (core/src/plugins/gorm/plugin.go) - When adding plugin functionality: add to
PluginFunctionsinterface, implement in each plugin - Use
ErrorHandler(core/src/plugins/gorm/errors.go) for user-friendly error messages - Never log sensitive data (passwords, API keys, tokens, connection strings)
envpackage is for pure env var declarations only (nologimport). Functions that parse env vars and needlogfor error reporting go inenvconfig- Delete build binaries after testing (
go buildartifacts)
- Use PNPM, not NPM. Use pnpx, not npx
- Define GraphQL operations in
.graphqlfiles, then runpnpm run generate - Import generated hooks from
@graphqlalias - never use inlinegqlstrings - Keyboard shortcuts are centralized in
frontend/src/utils/shortcuts.ts. Never hardcode shortcut keys inline — useSHORTCUTS.*for definitions,matchesShortcut()for event handling, andSHORTCUTS.*.displayKeysfor UI display. Platform-variant shortcuts (nav numbers) useresolveShortcut(). Some shortcuts also have Wails accelerators indesktop-common/app.gothat must be updated separately
Use core/go.mod as the reference point for dependency versions.
See .claude/docs/commands.md for full reference.
# Backend: cd core && go run ./cmd/whodb
# Frontend: cd frontend && pnpm start
# CLI: cd cli && go run .- Plugin self-registration — each plugin has
init() { engine.RegisterPlugin(...) }. The entry point's blank imports control which plugins are registered - Source-first public API — new public GraphQL/frontend work should use
SourceTypes,SourceProfiles,SourceFieldOptions,SourceSessionMetadata,SourceObjects,SourceRows,RunSourceQuery, andSourceGraph. Do not add new publicDatabase*queries or capability surfaces - AppConfig DI —
core/src/app/app.godefinesAppConfig(schema, HTTP handlers). The entry point callsapp.Run(config, staticFiles) - Frontend registries — components (
registerComponent), source types (registerSourceTypeOverrides), icons (registerIcons), and source utilities (registerSourceUtilities) can be registered at boot. The frontend renders from registries — if something isn't registered, it's not shown - Import cycle note —
src→router→graph→srccycle exists.Run()lives insrc/app/(notsrc/) to avoid it. Never add router/graph imports tosrc/
- Clean, readable code over clever code
- Keep every changed line tied directly to the user's request
- Only add what is required - no overengineering
- Prefer existing style and local helper APIs over new abstractions
- Do not modify existing functionality without justification
- Do not rename variables/files unless necessary
- Remove unused code introduced by your changes - no leftovers
- Do not delete unrelated dead code unless asked
- Only comment edge cases and complex logic, not obvious code
- Ask questions to understand requirements fully
- Use subagents to accomplish tasks faster
- Maintain professional, neutral tone without excessive enthusiasm
- When you finish a task, go back and check your work. Check that it is correct and that it is not over-engineered