Emanote: turning plain-text notes into a structured site with a live preview
Emanate a structured view of your plain-text notes
At a glance
- What is it?
- Emanote is a Haskell tool that reads plain-text notes and derives a structured website from them, with a live preview server and a static generation mode. It suits people who keep notes in text and want a wiki or Zettelkasten without hand-maintaining a site, and it asks for a Nix and Haskell toolchain on the development side.
- Who is it for?
- Adopt Emanote if your notes are plain text and you want the site structure derived from the notes themselves rather than maintained by hand, and if you are prepared to run the live preview server or to generate a static site from it. Do not adopt it if you want a conventional docs tool with a directory of hand-written pages, since the value here comes from the derivation.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 89 days ago.
- What is it written in?
- Mainly Haskell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A site derived from notes rather than authored as pages
Most static site generators want you to write pages. Emanote takes the opposite position: you write notes, and it emanates, which the README glosses as issuing or spreading out from a source, a structured view of those notes. The description at the top of the README is precise about the scope: create websites such as a personal webpage, blog, wiki, Zettelkasten, notebook, knowledge base or documentation from future-proof plain-text notes and arbitrary data, with a live preview that updates in real time.
The audience is people whose notes are already the primary artefact. If you keep a Zettelkasten in text files and you want it browsable, the usual route is to write a converter or to hand-maintain a site alongside the notes, and both rot. Emanote's premise is that the notes carry enough structure for the site to be derived, and the live preview exists so you can watch that derivation while you write.
The implementation is Haskell, and the repository layout shows a Haskell project built with Nix: a cabal.project, default.nix, flake.nix, a nix/ directory, hie.yaml for IDE support, and an emanote/ directory holding the source. The topics point to the same territory, with ema, haskell, markdown, obsidian-md, orgmode, pandoc, static-site and zettelkasten listed, and the project describes itself as the spiritual successor to neuron, itself built on Ema.
Live preview, static generation and the morph path in between
The justfile at the repository root is the clearest statement of the three execution modes, because it defines an end-to-end suite for each: e2e-live runs the suite in live mode using emanote run, e2e-static runs it in static mode with emanote gen plus serving the result, and e2e-morph runs emanote run while treating every I open action as an Ema-internal route switch. The comments in the file explain that morph exercises the morph code path that live and static skip because they reload the page instead.
That distinction matters for anyone planning a deployment. Static mode produces files you can host anywhere. Live mode runs a server that renders on request and is what you point a browser at while writing. Morph is a third behaviour in between, where navigation happens inside the running application rather than through a fresh page load, and the project keeps a dedicated test suite for it because that path is easy to break.
The development server runs on port 9010, and the run recipe also starts an MCP HTTP endpoint on port 8079. The generated output is a static site, and the search component is Stork, which is listed among the bundled dependencies under an Apache-2.0 licence.
The Nix and just workflow, recipe by recipe
Installing is documented on the project site rather than in the README, at emanote.srid.ca/install, and the examples page at emanote.srid.ca/examples shows what the output can look like. For development, the README points at a haskell-template repository for the full instructions and summarises it as installing Nix and running a single command:
nix develop -c just runThe justfile is the task surface, and it is short enough to read in one pass. Documentation is served through Hoogle on a local port:
docs:
echo http://127.0.0.1:8888
{{nix_shell}} hoogle serve -p 8888 --localRunning the application uses ghcid, which recompiles and reloads as you edit, with the notebook directory overridable so you can point the same code at your own notes:
run:
{{nix_shell}} ghcid -c 'cabal repl exe:emanote --flags=ghcid' --warnings -T ":main -L {{notebook}} run --port=9010 --mcp-port=8079"The test suite runs the same way, and formatting is delegated to pre-commit:
test:
{{nix_shell}} ghcid -c "cabal repl test:test --flags=ghcid" --warnings -T :mainfmt:
{{nix_shell}} pre-commit run --all-filesBefore opening a pull request, the README suggests running the project's CI tooling locally, which the GitHub Actions workflows run as well:
nix run github:juspay/vira ci -- -bEma is the base layer, and the structure is derived from Ema
Emanote is not a from-scratch static site generator. It is described as the spiritual successor to neuron, and neuron was built on Ema, a Haskell framework for typed route-based web applications. The repository also contains vira.hs and a vira configuration referenced by the CI command, which points at the same family of tooling.
What that inheritance means practically is that routes, templates and content types are typed and composable rather than convention-based, and that the notes are not merely copied into an output directory. The README mentions a default directory with an index.yaml and a templates subdirectory, both of which are listed as licensed separately from the code, which suggests that the default site layout is itself a configuration you can replace.
The structure of the codebase is documented separately at emanote.srid.ca/architecture, and the repository includes a CHANGELOG.md, a docs/ directory and a tests/ directory alongside the source. For anyone deciding whether to adopt the project, the architecture page is the better place to start than the README, because the README is deliberately short and points outward for everything else.
The repository is set up for AI-assisted contributions
This is unusual enough to mention. The README states that the repository is set up for AI-based coding with srid/agency and Microsoft APM, and it references the contributing guide of Kolu, where contributors are encouraged to open issues with detailed specifications rather than code changes per se.
The repository layout backs the claim. There are .agency/, .agents/, .apm/ and .claude/ directories, an apm.yml and apm.lock.yaml at the root, a .mcp.json file, and an AGENTS.md. The justfile comment ties it together: the MCP HTTP endpoint is available at http://localhost:8079/mcp for the emanote client configured in apm.yml under dependencies.mcp, and the run recipe is what starts that endpoint alongside the site server.
The practical implication for a potential user is that the development loop has been designed around an agent or an editor client talking to the running application over MCP rather than around a human editing files and refreshing. Whether you find that useful is a matter of taste, but it does explain why the MCP port is wired into the run recipe instead of being an afterthought.
Licensing is layered, and the aggregate is not a single identifier
The licence deserves care because the project mixes several. The README lists what it calls licences, starting with the default: emanote is licensed AGPL-3.0-or-later under an SPDX-License-Identifier tag. Then the components differ. The default/index.yaml file and the default/templates directory are each tagged CC0-1.0 OR AGPL-3.0-or-later, which is a dual licence letting you use them under the more permissive terms. The logo is CC0-1.0. Stork search is Apache-2.0. Tailwind CSS is MIT, and the SVG icons come from Heroicons under MIT.
The repository licence field is listed as a custom licence that GitHub cannot classify, so the LICENSE file in the repository root is the authoritative text rather than any badge. The distinction between the AGPL default and the CC0 options matters if you plan to publish a site with your own content and templates: the dual-licensed pieces give you a permissive path, the code as a whole does not.
Read the SPDX tags in the files themselves rather than relying on a single summary, because a project with a layered licence can have a permissive site template wrapped around a copyleft tool.
Where Emanote stops being the right choice
The first limitation is the toolchain. Developing against this codebase means Nix, a Haskell compiler and ghcid, and the justfile wraps every recipe in nix develop unless you are already inside a Nix shell. For a note-taker who wants a site and has no interest in a Haskell build, that is a heavy requirement, and the install path documented at emanote.srid.ca/install is the part to read first.
The second is the premise. Emanote derives structure from notes, which means the notes have to be written in a way that supports derivation, with the relationships and metadata the tool expects. A folder of unstructured prose is not going to become a well-linked wiki by itself.
The third is that live preview and static output are different products with different deployment stories. A live server means something to run and keep running, whereas static generation means files to publish and a rebuild step to trigger. The e2e suites for the three modes exist because these paths genuinely behave differently.
The fourth is pace. Releases are infrequent: version 1.2.0 dates from 2023-08-24 and 1.4.0.0 from 2025-08-19, and the most recent push was on 2026-07-26. That is fine for a personal project and awkward for a tool you depend on in a pipeline.
Against a general static site generator
The obvious comparison is with a conventional static site generator that takes a directory of Markdown files and renders pages from templates you write. The difference in approach is where the structure comes from.
In a conventional generator, the structure is the point of departure. You create a file per page, you decide the URL, you write the template, and the links between pages are your job. The notes are a source of content. In Emanote the direction is reversed: the notes are the site, the structure is derived from them and their links, and the templates and index are configuration for how that derivation is presented.
That reversal is worth a lot for a Zettelkasten, where the link structure is the knowledge and any manual page hierarchy would duplicate it. It is worth less for a documentation set where you want a fixed sidebar, a specific URL scheme and a versioned API reference, because deriving that from notes fights the goal.
A second comparison is with a general Haskell web framework used directly. Emanote is built on Ema and brings the note-derived content model with it. If you want typed routes and templates but no connection to your notes, the framework alone is the lighter choice. Emanote earns its extra weight when the derivation is the point.
Editorial conclusion
Adopt Emanote if your notes are plain text and you want the site structure derived from the notes themselves rather than maintained by hand, and if you are prepared to run the live preview server or to generate a static site from it. Do not adopt it if you want a conventional docs tool with a directory of hand-written pages, since the value here comes from the derivation. Check first the licensing of what you publish, because the default is AGPL-3.0-or-later while the bundled index and templates are CC0-1.0 OR AGPL-3.0-or-later, and note the release cadence is slow, with 1.4.0.0 on 2025-08-19 and the last push on 2026-07-26.
Frequently asked questions
How do I install Emanote?
The README does not carry the installation steps and instead links the install page at emanote.srid.ca/install, with worked examples at emanote.srid.ca/examples. For development the repository expects Nix, since the summary instruction is to install Nix and run nix develop -c just run.
What is the difference between emanote run and emanote gen?
The justfile defines an end-to-end suite for each mode: e2e-live runs emanote run for the live server, and e2e-static runs emanote gen plus serving the generated output. A third mode, morph, treats navigation as an Ema-internal route switch rather than a fresh page load.
Which ports does the Emanote development server use?
The run recipe starts the application on port 9010 and an MCP HTTP endpoint on port 8079, and the justfile comment notes that the MCP endpoint at http://localhost:8079/mcp is what the emanote client in apm.yml connects to.
What licence applies to Emanote?
The default is AGPL-3.0-or-later for the code, while the default index.yaml and the default templates are tagged CC0-1.0 OR AGPL-3.0-or-later, the logo is CC0-1.0, Stork search is Apache-2.0, and Tailwind CSS and the Heroicons icons are MIT. The LICENSE file at the repository root is the authoritative text.
Is Emanote related to neuron and Ema?
Yes. The README describes Emanote as the spiritual successor to neuron, and neuron itself was based on Ema, the Haskell framework Emanote builds on. The architecture page at emanote.srid.ca/architecture documents the codebase.
How do I run the Emanote test suites?
The justfile provides just test for the unit tests, run through ghcid, and three end-to-end suites named e2e-live, e2e-static and e2e-morph for the live, static and morph modes. A justfile recipe also formats the tree with pre-commit.
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/srid-emanote)Was this useful?