This file provides guidance to agents when working with code in this repository.
# Install all dependencies (root + workspaces, rebuilds native modules)
npm run install:all
# Development
npm run dev:backend # Backend on port 3000 (tsx watch)
npm run dev:frontend # Frontend dev server on port 5173
npm run dev:fullstack # Build frontend + serve everything from backend
# Build
npm run build # Build both frontend and backend
# Testing
npm run test # Run all tests (backend + frontend, no-watch)
npm run test --workspace=backend # Backend tests only
npm run test --workspace=frontend # Frontend tests only
npm run test:watch --workspace=backend # Backend watch mode
npm run test:e2e # Playwright E2E tests
npm run test:e2e:ui # Playwright with UI mode
npm run test:e2e:headed # Playwright in headed (visible) browser
npm run test:e2e:debug # Playwright debug mode
# Pre-commit hooks
npm run setup:hooks # Install pre-commit hooks
npm run precommit # Run pre-commit checks manually
# Run a single test file
cd backend && npx vitest run test/unit/SomeService.test.ts
# Linting
npm run lint # Lint both workspaces (0 warnings allowed)
npm run lint:fix # Auto-fix lint issuesBackend uses tsx watch for hot-reload during development. The frontend dev server proxies API calls to the backend.
Pabawi is an infrastructure management web UI — a monorepo with a Node.js/Express/TypeScript backend and a Svelte 5 SPA frontend.
All infrastructure integrations (Bolt, PuppetDB, Puppetserver, Hiera, Ansible, SSH, AWS, Azure, Proxmox) are plugins declared in backend/src/plugins/registry.ts. Every plugin:
- Extends
BasePlugin(integrations/BasePlugin.ts) and implementsisEnabled(),initialize(),healthCheck() - Optionally implements
ExecutionToolPlugin(can run commands) orInformationSourcePlugin(provides inventory/facts) - Is registered with
IntegrationManager(integrations/IntegrationManager.ts), which handles lifecycle, health aggregation, and routes data requests to the correct plugin
The plugin registry (plugins/registry.ts) is a declarative array of PluginRegistryEntry objects. server.ts iterates this array in a single loop — no per-plugin init blocks. Each entry has resolveConfig() (returns null to skip) and create() (factory).
IntegrationManager is the central registry. When inventory or facts are requested, it fans out to all enabled InformationSourcePlugins and merges results using a priority system (SSH: 50, Bolt: 5, PuppetDB: 10, Puppetserver: 8, Ansible: 5, Hiera: 6, Proxmox/AWS/Azure: 7). When executing commands, it dispatches to the correct ExecutionToolPlugin.
server.ts— Express app init, DI container setup, plugin registry loop, middleware wiring, route factory mountingcontainer/—DIContainerclass with typedServiceRegistryinterface (logger, config, expertMode). Route factories receive the container and resolve services from itplugins/—registry.tsdeclares all integration plugins as aPluginRegistryEntry[]array withresolveConfig()andcreate()per entryconfig/—ConfigServicewraps all env vars with Zod validation; always use this, neverprocess.envdirectly. Secrets:JWT_SECRET(required),PABAWI_LIFECYCLE_TOKEN(optional, defaults to empty)integrations/<name>/— One directory per integration:<Name>Plugin.ts(lifecycle + routing) and<Name>Service.ts(business logic, CLI spawning, API calls)mcp/— MCP (Model Context Protocol) server: read-only infrastructure query interface for LLM clients.McpServer.ts(factory + RBAC gates),McpToolHandlers.ts(11 tools:inventory_list,facts_get,facts_bulk,reports_query,catalogs_get,hiera_lookup,executions_list,integrations_list,journal_query,monitoring_services_get,monitoring_events_get),McpOutputSummariser.ts(strips verbose fields for LLM-friendly output),McpServiceUser.ts(idempotent provisioning of themcp-serviceuser). Enabled viaMCP_ENABLED=true; session-based HTTP transport atPOST/GET/DELETE /mcp.services/— Cross-cutting services:ExecutionQueue(concurrent limiting, FIFO),StreamingExecutionManager(SSE real-time output),CommandWhitelistService(security),DatabaseService,AuthenticationService,BatchExecutionService,JournalService(audit trail of infrastructure events),AuditLoggingService(user-action audit log),PuppetRunHistoryService(persists Puppet run history),NodeLinkingService(correlates the same node across integration sources),ExpertModeService(debug/verbose UI toggle), and RBAC services (UserService,RoleService,PermissionService,GroupService)routes/— Express route factories. All exportcreateXxxRouter(container)functions. All async handlers wrapped withasyncHandler()fromutils/middleware/— Auth (JWT), RBAC, error handler, rate limiting, security headers,deduplication.ts(request deduplication)database/—DatabaseService.ts(migration-first approach),ExecutionRepository.ts(CRUD for execution history). All schema inmigrations/*.sql. Multi-database support via adapter pattern:DatabaseAdapter.ts(interface),SQLiteAdapter.ts(default),PostgresAdapter.ts(optional),AdapterFactory.ts(selects adapter from config) — useDatabaseService, never instantiate adapters directly.types/— Shared type declarations (express.d.tsfor request augmentation,mcp-sdk.d.tsfor MCP SDK types)errors/— Typed error classes extending base classes; use these instead of genericErrorvalidation/— Zod schemas for request body validation
Bolt command output is parsed from JSON; both _output and _error fields must be extracted from failed task results. Inventory and facts are cached (30 s and 5 min TTL respectively) inside each plugin's service.
App.svelte— Root: initializes router, auth guard, and setup checkpages/— One Svelte component per page routecomponents/— Shared UI componentslib/— Core utilities and reactive state:router.svelte.ts— Client-side router using Svelte 5 runes ($state)auth.svelte.ts— JWT auth stateapi.ts— HTTP infrastructure (get, post, put, del) with retry logic and error handlingproxmoxApi.ts— Proxmox provisioning API functionsawsApi.ts— AWS EC2 API functionsazureApi.ts— Azure VM API functionsexecutionStream.svelte.ts— SSE client for real-time command output (SSE-first, single-fetch fallback)expertMode.svelte.ts— Debug info toggleintegrationColors.svelte.ts— Per-integration color constantstoast.svelte.ts— Notification system
The frontend uses Svelte 5 runes throughout ($state(), $effect(), $derived()). State that needs to persist across components lives in the lib/*.svelte.ts files as module-level rune state.
All configuration is via backend/.env. Run scripts/setup.sh for interactive setup. Key variable groups: PORT/HOST/LOG_LEVEL, JWT_SECRET (required), PABAWI_LIFECYCLE_TOKEN (optional), BOLT_*, PUPPETDB_*, PUPPETSERVER_*, HIERA_*, ANSIBLE_*, SSH_*, AWS_*, AZURE_*, PROXMOX_*, COMMAND_WHITELIST*, CACHE_*, CONCURRENT_EXECUTION_LIMIT, MCP_ENABLED.
See docs/configuration.md for the full reference. Other useful docs: docs/mcp.md (MCP setup and tools), docs/permissions-rbac.md (RBAC model), docs/architecture.md (system overview), docs/api.md (REST API reference), docs/integrations/ (per-integration guides).
- Backend tests live in
backend/test/(unit, integration, security, middleware, properties with fast-check) - Frontend tests co-located with source in
frontend/src/**/*.test.ts - E2E tests in
e2e/using Playwright - Database tests use in-memory SQLite
- Use
supertestfor HTTP route testing in backend
Use LoggerService everywhere — never console.log. Pass structured metadata: { component, integration, operation }.
KiroGraph builds a local semantic knowledge graph of this codebase. When the kirograph MCP server is available, prefer its tools over broad grep/glob/file-read exploration.
- Start code tasks with
kirograph_context. - Find symbols by name with
kirograph_search. - Inspect a symbol with
kirograph_node; setincludeCode: trueonly when source is needed. - Trace call flow with
kirograph_callersandkirograph_callees. - Check blast radius before edits with
kirograph_impact. - Use
kirograph_pathto explain how two symbols connect. - Use
kirograph_type_hierarchyfor inheritance/interface questions. - Use
kirograph_filesto inspect indexed file structure. - Use
kirograph_statusif results seem stale or incomplete. - Use
kirograph_architecture,kirograph_coupling, andkirograph_packagefor package/layer questions when architecture analysis is enabled. - Use
kirograph_hotspots,kirograph_surprising, andkirograph_difffor refactor planning and review.
- Call
kirograph_contextfor orientation. - Drill into specific symbols with
kirograph_node. - Use graph traversal tools before reading unrelated files.
- Fall back to normal filesystem tools only when the graph is missing, stale, or lacks the needed detail.
If .kirograph/ does not exist, ask whether to run kirograph init --index.