Programmer-friendly personal knowledge base in the vein of Zettelkasten based on logic programming
factbook is a note-taking app for persisting and organizing text-based knowledge. Its philosophy borrows from the Zettelkasten methodology, extending it with powerful logic programming capabilities. With SWI Prolog at its core it delivers a user-facing full-featured Turing-complete programming language with excellent relational capabilities.
Warning
This is a work in progress. Expect random crashes and general instability. It is also currently possible to execute arbitrary Prolog code from within the application (#24).
-
Zero friction: Dump anything into your knowledge base at any time, without any distraction with organization. No need to think about which directory an entry belongs to. Write first, organize second.
-
Atomic knowledge: Every thought is its own entity, allowing for powerful "just-in-time" organization. Gain a completely new perspective on your notes by simply adjusting your queries. Entries have no enforced structure, they are simple text. Don't worry about coming up with titles or formatting paragraphs.
-
Fluently embedded data: All organization is done via parseable tags embedded in entries. Tagging entries is as simple as typing an
@and a term, no need to do any meta-organization anywhere else. Easily express data you want to keep track of, create ontologies on the fly. Tags become part of your language, seamlessly scattered throughout your text where needed. They can be atomic or hold nested data, just like Prolog terms.walk the dog @todo @due(tomorrow) @priority(10) @cite("Einstein", 1905)
-
Powerful queries: Easily define views into your knowledge base by querying facts about entries—presence of tags, timestamps, relations between entries—or even executing custom code. This is where organization happens. Do it whenever you need to, at your own pace, outside of the flow of taking notes, and get all the power of Prolog to your advantage.
% Example only, specific available predicates and semantics may differ % % This would yield entries containing `@todo` and `@due(_)` with an argument % describing a time in the past, i.e. overdue tasks { now(N) }, % get current timestamp @todo, % filter entries with `@todo` tag @due(D), % filter entries with `@due(_)` tag and take the argument D created(D0), % get the entry creation time D0 { relative_datetime(D0, D, D1), % specify D1 as the threshold timestamp D1 < N % compare with current timestamp }
See Github releases for pre-built binaries.
factbook is built with Rust + Tauri + Solid + SWI Prolog
Unfortunately, SWI Prolog provides several challenges in terms of development experience:
- It does not provide pre-built static libraries, and the custom build process for some platforms like Windows is complicated and unreliable. This means we are forced to link and ship the shared version of the library.
- Most installations do not place the shared library in a system-default path discoverable by runtime linking. This means we need special tooling to help with locating the library in development and embed custom
rpathentries into the release binaries.
Details of dealing with this are described below.
- Rust v1.88+ (nightly is only required for
cargo fmt) - Node.js with pnpm (install with
npm i -g pnpm) - Tauri system prerequisites
- SWI-Prolog 10.0.2 or newer with a compatible C API. Common compilation errors result from mismatched SWI-Prolog versions. Platform-specific instructions are described below.
Automated scripts for installing system dependencies are provided: setup.sh and setup.ps1, but are intended for CI use and as such they do not currently include packages commonly present in CI images and don't support all platforms and package managers.
Install swi-prolog using a package manager, specifying the exact version 10.0.2 if necessary, then verify the installation:
pkg-config --modversion swipl # must be 10.0.2 or higherMore often than not, the shared library libswipl.so.10 is placed in a location missing from LD_LIBRARY_PATH. The project uses a suite of crates to help with the general awkwardness of linking against libswipl. swipl-info finds libswipl at build time and solves compile-time linking, but does not provide a way to embed the library path into executables. This means you may need to proxy some cargo commands via cargo-swipl:
cargo install cargo-swipl
cargo swipl test # Run tests ensuring libswipl is foundAlternatively, manually find and add the appropriate path to LD_LIBRARY_PATH.
Either:
- Download and install manually. Make sure to check one of the Add to PATH boxes during installation.
- Run
setup.ps1and set theSWIPLenvironment variable to an absolute path pointing atlibs/swipl/bin/swipl.exe.
Run the project in development:
pnpm tauri dev
Make and run the release build:
pnpm tauri build --no-bundle
target/release/factbook
Make and run the debug build:
pnpm tauri build --debug --no-bundle
target/debug/factbook
If you want to produce bundles locally, remove the --no-bundle flag and include the platform-dependent config:
pnpm tauri build --config src-tauri/tauri.<platform>.release.conf.json
Note however that generating proper portable bundles requires importing shared libraries into the libs directory. setup.sh does this by first installing swi-prolog as a system dependency, then attempting to locate and copy libswipl.so.10 (or libswipl.10.dylib on Mac) into the libs directory. setup.ps1 downloads and extracts libswipl.dll from the Windows installer. Automating the system-wide installation on Windows does not seem possible.
Format the codebase:
pnpm format
cargo +nightly fmt