micelio 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- micelio-0.1.0/.gitignore +27 -0
- micelio-0.1.0/CHANGELOG.md +83 -0
- micelio-0.1.0/Dockerfile +54 -0
- micelio-0.1.0/LICENSE +21 -0
- micelio-0.1.0/PKG-INFO +246 -0
- micelio-0.1.0/README.md +212 -0
- micelio-0.1.0/compose.example.yml +36 -0
- micelio-0.1.0/docs/guides/README.md +42 -0
- micelio-0.1.0/examples/demo.toml +6 -0
- micelio-0.1.0/examples/vault/.obsidian/app.json +1 -0
- micelio-0.1.0/examples/vault/journal/2026-11-04 Free will.md +13 -0
- micelio-0.1.0/examples/vault/journal/2026-11-09 Planets.md +14 -0
- micelio-0.1.0/examples/vault/notes/A planet's tidal pull is smaller than a nearby wall's.md +14 -0
- micelio-0.1.0/examples/vault/notes/A stray thought with no home.md +8 -0
- micelio-0.1.0/examples/vault/notes/Bayes theorem in one line.md +19 -0
- micelio-0.1.0/examples/vault/notes/Caf/303/251 conversations shape ideas.md" +13 -0
- micelio-0.1.0/examples/vault/notes/Can planetary gravity affect a newborn.md +16 -0
- micelio-0.1.0/examples/vault/notes/Choosing a prior is a modelling decision.md +13 -0
- micelio-0.1.0/examples/vault/notes/Choosing feels different from being pushed.md +12 -0
- micelio-0.1.0/examples/vault/notes/Cities scale like metabolism.md +14 -0
- micelio-0.1.0/examples/vault/notes/Compatibilism dissolves part of the problem.md +13 -0
- micelio-0.1.0/examples/vault/notes/Effects too small to matter can still be real.md +15 -0
- micelio-0.1.0/examples/vault/notes/Every physical event has a prior cause.md +13 -0
- micelio-0.1.0/examples/vault/notes/Is a measured tendency a cause.md +14 -0
- micelio-0.1.0/examples/vault/notes/Likelihood is not a probability of the hypothesis.md +14 -0
- micelio-0.1.0/examples/vault/notes/Priors are beliefs you can update.md +15 -0
- micelio-0.1.0/examples/vault/notes/Randomness does not rescue freedom.md +12 -0
- micelio-0.1.0/examples/vault/notes/Season of birth correlates with some traits.md +15 -0
- micelio-0.1.0/examples/vault/notes/Streets behave like veins.md +13 -0
- micelio-0.1.0/examples/vault/notes/Streets behave like veins.sync-conflict-20261109-ABCDEF.md +1 -0
- micelio-0.1.0/examples/vault/notes/What experiment would tell this apart from chance.md +15 -0
- micelio-0.1.0/examples/vault/projects/An abandoned idea.md +10 -0
- micelio-0.1.0/examples/vault/projects/Cities as living organisms.md +17 -0
- micelio-0.1.0/examples/vault/projects/Do planets at birth leave a trace.md +33 -0
- micelio-0.1.0/examples/vault/projects/Free will in a determined world.md +30 -0
- micelio-0.1.0/examples/vault/projects/Learning Bayesian statistics.md +28 -0
- micelio-0.1.0/examples/vault/sources/McElreath - Statistical Rethinking.md +13 -0
- micelio-0.1.0/examples/vault/sources/Season of birth study notes.md +10 -0
- micelio-0.1.0/micelio.example.toml +70 -0
- micelio-0.1.0/pyproject.toml +112 -0
- micelio-0.1.0/src/micelio/__init__.py +12 -0
- micelio-0.1.0/src/micelio/app.py +120 -0
- micelio-0.1.0/src/micelio/appearance.py +465 -0
- micelio-0.1.0/src/micelio/auth/__init__.py +5 -0
- micelio-0.1.0/src/micelio/auth/passwords.py +27 -0
- micelio-0.1.0/src/micelio/auth/settings.py +83 -0
- micelio-0.1.0/src/micelio/auth/store.py +109 -0
- micelio-0.1.0/src/micelio/auth/totp.py +68 -0
- micelio-0.1.0/src/micelio/auth/web.py +266 -0
- micelio-0.1.0/src/micelio/cli.py +227 -0
- micelio-0.1.0/src/micelio/config.py +282 -0
- micelio-0.1.0/src/micelio/formatting.py +45 -0
- micelio-0.1.0/src/micelio/graph.py +250 -0
- micelio-0.1.0/src/micelio/i18n.py +82 -0
- micelio-0.1.0/src/micelio/landing.py +175 -0
- micelio-0.1.0/src/micelio/landing_web.py +260 -0
- micelio-0.1.0/src/micelio/locales/en.toml +286 -0
- micelio-0.1.0/src/micelio/locales/es.toml +285 -0
- micelio-0.1.0/src/micelio/pages.py +316 -0
- micelio-0.1.0/src/micelio/py.typed +0 -0
- micelio-0.1.0/src/micelio/render.py +183 -0
- micelio-0.1.0/src/micelio/static/css/appearance.css +76 -0
- micelio-0.1.0/src/micelio/static/css/fonts.css +35 -0
- micelio-0.1.0/src/micelio/static/css/graph.css +162 -0
- micelio-0.1.0/src/micelio/static/css/landing.css +174 -0
- micelio-0.1.0/src/micelio/static/css/micelio.css +330 -0
- micelio-0.1.0/src/micelio/static/img/psychedelic-dusk.webp +0 -0
- micelio-0.1.0/src/micelio/static/js/appearance.js +115 -0
- micelio-0.1.0/src/micelio/static/js/backdrop.js +14 -0
- micelio-0.1.0/src/micelio/static/js/draw.js +300 -0
- micelio-0.1.0/src/micelio/static/js/explore.js +96 -0
- micelio-0.1.0/src/micelio/static/js/graph-embed.js +4 -0
- micelio-0.1.0/src/micelio/static/js/graph.js +536 -0
- micelio-0.1.0/src/micelio/static/js/landing.js +307 -0
- micelio-0.1.0/src/micelio/static/js/specimens.js +42 -0
- micelio-0.1.0/src/micelio/static/vendor/README.md +33 -0
- micelio-0.1.0/src/micelio/static/vendor/d3-force/LICENSE +13 -0
- micelio-0.1.0/src/micelio/static/vendor/d3-force/d3-force.bundle.min.js +8 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/atkinson-hyperlegible/OFL.txt +93 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/atkinson-hyperlegible/atkinson-hyperlegible-latin-400.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/atkinson-hyperlegible/atkinson-hyperlegible-latin-700.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/bagel-fat-one/OFL.txt +93 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/bagel-fat-one/bagel-fat-one-latin-400.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/fraunces/OFL.txt +93 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/fraunces/fraunces-latin-900.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/literata/OFL.txt +93 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/literata/literata-latin-400.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/literata/literata-latin-700.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/righteous/OFL.txt +93 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/righteous/righteous-latin-400.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/shrikhand/OFL.txt +93 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/shrikhand/shrikhand-latin.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/space-grotesk/OFL.txt +93 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/space-grotesk/space-grotesk-latin-400.woff2 +0 -0
- micelio-0.1.0/src/micelio/static/vendor/fonts/space-grotesk/space-grotesk-latin-700.woff2 +0 -0
- micelio-0.1.0/src/micelio/templates/_macros.html +31 -0
- micelio-0.1.0/src/micelio/templates/appearance.html +184 -0
- micelio-0.1.0/src/micelio/templates/base.html +58 -0
- micelio-0.1.0/src/micelio/templates/explore.html +87 -0
- micelio-0.1.0/src/micelio/templates/health.html +45 -0
- micelio-0.1.0/src/micelio/templates/journal.html +20 -0
- micelio-0.1.0/src/micelio/templates/landing.html +67 -0
- micelio-0.1.0/src/micelio/templates/login.html +20 -0
- micelio-0.1.0/src/micelio/templates/not_found.html +12 -0
- micelio-0.1.0/src/micelio/templates/note.html +51 -0
- micelio-0.1.0/src/micelio/templates/project.html +58 -0
- micelio-0.1.0/src/micelio/templates/projects.html +35 -0
- micelio-0.1.0/src/micelio/vault/__init__.py +17 -0
- micelio-0.1.0/src/micelio/vault/index.py +377 -0
- micelio-0.1.0/src/micelio/vault/parser.py +114 -0
- micelio-0.1.0/src/micelio/vault/public.py +66 -0
- micelio-0.1.0/tests/__init__.py +0 -0
- micelio-0.1.0/tests/conftest.py +65 -0
- micelio-0.1.0/tests/test_app.py +54 -0
- micelio-0.1.0/tests/test_auth_settings.py +86 -0
- micelio-0.1.0/tests/test_auth_store.py +82 -0
- micelio-0.1.0/tests/test_auth_totp.py +70 -0
- micelio-0.1.0/tests/test_auth_web.py +253 -0
- micelio-0.1.0/tests/test_cli.py +163 -0
- micelio-0.1.0/tests/test_config.py +115 -0
- micelio-0.1.0/tests/test_formatting.py +33 -0
- micelio-0.1.0/tests/test_graph.py +446 -0
- micelio-0.1.0/tests/test_i18n.py +23 -0
- micelio-0.1.0/tests/test_index.py +258 -0
- micelio-0.1.0/tests/test_landing.py +457 -0
- micelio-0.1.0/tests/test_look.py +310 -0
- micelio-0.1.0/tests/test_pages.py +191 -0
- micelio-0.1.0/tests/test_parser.py +84 -0
- micelio-0.1.0/tests/test_public.py +318 -0
- micelio-0.1.0/tests/test_release.py +64 -0
- micelio-0.1.0/tests/test_render.py +129 -0
micelio-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.venv/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
|
|
9
|
+
# Tools
|
|
10
|
+
.coverage
|
|
11
|
+
coverage.xml
|
|
12
|
+
htmlcov/
|
|
13
|
+
.mypy_cache/
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
|
|
17
|
+
# Local config and data
|
|
18
|
+
.env
|
|
19
|
+
micelio.toml
|
|
20
|
+
data/
|
|
21
|
+
*.sqlite3
|
|
22
|
+
|
|
23
|
+
# Editors and OS
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
.DS_Store
|
|
27
|
+
Thumbs.db
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-11-10
|
|
10
|
+
|
|
11
|
+
The first release: a folder of Markdown notes shown as a forest of ideas, read-only and
|
|
12
|
+
self-hosted. The project was called Mycelium while it was built; it is released as Micelio
|
|
13
|
+
(Spanish for mycelium).
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
**Reading the vault**
|
|
18
|
+
|
|
19
|
+
- Vault reader: frontmatter, titles and Obsidian-style wikilinks (aliases, headings, paths);
|
|
20
|
+
hidden folders and Syncthing conflict copies are skipped.
|
|
21
|
+
- In-memory index with backlinks, project membership, bridges, ghost links and orphans,
|
|
22
|
+
refreshed from file modification times.
|
|
23
|
+
- `micelio check` lists problems in a vault; `micelio serve` runs the site.
|
|
24
|
+
- `micelio.toml` loading and validation: site, vault folders, categories with mushroom
|
|
25
|
+
species, graph, landing, typography, sign-in and data folder.
|
|
26
|
+
|
|
27
|
+
**Pages**
|
|
28
|
+
|
|
29
|
+
- The landing: the vault drawn as a forest over a painted background. Projects are
|
|
30
|
+
mushrooms (eight species, grown by status, sized by notes), notes are spore clouds in
|
|
31
|
+
the mycelium, links are hyphae with sparks, sources are crystals and the latest journal
|
|
32
|
+
notes are golden spores; positions from a vendored, seeded d3-force.
|
|
33
|
+
- The graph of everything at `/explore`, with search and filters, plus a graph on every
|
|
34
|
+
project and note page, all drawn as mycelium by the same engine (`static/js/draw.js`);
|
|
35
|
+
`graph.max_nodes` keeps big vaults readable.
|
|
36
|
+
- Reading pages: projects by category, each project with its notes and conversations,
|
|
37
|
+
notes with backlinks and the projects they belong to, the journal and a health page.
|
|
38
|
+
- Markdown rendered like Obsidian (wikilinks, ghost links, callouts, task lists, tables,
|
|
39
|
+
footnotes) and sanitized with nh3.
|
|
40
|
+
- `/api/graph` and `/api/landing` with the same data as the pages; `/healthz` for
|
|
41
|
+
containers and monitoring.
|
|
42
|
+
|
|
43
|
+
**Look**
|
|
44
|
+
|
|
45
|
+
- One dark look on every page: the painted background, text on ink glass, pill buttons.
|
|
46
|
+
- The Appearance page (`/appearance`): four palettes (Psychedelic, Tokyo Night, Catppuccin
|
|
47
|
+
Mocha, Rosé Pine) that recolor the background, the mushrooms and the categories; an
|
|
48
|
+
uploaded background; the soil line; the title, tagline and site name; fonts, title
|
|
49
|
+
effect and sizes; and a prompt builder for painting a background with any image
|
|
50
|
+
generator. Saved in the data folder, never in the vault. Seven fonts ship with
|
|
51
|
+
Micelio (SIL OFL).
|
|
52
|
+
|
|
53
|
+
**Languages**
|
|
54
|
+
|
|
55
|
+
- English and Spanish interfaces, including the names of the default categories; own
|
|
56
|
+
categories take `label = "Art"` or `label = { en = "Art", es = "Arte" }`; dates per
|
|
57
|
+
language and in the configured time zone. Adding a language takes one file.
|
|
58
|
+
|
|
59
|
+
**Sign-in and sharing**
|
|
60
|
+
|
|
61
|
+
- Sign-in for one person: argon2 password and TOTP code, server-side sessions in SQLite,
|
|
62
|
+
lockout after repeated failures, `auth.mode = "none"` for gateways, and `micelio user`
|
|
63
|
+
commands to create the secrets. On `127.0.0.1` with no secrets, sign-in is off.
|
|
64
|
+
- Public notes: anonymous visitors see the landing, `/explore`, `/projects`, the journal
|
|
65
|
+
and the APIs built from `public: true` notes only. Private notes do not exist for them:
|
|
66
|
+
no titles, links, nodes, ghosts or counts, and their URLs answer 404.
|
|
67
|
+
- Security headers (CSP without inline code, no framing) on every response.
|
|
68
|
+
|
|
69
|
+
**Installing**
|
|
70
|
+
|
|
71
|
+
- A Docker image, `ghcr.io/0xpietri/micelio`, for `linux/amd64` and `linux/arm64`: a
|
|
72
|
+
non-root user, a read-only root filesystem, the vault mounted read-only, one data volume
|
|
73
|
+
and a health check. `compose.example.yml` runs it on the sample vault in one command.
|
|
74
|
+
- The Python package `micelio` on PyPI: `uvx micelio serve --vault ~/Notes`.
|
|
75
|
+
- `micelio serve` takes its defaults from `MICELIO_HOST`, `MICELIO_PORT` and
|
|
76
|
+
`MICELIO_FORWARDED_ALLOW_IPS`.
|
|
77
|
+
- Self-hosting guides for Micelio plus a notes MCP server, on your own computer or on a
|
|
78
|
+
server.
|
|
79
|
+
- A sample vault in `examples/vault`, CI on Linux, macOS and Windows, and releases from a
|
|
80
|
+
tag (image, package and GitHub release).
|
|
81
|
+
|
|
82
|
+
[Unreleased]: https://github.com/0xpietri/micelio/compare/v0.1.0...HEAD
|
|
83
|
+
[0.1.0]: https://github.com/0xpietri/micelio/releases/tag/v0.1.0
|
micelio-0.1.0/Dockerfile
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
# Micelio: one small container that reads a vault mounted read-only.
|
|
3
|
+
|
|
4
|
+
ARG PYTHON_VERSION=3.12
|
|
5
|
+
|
|
6
|
+
# --- build: resolve the locked dependencies and install the package into /app/.venv
|
|
7
|
+
FROM ghcr.io/astral-sh/uv:0.13 AS uv
|
|
8
|
+
FROM python:${PYTHON_VERSION}-slim AS build
|
|
9
|
+
COPY --from=uv /uv /usr/local/bin/uv
|
|
10
|
+
ENV UV_COMPILE_BYTECODE=1 \
|
|
11
|
+
UV_LINK_MODE=copy \
|
|
12
|
+
UV_PYTHON_DOWNLOADS=never \
|
|
13
|
+
UV_PROJECT_ENVIRONMENT=/app/.venv
|
|
14
|
+
WORKDIR /src
|
|
15
|
+
# Dependencies first, so editing the code does not reinstall them.
|
|
16
|
+
COPY pyproject.toml uv.lock ./
|
|
17
|
+
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
18
|
+
uv sync --locked --no-dev --no-install-project
|
|
19
|
+
COPY README.md LICENSE ./
|
|
20
|
+
COPY src ./src
|
|
21
|
+
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
22
|
+
uv sync --locked --no-dev --no-editable
|
|
23
|
+
|
|
24
|
+
# --- runtime: Python and the virtual environment, nothing else
|
|
25
|
+
FROM python:${PYTHON_VERSION}-slim
|
|
26
|
+
ARG VERSION=dev
|
|
27
|
+
LABEL org.opencontainers.image.title="Micelio" \
|
|
28
|
+
org.opencontainers.image.description="Your Markdown notes as a living network of ideas" \
|
|
29
|
+
org.opencontainers.image.source="https://github.com/0xpietri/micelio" \
|
|
30
|
+
org.opencontainers.image.licenses="MIT" \
|
|
31
|
+
org.opencontainers.image.version="${VERSION}"
|
|
32
|
+
|
|
33
|
+
RUN groupadd --gid 10001 micelio \
|
|
34
|
+
&& useradd --uid 10001 --no-log-init --gid micelio --no-create-home --home-dir /data micelio \
|
|
35
|
+
&& mkdir -p /vault /data \
|
|
36
|
+
&& chown micelio:micelio /data
|
|
37
|
+
COPY --from=build /app/.venv /app/.venv
|
|
38
|
+
|
|
39
|
+
ENV PATH=/app/.venv/bin:$PATH \
|
|
40
|
+
PYTHONDONTWRITEBYTECODE=1 \
|
|
41
|
+
PYTHONUNBUFFERED=1 \
|
|
42
|
+
MICELIO_VAULT=/vault \
|
|
43
|
+
MICELIO_DATA=/data \
|
|
44
|
+
MICELIO_HOST=0.0.0.0 \
|
|
45
|
+
MICELIO_PORT=8765
|
|
46
|
+
|
|
47
|
+
USER micelio
|
|
48
|
+
WORKDIR /data
|
|
49
|
+
VOLUME ["/data"]
|
|
50
|
+
EXPOSE 8765
|
|
51
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
52
|
+
CMD ["python", "-c", "import os, urllib.request; urllib.request.urlopen(f\"http://127.0.0.1:{os.environ.get('MICELIO_PORT', '8765')}/healthz\", timeout=4)"]
|
|
53
|
+
ENTRYPOINT ["micelio"]
|
|
54
|
+
CMD ["serve"]
|
micelio-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marcos Pietri
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
micelio-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: micelio
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Your Markdown notes as a living network of ideas: projects, graphs and links, self-hosted and read-only.
|
|
5
|
+
Project-URL: Homepage, https://github.com/0xpietri/micelio
|
|
6
|
+
Project-URL: Issues, https://github.com/0xpietri/micelio/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/0xpietri/micelio/blob/main/CHANGELOG.md
|
|
8
|
+
Author: Marcos Pietri
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: knowledge-graph,markdown,mcp,obsidian,second-brain,zettelkasten
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Web Environment
|
|
14
|
+
Classifier: Framework :: FastAPI
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: argon2-cffi>=23.1
|
|
21
|
+
Requires-Dist: babel>=2.16
|
|
22
|
+
Requires-Dist: fastapi>=0.115
|
|
23
|
+
Requires-Dist: jinja2>=3.1
|
|
24
|
+
Requires-Dist: markdown-it-py>=3.0
|
|
25
|
+
Requires-Dist: mdit-py-plugins>=0.4
|
|
26
|
+
Requires-Dist: nh3>=0.2.18
|
|
27
|
+
Requires-Dist: pydantic>=2.9
|
|
28
|
+
Requires-Dist: python-multipart>=0.0.18
|
|
29
|
+
Requires-Dist: pyyaml>=6.0
|
|
30
|
+
Requires-Dist: qrcode>=8.0
|
|
31
|
+
Requires-Dist: tzdata>=2024.1; sys_platform == 'win32'
|
|
32
|
+
Requires-Dist: uvicorn>=0.32
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# Micelio
|
|
36
|
+
|
|
37
|
+
**Your Markdown notes as a living network of ideas.** Micelio reads a folder of notes (an
|
|
38
|
+
Obsidian vault, or any folder of `.md` files) and shows it as projects, links and graphs on a
|
|
39
|
+
small self-hosted website. It is read-only: your notes stay plain files that you, your editor
|
|
40
|
+
or an AI assistant write.
|
|
41
|
+
|
|
42
|
+
*Micelio* is Spanish for mycelium, the web of threads that grows under a forest; say
|
|
43
|
+
"mee-SEH-lyo".
|
|
44
|
+
|
|
45
|
+
[](https://github.com/0xpietri/micelio/actions/workflows/ci.yml)
|
|
46
|
+
[](https://pypi.org/project/micelio/)
|
|
47
|
+
[](LICENSE)
|
|
48
|
+
|
|
49
|
+

|
|
51
|
+
|
|
52
|
+
## Why
|
|
53
|
+
|
|
54
|
+
Notes written over months, by hand or by an assistant over [MCP](https://modelcontextprotocol.io),
|
|
55
|
+
pile up into a web of ideas that a file list cannot show. Micelio makes that web visible:
|
|
56
|
+
|
|
57
|
+
- **Projects** grow above ground like mushrooms; the **notes** they link to spread below as
|
|
58
|
+
mycelium, and notes shared by projects of different categories become visible **bridges**.
|
|
59
|
+
- **Graphs** for the whole vault, for each project and around each note.
|
|
60
|
+
- **Health**: broken links (shown as ghost nodes), unknown frontmatter values and orphans.
|
|
61
|
+
- **Sharing**: mark a note `public: true` and anonymous visitors can read it; everything else
|
|
62
|
+
needs a sign-in.
|
|
63
|
+
- **Any assistant**: Micelio does not care who wrote the notes. Claude, ChatGPT, a local
|
|
64
|
+
model or you in Obsidian all work.
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
**Try it** on the bundled sample vault, with Docker:
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
git clone https://github.com/0xpietri/micelio
|
|
72
|
+
cd micelio
|
|
73
|
+
docker compose -f compose.example.yml up # http://localhost:8765
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**On your own computer**, with [uv](https://docs.astral.sh/uv/) (Linux, macOS or Windows),
|
|
77
|
+
no Docker needed:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
uvx micelio serve --vault ~/Obsidian # http://127.0.0.1:8765
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
(or `pipx install micelio`, then `micelio serve --vault ~/Obsidian`). On
|
|
84
|
+
`127.0.0.1` sign-in is off until you set it up; nobody else can reach it.
|
|
85
|
+
|
|
86
|
+
**On a server**, run the image `ghcr.io/0xpietri/micelio` (amd64 and arm64, so a Raspberry
|
|
87
|
+
Pi works too) with the vault mounted read-only:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
docker run -d --name micelio --read-only --tmpfs /tmp -p 127.0.0.1:8765:8765 \
|
|
91
|
+
-v ~/Obsidian:/vault:ro -v micelio-data:/data --env-file .env \
|
|
92
|
+
ghcr.io/0xpietri/micelio:0.1
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`.env` holds the sign-in secrets (see [Signing in](#signing-in)); put a reverse proxy with
|
|
96
|
+
TLS (Caddy, Nginx, Traefik) in front. [`compose.example.yml`](compose.example.yml) shows the
|
|
97
|
+
same as a Compose file, and the [server guide](docs/guides/self-hosting-server.md) walks
|
|
98
|
+
through a whole setup with a notes MCP server.
|
|
99
|
+
|
|
100
|
+
To work on Micelio itself, see [CONTRIBUTING.md](CONTRIBUTING.md): `uv sync`, then
|
|
101
|
+
`uv run micelio serve --vault examples/vault`.
|
|
102
|
+
|
|
103
|
+
## How it works
|
|
104
|
+
|
|
105
|
+
```mermaid
|
|
106
|
+
flowchart LR
|
|
107
|
+
subgraph writers [Who writes]
|
|
108
|
+
A["AI assistant<br/>(Claude, ChatGPT, local model)"] -->|MCP| M[Notes MCP server]
|
|
109
|
+
O[You in Obsidian]
|
|
110
|
+
end
|
|
111
|
+
M --> V[("Vault<br/>Markdown files")]
|
|
112
|
+
O --> V
|
|
113
|
+
V -->|read-only| R
|
|
114
|
+
subgraph app [Micelio: one process]
|
|
115
|
+
R[Vault reader<br/>frontmatter + wikilinks] --> I[In-memory index<br/>links, projects, bridges]
|
|
116
|
+
I --> P[Pages<br/>FastAPI + Jinja]
|
|
117
|
+
I --> J["/api/graph, /api/landing"]
|
|
118
|
+
S[("data/<br/>SQLite: sessions,<br/>Appearance")] --- P
|
|
119
|
+
end
|
|
120
|
+
P --> B[Browser]
|
|
121
|
+
J --> B
|
|
122
|
+
B -.->|"draw.js + d3-force<br/>mushrooms and hyphae"| B
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- The vault is the only source of truth. Micelio re-reads files when they change and keeps
|
|
126
|
+
the index in memory; delete its data folder and nothing is lost.
|
|
127
|
+
- Its own state (sign-in sessions, the Appearance page's choices, an uploaded background)
|
|
128
|
+
lives in a small SQLite file in the data folder, never in the vault.
|
|
129
|
+
- Pages are rendered on the server; the landing and the graphs are plain JavaScript modules
|
|
130
|
+
over JSON, with vendored libraries and no build step.
|
|
131
|
+
- Anonymous visitors get a filtered view built from `public: true` notes only.
|
|
132
|
+
|
|
133
|
+
## Talking to your notes
|
|
134
|
+
|
|
135
|
+
Micelio shows notes; an MCP server writes them when you talk to an assistant, from a desktop
|
|
136
|
+
app or from your phone in voice mode. The [self-hosting guides](docs/guides/README.md) set up
|
|
137
|
+
both, either [on your own computer](docs/guides/self-hosting-computer.md) (Linux, macOS,
|
|
138
|
+
Windows) or [on a server](docs/guides/self-hosting-server.md).
|
|
139
|
+
|
|
140
|
+
## How a vault is read
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
vault/
|
|
144
|
+
projects/ one note per project, with a category; it links to its notes
|
|
145
|
+
notes/ one idea per note
|
|
146
|
+
journal/ dated entries
|
|
147
|
+
sources/ books, papers, links
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Each note may start with a frontmatter block:
|
|
151
|
+
|
|
152
|
+
```yaml
|
|
153
|
+
---
|
|
154
|
+
type: project # project | note | journal | source (otherwise taken from the folder)
|
|
155
|
+
category: science # projects only; one of the categories in micelio.toml
|
|
156
|
+
status: active # draft | active | paused | closed
|
|
157
|
+
tags: [gravity, astrology]
|
|
158
|
+
created: 2026-11-09
|
|
159
|
+
public: false # true lets anonymous visitors read it
|
|
160
|
+
aliases: [Planets at birth]
|
|
161
|
+
---
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Links use Obsidian's `[[wikilink]]` syntax, including `[[Note#Heading|label]]`, aliases and
|
|
165
|
+
paths. A note belongs to a project when the project links to it. Hidden folders (`.obsidian`,
|
|
166
|
+
`.trash`) and Syncthing conflict copies are ignored. Nothing in the frontmatter is required;
|
|
167
|
+
odd values are reported by `micelio check`, never fatal.
|
|
168
|
+
|
|
169
|
+
## Interface languages
|
|
170
|
+
|
|
171
|
+
The interface ships in English and Spanish (`language = "es"` in `micelio.toml`); your notes
|
|
172
|
+
are always shown as written. Adding a language takes one file, see
|
|
173
|
+
[CONTRIBUTING.md](CONTRIBUTING.md#adding-a-language).
|
|
174
|
+
|
|
175
|
+
## Configuration
|
|
176
|
+
|
|
177
|
+
Copy [`micelio.example.toml`](micelio.example.toml) to `micelio.toml` and point
|
|
178
|
+
`--config` (or `MICELIO_CONFIG`) at it. It holds the site title, the owner's name, the vault
|
|
179
|
+
folders and the categories, each with a mushroom species for the landing page.
|
|
180
|
+
Secrets never go in this file; see [`.env.example`](.env.example).
|
|
181
|
+
|
|
182
|
+
## The landing and its look
|
|
183
|
+
|
|
184
|
+
The home page draws your vault as a forest: each project is a mushroom above the soil (its
|
|
185
|
+
species comes from the category, its size from its notes, its shape from its status), notes
|
|
186
|
+
are clouds of spores in the mycelium below, links are threads, sources are crystals and the
|
|
187
|
+
latest journal notes float as golden spores. Hover for titles, click to open.
|
|
188
|
+
|
|
189
|
+
Signed in, **Appearance** (`/appearance`) changes how it looks: four palettes (Psychedelic,
|
|
190
|
+
Tokyo Night, Catppuccin Mocha, Rosé Pine), your own background image, where the soil starts,
|
|
191
|
+
and the title and tagline. It also builds a prompt you can paste into any image generator to
|
|
192
|
+
paint a background that fits. These choices are saved in the data folder, never in your notes;
|
|
193
|
+
`[landing]` in the config sets the defaults.
|
|
194
|
+
|
|
195
|
+
## Signing in
|
|
196
|
+
|
|
197
|
+
One person signs in, with a password and a code from an authenticator app (any TOTP app:
|
|
198
|
+
Aegis, 2FAS, Google Authenticator, 1Password…). Generate the three secrets once and put them
|
|
199
|
+
in your environment:
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
micelio user set-password # prints MICELIO_PASSWORD_HASH
|
|
203
|
+
micelio user totp # shows a QR code, prints MICELIO_TOTP_SECRET
|
|
204
|
+
micelio user session-key # prints MICELIO_SESSION_KEY
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
- Sessions last 12 hours and are stored server-side, so signing out really ends them.
|
|
208
|
+
`micelio user sign-out-all` ends every session.
|
|
209
|
+
- Five failed attempts from one address lock it out for 15 minutes.
|
|
210
|
+
- On your own computer, `micelio serve` listens on `127.0.0.1` only; with no secrets set,
|
|
211
|
+
sign-in is simply off there. On any other address, Micelio refuses to start without them.
|
|
212
|
+
- Already behind Cloudflare Access, Authelia or another gateway? Set `auth.mode = "none"` and
|
|
213
|
+
Micelio trusts whoever reaches it. Only do this when the gateway really guards every path.
|
|
214
|
+
|
|
215
|
+
## Security
|
|
216
|
+
|
|
217
|
+
- Micelio never writes to the vault; mount it read-only. The image runs as a non-root user
|
|
218
|
+
with a read-only root filesystem and writes only to `/data`.
|
|
219
|
+
- Anonymous visitors see notes marked `public: true` and nothing else: no private titles,
|
|
220
|
+
links, counts or ghost nodes, and a private note's URL answers 404.
|
|
221
|
+
- Sign-in is a password plus a TOTP code, with server-side sessions and a lockout. Micelio
|
|
222
|
+
refuses to listen on a public address without its secrets, unless you say a gateway
|
|
223
|
+
handles sign-in (`auth.mode = "none"`).
|
|
224
|
+
- Every response carries a strict Content Security Policy (no inline code, no framing), and
|
|
225
|
+
note bodies are sanitized.
|
|
226
|
+
- Secrets live in the environment, never in `micelio.toml`. Report problems privately, see
|
|
227
|
+
[SECURITY.md](SECURITY.md).
|
|
228
|
+
|
|
229
|
+
## Roadmap
|
|
230
|
+
|
|
231
|
+
- **v0.1** (this release): the landing, the graphs, the reading pages, sign-in, public notes,
|
|
232
|
+
the Appearance page, English and Spanish, Docker image and PyPI package.
|
|
233
|
+
- **v0.2**: a static export of the public notes, to share them without a server
|
|
234
|
+
(GitHub Pages, Cloudflare Pages, Netlify or a zip).
|
|
235
|
+
- **v0.3**: an Obsidian plugin with the landing and the graph inside Obsidian.
|
|
236
|
+
|
|
237
|
+
The full specification is in [`docs/spec`](docs/spec/MICELIO_SPEC_v0.1.md); what changed in
|
|
238
|
+
each version is in the [CHANGELOG](CHANGELOG.md).
|
|
239
|
+
|
|
240
|
+
## Contributing
|
|
241
|
+
|
|
242
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Security reports: [SECURITY.md](SECURITY.md).
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
[MIT](LICENSE) © 2026 Marcos Pietri
|
micelio-0.1.0/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Micelio
|
|
2
|
+
|
|
3
|
+
**Your Markdown notes as a living network of ideas.** Micelio reads a folder of notes (an
|
|
4
|
+
Obsidian vault, or any folder of `.md` files) and shows it as projects, links and graphs on a
|
|
5
|
+
small self-hosted website. It is read-only: your notes stay plain files that you, your editor
|
|
6
|
+
or an AI assistant write.
|
|
7
|
+
|
|
8
|
+
*Micelio* is Spanish for mycelium, the web of threads that grows under a forest; say
|
|
9
|
+
"mee-SEH-lyo".
|
|
10
|
+
|
|
11
|
+
[](https://github.com/0xpietri/micelio/actions/workflows/ci.yml)
|
|
12
|
+
[](https://pypi.org/project/micelio/)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
|
|
15
|
+

|
|
17
|
+
|
|
18
|
+
## Why
|
|
19
|
+
|
|
20
|
+
Notes written over months, by hand or by an assistant over [MCP](https://modelcontextprotocol.io),
|
|
21
|
+
pile up into a web of ideas that a file list cannot show. Micelio makes that web visible:
|
|
22
|
+
|
|
23
|
+
- **Projects** grow above ground like mushrooms; the **notes** they link to spread below as
|
|
24
|
+
mycelium, and notes shared by projects of different categories become visible **bridges**.
|
|
25
|
+
- **Graphs** for the whole vault, for each project and around each note.
|
|
26
|
+
- **Health**: broken links (shown as ghost nodes), unknown frontmatter values and orphans.
|
|
27
|
+
- **Sharing**: mark a note `public: true` and anonymous visitors can read it; everything else
|
|
28
|
+
needs a sign-in.
|
|
29
|
+
- **Any assistant**: Micelio does not care who wrote the notes. Claude, ChatGPT, a local
|
|
30
|
+
model or you in Obsidian all work.
|
|
31
|
+
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
**Try it** on the bundled sample vault, with Docker:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
git clone https://github.com/0xpietri/micelio
|
|
38
|
+
cd micelio
|
|
39
|
+
docker compose -f compose.example.yml up # http://localhost:8765
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**On your own computer**, with [uv](https://docs.astral.sh/uv/) (Linux, macOS or Windows),
|
|
43
|
+
no Docker needed:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
uvx micelio serve --vault ~/Obsidian # http://127.0.0.1:8765
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
(or `pipx install micelio`, then `micelio serve --vault ~/Obsidian`). On
|
|
50
|
+
`127.0.0.1` sign-in is off until you set it up; nobody else can reach it.
|
|
51
|
+
|
|
52
|
+
**On a server**, run the image `ghcr.io/0xpietri/micelio` (amd64 and arm64, so a Raspberry
|
|
53
|
+
Pi works too) with the vault mounted read-only:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
docker run -d --name micelio --read-only --tmpfs /tmp -p 127.0.0.1:8765:8765 \
|
|
57
|
+
-v ~/Obsidian:/vault:ro -v micelio-data:/data --env-file .env \
|
|
58
|
+
ghcr.io/0xpietri/micelio:0.1
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`.env` holds the sign-in secrets (see [Signing in](#signing-in)); put a reverse proxy with
|
|
62
|
+
TLS (Caddy, Nginx, Traefik) in front. [`compose.example.yml`](compose.example.yml) shows the
|
|
63
|
+
same as a Compose file, and the [server guide](docs/guides/self-hosting-server.md) walks
|
|
64
|
+
through a whole setup with a notes MCP server.
|
|
65
|
+
|
|
66
|
+
To work on Micelio itself, see [CONTRIBUTING.md](CONTRIBUTING.md): `uv sync`, then
|
|
67
|
+
`uv run micelio serve --vault examples/vault`.
|
|
68
|
+
|
|
69
|
+
## How it works
|
|
70
|
+
|
|
71
|
+
```mermaid
|
|
72
|
+
flowchart LR
|
|
73
|
+
subgraph writers [Who writes]
|
|
74
|
+
A["AI assistant<br/>(Claude, ChatGPT, local model)"] -->|MCP| M[Notes MCP server]
|
|
75
|
+
O[You in Obsidian]
|
|
76
|
+
end
|
|
77
|
+
M --> V[("Vault<br/>Markdown files")]
|
|
78
|
+
O --> V
|
|
79
|
+
V -->|read-only| R
|
|
80
|
+
subgraph app [Micelio: one process]
|
|
81
|
+
R[Vault reader<br/>frontmatter + wikilinks] --> I[In-memory index<br/>links, projects, bridges]
|
|
82
|
+
I --> P[Pages<br/>FastAPI + Jinja]
|
|
83
|
+
I --> J["/api/graph, /api/landing"]
|
|
84
|
+
S[("data/<br/>SQLite: sessions,<br/>Appearance")] --- P
|
|
85
|
+
end
|
|
86
|
+
P --> B[Browser]
|
|
87
|
+
J --> B
|
|
88
|
+
B -.->|"draw.js + d3-force<br/>mushrooms and hyphae"| B
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- The vault is the only source of truth. Micelio re-reads files when they change and keeps
|
|
92
|
+
the index in memory; delete its data folder and nothing is lost.
|
|
93
|
+
- Its own state (sign-in sessions, the Appearance page's choices, an uploaded background)
|
|
94
|
+
lives in a small SQLite file in the data folder, never in the vault.
|
|
95
|
+
- Pages are rendered on the server; the landing and the graphs are plain JavaScript modules
|
|
96
|
+
over JSON, with vendored libraries and no build step.
|
|
97
|
+
- Anonymous visitors get a filtered view built from `public: true` notes only.
|
|
98
|
+
|
|
99
|
+
## Talking to your notes
|
|
100
|
+
|
|
101
|
+
Micelio shows notes; an MCP server writes them when you talk to an assistant, from a desktop
|
|
102
|
+
app or from your phone in voice mode. The [self-hosting guides](docs/guides/README.md) set up
|
|
103
|
+
both, either [on your own computer](docs/guides/self-hosting-computer.md) (Linux, macOS,
|
|
104
|
+
Windows) or [on a server](docs/guides/self-hosting-server.md).
|
|
105
|
+
|
|
106
|
+
## How a vault is read
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
vault/
|
|
110
|
+
projects/ one note per project, with a category; it links to its notes
|
|
111
|
+
notes/ one idea per note
|
|
112
|
+
journal/ dated entries
|
|
113
|
+
sources/ books, papers, links
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Each note may start with a frontmatter block:
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
---
|
|
120
|
+
type: project # project | note | journal | source (otherwise taken from the folder)
|
|
121
|
+
category: science # projects only; one of the categories in micelio.toml
|
|
122
|
+
status: active # draft | active | paused | closed
|
|
123
|
+
tags: [gravity, astrology]
|
|
124
|
+
created: 2026-11-09
|
|
125
|
+
public: false # true lets anonymous visitors read it
|
|
126
|
+
aliases: [Planets at birth]
|
|
127
|
+
---
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Links use Obsidian's `[[wikilink]]` syntax, including `[[Note#Heading|label]]`, aliases and
|
|
131
|
+
paths. A note belongs to a project when the project links to it. Hidden folders (`.obsidian`,
|
|
132
|
+
`.trash`) and Syncthing conflict copies are ignored. Nothing in the frontmatter is required;
|
|
133
|
+
odd values are reported by `micelio check`, never fatal.
|
|
134
|
+
|
|
135
|
+
## Interface languages
|
|
136
|
+
|
|
137
|
+
The interface ships in English and Spanish (`language = "es"` in `micelio.toml`); your notes
|
|
138
|
+
are always shown as written. Adding a language takes one file, see
|
|
139
|
+
[CONTRIBUTING.md](CONTRIBUTING.md#adding-a-language).
|
|
140
|
+
|
|
141
|
+
## Configuration
|
|
142
|
+
|
|
143
|
+
Copy [`micelio.example.toml`](micelio.example.toml) to `micelio.toml` and point
|
|
144
|
+
`--config` (or `MICELIO_CONFIG`) at it. It holds the site title, the owner's name, the vault
|
|
145
|
+
folders and the categories, each with a mushroom species for the landing page.
|
|
146
|
+
Secrets never go in this file; see [`.env.example`](.env.example).
|
|
147
|
+
|
|
148
|
+
## The landing and its look
|
|
149
|
+
|
|
150
|
+
The home page draws your vault as a forest: each project is a mushroom above the soil (its
|
|
151
|
+
species comes from the category, its size from its notes, its shape from its status), notes
|
|
152
|
+
are clouds of spores in the mycelium below, links are threads, sources are crystals and the
|
|
153
|
+
latest journal notes float as golden spores. Hover for titles, click to open.
|
|
154
|
+
|
|
155
|
+
Signed in, **Appearance** (`/appearance`) changes how it looks: four palettes (Psychedelic,
|
|
156
|
+
Tokyo Night, Catppuccin Mocha, Rosé Pine), your own background image, where the soil starts,
|
|
157
|
+
and the title and tagline. It also builds a prompt you can paste into any image generator to
|
|
158
|
+
paint a background that fits. These choices are saved in the data folder, never in your notes;
|
|
159
|
+
`[landing]` in the config sets the defaults.
|
|
160
|
+
|
|
161
|
+
## Signing in
|
|
162
|
+
|
|
163
|
+
One person signs in, with a password and a code from an authenticator app (any TOTP app:
|
|
164
|
+
Aegis, 2FAS, Google Authenticator, 1Password…). Generate the three secrets once and put them
|
|
165
|
+
in your environment:
|
|
166
|
+
|
|
167
|
+
```sh
|
|
168
|
+
micelio user set-password # prints MICELIO_PASSWORD_HASH
|
|
169
|
+
micelio user totp # shows a QR code, prints MICELIO_TOTP_SECRET
|
|
170
|
+
micelio user session-key # prints MICELIO_SESSION_KEY
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
- Sessions last 12 hours and are stored server-side, so signing out really ends them.
|
|
174
|
+
`micelio user sign-out-all` ends every session.
|
|
175
|
+
- Five failed attempts from one address lock it out for 15 minutes.
|
|
176
|
+
- On your own computer, `micelio serve` listens on `127.0.0.1` only; with no secrets set,
|
|
177
|
+
sign-in is simply off there. On any other address, Micelio refuses to start without them.
|
|
178
|
+
- Already behind Cloudflare Access, Authelia or another gateway? Set `auth.mode = "none"` and
|
|
179
|
+
Micelio trusts whoever reaches it. Only do this when the gateway really guards every path.
|
|
180
|
+
|
|
181
|
+
## Security
|
|
182
|
+
|
|
183
|
+
- Micelio never writes to the vault; mount it read-only. The image runs as a non-root user
|
|
184
|
+
with a read-only root filesystem and writes only to `/data`.
|
|
185
|
+
- Anonymous visitors see notes marked `public: true` and nothing else: no private titles,
|
|
186
|
+
links, counts or ghost nodes, and a private note's URL answers 404.
|
|
187
|
+
- Sign-in is a password plus a TOTP code, with server-side sessions and a lockout. Micelio
|
|
188
|
+
refuses to listen on a public address without its secrets, unless you say a gateway
|
|
189
|
+
handles sign-in (`auth.mode = "none"`).
|
|
190
|
+
- Every response carries a strict Content Security Policy (no inline code, no framing), and
|
|
191
|
+
note bodies are sanitized.
|
|
192
|
+
- Secrets live in the environment, never in `micelio.toml`. Report problems privately, see
|
|
193
|
+
[SECURITY.md](SECURITY.md).
|
|
194
|
+
|
|
195
|
+
## Roadmap
|
|
196
|
+
|
|
197
|
+
- **v0.1** (this release): the landing, the graphs, the reading pages, sign-in, public notes,
|
|
198
|
+
the Appearance page, English and Spanish, Docker image and PyPI package.
|
|
199
|
+
- **v0.2**: a static export of the public notes, to share them without a server
|
|
200
|
+
(GitHub Pages, Cloudflare Pages, Netlify or a zip).
|
|
201
|
+
- **v0.3**: an Obsidian plugin with the landing and the graph inside Obsidian.
|
|
202
|
+
|
|
203
|
+
The full specification is in [`docs/spec`](docs/spec/MICELIO_SPEC_v0.1.md); what changed in
|
|
204
|
+
each version is in the [CHANGELOG](CHANGELOG.md).
|
|
205
|
+
|
|
206
|
+
## Contributing
|
|
207
|
+
|
|
208
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Security reports: [SECURITY.md](SECURITY.md).
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
[MIT](LICENSE) © 2026 Marcos Pietri
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Micelio with Docker Compose.
|
|
2
|
+
#
|
|
3
|
+
# Try it on the bundled sample vault, from a clone of the repository:
|
|
4
|
+
#
|
|
5
|
+
# docker compose -f compose.example.yml up
|
|
6
|
+
#
|
|
7
|
+
# and open http://localhost:8765. The demo turns sign-in off and only listens on this
|
|
8
|
+
# computer. For your own notes, copy this file to compose.yml and follow the comments.
|
|
9
|
+
|
|
10
|
+
services:
|
|
11
|
+
micelio:
|
|
12
|
+
image: ghcr.io/0xpietri/micelio:0.1
|
|
13
|
+
# build: . # or build the image from this folder
|
|
14
|
+
restart: unless-stopped
|
|
15
|
+
read_only: true # the image writes only to /data (and /tmp)
|
|
16
|
+
tmpfs:
|
|
17
|
+
- /tmp
|
|
18
|
+
cap_drop: [ALL]
|
|
19
|
+
security_opt:
|
|
20
|
+
- no-new-privileges:true
|
|
21
|
+
ports:
|
|
22
|
+
- "127.0.0.1:8765:8765" # behind a reverse proxy, keep it on 127.0.0.1
|
|
23
|
+
volumes:
|
|
24
|
+
- ./examples/vault:/vault:ro # your vault: e.g. ~/Obsidian:/vault:ro
|
|
25
|
+
- ./examples/demo.toml:/config/micelio.toml:ro # your micelio.toml
|
|
26
|
+
- micelio-data:/data # sessions and the Appearance page's choices
|
|
27
|
+
environment:
|
|
28
|
+
MICELIO_CONFIG: /config/micelio.toml
|
|
29
|
+
# Behind a reverse proxy on the host, trust it for the visitor's address
|
|
30
|
+
# (used by the sign-in lockout). Docker networks usually sit in 172.16.0.0/12:
|
|
31
|
+
# MICELIO_FORWARDED_ALLOW_IPS: 172.16.0.0/12
|
|
32
|
+
# With sign-in on, put the three secrets from `micelio user ...` in .env:
|
|
33
|
+
# env_file: .env
|
|
34
|
+
|
|
35
|
+
volumes:
|
|
36
|
+
micelio-data:
|