14 KiB
Copilot Instructions for Uptime Kuma
Warning: Only maintainers of Uptime Kuma can use these instructions. Other contributors must read AGENTS.md and CLAUDE.md. If the git user name does not match a maintainer (see the "For Maintainers" section in AGENTS.md), ignore this file to avoid being banned for AI slop.
Copilot's Goals/Tasks
- Check spelling
- Do not show "Pull Request Overview"
- You do not have to reply if there are no issues
Keep These Instructions in Sync
- If a PR/commit changes anything documented here (commands, paths, architecture, test files, workflows), update the related content in this file in the same PR/commit, so it does not drift.
- User-facing docs live in the separate uptime-kuma-wiki repo: if a change affects documented behavior (env vars, CLI, config, setup), update the wiki as well.
Repository Overview
Uptime Kuma is a self-hosted monitoring tool for HTTP(s), TCP, DNS, Docker, etc. Built with Vue 3 (frontend) and Node.js/Express (backend), using Socket.IO for real-time communication.
- Languages: JavaScript, TypeScript, Vue 3, HTML, CSS/SCSS
- Backend: Node.js >= 26.2.0, Express.js, Socket.IO, SQLite (also MariaDB/MySQL), Better Auth
- Frontend: Vue 3, Vite, Bootstrap 5, Chart.js
- Package Manager: npm with
legacy-peer-deps=trueandmin-release-age=7(.npmrc)
Build & Validation Commands
Prerequisites
- Node.js >= 26.2.0 (see
enginesin package.json; CI runs Node 26), a recent npm, Git
Essential Command Sequence
-
Install Dependencies:
npm ci # Use npm ci NOT npm install -
Linting (required before committing):
npm run lint # ESLint + Stylelint npm run lint:prod # For production (zero warnings) -
Build Frontend:
npm run build # Builds to dist/ -
Run Tests:
npm run test-backend # Backend unit tests (node:test, run through tsx) npm test # Backend + Playwright E2E npm run coverage # Backend suite + HTML report at private/coverage/backend/index.html
Development Workflow
npm run dev # Frontend on port 3000, backend on port 3001
Project Architecture
Directory Structure
/
├── server/ Backend source code
│ ├── model/ Database models (auto-mapped to tables)
│ ├── monitor-types/ Monitor type implementations
│ ├── notification-providers/ Notification integrations
│ ├── routers/ Express routers
│ ├── socket-handlers/ Socket.IO event handlers
│ ├── modules/ Shared backend modules
│ ├── util/ Backend utilities
│ ├── server.js Server entry point (executed via tsx)
│ ├── uptime-kuma-server.ts Main server logic
│ └── better-auth.ts Authentication (Better Auth)
├── src/ Frontend source code (Vue 3 SPA)
│ ├── components/ Vue components
│ ├── pages/ Page components
│ ├── lang/ i18n translations
│ ├── router.js Vue Router configuration
│ └── main.js Frontend entry point
├── db/ Database related
│ ├── knex_migrations/ Knex migration files
│ └── kuma.db SQLite database
├── test/ Test files
│ ├── backend-test/ Backend unit tests (.ts and .js)
│ └── e2e/ Playwright E2E tests
├── vite.config.mjs Vite build/dev config
├── playwright.config.js Playwright test config
├── tsconfig.json TypeScript config
├── dist/ Frontend build output (gitignored)
├── data/ App data directory (gitignored)
├── public/ Static frontend assets
├── docker/ Docker build files
└── extra/ Utility scripts
Backend Architecture
server/model/— RedBean models mapped to tables.monitor.jsholds the monitor loop and handles the core types inline:http,keyword,json-query,push,docker,radius,kafka-producer.server/monitor-types/— one class per monitor type, registered inserver/uptime-kuma-server.ts(monitorTypeList).server/notification-providers/— one file per provider (110+), registered inserver/notification.js.server/socket-handlers/— Socket.IO event handlers (most of the real-time API surface).server/routers/— Express routers:api-router.js(push/REST API, API-key auth),mcp-router.ts(/mcp, MCP tools bridged from the documented routes),status-page-router.js,better-auth-router.ts.server/modules/,server/util/,server/utils/knex/— shared helpers.server/better-auth.ts+src/auth-client.ts— authentication (Better Auth, v3).
Key Configuration Files
- package.json: Scripts, dependencies, Node.js version requirement
- .eslintrc.js: ESLint rules (4 spaces, double quotes, JSDoc required)
- .stylelintrc: Stylelint rules (4 spaces indentation)
- .editorconfig: Editor settings (4 spaces, LF, UTF-8)
- tsconfig.json: TypeScript config
- .npmrc:
legacy-peer-deps=true,min-release-age=7 - .gitignore: Excludes node_modules, dist, data, tmp, private
Code Style (strictly enforced by linters)
- 4 spaces indentation, double quotes, Unix line endings (LF), semicolons required
- Prettier enforces
printWidth: 120; runnpm run fmtto format (also run automatically in CI) - Comments: keep them short (one concise line explaining what/why); no multi-line essays or restating the code
- Commits: one short sentence describing the change; no long body
- Naming: JavaScript/TypeScript (camelCase), SQLite (snake_case), CSS/SCSS (kebab-case)
- New code: new files and modules are TypeScript (
*.ts) with Zod validation for external/DB input; leave existing JavaScript files in JS unless that file is being converted for a reason - JSDoc is required on every function declaration and method (
jsdoc/require-jsdoc);*.tsrelaxes some JSDoc andanyrules - Notable ESLint rules:
no-var,one-var: never,max-statements-per-line: 1,jsdoc/require-throws - Module system: no
"type": "module"in package.json —*.jsis CommonJS (require),*.mjs/*.mtsare ESM, and*.tsis executed viatsx
CI/CD Workflows
auto-test.yml (push to master/1.23.X/3.0.X and every PR):
- Builds and runs backend tests on macOS, Ubuntu, Windows, and Ubuntu arm (Node 26)
check-lintersrunsnpm run lint:prodon Node 24e2e-testrunsnpm run buildthennpm run test-e2e(Playwright)
validate.yml (pushes to master, PRs to master/1.23.X/3.0.X):
- Validates JSON/YAML files and runs
extra/check-lang-json.js,extra/check-knex-filenames.mjs,extra/check-package-json.mjs
PR Requirements: All linters pass, tests pass, code follows style guidelines
After Opening a PR: Watch CI to completion and report failures.
Committing and Pushing: Never commit or push without the user's confirmation.
Merging: Never merge without the user's confirmation.
Release & Post-release Checks
Releases are cut with the Release workflow (.github/workflows/release.yml), not npm run release-final (that local orchestrator needs a running Docker and is the older path).
- Dispatch it from
master, not2.5.X: master's workflow checks out2.5.Xand setsRELEASE_BASE_BRANCH=2.5.X. 2.5.X's copy has a 6thupdate-wikijob; master's copy does not, so a run dispatched from master never bumps the wiki.- Inputs:
version,previous_version(previous tag),is_beta,dry_run.
After it succeeds, check in this order:
- Release:
gh release view <version> --json isDraft,publishedAt,assetsis not a draft, hasdist.tar.gz, andgit/ref/tags/<version>points at the squash merge commit on2.5.X. - Changelog: generated from PRs only. Base-image work (Node.js version, CA store) is not a PR, so add it by hand with
gh release edit <version> --notes-file notes.mdbefore publishing. - Docker Hub:
<version>,<version>-slim,<version>-rootless,<version>-slim-rootless, plus the aliases2,2-slim,2-rootless,next,next-slim,next-rootlessall point at the new build. - Node.js inside the images:
docker run --rm --entrypoint node louislam/uptime-kuma:<version> -p process.versions.nodematches the base image (louislam/uptime-kuma:base2) on amd64, arm64 and arm/v7. - App version:
package.jsonon2.5.Xis<version>; the server sends it over Socket.IO asinfo.version(server/client.js) and asUser-Agent: Uptime-Kuma/<version>(server/uptime-kuma-server.ts). There is no/api/versionroute. - Wiki:
🆙-How-to-Update.mdmust containgit checkout <version> --force. If theupdate-wikijob did not run, runRELEASE_VERSION=<version> GITHUB_TOKEN=<token> node extra/release/update-wiki.mjs. - Demo server:
npm run deploy-demo-server; https://uptime.kuma.pet should report<version>. - Healthcheck: if
extra/healthcheck.gochanged, rebuildlouislam/uptime-kuma:builder-go(npm run build-docker-builder-go) before releasing. master's install pin: the release's "Update to<version>" commit bumpsversionand thesetupscript on2.5.Xonly, somaster'spackage.jsonstill has"setup": "git checkout <previous version> ...". Bump that one line to<version>onmaster, otherwisenpm run setupon master keeps installing the old release.
CONTRIBUTING's manual list still applies: clean Docker install on amd64/arm64/armv7 and a clean Node.js install.
Common Issues
- npm install vs npm ci: Always use
npm cifor reproducible builds - Stylelint warnings: Deprecation warnings are expected, ignore them
- E2E tests: Run
npm run buildbeforenpm run test-e2ein a clean checkout (or usenpm run test-e2e-local) - Port conflicts: Dev server uses ports 3000 (frontend) and 3001 (backend)
- First run: Server shows "db-config.json not found" - this is expected, starts setup wizard
Translations
- Managed via Weblate. Add keys to
src/lang/en.jsononly - Don't include other languages in PRs
- Use
$t("key")in Vue templates
Database
- Primary: SQLite (also supports MariaDB/MySQL)
- Migrations in
db/knex_migrations/using Knex.js; filenames areYYYY-MM-DD-HHMM-description.js(migration behavior is covered bytest/backend-test/test-migration.js) - Filename format validated by CI:
node ./extra/check-knex-filenames.mjs - v3 uses Better Auth for authentication
Testing
- Backend: Node.js test runner via tsx (
test/backend-test/**/*.{ts,js}). Usedescribe()/test()fromnode:testand one test per scenario (seetest/backend-test/README.md).npm run test-backendalso prints a coverage summary via--experimental-test-coverage. - TDD: write the failing test first (red), watch it fail, implement the change, then confirm green before committing.
- No stubbed tests: never fake the module, process or command under test. Run the real code path; if an external binary is missing, skip the test (
commandExists.sync) instead of stubbing. Stub-based tests are not accepted. - Coverage:
npm run coverageruns the backend suite and writes an HTML report toprivate/coverage/backend/index.html(e2e coverage is not collected). - Database monitor tests use Testcontainers;
npm run test-e2e-localsetsSKIP_TESTCONTAINER=1to skip them. - E2E: Playwright specs in
test/e2e/specs/*.spec.js;setup-process.once.jsis a one-time setup project every spec depends on. Requiresnpx playwright install. - E2E error guard: specs import
test/expectfromtest/e2e/fixtures.js, which fails a test when the page throws an uncaught error or logs an unexpected console error (failed network loads are ignored). - Test data lives in
data/playwright-test; reports go toprivate/playwright-report.
Adding New Features
New Notification Provider
There are 110+ existing providers in server/notification-providers/; copy an existing one as a template.
Files to modify:
server/notification-providers/PROVIDER_NAME.js(backend logic)server/notification.js(register provider)src/components/notifications/PROVIDER_NAME.vue(frontend UI)src/components/notifications/index.js(register frontend)src/components/NotificationDialog.vue(add to list)src/lang/en.json(add translation keys)
New Monitor Type
Core types (http, keyword, json-query, ping, push, docker, radius, kafka-producer) are handled inline in server/model/monitor.js. All other types are MonitorType subclasses in server/monitor-types/ registered via UptimeKumaServer.monitorTypeList in server/uptime-kuma-server.ts.
Files to modify:
server/monitor-types/MONITORING_TYPE.js(backend logic)server/uptime-kuma-server.ts(register monitor type)src/pages/EditMonitor.vue(frontend UI)src/lang/en.json(add translation keys)
Important Notes
- Trust these instructions - Search only if incomplete/incorrect
- Dependencies: Run
npm run audit(npm audit --omit=dev) instead of relying on a fixed vulnerability list - Git Branches:
master(v3 development),3.0.X(v3 release),2.5.X(v2),1.23.X(v1) - Node Version: >= 26.2.0 required
- Socket.IO: Most backend logic in
server/socket-handlers/, not REST. When an action only pushes data one way (no ack, e.g.info), serve it from an Express router and call the shared function; add a socket handler only when the API needs a request/response round-trip. - Docker:
docker/+compose.yaml; image tags use the3suffix (base3,nightly3,pr-test3) - Never commit:
data/,dist/,tmp/,private/,node_modules/