This release is a pre-release and may not be stable for production use.
foamwiki
A Rust-backed, notebook-first Python library and thin CLI for Foam-style
Markdown wikis (folders of notes connected by [[wikilinks]]).
The native core reads and parses notes in parallel, maintains the identity and resolution indexes, and stores the link graph. The Python layer preserves the convenient data-oriented API, PyYAML frontmatter values, templates, and filesystem mutation receipts.
Installation
The distribution is named foam-wiki; the Python package and command are both
named foamwiki.
Install the stable release:
uv add foam-wiki
# or: python -m pip install foam-wiki
Until the first stable release, opt into the published prerelease:
uv add --prerelease allow foam-wiki
# or: python -m pip install --pre foam-wiki
Run the CLI without adding a project dependency:
uvx --from foam-wiki foamwiki --help
To install the current branch directly from Git:
foam-wiki @ git+https://github.com/nimashoghi/foampy.git
Git installations build the extension from source and require Rust 1.88 or newer. CI produces CPython stable-ABI wheels for manylinux2014 x86_64 and AArch64 (glibc-based Linux), macOS x86_64 and Apple silicon, and Windows x86_64. Each wheel supports Python 3.10 and newer.
Core API
import foamwiki
ws = foamwiki.load() # walk up to .foam/ ; parse + index once
note = ws["mean-flow"] # lookup by shortest id or path
note.title, note.tags, note.outline
note.backlinks() # who links here
ws.resolve("flow-matching") # -> the target Note (falsy Unresolved if broken)
hits = ws.search("TM-align") # compact immutable Sequence[Hit]
hits[:20] # materialize only the rows being inspected
hits.materialize() # explicit eager Rows[Hit], when required
foamwiki.orphans(ws) # whole-graph census (free functions)
foamwiki.check(ws) # strict link diagnostics
foamwiki.rename(ws, note, "papers/meanflow.md") # dry-run preview; pass dry_run=False to apply
Resolution validates #heading and #^block fragments. Ambiguous attachment
suffixes return a falsy Unresolved(reason="ambiguous") rather than silently
choosing one file. Percent-encode reserved characters in attachment paths, for
example ![[fig%23draft%5D.png]] for fig#draft].png; diagnostic suggestions
do this automatically.
Workspace-wide operations verify that the effective configuration, indexed file census, and every indexed note still match the loaded snapshot. Applied mutations also reject symlink-backed write sources, stage all output before changing the workspace, and roll back on write or reload failure. A dry run therefore remains safe to review even while another editor is active: replanning or applying it fails loudly instead of overwriting newer content.
Compact notebook output
Public records use compact, payload-free representations while keeping
identifiers and paths intact. Potentially large text fields are bounded. Search
hits center an 88-character excerpt on the match instead of dumping the complete
source line and nested Note/Pos records:
<Hit alphafold-2/paper L272:550 '...colaboratory). TM-align v. 20190822 (https://zhanglab.dcmb.med.umich.edu/...'>
Rows, SearchResults, tag indexes, document outlines, and node child menus
display at most 20 entries and report how many remain. Slice them to continue.
Literal SearchResults also materialize public hit records only on access;
call .materialize() for an eager Rows[Hit]. Automatic mutation diff
previews are bounded; call ChangeSet.diff() for the complete diff. These
limits affect display only: Hit.text and Match.line retain the exact source
line (including indentation), while record fields, iteration, and .to_df()
retain complete data. Passage remains intentionally unbounded because
evaluating .body or .read() is an explicit request for content.
Template authoring
Markdown templates can declare foam_template.filepath and use Foam variables
in both their content and destination. Preview first, then repeat the reviewed
call with dry_run=False:
draft = foamwiki.create(
ws,
template="meeting-scratchpad",
when="2026-07-15T14:30:00+01:00",
dry_run=True,
)
draft.path, draft.frontmatter, draft.text
note = foamwiki.create(
ws,
template="meeting-scratchpad",
when="2026-07-15T14:30:00+01:00",
dry_run=False,
)
foamwiki.daily(ws, "2026-07-15", dry_run=True) uses daily-note.md and prefers
its template filepath. Explicit destinations always override template metadata.
Structure-aware reading (for notebook agents)
Read a large markdown file without dumping it into context. foamwiki.read
returns a priced, navigable map of the file's sections — orient cheaply, drill
by stable numeric path, search to a section, then read only what you choose:
doc = foamwiki.read("design.md") # (or note.doc for a vault note — no reparse)
doc # repr = a priced table-of-contents (~150 tok for a 40k-tok file)
doc["3.2"] # drill by numeric path (or doc["Method"] / doc[3]); prints a menu, never dumps
doc.search("KL") # term -> the sections that contain it (Rows[Match])
doc["3.2"].body # read just this section's prose (a priced Passage); .read() for the whole subtree
doc["3.2"].children # tree nav as properties: .parent .children .siblings .next .prev
Every view quotes exact line counts + ~token estimates, so you budget before
you spend. Works standalone on any .md file (no workspace needed).
See AGENTS.md for the design philosophy and the placement rule.
pandas and networkx are optional extras used lazily by .to_df() and
to_networkx(); request the all extra in the Git dependency when needed:
foam-wiki[all] @ git+https://github.com/nimashoghi/foampy.git.
Development
uv sync
uv run pytest -q
uv run ruff check .
uv run basedpyright src scripts
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
See PERFORMANCE.md for the real-workspace baseline and
reproducible benchmark command. MIGRATION.md lists the
intentional behavior and naming changes. RELEASING.md
documents local and CI release validation.
MIT licensed.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file foam_wiki-0.4.0.dev0.tar.gz.
File metadata
- Download URL: foam_wiki-0.4.0.dev0.tar.gz
- Upload date:
- Size: 177.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb58c9518a1286ace29b545ffedf6c4e8235cfd5c6c9b768f503e16d708ace7a
|
|
| MD5 |
70377248cd0ea4264b196c19003b754b
|
|
| BLAKE2b-256 |
d9c1da782d3458636c25301b55b65ef699afbd2393fe6733c8da29daf20d489d
|
File details
Details for the file foam_wiki-0.4.0.dev0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: foam_wiki-0.4.0.dev0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04917edad16e5254ac46a232fa6388c6ec1a466bc63a910156ab04fc3daef0b1
|
|
| MD5 |
7e02b437f2ef53de6d9ae1b53bf0c02d
|
|
| BLAKE2b-256 |
58945775abef594a3d449117bd0643c8d3e51d42ffa3fa28ed24b130e412e6b2
|