EdgeEver requires its password and defaults its username to admin
Project brief: Serverless, 100% free, and open-source Evernote alternative on Cloudflare with native MCP | 0 AI Agent .
At a glance
- What is it?
- An AGPL notes and knowledge base that runs on Cloudflare free quotas or in one Docker container, where the compose file makes the password a hard requirement and the username optional, the image tag defaults to latest, the server image contains no desktop client, extension, mobile app or site, and the project's central argument is four paragraphs about other people's software.
- Who is it for?
- EdgeEver is the most carefully configured self-hosted compose file in this batch, and the three details that matter most are all in it. Set `EDGE_EVER_AUTH_PASSWORD` before the first start, because the file refuses to come up without it, and change `EDGE_EVER_AUTH_USERNAME` while you are there, because it defaults to `admin`.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- tianma-if/edgeever3,243 ★ · +2,523
| Repository | 2026-07-30 | 2026-11-14 |
|---|---|---|
| tianma-if/edgeever | 720 | 3.2k |
2,523 Stars in the last 107 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
compose.yaml makes the password a requirement and the username a default
The whole deployment is one service in one file, and it is worth reading line by line because the design choices are unusually deliberate:
services:
edgeever:
image: "${EDGE_EVER_IMAGE:-ghcr.io/tianma-if/edgeever}:${EDGE_EVER_VERSION:-latest}"
restart: unless-stopped
init: true
ports:
- "${EDGE_EVER_PORT:-8787}:8787"
environment:
EDGE_EVER_AUTH_USERNAME: "${EDGE_EVER_AUTH_USERNAME:-admin}"
EDGE_EVER_AUTH_PASSWORD: "${EDGE_EVER_AUTH_PASSWORD:?Set EDGE_EVER_AUTH_PASSWORD before starting EdgeEver}"
EDGE_EVER_CONTAINER_IMAGE: "${EDGE_EVER_IMAGE:-ghcr.io/tianma-if/edgeever}"
volumes:
- edgeever-data:/data
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
stop_grace_period: 30sThe password uses Compose's `:?` form, which is the part that is done right. If `EDGE_EVER_AUTH_PASSWORD` is unset or empty the file fails to parse and the container never starts, so there is no window in which the service comes up with no credential configured. That single line is worth more than a paragraph in a security section.
The username is a different story. It uses `:-`, so it falls back to `admin` when unset. The result is a service that will not start without a password and will start with the username `admin` unless you say otherwise, and the documentation does not draw attention to the asymmetry. Anyone who reads the variable name and assumes both credentials are required is wrong about half of it.
The hardening is otherwise real: `no-new-privileges`, all capabilities dropped, an init process so signals reach the application, a 30 second grace period, one named volume and one published port on 8787. The licence inside the image is labelled AGPL-3.0-only, which matches the repository's declared licence and is the one with teeth for a self-hosted team deployment, since the network-use clause reaches a modified instance.
The image tag defaults to latest, so a certified deployment can change under you
Two defaults sit in that image line, and one of them is the more defensible. `EDGE_EVER_IMAGE` falls back to the project's own registry path, which is what you want from a compose file you copied from a project. `EDGE_EVER_VERSION` falls back to `latest`, which is the one that will cost you.
Nothing in the file pins a version, a tag pattern or a digest. So the deployment procedure is: copy the file, set a password, start. What you get is whatever was published to that tag most recently, and the next time you run `docker compose pull` you get something else. For a service whose entire pitch is that your knowledge base is yours and not locked to a vendor, having the server binary change underneath you on an upgrade you did not initiate is the wrong trade.
The fix is one line, and the variable is already there. Set `EDGE_EVER_VERSION` to a tag before the first start and the deployment becomes reproducible.
The release record shows why it matters here specifically. v1.98.0 was published on 2026-10-02, v1.99.0 on 2026-10-03 in the morning and v1.99.1 on 2026-10-03 later the same day. Three releases across two days, on a version line parked just under 2.0. A project shipping patch releases that fast and leaving its own default image tag unpinned is asking the operator to absorb release risk on their behalf.
There is also a second-order detail. The last commit pushed to the repository is dated 2026-10-02, while v1.99.1 was published on 2026-10-03. The published release is newer than the last recorded push, which is normal for a build pipeline and means the tag, not the branch, is the thing to record.
The server image copies six workspaces, installs four and builds two
The Dockerfile is a four-stage build and the first stage exists purely to hand the package manager a set of manifests. It copies `package.json` for six applications, api, desktop, extension, mobile, site and web, and for five packages, client, plugin-api, public-network, shared and wrangler. It also copies `bun.lock`, `bunfig.toml` and the whole `patches` directory. Then the install stage narrows it:
FROM manifests AS dependencies
RUN bun install --frozen-lockfile \
--filter edgeever \
--filter @edgeever/api \
--filter @edgeever/public-network \
--filter @edgeever/webFour of the eleven workspaces survive. The build stage then copies only `apps/api`, `apps/web` and `packages` before running `build:web` and `build:self-hosted`.
So the enumeration in the first stage is not padding. Listing a workspace's manifest is what lets the lockfile resolve for the whole graph while the install filter keeps the heavy optional parts out of the image, and `--frozen-lockfile` means the lock has to agree or the build stops. The `patches` directory being copied at manifest stage is the other half: the project applies patches to dependencies, so the patch set has to be present before resolution rather than after.
The consequence for an operator is worth stating plainly. The container you pull contains an API and a web front end. It does not contain the desktop application, the browser extension, the mobile applications or the marketing site, because four of the six application workspaces are dropped at install. Every claim about focus mode, system tray behaviour, or the connection to local agents is about a separate download from the releases page.
The runtime stage pins `oven/bun:1.3.14-alpine` in both the manifest and runtime stages, matching the `packageManager` field in the root manifest, and sets a data directory, a web directory and port 8787. The build id is passed in as an argument defaulting to the string `unknown`.
One script drives local, demo and remote, and the demo resets at 3 AM
The development surface is unusual enough to be worth reading, because it encodes the three ways this project is meant to be run.
Every local task goes through a single file, `scripts/local-dev.mjs`, with the target as an argument: `dev:local` runs `start local`, `dev:prepare` runs `prepare local`, `dev:ready` runs `ready local`, `dev:api:local` runs `api local`, `dev:demo` runs `start demo`, `dev:demo:reset` runs `reset demo`, and `dev:api:demo` runs `api demo`. A `dev:doctor` target runs the same script with `doctor` and no profile, which is the diagnostic entry point.
The third target is Cloudflare itself. `dev:api:remote` wraps wrangler with the `--remote` flag on port 8787, and `dev:remote` runs that alongside a Vite dev server with `concurrently -k -n api,web`, which is a short-lived parallel runner rather than a task queue.
The demo target is the one with a documented consequence. The public demo at `demo.edgeever.org` resets every day at 3:00 AM China Standard Time and restores sample notes, and the documentation says plainly not to store private content there. That is a good practice and a good warning, and the `reset demo` target is the same operation on demand, so the reset is a code path you can run rather than a cron job you have to trust.
Configuration follows the same three-way split. There is a `.env.local.example`, a `.env.local-dev.example`, a `.env.android.local.example` and a `.dev.vars.example`, which is the file Cloudflare Workers reads for local secrets. Four templates for four surfaces, and a self-hosted path that reads none of them, since the compose file takes its credentials from the shell environment.
The bulk test run excludes two files by path and then runs those two files
The top-level test script is a chain, and the chain has an unusual shape:
"test": "bun run test:bulk && bun run test:integration",`test:bulk` is a single `bun test` call carrying three `--path-ignore-patterns`. One is `tests/e2e/**`. The other two name specific files, `apps/api/src/companion-learning.test.mjs` and `apps/api/src/resource-upload-integration.test.mjs`. Then `test:integration` runs `bun test` on exactly those two files, in that order, with no ignore patterns.
The mechanism is legible: two tests need a live backend and would either hang or fail spuriously inside the bulk pass, so they are named twice, once to exclude them and once to run them. Writing the same two paths in two different script entries is the fragile part of it. Rename a file and one entry is obviously wrong, but there is nothing that ties the ignore list to the integration list, so a file could be dropped from the bulk pass and never added to the integration pass and the suite would still go green with a file nobody runs.
The names are worth reading for what they suggest about the system rather than about the harness. A companion-learning test and a resource-upload integration test point at a client that learns alongside you and at resource upload as a path that has its own integration conditions, both of which would be the places a server-side rewrite could break.
There is a second suite, `test:docker-release`, which runs five files covering the Docker release path, a script for pruning registry digest tags, a Docker installer script, a Cloudflare worker build script and `tests/storage-adapter.test.ts`. That last one is the important signal: storage sits behind an adapter, which is how a SQLite file and Cloudflare's object and key stores can back the same code. `playwright.config.ts` is also present at the root, matching the `tests/e2e/` path the bulk run excludes.
MCP is inbound, ACP is outbound, and the desktop app is a separate download
Two protocols appear in this project and they point in opposite directions, which the feature list does not make obvious.
MCP is the inbound one. The built-in Model Context Protocol support is what lets an external AI agent read, organise and summarise your notes, and it sits alongside a complete REST API and a CLI as one of three access paths to the same data. The data underneath is standard SQLite, which is the reason the other two paths are worth having: you can query the store directly, and the export produces Markdown with front matter, nested folders, relative attachment links and version histories rather than a proprietary archive.
ACP is the outbound one. The desktop application connects to AI agents running on your own machine, naming Codex, Antigravity, Claude Code and WorkBuddy as examples, over the Agent Client Protocol, for collaborative writing. That is the desktop app acting as a client to someone else's agent, which is the reverse of the MCP relationship and is a genuinely different design decision: your notes stay local while a local model edits them.
The third path is bring your own model. OpenAI, Anthropic or Gemini-compatible services and third-party API relays power the built-in agent and the companion sidebar, which covers summarisation, key point extraction, proofreading, translation and text continuation for a whole note or a selection. That is a hosted model with your notes going to it, which is the opposite trust posture from the ACP path, and both are offered side by side without the readme discussing the difference.
All of this is client-side or agent-side. The container holds the API and the web app; the desktop client, browser extension, mobile apps and the marketing site are five other workspaces, distributed through the releases page and two app stores. The iOS app additionally requires an Apple ID from outside mainland China, which the readme states in one line with no explanation.
The case for the project is four paragraphs of claims about other software
The readme's argument is not about EdgeEver. It is about four other products, and the objections are specific enough to be useful and unverifiable enough to be worth flagging.
Evernote is described as increasingly bloated with commercial ads and unnecessary features, degrading performance, with cumbersome data export, heavily restricted free tiers, and AI and MCP features that require costly subscriptions. Obsidian is characterised as open files with a closed-source core, paid official sync, tedious third-party sync, noticeable cold-start and search lag once notes reach thousands or heavy plugins load, vault bloat from images and attachments leaving orphaned files behind, and being overly heavy for lightweight capture. Memos and Stream Notes are credited as clean and simple but are said to have social-timeline layouts that differ fundamentally from a three-pane workflow. SiYuan and block-based tools are called powerful with self-hosting support but are said to impose cognitive overhead for quick capture and continuous prose, to lack a true zero-cost serverless tier, and to require paid subscriptions or extra payment to unlock S3 or WebDAV sync.
Every one of those is a competitive claim. Nothing in this repository substantiates any of them, and a reader has no way to check them from here. Two are checkable in principle by anyone, which is precisely why they should be.
The positive claims have the same character. Storage capacity for a personal deployment on Cloudflare's free allowances is given as roughly 150,000 short notes and 50,000 images, with Docker said to scale to millions; the performance claim is that the layout stays smooth with 10,000+ notes and that switching notes does not keep old images and documents in memory, which is a mechanism rather than a measurement. The performance mechanism is the one you can verify for yourself by watching memory during a fast switch, and the capacity figures are the ones to test with your own note sizes rather than accept.
The repository's own description field is also worth noting, since it is what people read first: it ends with the fragment `0 AI Agent .`, which is not a sentence.
AGPL, a Rust directory and a second CI provider sit under a TypeScript monorepo
The licence is AGPL-3.0 and the project is deliberate about it. The readme's argument is that the whole stack is open source including sync and self-hosting, and the competitors it names are proprietary, closed-core, or charge for sync. The image label carries `AGPL-3.0-only`. For a self-hosted deployment that is the right choice and also the one with obligations: a team running a modified instance over a network is within the scope of the copyleft, which is exactly the situation the project's target user is in. Anyone adopting this for a team should read that clause rather than assume it behaves like MIT.
The repository is larger than the language field suggests. The primary language is TypeScript and the root is a Bun workspace with `apps/*` and `packages/*`, but the tree also contains `crates/` and `.cargo/`, so there is a Rust component with its own committed cargo configuration inside a TypeScript monorepo. The build I can read does not compile it, which suggests it belongs to a surface the self-hosted image does not include.
There is a second continuous integration provider. `.github/` is present, and `.cnb.yml` sits at the root, which is the configuration format for a non-GitHub CI host. Two CI systems for one repository means release and test runs can diverge, and the release summary file at the root, which the Dockerfile copies into the build, is the kind of artefact that is easy to generate in one place and stale in the other.
The smaller entries are all in service of the build. `patches/` is copied at manifest stage so dependency patches are applied before resolution. `bunfig.toml` and `bun.lock` are the package manager's configuration and its lockfile, with the Bun version pinned in three places. `migrations/` holds schema migrations for the SQLite store. `AGENTS.md` is there for coding agents, and there are four translations of the readme, which is either very good practice or four more places for the version numbers to drift.
Editorial conclusion
EdgeEver is the most carefully configured self-hosted compose file in this batch, and the three details that matter most are all in it. Set `EDGE_EVER_AUTH_PASSWORD` before the first start, because the file refuses to come up without it, and change `EDGE_EVER_AUTH_USERNAME` while you are there, because it defaults to `admin`. Set `EDGE_EVER_VERSION` too, because the default of `latest` means a deployment you certified last month can be running different code today, and that is a poor property for a system holding years of personal notes. Decide which surface you are deploying as well: the self-hosted image is server-only, so the desktop client with its focus mode, the browser extension, the mobile apps and the ACP connection to local agents are separate downloads, and the iOS app additionally needs an Apple ID from outside mainland China. The data story is the real strength, since the store is standard SQLite, the export produces Markdown with front matter and relative attachment links plus version histories, and there is a REST API, an MCP server and a CLI. Two caveats to weigh first. The capacity figures for a free Cloudflare deployment are estimates in the documentation rather than measurements, so test with your own note sizes before trusting them. And the case this project makes is largely about Evernote, Obsidian, Memos, Stream and SiYuan, which means the argument you are reading is a set of claims about competitors that nothing in the repository substantiates.
Frequently asked questions
What is edgeever and what is it an alternative to?
It is an open-source notes and knowledge base workspace that revives the Evernote three-pane layout, with a REST API, MCP server, CLI and a ZIP export containing Markdown, front matter, nested folders, relative attachment links and version histories. The readme positions it against Evernote, Obsidian, Memos, Stream and SiYuan.
How do I deploy edgeever with Docker?
The repository ships a compose.yaml with a single service built on a published image, one named volume mounted at /data, and one port on 8787. The file requires EDGE_EVER_AUTH_PASSWORD to be set, since it uses the Compose form that fails on an unset value, and defaults EDGE_EVER_AUTH_USERNAME to admin and EDGE_EVER_VERSION to latest.
Can edgeever run on Cloudflare Workers?
Yes, that is the primary serverless target. The readme says a personal deployment fits within Cloudflare's free storage allowances, estimating roughly 150,000 short notes and 50,000 images, and a remote development target wraps wrangler with the --remote flag. The same application can be run with Docker on a VPS, NAS or home server instead.
What are the MCP and ACP integrations in edgeever?
MCP is inbound: it lets an external agent read, organise and summarise notes, alongside the REST API and CLI. ACP is outbound and belongs to the desktop application, which connects to agents running on your own machine, naming Codex, Antigravity, Claude Code and WorkBuddy, for collaborative writing.
Which clients are available for edgeever?
A desktop application, a browser extension, mobile apps distributed through Google Play under org.edgeever.mobile and the iOS App Store, plus a web app, a PWA and browser access. The iOS app requires an Apple ID from outside mainland China, and the container image itself contains only the API and the web app.
What licence is edgeever under?
AGPL-3.0, with the container image labelled AGPL-3.0-only. A self-hosted team running a modified instance over a network falls within the copyleft's scope, which is the clause adopters should check against their own obligations.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tianma-if-edgeever)Star history chart for your README
[](https://hysenlabs.com/projects/tianma-if-edgeever)Was this useful?