A Vue and Go-based notes application designed for instant startup, effortless viewing, and organized archiving. https://memodump.carbonc.cc/
  • Go 52.5%
  • JavaScript 36.4%
  • Vue 10.3%
  • CSS 0.7%
  • HTML 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-08 07:59:11 -07:00
.forgejo/workflows ci: GitHub Actions for CLI + Wails desktop; disable Forgejo auto-triggers 2026-05-27 15:06:28 -07:00
.github/workflows fix: release existing Git tags 2026-07-30 07:54:23 -07:00
build feat: add Wails desktop app and improve auth/config handling 2026-04-26 15:57:24 -07:00
docs docs: remove obsolete sync plan/spec documents (archive three) 2026-08-12 02:18:43 -07:00
frontend fix: polish editor and sidebar 2026-09-08 07:59:11 -07:00
images fix: update Docker image path to carbonc39, expand README features 2026-07-17 03:13:29 -07:00
internal fix: polish editor and sidebar 2026-09-08 07:59:11 -07:00
testdata feat(sync): R6.1 — browser wire contract and pure decision core 2026-08-10 07:24:53 -07:00
.dockerignore feat: add Docker image build/push to GHCR in GitHub Actions CI 2026-06-21 23:29:05 -07:00
.gitignore chore: ignore local R2 test credential folder 2026-08-01 01:51:57 -07:00
api.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
api_test.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
api_v2.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
api_v2_crud_test.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
app_wails.go feat(sync): Wails cloud-sync config form with unified setup UX 2026-08-11 05:47:46 -07:00
config_report_test.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
Dockerfile docs(sync): R6.7 - runtime matrix, browser docs, and R6 manual release gate 2026-08-10 23:10:38 -07:00
go.mod feat(syncindex): portable sync-index with enable flow, durability, validation 2026-08-05 04:29:28 -07:00
go.sum feat(cloudsync): Phase 1 wire contract, fixtures, and in-memory RemoteStore 2026-08-05 03:18:24 -07:00
image_vault_test.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
LICENSE chore: add MIT license and github action for multi-platform build 2026-04-20 17:55:31 -07:00
main_cli.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
main_wails.go feat(sync): R5.1-R5.3 — shared attempt boundary, in-memory scheduler, process lifecycle + status 2026-08-09 21:11:24 -07:00
README.md docs: update README for online version, declutter features & cloud sync 2026-08-12 01:09:41 -07:00
README.zh-CN.md docs: update README for online version, declutter features & cloud sync 2026-08-12 01:09:41 -07:00
runtime_matrix_test.go refactor: split flat package main into internal feature packages 2026-08-10 23:51:39 -07:00
runtime_wails.go fix(refactor): add missing appstate import to the Wails runtime tag file 2026-08-11 00:15:09 -07:00
server.go feat(sync): Wails cloud-sync config form with unified setup UX 2026-08-11 05:47:46 -07:00
server_test.go fix: keep embedded builds on server backend 2026-07-29 06:22:24 -07:00
wails.json feat: add Wails desktop app and improve auth/config handling 2026-04-26 15:57:24 -07:00

MemoDump

English | 简体中文

MemoDump logo

Go License PWA Wails Docker

Website · Online Donate

A simple, clean, easy-to-use, neurodiversity-friendly Markdown notes app. Run it as a self-hosted web server, a native desktop application (via Wails), or a Docker container. There's even a ready-to-use online version!

The online version stores data in the browser when sync is not enabled. Clearing browser data may result in lost notes.


Why MemoDump?

Lost in formatting and organising, we end up focusing less on the content itself. MemoDump just wants you to start writing quickly and stay focused on your thoughts, so it keeps the design deliberately low-friction.

  • No need for complex databases or nested structures — you don't even have to name a note. Everything beyond the content is optional.
  • MemoDump works hard to make information stand out: waterfall card view for notes, and no secondary menus unless necessary — friendly to your working memory.

Features

  • Single binary — Go backend with embedded Vue 3 frontend. Drop it anywhere and run.
  • Markdown editor — Milkdown WYSIWYG editor with full Markdown support.
  • Folder organisation — Hierarchical folders with drag-and-drop and .md file import.
  • Full-text search — Fast in-memory AND-mode search across note bodies and tags.
  • Image paste & upload — Paste or drop image files to insert them; stored in the local vault by default, with optional S3-compatible hosting.
  • Waterfall card view — Visual masonry-style note browser alongside the folder tree.
  • Autosave against data loss — Silent autosave when offline; edits made offline replay automatically once connectivity returns.
  • Custom fonts — Built-in system, serif, and sans font family presets; custom CSS font stacks; independent font sizes for app UI, WYSIWYG editor, and raw editor.
  • Custom CSS — Inject a stylesheet via --css CLI flag, or edit custom CSS directly in the settings panel.
  • Config layering — Flags → environment variables → .env file (any combination works).
  • Desktop app — Native window via Wails — same codebase, no browser required.
  • Mobile/PWA friendly — Responsive design, installable as a PWA with back-navigation support.

Markdown editor view Waterfall notes view


CLI Server

Quick start

# No authentication (personal / trusted-network use)
memodump --data ./notes

# With credentials
memodump --data ./notes --user alice --pass secret

# Custom port
memodump --data ./notes --user alice --pass secret --port 9090

Open http://localhost:8080 in your browser (or the custom port).

Flags

Flag Description Default
--data Path to notes directory (required) —
--user Login username —
--pass Login password —
--port HTTP port 8080
--css Custom CSS file injected into the UI —

Configuration sources

Settings can be supplied three ways, in priority order:

Priority Source Notes
1 (highest) CLI flags --user alice --pass secret
2 Environment variables MEMODUMP_DATA, MEMODUMP_USER, MEMODUMP_PASS, MEMODUMP_PORT, MEMODUMP_CSS
3 (lowest) .env file in working directory DATA=, USER=, PASS=, PORT=, CSS=

.env file example

DATA=./notes
USER=alice
PASS=secret
PORT=9090
CSS=./custom.css

Cloud sync has no CLI surface: the CLI Web server does not sync (see Cloud sync); the Wails desktop build reads its sync state from the OS application-data directory.

Lines starting with # and blank lines are ignored. Values are not quote-stripped.

No-auth mode

If no credentials are configured from any source, the server starts in no-auth mode — all API endpoints are accessible without a session cookie.

memodump --data ./notes
# WARNING: No credentials configured — running in no-auth mode (all requests allowed)

Desktop App (Wails)

The Wails build wraps the same backend in a native window.

  • On first launch the data directory is resolved automatically (no dialog):
    1. DATA= key in a .env file next to the binary / in the working directory
    2. ./data subfolder of the working directory (auto-created if absent)
  • The chosen path is saved to the OS user-config directory and reused on subsequent launches.
  • Use the Data Folder button in the sidebar to pick a different folder (restart required to apply).
  • Always runs in no-auth mode (credentials are not applicable).

Config file location

OS Path
Windows %APPDATA%\memodump\config.json
macOS ~/Library/Application Support/memodump/config.json
Linux ~/.config/memodump/config.json

Docker

Pre-built images are published to GitHub Container Registry on every tagged release: ghcr.io/carbonc39/memodump. The image runs the headless CLI server only.

# No authentication
docker run -d -p 8080:8080 -v ./notes:/data ghcr.io/carbonc39/memodump:latest

# With credentials and a custom port
docker run -d -p 9090:9090 -v ./notes:/data \
  -e MEMODUMP_USER=alice -e MEMODUMP_PASS=secret -e MEMODUMP_PORT=9090 \
  ghcr.io/carbonc39/memodump:latest

The data volume mounts to /data (set via MEMODUMP_DATA=/data inside the image). Available tags: latest, vX.Y.Z, vX.Y. All CLI environment variables work the same way inside the container. Cloud sync does not run in the container: the image is the headless CLI server, whose browser clients share one server vault (see Cloud sync).

Build the image locally with docker build -t memodump . (see Dockerfile).


Building

Prerequisites

  • Go 1.25+
  • Node 20+ with npm

Before preparing a release, complete the manual testing checklist.

CLI server

# Build frontend
cd frontend && npm install && npm run build && cd ..

# Build for current platform
go build -o memodump .

# Cross-compile example (Linux arm64)
GOOS=linux GOARCH=arm64 go build -o memodump-linux-arm64 .

Desktop app (Wails)

# Install Wails CLI (once)
go install github.com/wailsapp/wails/v2/cmd/wails@latest

# Production build
wails build

# Development (hot-reload)
wails dev

Output is placed in build/bin/.

Note: wails dev opens a terminal window for its hot-reload proxy — this is expected. Production builds (wails build) use -H windowsgui on Windows and produce a GUI-only binary with no console.

Linux system dependencies. Wails links against GTK 3 and WebKitGTK. On Debian 12 / Ubuntu ≤ 23.10 install libgtk-3-dev libwebkit2gtk-4.0-dev (plus libayatana-appindicator3-dev and librsvg2-bin for the tray/icon tooling). On Debian 13 / Ubuntu ≥ 24.04, webkit2gtk-4.0 no longer exists — only webkit2gtk-4.1 — so install libgtk-3-dev libwebkit2gtk-4.1-dev and build with the webkit2_41 tag:

sudo apt install libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-bin
wails build -tags "webkit2_41"

Without the tag, wails build fails at bindings generation with webkit2gtk-4.0 was not found.

Pure frontend / PWA

A browser-only build with no Go server: notes live in IndexedDB and cloud sync runs in the browser (see Cloud sync). Build it with VITE_LOCAL=1 and serve the static dist directory, or run the local dev server with npm run dev:local (Vite serves it directly and proxies /api to a local server for non-sync features):

cd frontend && npm run build:local           # production build (verified local mode)
cd frontend && npm run dev:local            # hot-reload dev server

frontend/vercel.json makes Vercel use this local build and serves dist as a Vite SPA. After deployment, /build-mode.json must return {"mode":"local"}; if it does not, the Vercel project's Root Directory is not frontend or a dashboard build-command override is taking precedence over the repository.

The browser build must run in a secure context: serve it over HTTPS (or http://localhost during development). Web Locks, crypto.subtle, and secure IndexedDB rely on it, and a second device must not be pointed at a plain LAN HTTP address.

Build tags reference

Tag Used by Entry point
(none) go build . main_cli.go
production wails build main_wails.go
dev wails dev main_wails.go
bindings Wails JS-binding generation (internal) main_wails.go

Image support

Image storage across the three builds:

Build Default Configurable
Web server Local vault (<dataDir>/.images/) S3-compatible (settings panel or environment)
Wails desktop Local vault (<dataDir>/.images/) S3-compatible (settings panel)
Pure frontend / PWA Off (image links only) S3-compatible (settings panel, browser-direct)
  • Paste or drop image files in the editor to insert them. The local vault stores images under the data dir and the markdown keeps a relative URL (/api/images/<key>) that resolves only inside the app origin — the portability tradeoff of self-hosted images.
  • S3 mode requires the bucket to be publicly readable (otherwise images show 403). The pure-frontend build additionally needs bucket CORS configured (allow the app origin, PUT/POST/GET/HEAD, Content-Type and x-amz-* headers, and expose ETag for multipart uploads).
  • Privacy notice: in S3 mode images are publicly readable by anyone with the link; the content hash is not access control, and identical files produce identical links. Do not upload images that must stay private.
  • Images pasted offline are kept in browser IndexedDB and upload automatically once connectivity returns; an entry is removed only after the image is uploaded and verified readable (a few orphan objects may remain, which is accepted).
  • Optional periodic cleanup (settings → Images): when enabled, the server periodically deletes images no note references (local vault and S3, with a 7-day grace period; in S3 mode deletion is remote and permanent), and the web/Wails build additionally removes permanently-failed pending entries after 30 days. Use a dedicated bucket/prefix for MemoDump so other files are never affected. Cleanup is off by default.
  • Security: image keys are sha256(content) + canonical extension (JPEG is always .jpg); the server validates the content hash, magic bytes and the extension match. Only png/jpg/gif/webp/avif are accepted — no SVG (same-origin stored-XSS risk).

The web server can also be configured via environment: MEMODUMP_IMAGE_S3_ENDPOINT, _REGION, _BUCKET, _PREFIX, _PUBLIC_URL, _ACCESS_KEY, _SECRET_KEY, _FORCE_PATH_STYLE (higher priority than the settings panel, which becomes read-only).


Cloud sync (experimental)

Cloud sync keeps two or more MemoDump installations' Markdown notes in sync through an S3-compatible bucket; enable it from settings in the online version and the Wails desktop app. It is eventual, not real-time, synchronization: a change on device A is uploaded on A's next run and downloaded on B's next run, so normal latency is about two intervals.

Configure note sync from Settings → Cloud sync — the panel persists endpoint, region, bucket, prefix, access/secret key, and path style in the OS user-config directory (<user-config>/memodump/sync-config.json). The secretKey is stored server-side and never returned to the UI; leaving it blank when reconnecting keeps the current secret. The panel refuses to change the provider while sync is connected (Disconnect first, then edit). The panel combines saving and the provider capability check into one Connect action.

  • The PWA keeps its own S3 configuration in browser localStorage. The bucket must allow signed traffic from the app origin. Sync runs only while the page or PWA is open — closing it stops sync, and no background work happens afterwards. The PWA vault, sync identity, snapshot, and recovery copies live in IndexedDB: clearing site data, or using a private browsing window, discards or isolates them, so local unsynced changes and recovery copies are lost.
  • The Wails desktop keeps its sync device state — the Device ID and path→Replica registry, the connection record, one disposable snapshot, and the recovery copies — in the OS application-data directory, outside the vault. Do not delete it while a vault is connected or the replica will re-onboard conservatively.

The provider can also be supplied entirely with environment variables — they take precedence over the saved file and make the panel read-only:

Variable Meaning
MEMODUMP_SYNC_ENDPOINT S3-compatible endpoint URL (e.g. https://s3.region.amazonaws.com). Plain HTTP is allowed only for localhost/loopback development. The endpoint must not carry a path.
MEMODUMP_SYNC_BUCKET A private bucket.
MEMODUMP_SYNC_PREFIX Optional object prefix (e.g. memo/vault-a).
MEMODUMP_SYNC_REGION Region (default us-east-1).
MEMODUMP_SYNC_ACCESS_KEY / MEMODUMP_SYNC_SECRET_KEY Credentials.
MEMODUMP_SYNC_FORCE_PATH_STYLE 1 for path-style addressing (MinIO, R2, LocalStack).

A connected replica (you clicked Connect once) runs automatically while its runtime is open: once after a 10-second startup delay, then every five minutes, plus immediately after a successful connection. Sync now in the settings panel still forces an immediate run. The schedule is identical for the Wails desktop (while the app is open) and the PWA (while the page is open), and no sync runs after a runtime closes. A transient provider failure retries with in-memory backoff (1m, 2m, 5m, 10m, 30m, honoring a larger provider Retry-After, reset by success; restart forgets it). An auth/permission/quota/mismatch failure pauses automatic sync for the rest of the runtime — the status shows the paused reason — while Sync now still works; a successful manual run or reconnect clears the pause.

The settings panel shows connection state, the last successful sync, actionable errors, and recovery copies. Disconnect stops automatic runs and keeps your identity and provider configuration, so Reconnect resumes cleanly.

Notes:

  • Sync is not end-to-end encrypted. Use a private bucket and restrict its credentials.
  • Deletes propagate to every device. The durable recovery copies the app writes before a pulled deletion can be inspected and restored from the settings panel.
  • Do not combine with another filesystem sync tool. Do not place the same vault under Dropbox/iCloud/OneDrive, git automation, or another file-sync tool while cloud sync is enabled — the two tools would race on the same Markdown files.
  • Connect different storage discards this replica's snapshot and connection pin so you can deliberately switch providers or recreate a lost repository. A normal run never re-creates a lost repository on its own.

Project structure

memodump/
├── main_cli.go       # CLI entry point (build tag: !production && !dev && !bindings)
├── main_wails.go     # Wails entry point (build tag: production || dev || bindings)
├── app_wails.go      # Wails App struct — startup, data-dir config, change-folder dialog
├── server.go         # Shared: package vars + buildAPIMux()
├── api.go            # Note & folder API handlers
├── auth.go           # Session auth middleware and login/logout handlers
├── wails.json        # Wails project config
├── frontend/         # Vue 3 + Milkdown frontend (built into binary via embed)
│   └── src/
│       ├── views/MainView.vue
│       └── style.css
├── Dockerfile        # Headless CLI server image (multi-stage: frontend → go build → distroless)
└── .github/workflows/build.yml   # CI/CD (primary) — see below

CI / CD

CI runs on GitHub Actions (.github/workflows/build.yml), triggered on every push/PR to public and on v* tags.

build-cli — CLI cross-compilation

Target Output
Linux amd64 memodump-server-linux-amd64
Linux arm64 memodump-server-linux-arm64
Linux arm memodump-server-linux-arm
Windows amd64 memodump-server-windows-amd64.exe
Windows 386 memodump-server-windows-386.exe
macOS amd64 memodump-server-darwin-amd64
macOS arm64 memodump-server-darwin-arm64

build-desktop — Wails desktop builds

Gated to v* tags / manual dispatch (native macOS/Windows/Linux runners bill more, so they don't run on every push): Windows amd64, macOS universal, Linux amd64.

docker — Docker image

Also gated to v* tags / manual dispatch. Builds linux/amd64 + linux/arm64 and pushes to ghcr.io/carbonc39/memodump, tagged latest, vX.Y.Z, and vX.Y.

release — GitHub Release

Triggered only on v* tags. Collects every build artifact onto a GitHub Release.


If you find MemoDump useful, consider buying me a hot chocolate ☕