umputun/remark42
comment engine
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1d ago
- ✓16 active contributors
- ✓Distributed ownership (top contributor 42% of recent commits)
Show all 6 evidence items →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/umputun/remark42)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/umputun/remark42 on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: umputun/remark42
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/umputun/remark42 shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 1d ago
- 16 active contributors
- Distributed ownership (top contributor 42% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live umputun/remark42
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/umputun/remark42.
What it runs against: a local clone of umputun/remark42 — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in umputun/remark42 | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of umputun/remark42. If you don't
# have one yet, run these first:
#
# git clone https://github.com/umputun/remark42.git
# cd remark42
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of umputun/remark42 and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "umputun/remark42(\\.git)?\\b" \\
&& ok "origin remote is umputun/remark42" \\
|| miss "origin remote is not umputun/remark42 (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "backend/app/main.go" \\
&& ok "backend/app/main.go" \\
|| miss "missing critical file: backend/app/main.go"
test -f "backend/app/cmd/server.go" \\
&& ok "backend/app/cmd/server.go" \\
|| miss "missing critical file: backend/app/cmd/server.go"
test -f "backend/app/migrator/migrator.go" \\
&& ok "backend/app/migrator/migrator.go" \\
|| miss "missing critical file: backend/app/migrator/migrator.go"
test -f "backend/app/notify/notify.go" \\
&& ok "backend/app/notify/notify.go" \\
|| miss "missing critical file: backend/app/notify/notify.go"
test -f "backend/_example/memory_store/main.go" \\
&& ok "backend/_example/memory_store/main.go" \\
|| miss "missing critical file: backend/_example/memory_store/main.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/umputun/remark42"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Remark42 is a self-hosted comment engine written in Go with a TypeScript/React frontend that can be embedded into any website without external databases. It provides multi-level nested comments, social/email authentication (Google, Facebook, GitHub, etc.), markdown support, moderation tools, voting, and notifications—all in a single Docker container with an embedded BBolt database. Classic monorepo: /backend contains the Go server (cmd, app, storage modules), /frontend or similar holds TypeScript/React UI (based on TS file count: 415KB), and /backend/_example/memory_store provides a reference implementation. Data layer uses go.etcd.io/bbolt for persistence. CI split by component (.github/workflows/ci-backend.yml, ci-frontend.yml, ci-site.yml) reflects separation of concerns.
👥Who it's for
Blog owners, CMS integrators, and site operators who want a privacy-focused comment system they control completely, without relying on third-party services like Disqus. Also relevant for developers building embedded comment widgets or integrating comments into custom web applications.
🌱Maturity & risk
Production-ready. The project has multiple CI/CD pipelines (.github/workflows/), comprehensive Docker setup, active test suites across backend (.go files with _test.go companions), and a clear versioning scheme. The monorepo structure with both backend and frontend indicates sustained maintenance, though commit recency should be verified against GitHub activity.
Low-to-moderate risk. Single-maintainer concern (umputun) is evident from GitHub structure, but no major red flags in dependency count—modern Go module hygiene with selective imports (go-pkgz, testify, bbolt). The embedded database approach (BBolt) eliminates external service dependencies, reducing operational risk. Main risk: custom OAuth2 providers require careful configuration, and multi-site mode adds complexity.
Active areas of work
Unable to determine from static file list—check GitHub Actions tab for recent workflow runs and GitHub Issues/PRs. The presence of dependabot.yml (.github/dependabot.yml) indicates active dependency maintenance. Frontend (415KB TypeScript) and backend (1MB+ Go) both appear actively developed based on code volume.
🚀Get running
Clone: git clone https://github.com/umputun/remark42.git && cd remark42. For backend: cd backend && go mod download && go run ./app/cmd. For frontend: likely npm install && npm start or yarn (infer from TS/JS presence). Docker: docker-compose up (Dockerfile and compose files present). Full setup: see backend/README.md and contribution docs referenced in main README.
Daily commands:
Backend dev: cd backend && make build or go run ./app/cmd (see Makefile patterns). Frontend dev: npm install && npm start or check frontend package.json. Full stack: docker-compose up or docker-compose -f backend/_example/memory_store/compose-dev-memstore.yml up. Tests: make test (Makefile present) or go test ./....
🗺️Map of the codebase
backend/app/main.go— Entry point for the entire Remark42 backend application; sets up the core server and initializes all major componentsbackend/app/cmd/server.go— Configures the HTTP server, registers API routes, and orchestrates middleware; essential for understanding request routingbackend/app/migrator/migrator.go— Core migration framework supporting imports from Disqus, WordPress, and other comment engines; critical for data integration pathsbackend/app/notify/notify.go— Notification dispatch system handling email, Slack, Telegram, and webhooks; central to user engagement featuresbackend/_example/memory_store/main.go— Reference implementation of a custom data accessor; shows how to extend Remark42 with alternative storage backendsbackend/.golangci.yml— Linter configuration defining code quality standards and project-wide Go conventionsMakefile— Build automation for backend, frontend, and Docker images; required for local development and CI/CD understanding
🛠️How to make changes
Add a new notification channel
- Create a new notifier struct in
backend/app/notify/following the interface defined innotify.go(backend/app/notify/notify.go) - Implement
Notify(ctx context.Context, req Request) errormethod for your channel (e.g., WebEx, Matrix, Discord) (backend/app/notify/<channel>.go) - Register the notifier in the dispatcher's init logic within the notify package constructor (
backend/app/notify/notify.go) - Add channel-specific configuration flags to
backend/app/cmd/server.gofor CLI argument parsing (backend/app/cmd/server.go) - Add unit tests in
<channel>_test.gocovering success, rate-limit, and network-error scenarios (backend/app/notify/<channel>_test.go)
Add support for a new comment platform import
- Create a new importer in
backend/app/migrator/implementing theImporterinterface frommigrator.go(backend/app/migrator/migrator.go) - Implement parsing logic to extract comments from the source platform's export format (XML, JSON, CSV) (
backend/app/migrator/<platform>.go) - Use the
Mapperutility inmapper.goto normalize external comment data into Remark42 Comment struct (backend/app/migrator/mapper.go) - Add test cases with sample export data in
backend/app/migrator/testdata/(backend/app/migrator/<platform>_test.go) - Register the importer in
backend/app/migrator/migrator.gowithin the available importers list (backend/app/migrator/migrator.go)
Implement a custom data storage backend
- Study the reference in-memory store in
backend/_example/memory_store/accessor/to understand the data accessor interface (backend/_example/memory_store/accessor/data.go) - Create a new package (e.g.,
backend/app/store/mongodb/) implementingDataAccessorandAdminAccessorinterfaces (backend/_example/memory_store/accessor/data.go) - Implement CRUD operations:
Create,Update,Get,List,Deletefor comments with proper indexing for query performance (backend/_example/memory_store/accessor/data.go) - Add admin operations:
SetBlock,SetVerified,Delete,DeleteByUserfor moderation workflows (backend/_example/memory_store/accessor/admin.go) - Integrate the accessor into server initialization in
backend/app/cmd/server.govia dependency injection (backend/app/cmd/server.go)
Add a new CLI maintenance command
- Create a new file in
backend/app/cmd/following the pattern ofbackup.goorcleanup.go(backend/app/cmd/backup.go) - Implement a command struct with flags using jessevdk/go-flags tags for CLI parsing (
backend/app/cmd/cmd.go) - Register the command in the
Execute()dispatcher withinbackend/app/cmd/cmd.go(backend/app/cmd/cmd.go) - Add comprehensive tests in
<command>_test.gocovering success paths and error handling (backend/app/cmd/<command>_test.go)
🔧Why these technologies
- Go (backend) — Lightweight, single-binary deployment; low memory footprint ideal for embeddable comment engine;
🪤Traps & gotchas
- Multi-site mode requires careful URL routing and tenant isolation in config—see cmd.go for site-specific flags
- OAuth2 provider setup is non-trivial; each provider (Google, Facebook, GitHub, etc.) needs separate credentials passed as environment variables or flags
- BBolt database is file-based and not networked; if horizontal scaling is needed, data synchronization must be handled externally
- Email/Telegram/Slack notifications require SMTP or API credentials; missing these will cause silent failures or panics—check error handling in notifier modules
- TypeScript frontend must be built before Docker image creation (see Dockerfile.artifacts); frontend changes require npm build step
- Admin interface security depends on auth middleware—misconfiguration could expose moderation panel; always review auth setup in cmd.go
🏗️Architecture
💡Concepts to learn
- Embedded Database (BBolt/BoltDB) — Remark42 uses go.etcd.io/bbolt for single-file, zero-dependency persistence; understanding B+tree structure and transaction semantics is critical for storage reliability and backups
- Multi-tenant Architecture — Remark42 supports multi-site mode from a single instance; requires understanding site isolation, tenant routing, and data partitioning in a shared database
- OAuth2 and Social Login Flow — The system integrates with 9+ OAuth2 providers (Google, Facebook, GitHub, etc.); understanding grant flows and token handling is essential for auth troubleshooting
- Nested Comment Trees (Adjacency List / Materialized Path) — Remark42 supports multi-level nested comments with efficient query/render patterns; storage implementation requires understanding tree traversal and indexing strategies
- Webhook and Push Notifications — The system sends async notifications via email, Telegram, Slack, and webhooks; understanding event-driven architecture and retry logic prevents notification loss
- Go RPC (via go-pkgz/jrpc) — Backend exposes RPC endpoints for frontend communication; go-pkgz/jrpc is the transport layer; understanding JSON-RPC protocol is needed for API debugging
- Markdown Rendering and HTML Sanitization — Comments support markdown with bluemonday sanitization to prevent XSS; blackfriday parses markdown; understanding safe HTML generation is critical for security
🔗Related repos
gogs/gogs— Self-hosted Git service with embedded user management and comment-like discussion features; shares Go backend + embedded DB philosophydiscourse/discourse— Full-featured forum engine; primary commercial alternative to Remark42 but requires Rails/PostgreSQL; represents the heavyweight comparisoncommento/commento— Lightweight privacy-focused comment system similar in scope to Remark42; Go backend, embeddable widget, direct competitor in self-hosted spacego-pkgz/lgr— Logging library used by Remark42 (in go.mod); understand the logging patterns for debugging backend issuesetcd-io/bbolt— The embedded KV database used by Remark42 for all persistence; understanding BBolt internals is essential for storage optimization
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for memory_store example implementation
The backend/_example/memory_store directory contains a full working example of the remark42 backend with in-memory storage, but lacks comprehensive integration tests. Currently, only unit tests exist for individual components (admin_test.go, data_test.go, image_test.go, rpc_test.go). A new integration test suite would validate the complete request/response flow, ensuring the example remains functional as the main backend evolves. This directly supports new contributors who use the example to understand the architecture.
- [ ] Create backend/_example/memory_store/integration_test.go with full server lifecycle tests
- [ ] Add tests for admin operations (create comment, delete, approve) through the RPC server
- [ ] Add tests for data operations (list comments, get thread) through the RPC server
- [ ] Add tests for image upload/retrieval workflows
- [ ] Ensure integration tests are isolated and don't share state between test cases
Add E2E test coverage for Apple and custom OAuth flows
The repo has e2e-tests.yml workflow but the codebase shows Apple OAuth certificates in testdata (apple.p8, apple-bad.p8) and custom OAuth support. The incomplete README mentions 'custom OAu' (appears truncated). There's no evidence of E2E tests validating the Apple and custom OAuth login flows specifically. Adding E2E test scenarios would ensure these authentication methods work end-to-end and catch regressions early.
- [ ] Review .github/workflows/e2e-tests.yml to understand current test structure
- [ ] Add E2E test scenario for Apple OAuth sign-in flow using backend/app/cmd/testdata/apple.p8
- [ ] Add E2E test scenario for custom OAuth provider configuration and login
- [ ] Document test setup requirements for Apple OAuth (developer account, certificates) in backend/README.md
- [ ] Ensure tests run in CI without exposing sensitive credentials
Add missing unit tests for backup, restore, and import commands
The backend/app/cmd directory has cmd files for backup.go, restore.go, and import.go with corresponding test files, but based on the file structure, there appear to be complex operations (import.txt, import.txt.gz in testdata) that may not have full coverage. These critical data operations need thorough testing to prevent data loss. Adding comprehensive tests for edge cases (corrupted files, malformed data, concurrent operations) would improve reliability.
- [ ] Review backend/app/cmd/backup_test.go and identify missing test cases (e.g., large comment sets, special characters, concurrent backups)
- [ ] Review backend/app/cmd/restore_test.go and add tests for corrupted backup files and partial restore scenarios
- [ ] Review backend/app/cmd/import_test.go and add tests for both plain and gzip-compressed import files, malformed entries, and duplicate comment handling
- [ ] Add test fixtures in backend/app/cmd/testdata for edge cases (empty imports, invalid formats, encoding issues)
- [ ] Ensure tests validate data integrity before and after import/restore operations
🌿Good first issues
- Add unit tests for backend/app/cmd/avatar.go and avatar_test.go—these files appear to handle avatar management but test coverage is uncertain; inspect the current test structure and add missing edge cases (invalid URLs, missing images, cache behavior)
- Document the OAuth2 provider configuration process—create a guide mapping each provider (Google, GitHub, Facebook, Yandex, Discord, Telegram, Apple, Patreon) to required environment variables and callback URL format; place in docs/ or CONTRIBUTING.md
- Implement TypeScript strict mode linting—with 415KB of TypeScript, enforce stricter null/undefined checks by adding
strict: trueto tsconfig.json and fix resulting type errors incrementally in the frontend codebase
⭐Top contributors
Click to expand
Top contributors
- @paskal — 42 commits
- @umputun — 25 commits
- @dependabot[bot] — 18 commits
- @diosfera — 2 commits
- @up9cloud — 2 commits
📝Recent commits
Click to expand
Recent commits
c0636f2— Merge pull request #2053 from umputun/dependabot/github_actions/github-actions-updates-512a575e1a (umputun)c418f8e— Merge pull request #2052 from umputun/dependabot/go_modules/backend/go-modules-updates-47fdc5c9f4 (umputun)e9ad5dc— chore(deps): bump the go-modules-updates group (dependabot[bot])d072f34— chore(deps): bump pnpm/action-setup in the github-actions-updates group (dependabot[bot])a4c5e17— Probe /auth/status from frontend to avoid 401 on /user (closes #1188) (#1763) (paskal)8d9290e— Bump picomatch from 2.3.1 to 2.3.2 in /site (#2028) (dependabot[bot])07d8920— chore(deps): bump liquidjs from 10.19.0 to 10.25.6 in /site (#2050) (dependabot[bot])5d65992— Bump the github-actions-updates group across 1 directory with 7 updates (#2034) (dependabot[bot])b13b737— Bump handlebars from 4.7.8 to 4.7.9 in /site (#2030) (dependabot[bot])c9ba852— fix(auth): close OAuth open-redirect by wiring AllowedRedirectHosts (#2049) (paskal)
🔒Security observations
The remark42 codebase has moderate security concerns primarily related to outdated dependencies and runtime environments. The most critical issues are: (1) Node.js 16 EOL base image requiring
- High · Outdated Node.js Base Image —
Dockerfile, line 1. The Dockerfile uses node:16.20-alpine as the base image. Node.js 16 reached end-of-life on September 11, 2023. Using outdated Node.js versions exposes the application to known security vulnerabilities that will not receive patches. Fix: Upgrade to Node.js 18 LTS or 20 LTS (e.g., node:20-alpine). Ensure all dependencies are compatible with the newer version. - High · Outdated pnpm Package Manager Version —
Dockerfile, pnpm installation line. The Dockerfile pins pnpm to version 8, which may contain known vulnerabilities. Package manager versions should be kept current to ensure secure dependency resolution. Fix: Update to the latest stable pnpm version (currently v9.x). Review pnpm changelog for security fixes between version 8 and the latest release. - Medium · Incomplete Dockerfile Build Instructions —
Dockerfile, build-frontend stage (incomplete). The Dockerfile snippet provided is incomplete (cuts off mid-line in the build-frontend stage). This makes it difficult to verify the complete build process for security issues such as layer caching, build argument injection, or insecure final image configuration. Fix: Review the complete Dockerfile to ensure: no secrets are exposed in build args, multi-stage builds properly clean up intermediate layers, and the final runtime image is minimal and secure. - Medium · Potential Dependency Supply Chain Risk —
backend/_example/memory_store/go.mod. The go.mod file uses a local replace directive (replace github.com/umputun/remark42/backend v1.1000.0 => ../../) which is a development pattern. If this is committed in production builds, it could lead to unexpected behavior or bypass of dependency verification mechanisms. Fix: Ensure replace directives are only used in development. For production builds, use versioned tags and proper semantic versioning. Remove or conditionally apply replace directives in CI/CD pipelines. - Medium · Multiple Outdated Go Dependencies —
backend/_example/memory_store/go.mod (indirect dependencies). The indirect dependencies include several packages that may have known vulnerabilities: golang.org/x/crypto v0.50.0, golang.org/x/net v0.53.0, and golang.org/x/sys v0.43.0 are all outdated. These are foundational security-critical packages. Fix: Run 'go get -u' to update all dependencies to their latest secure versions. Specifically update golang.org/x/crypto, golang.org/x/net, and golang.org/x/sys to the latest patches. - Low · Testdata Containing Cryptographic Keys —
backend/app/cmd/testdata/. The repository contains test data files with cryptographic keys (apple.p8, apple-bad.p8, cert.pem, key.pem). While these are test/example keys, their presence could serve as templates for accidental exposure of real credentials. Fix: Ensure these are clearly marked as test fixtures and document that they should never be used with real credentials. Consider generating keys programmatically in tests rather than storing them as files. - Low · Missing HTTPS Enforcement Documentation —
SECURITY.md. While SECURITY.md exists, there is no explicit documentation about HTTPS/TLS enforcement, certificate pinning, or secure communication protocols for the comment engine deployment. Fix: Enhance SECURITY.md with clear guidance on: mandatory HTTPS usage, TLS version requirements, certificate management, and secure configuration recommendations for deployment. - Low · Verbose Error Messages in Build Process —
Dockerfile, multiple echo statements. The Dockerfile uses 'echo' statements for skipped steps without consistent error handling. This could potentially expose information about build configuration in logs. Fix: Implement structured logging for build steps. Avoid exposing build configuration details in container logs accessible to end users.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.