Metadata-Version: 2.4
Name: foam-wiki
Version: 0.4.1a2
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Rust
Classifier: Typing :: Typed
Requires-Dist: pyyaml>=6
Requires-Dist: pathspec>=0.12
Requires-Dist: json5>=0.9
Requires-Dist: tomli>=2 ; python_full_version < '3.11'
Requires-Dist: pandas>=2 ; extra == 'all'
Requires-Dist: networkx>=3 ; extra == 'all'
Requires-Dist: networkx>=3 ; extra == 'graph'
Requires-Dist: pandas>=2 ; extra == 'pandas'
Provides-Extra: all
Provides-Extra: graph
Provides-Extra: pandas
License-File: LICENSE
Summary: A Pythonic, notebook-first library + CLI for Foam-style markdown wikis.
Keywords: foam,wikilink,markdown,knowledge-base,notebook
Author-email: Nima Shoghi <nimashoghi@gmail.com>
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/nimashoghi/foampy
Project-URL: Issues, https://github.com/nimashoghi/foampy/issues
Project-URL: Repository, https://github.com/nimashoghi/foampy

# 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:

```bash
uv add foam-wiki
# or: python -m pip install foam-wiki
```

Until the first stable release, opt into the published prerelease:

```bash
uv add --prerelease allow foam-wiki
# or: python -m pip install --pre foam-wiki
```

Run the CLI without adding a project dependency:

```bash
uvx --from foam-wiki foamwiki --help
```

To install the current branch directly from Git:

```text
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

```python
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:

```text
<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`:

```python
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:

```python
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`](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

```bash
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`](PERFORMANCE.md) for the real-workspace baseline and
reproducible benchmark command. [`MIGRATION.md`](MIGRATION.md) lists the
intentional behavior and naming changes. [`RELEASING.md`](RELEASING.md)
documents local and CI release validation.

MIT licensed.

