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.
Full paths from the vault root
Set link_format = "absolute" in foamwiki.toml to use full vault-relative note IDs and links such as [[users/nima/model]], [[users/nima/model.md#Setup|Configuration]], and ![[users/nima/model#^result]]. Folder-qualified wikilinks resolve only from the vault root in this mode; a missing users/nima/model does not fall back to archive/users/nima/model. Basename links still resolve when unambiguous, and fix expands them to the preferred full path. Directory-index links remain available when directory_mode is enabled. Explicit ./ and ../ paths keep their source-relative meaning, and ordinary Markdown links keep their existing path semantics.
This uses Obsidian's documented folder-path syntax. In Obsidian, select Settings > Files and links > New link format > Absolute path in vault to generate that spelling. Foampy's strict missing-path behavior is an explicit workspace policy; it is not a claim about undocumented Obsidian fallback behavior. Foampy does not read or change Obsidian settings.
The default link_format = "shortest" retains global shortest-ID and suffix lookup. In either mode, validation, fix, and coordinated note, heading, and block renames preserve intentional full vault-relative links, including an explicitly written note extension. Meaningful display text and embed markers survive renames. Redundant display text is still reported and removable by fix.
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.
Selective indexing below an excluded directory
Exclusions use ordered Gitignore syntax. A rooted negation can re-include a narrow subtree without disabling pruning for unrelated excluded directories:
{
"foam.files.exclude": ["!.agents/skills/**/*.md"]
}
foamwiki descends only through .agents/skills for this pattern; excluded
siblings such as .agents/sessions remain pruned. Negations without a safe
rooted prefix, such as !**/skills/**/*.md, retain conservative full-tree
traversal so their matching behavior remains correct.
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.
Commit checks
foamwiki check explicitly checks the working tree. For the exact content about to be committed, use:
foamwiki check --staged
foamwiki check --staged --new-only
The staged checker reads the active Git index and Git blobs directly. It checks the full selected graph, including unchanged notes whose destinations changed, without walking or modifying the worktree. Configuration and symlinks also come from the snapshot. Attachment contents are not read. Links outside the snapshot cannot resolve; selected notes stored as Git LFS pointers make the check incomplete. --new-only compares with HEAD using source path, diagnostic code, message, and occurrence count, so moving an existing problem to another line stays quiet. An initial commit has an empty baseline. Renamed source notes count as new source paths.
Install an advisory Git pre-commit hook in each clone with:
uv tool install foam-wiki==0.6.1
foamwiki install-hook
The installer requires POSIX and keeps the current Python environment's absolute executable path. Keep that environment available; rerun installation after moving the clone or replacing the environment. Git hooks run the prepared environment directly, without uv, downloads, daemons, watchers, or validation caches. New findings are printed with source locations and commits continue. Check failures visibly report check incomplete; they also allow the commit. Explicit checks exit 1 for findings (warnings require --strict) and 2 when incomplete.
Installation sets repository-local core.hooksPath and forwards the existing hook suite, including Git LFS, to its original scripts. Original exit statuses, arguments, stdin, environment, and working directory are preserved; an existing pre-commit failure still blocks the commit. Repeated installation is idempotent and concurrent installers do not wait. If changing the upstream hook directory later, set the desired core.hooksPath and rerun foamwiki install-hook. Git's --no-verify bypass remains available. See Git's hook contract.
Agent event hooks and the agent-hooks extra were removed in 0.6.1. Remove their old registrations from agent settings when upgrading. All other graph operations remain explicit library or CLI calls.
Metadata
Release files for foam-wiki 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| foam_wiki-0.6.1.tar.gz | 206.3 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| foam_wiki-0.6.1-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| foam_wiki-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| foam_wiki-0.6.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| foam_wiki-0.6.1-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| foam_wiki-0.6.1-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 5.9 MB
Release files / foam_wiki-0.6.1.tar.gz
| Download URL | foam_wiki-0.6.1.tar.gz |
|---|---|
| Size | 206.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
04ae1ac3ff6582922621a3b90a65103f8e21bbc5fcc0717d4c21e88884391f23
|
|
BLAKE2b-256 checksum How to use checksums |
b0b6a347483dc08332fa406fe911fddd31bcfbc0fca8a4b5f61911ea8814b80c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / foam_wiki-0.6.1-cp310-abi3-win_amd64.whl
| Download URL | foam_wiki-0.6.1-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
36cd69d051d5bb24f39881361899fb66f18a80974448d4ae2961bcdd3834feff
|
|
BLAKE2b-256 checksum How to use checksums |
323899dd2781e5a872438f0ccdf66cf9f21dd9677b7ccc900de38564ffab19c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / foam_wiki-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | foam_wiki-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
d3d3d45e96dd845529d1a53c36b29bfa2dab1c5e33df25c20a8520e0265963b2
|
|
BLAKE2b-256 checksum How to use checksums |
0f87f94c612eea3c770f38efbeb5885de90dfebf67bf592e7923f6c8cc4b60d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / foam_wiki-0.6.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | foam_wiki-0.6.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
44682425f57c2f210a478f8cec6aa39b48ed21664edbcfe7b332564741948561
|
|
BLAKE2b-256 checksum How to use checksums |
3246a4bde010d303c1f98876315dd7c65f57bc9e9c4460860a74210483d0c973
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / foam_wiki-0.6.1-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | foam_wiki-0.6.1-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
53bf41968d308be77a30361d7ad5544579ca39a08d88170c19f3b192d24109b4
|
|
BLAKE2b-256 checksum How to use checksums |
b8438f60ff5f2794fdd9a4389def401d2063caa7937f9c70b094dd04576280ba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / foam_wiki-0.6.1-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | foam_wiki-0.6.1-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
98e2af8bf57c3e752378e51072ab1c2fa89aa2f1b849d0589aaaf008033a8115
|
|
BLAKE2b-256 checksum How to use checksums |
a3f99d39d1a15bf193c34c3be900ab6ec20e6dd1cc87cb5f0811c73220c915d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log