Skip to main content

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.

Agent hooks (optional)

Install the agent-hooks extra to use the foamwiki-hooks console application. It registers project-scoped hooks for Codex and Claude Code through typed-agent-hooks, preserving unrelated settings. In a Foam workspace, run:

foamwiki-hooks install --provider all --root /path/to/wiki

Use --provider codex or --provider claude_code for one host. foamwiki-hooks uninstall removes only this application's managed entries. Restart the host and follow its normal project and hook trust flow. The executable path is specific to this installation; reinstall registrations after moving the environment or cloning a wiki onto another machine.

Hooks resolve prompt and tool-output wikilinks, expand explicit transclusions, advise about graph mutations, and report newly relevant graph diagnostics. Discovery uses .foam/ or foamwiki.toml through foamwiki.discover; Git is not required. Runtime state lives in the platform user cache, with file locks coordinating hook processes. FOAMWIKI_HOOK_STATE_ROOT can override that location for isolated tests.

Validation observes the whole workspace, including opaque notebook, shell, and background writes. One on-demand background worker per workspace and cache directory owns the graph and processes small hook event files for all sessions. It polls rather than relying on local filesystem notifications, so edits from other machines on shared filesystems are observable. Each scan reuses unchanged note contents and parsed documents by file identity and rereads only changed notes. Command hooks neither load the whole index nor scan or reread the source wiki. They wait at most half a second for advice, in addition to process startup, workspace discovery, and local message I/O.

Notifications are advisory and scoped to paths explicitly selected through resolved prompt wikilinks or recognized tool path arguments, plus affected inbound links to those paths. Selection establishes relevance, not authorship: two sessions can read or edit the same note. Unrelated changes produce neither diagnostics nor link-conversion advice in that session. New findings observed silently remain available when their notes become relevant; repairs remove stale findings when the next observation includes them. The first completed observation seen by a session quietly baselines existing diagnostics. A fork reuses the shared index but keeps its own relevance and notification state.

Observation is asynchronous. Advice and transclusions include the observation interval; concurrent or later edits may still be pending. The index verifies individual changed files around their reads, but cannot make concurrent filesystem writers transactional. Events request a refresh, requests during a scan trigger a subsequent scan, and scans are separated by at least five seconds. A worker exits after fifteen minutes without new requests and is restarted automatically on demand; process locks prevent concurrent scanners and recover after a crash. An unavailable index or busy worker produces a deduplicated pending notice rather than a claim that validation succeeded. Observations older than five minutes are not used to process events. Deferred events and advice stay in private local files; only later callbacks from the same provider, session, and agent can consume that advice. First-use link expansion may therefore require a later event, or a direct file read while the index warms up.

Use a node-local FOAMWIKI_HOOK_STATE_ROOT on hosts whose ordinary user cache is on a network filesystem. Each workspace's index-v2/ cache directory contains observation.json, the latest status.json, worker errors in worker.log, and private events/ and replies/ message directories. Failed refreshes preserve the previous published observation. The cache contains note text and hook inputs and uses private directories; it is not a durable copy of the wiki. Removing this cache discards pending advice and causes a cold rebuild on the next event.

Stop callbacks only update observation state; they never block completion or inject notifications, including on validation failure. Late background findings can be delivered on the next context-capable event when relevant. Opaque code without an explicit selected path does not assign its output files to the session merely because they changed during execution. For an explicit audit, use foamwiki check; automatic silence does not certify all task outputs. The package does not provide process-level write attribution.

This extra contains generic Foam behavior only. Source-corpus evidence policies, wiki authoring rules, and Git synchronization belong to the consuming wiki or setup package. The initial generic extraction comes from the author's wiki hooks; executable behavior is covered by tests/test_agent_hooks.py using a non-Git vault and both provider schemas.

Metadata

Release files for foam-wiki 0.5.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for foam-wiki 0.5.2
File Size Uploaded
foam_wiki-0.5.2.tar.gz 246.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for foam-wiki 0.5.2
File
foam_wiki-0.5.2-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
foam_wiki-0.5.2-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.5.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
foam_wiki-0.5.2-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
foam_wiki-0.5.2-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 6.0 MB

Release files / foam_wiki-0.5.2.tar.gz

Download URL foam_wiki-0.5.2.tar.gz
Size 246.4 kB
Tags Source
SHA-256 checksum
How to use checksums
773adc33a762ef804686edbfacfddd5220f150b61fc182307740526f86b6e9b0
BLAKE2b-256 checksum
How to use checksums
e5c7f40c6bb852e3310730a61eeeed6869f15494d86749a138f4a474d35d9eb1
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

Release files / foam_wiki-0.5.2-cp310-abi3-win_amd64.whl

Download URL foam_wiki-0.5.2-cp310-abi3-win_amd64.whl
Size 1.1 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
96ec36c2f1f25921fa09eda71f46fb3a85123ed2c5b215f305e6eeb5e6f680e7
BLAKE2b-256 checksum
How to use checksums
8942545848c0d7d819808136feb7237c188f51ab9c774cd801084a736f13e823
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

Release files / foam_wiki-0.5.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL foam_wiki-0.5.2-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
01b1aa6d3680f1e9fdc53d2919fbd92f15f4fe6e65c4f168265ffed8f00318f7
BLAKE2b-256 checksum
How to use checksums
4fa1057e0c8a942eb128e4453ef924e3a96341838f1a9860c4f56619caecdf4e
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

Release files / foam_wiki-0.5.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL foam_wiki-0.5.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.2 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
7c817d3969aa273696a625af48dc0f34a3d5893ad3e3b2b93716bfdfbbd99c09
BLAKE2b-256 checksum
How to use checksums
532739ff14173a9c8e228be893febedcae1a5aed4e2bd2ea4f961ae8086df9b1
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

Release files / foam_wiki-0.5.2-cp310-abi3-macosx_11_0_arm64.whl

Download URL foam_wiki-0.5.2-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
278a0502cbec4c76d2a49bbd7d912f8fbcc8633fcd7e0553edfea2b185b550ae
BLAKE2b-256 checksum
How to use checksums
27b96f58a8527a8cd70bd34dbed295d3a5e97d4d2442835ab613f4491a0c390e
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

Release files / foam_wiki-0.5.2-cp310-abi3-macosx_10_12_x86_64.whl

Download URL foam_wiki-0.5.2-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
348bc077cba35f1f31c8bcddcecdc94e24a27e2020ea43d4ebc9d19a2661ec6f
BLAKE2b-256 checksum
How to use checksums
6593b514676b26beb0a585ee83ca607a6cf3dd4986268086d94057183673af10
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
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page