Forester, a tool for scientific and mathematical hypertexts

1 week ago 6
https://www.forester-notes.org/index/ index /index/ Forester

Forester is a tool for authoring, exploring, and sharing scientific and mathematical hypertexts. It is your lab notebook, your journal, your blackboard, and the home of your lecture notes.

Forester is maintained by and .

References Context Backlinks 2023 5 14 2024 4 25 2025 5 26 https://www.forester-notes.org/0052/ 0052 /0052/ Build your own in 10 minutes

is the most successful scientific hypertext project in history. Its goal is to lay the foundations for the theory of algebraic stacks; to facilitate its scalable and sustainable development, several important innovations have been introduced, with the tags system being the most striking.

Each tag refers to a unique item (section, lemma, theorem, etc.) in order for this project to be referenceable. These tags don't change even if the item moves within the text. (, ).

Many working scientists, students, and hobbyists have wished to create their own tag-based hypertext knowledge base, but the combination of tools historically required to make this happen are extremely daunting. Both the and use a cluster of software called , but bitrot has set in and it is to build its dependencies on a modern environment without significant difficulty, raising questions of longevity.

Moreover, ’s deployment involves running a database on a server (in spite of the fact that almost the entire functionality is static HTML), an architecture that is incompatible with the constraints of the everyday working scientist or student who knows at most how to upload static files to their university-provided public storage. The recent experience of the ’s pandemic-era hiatus and near death experience has demonstrated with some urgency the pracarity faced by any project relying heavily on volunteer system administrators.

2023 5 14 https://www.forester-notes.org/0053/ 0053 /0053/ Introducing : a

After spending two years exploring the that meet the unique needs of real, scalable scientific writing in hypertext, I have created a tool called which has the following benefits:

  1. is tag-based like , and can therefore power large-scale generational projects like and .
  2. produces static content that without needing to run or install any serverside software.
  3. is on your own machine.
  4. To prevent bitrot, is a single tool rather than a composition of several tools.
  5. satisfies all the , including sophisticated notational macros, typesetting of diagrams, etc.

combines networks of (called “trees”) into hypertext sites called “forests”.

2023 3 4 https://www.forester-notes.org/tfmt-000R/ tfmt-000R /tfmt-000R/ Forests and trees of evergreen notes Definition

A forest of (or a forest for short) is loosely defined to be a collection of in which multiple are allowed to emerge and evolve over time. Concretely, one note may contextualize several other notes via transclusion within its textual structure; in the context of a forest, we refer to an individual note as a tree. Of course, a tree can be viewed as a forest that has a root node.

Trees correspond roughly to what are referred to as “tags” in the .

In this article, I will show you how to set up your own using the software. These instructions pertain to the version.

2023 8 13 https://www.forester-notes.org/006R/ 006R /006R/ Preparing to run the software

In this section, we will walk through the installation of the software.

2023 8 13 https://www.forester-notes.org/006S/ 006S /006S/ System requirements of 2023 8 13 https://www.forester-notes.org/006T/ 006T /006T/ A unix-based system Requirement

requires a unix-based system to run; it has been tested on both macOS and Linux. Windows support is , but there are no concrete plans to implement it at this time.

2023 8 13 https://www.forester-notes.org/006U/ 006U /006U/ A working OCaml 5 installation Requirement

is written in the programming language, and makes use of the latest features of OCaml 5. Most users should install through OCaml's package manager; instructions to install opam and OCaml simultaneously can be found .

2023 8 13 https://www.forester-notes.org/006V/ 006V /006V/ A working installation Requirement

If you intend to in your , you will need to have a working installation of installed, such as . If all your mathematical expressions are supported by , this is not necessary.

2023 8 14 https://www.forester-notes.org/006Y/ 006Y /006Y/ The distributed version control system Requirement

It is best practice to maintain your inside of . This serves not only as a way to prevent data loss (because you will be pushing frequently to a remote repository); it also allows you to easily roll back to an earlier version of your , or to create “branches” in which you prepare that are not yet ready to be integrated into the .

The recommended system is , which comes preinstalled on many unix-based systems and is easy to install otherwise. is not the most user-friendly piece of software, unfortunately, but it is ubiquitous. It is possible (but not recommended) to use without version control, but note that the simplest way to involves cloning a repository.

2023 8 13 https://www.forester-notes.org/006W/ 006W /006W/ Installing the software

Once you have met the , installing requires only a single shell command:

To verify that is installed, please run forester --version in your shell.

2023 8 14 2024 4 25 2024 6 17 https://www.forester-notes.org/006X/ 006X /006X/ Setting up your from the template

Now that you have the software, it is time to set up your . provides a simple command to initialise a fresh within a folder. We’ll call our folder forest, but you can call it anything you want.

Now that we are inside our new directory, we can instruct to initialise a .

forester init

This command initialises a repository with the skeleton of a , which contains a configuration file named forest.toml; this file specifies the locations of your trees, assets, etc. There is also a submodule bound to the theme/ directory (pointing to the repository) that contains the stylesheets that web browsers will need in order to render your as HTML.

2023 8 14 2024 6 17 https://www.forester-notes.org/0073/ 0073 /0073/ Tree addresses in a

A in is usually associated to an address of the form NNNN is a four-digit . The purpose of the code is to uniquely identify a within your in such a way that you are not tempted to rename it, as you might be when titles or dates are embedded into filenames. A tree with address NNNN is stored in a file named NNNN.tree (unless it is emitted from inside another tree by means of the feature).

Note that the format of addresses is purely a matter of convention, and is not forced by the tool. Users are free to use their own naming convention for tree addresses, and in some cases alternative (human-readable) formats may be desirable: this includes trees representing bibliographic references, as well as biographical trees. If you don’t like numerical tree addresses, nobody is forcing you to use them. The use of numerical addresses is suitable for projects like , but it may not be appropriate for your own use-case.

Addresses in are not hierarchical: all resources are rendered at the root of the forest, no matter where their source files are kept. This limitation is intentional, but we might revisit it in the future.

2023 8 15 2024 4 25 https://www.forester-notes.org/007D/ 007D /007D/ Building and viewing your for the first time

To build your , you can run the following command of 's executable in your shell:

forester build forest.toml

The --dev flag is optional, and when activated supplies metadata to the generated website to support an “edit button” on each tree; this flag is meant to be used when developing your locally, and should not be used when building the to be uploaded to your public web host.

2023 8 15 https://www.forester-notes.org/007G/ 007G /007G/ renders each tree to an XML document

renders your to some XML files in the output/ directory; XML is, like HTML, a format for structured documents that can be displayed by web browsers. The template comes equipped with a built-in XSLT stylesheet (theme/default.xsl) which is used to instruct web browsers how to render your into a pleasing and readable format.

2023 8 15 https://www.forester-notes.org/007I/ 007I /007I/ Serving and viewing your from a local web server

To view your while editing it, you must serve it from a local web server..To do this, first ensure that you have correctly installed. Then run the following command from the root directory of your :

python3 -m http.server 1313 -d output

(You could replace 1313 with whatever port you prefer.) While this command is running, you will be able to access your by navigating to in your preferred web browser.

In the future, to avoid the dependency on external tools like Python.

2023 8 15 https://www.forester-notes.org/007K/ 007K /007K/ Creating your personal biographical

The first that you should create is a biographical tree to represent your own identity; ultimately you will link to this tree when you set the of other that you create later on. It is convenient to simply use a person’s full name to address a biographical . is located at trees/people/jonmsterling.tree and contains the following source code:

Let’s break this code down to understand what it does.

  1. The declaration sets the title of the to my name.
  2. The declaration informs that the is biographical. Not ever needs to have a taxon; common taxa include Person, Theorem, Definition, Lemma, etc. You are free to use whatever you want, but some taxa are treated specially by .
  3. The subsequent declarations attach additional information to the tree that can be used during rendering. These declarations are optional, and you are free to put whatever metadata you want.
  4. Like in HTML, paragraphs must be wrapped in .

Do not hard-wrap your text, as this can have visible impact on how are rendered; it is recommended that you use a text editor with good support for soft-wrapping, like .

You can see that the looks superficially like a combination of and Markdown; Markdown-style links are used both for links to other trees and for links to external URLs. 's concrete syntax is not fully documented, but it is less ambiguous than both and Markdown.

2023 8 15 2024 4 25 https://www.forester-notes.org/007H/ 007H /007H/ Creating a new using forester new

Creating a new in your is as simple as adding a .tree file to the trees folder. Because it is hard to manually choose the , provides a command to do this automatically:

forester new forest.toml --dest=trees

In return, should output the location of the new tree, e.g. trees/0002.tree. If we look at the contents of this new file, we will see that it is empty except for metadata assigning a date to the tree:

You may prefer to use randomised addresses over sequential addresses; this can be particularly useful if multiple people are contributing to a . In that case, pass the --random option to forester new.

Most should have a annotation; this date is meant to be the date of the 's creation; you can have more than one date, if you like to keep track of when a tree has been updated. You should proceed by adding further metadata: the title and the ; for the latter, you will use the address of your .

titles should be given in lower case (except for proper names, etc.); these titles will be rendered by in sentence case. A can have as many declarations as it has ; these will be rendered in their order of appearance.

Now you can begin to populate the tree with its content, written in the . .

2023 8 15 https://www.forester-notes.org/007L/ 007L /007L/ Bottom-up hierarchy via transclusion

You may be used to writing documents, where you work from the top down: you create some section headings, put some text under those headings, make some deeper section headings, put more text, etc. work in the opposite way, from the bottom up: you start by writing independent, notes/ and then only later start to (sparingly) assemble these into a hierarchy in order to reify the emerging structure.

’s bottom-up approach to section hierarchy works via something called transclusion. The idea is that at any time, you can include (“transclude”) the full contents of another into the current tree as a subsection by adding the following code:

This is kind of like ’s command, but much better behaved: for instance, section levels are computed on the fly depending on the position in the hierarchy. This is cobbled together by transcluding many smaller , each with their own independent existence. For example, the following two sections are transcluded from an of my forest:

2022 12 27 https://www.forester-notes.org/tfmt-0009/ tfmt-0009 /tfmt-0009/ The best structure to impose is relatively flat

It is easy to make the mistake of prematurely imposing a complex hierarchical structure on a network of notes, which leads to excessive refactoring. Hierarchy should be used sparingly, and its strength is for the large-scale organization of ideas. The best structure to impose on a network of many small related ideas is a relatively flat one. I believe that this is one of the mistakes made in the writing of the foundations of relative category theory, whose hierarchical nesting was too complex and quite beholden to my experience with pre-hypertext media.

One of the immediate impacts and strengths of ’s transclusion model is that a given has no canonical “geographic” location in the . One can appear as a child of many other , which allows the same content to be incorporated into different textual and intellectual narratives.

2022 12 26 https://www.forester-notes.org/tfmt-0006/ tfmt-0006 /tfmt-0006/ Hierarchical structure as non-unique narrative

Multiple hierarchical structures can be imposed on the same associative network of nodes; a hierarchical structure amounts to a “narrative” that contextualizes a given subgraph of the network. One example could be the construction of lecture notes; another example could be a homework sheet; a further example could be a book chapter or scientific article. Although these may draw from the same body of definitions, theorems, examples, and exercises, these objects are contextualized within a different narrative, often toward fundamentally different ends.

As a result, any interface for navigating the neighbor-relation in hierarchically organized notes would need to take account of the multiplicity of parent nodes. Most hypertext tools assume that the position of a node in the hierarchy is unique, and therefore have a single “next/previous” navigation interface; we must investigate the design of interfaces that surface all parent/neighbor relations.

2023 8 16 https://www.forester-notes.org/007N/ 007N /007N/ The markup language

A in is a single file written in a markup language designed specifically for scientific writing . A has two components: the and the .

2023 8 16 https://www.forester-notes.org/007P/ 007P /007P/ markup: frontmatter

The frontmatter of a is a sequence of declarations that we summarize below.

Declaration Meaning
sets the title of the ; can contain markup
sets the of the to be the biographical tree at address name
sets the creation date of the ; full ISO 8601 date-times are supported.
sets the taxon of the ; example taxa include lemma, theorem, person, reference; the latter two taxa are treated specially by for tracking biographical and bibliographical respectively
defines and exports from the current a function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for
brings the functions exported by the tree address into scope
brings the functions exported by the tree address into scope, and exports them from the current tree
2023 8 16 https://www.forester-notes.org/007O/ 007O /007O/ markup: mainmatter

Below we summarize the concrete syntax of the mainmatter in a .

Function Meaning
creates a paragraph containing ...; unlike Markdown, it is mandatory to annotate paragraphs explicitly
typesets the content in italics
typesets the content in boldface
creates an ordered list
creates an unordered list
creates a list item
typesets the content in (inline) math mode using ; note that math mode is idempotent in
typesets the content in (display) math mode using
the at address address as a subsection
formats the text title as a hyperlink to address address; if address is the address of a , the link will point to that tree, and otherwise it is treated as a URL
defines a local function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for .
typesets the content in monospace
typesets the body externally using using preamble as preamble code (e.g. to set up tikz packages, etc.). It can be useful to wrap this in your own macro in order to insert your preamble code automatically.
2023 8 16 https://www.forester-notes.org/007Q/ 007Q /007Q/ An complete worked example in Example

An example of a complete in the markup language can be seen below.

The code above results in the following tree:

2023 2 11 https://www.forester-notes.org/001H/ 001H /001H/ Creation of (co)limits Definition

Let be a functor and let be a category. The functor is said to create (co)limits of -figures when for any diagram such that has a (co)limit, then has a (co)limit that is both preserved and reflected by .

2023 8 16 https://www.forester-notes.org/007R/ 007R /007R/ Deploying your to a web host

Now that you have and , it is time to upload it to your web host. Many users of will have university-supplied static web hosting, and others may prefer to use GitHub pages; deploying a works the same way in either case.

  1. First, make sure your is built using .
  2. Then take the entire contents of your output directory and upload them to your preferred web host.
2023 8 16 https://www.forester-notes.org/007S/ 007S /007S/ Let a hundred bloom!

I am eager to see the new that people create using . I am happy to offer personal assistance via the .

Many aspects of are in flux and not fully documented; it will often be instructive to consult the source of existings , such as .

Have fun, and be sure to send me links to your when you have made them!

2025 3 28 https://www.forester-notes.org/MZSF/ MZSF /MZSF/ The language server

Forester provides an implementation of the Language Server Protocol (LSP). Developers of editor plugins can consult forester lsp --help.

2025 5 26 https://www.forester-notes.org/24B1/ 24B1 /24B1/ Features of the

Forester’s implementation of the language server protocol supports several standard features to varying degrees. At the moment we support some code actions (e.g. creating a new tree), inlay hints, syntax error diagnostics, document symbols, workspace symbols, and link completion.

There may be limitations in the implementations of these features, which we will continue to improve; we appreciate user feedback.

(Please note that LSP features are surfaced differently in every editor (language server client); although we a sample configuration for Neovim, for example, not all features of the LSP have been surfaced to the user in that configuration.)

https://www.forester-notes.org/QLG4/ QLG4 /QLG4/ Example configurations

Users of other text editors are encouraged to contribute to this section.

https://www.forester-notes.org/LN6D/ LN6D /LN6D/ configuration

Since , you can configure language servers by simply adding the following snippet to your configuration:

For a more complete configuration that includes keybinds to various features, you can use as a starting point.

If you are not yet using version 0.11, please refer to the

https://www.forester-notes.org/6Y7J/ 6Y7J /6Y7J/ configuration 2025 3 28 Known issues
  • While the language server does not yet support semantic syntax highlighting, you may try to use , although it is currently not officially supported
  • Neovim does not handle WorkspaceEdit notifications. This means that after creating a new tree via a code action, the language server will become out of sync.
  • Inlay hints do not properly refresh upon changes. Toggling the feature on and off seems to resolve this in Neovim
  • The server will not be aware of any trees or assets added in file system after startup.
2023 8 14 2024 4 25 2024 6 17 https://www.forester-notes.org/006X/ 006X /006X/ Setting up your from the template

Now that you have the software, it is time to set up your . provides a simple command to initialise a fresh within a folder. We’ll call our folder forest, but you can call it anything you want.

Now that we are inside our new directory, we can instruct to initialise a .

forester init

This command initialises a repository with the skeleton of a , which contains a configuration file named forest.toml; this file specifies the locations of your trees, assets, etc. There is also a submodule bound to the theme/ directory (pointing to the repository) that contains the stylesheets that web browsers will need in order to render your as HTML.

2023 8 14 2024 6 17 https://www.forester-notes.org/0073/ 0073 /0073/ Tree addresses in a

A in is usually associated to an address of the form NNNN is a four-digit . The purpose of the code is to uniquely identify a within your in such a way that you are not tempted to rename it, as you might be when titles or dates are embedded into filenames. A tree with address NNNN is stored in a file named NNNN.tree (unless it is emitted from inside another tree by means of the feature).

Note that the format of addresses is purely a matter of convention, and is not forced by the tool. Users are free to use their own naming convention for tree addresses, and in some cases alternative (human-readable) formats may be desirable: this includes trees representing bibliographic references, as well as biographical trees. If you don’t like numerical tree addresses, nobody is forcing you to use them. The use of numerical addresses is suitable for projects like , but it may not be appropriate for your own use-case.

Addresses in are not hierarchical: all resources are rendered at the root of the forest, no matter where their source files are kept. This limitation is intentional, but we might revisit it in the future.

2023 8 15 2024 4 25 https://www.forester-notes.org/007D/ 007D /007D/ Building and viewing your for the first time

To build your , you can run the following command of 's executable in your shell:

forester build forest.toml

The --dev flag is optional, and when activated supplies metadata to the generated website to support an “edit button” on each tree; this flag is meant to be used when developing your locally, and should not be used when building the to be uploaded to your public web host.

2023 8 15 https://www.forester-notes.org/007G/ 007G /007G/ renders each tree to an XML document

renders your to some XML files in the output/ directory; XML is, like HTML, a format for structured documents that can be displayed by web browsers. The template comes equipped with a built-in XSLT stylesheet (theme/default.xsl) which is used to instruct web browsers how to render your into a pleasing and readable format.

2023 8 15 https://www.forester-notes.org/007I/ 007I /007I/ Serving and viewing your from a local web server

To view your while editing it, you must serve it from a local web server..To do this, first ensure that you have correctly installed. Then run the following command from the root directory of your :

python3 -m http.server 1313 -d output

(You could replace 1313 with whatever port you prefer.) While this command is running, you will be able to access your by navigating to in your preferred web browser.

In the future, to avoid the dependency on external tools like Python.

2023 8 14 2024 6 17 https://www.forester-notes.org/0073/ 0073 /0073/ Tree addresses in a

A in is usually associated to an address of the form NNNN is a four-digit . The purpose of the code is to uniquely identify a within your in such a way that you are not tempted to rename it, as you might be when titles or dates are embedded into filenames. A tree with address NNNN is stored in a file named NNNN.tree (unless it is emitted from inside another tree by means of the feature).

Note that the format of addresses is purely a matter of convention, and is not forced by the tool. Users are free to use their own naming convention for tree addresses, and in some cases alternative (human-readable) formats may be desirable: this includes trees representing bibliographic references, as well as biographical trees. If you don’t like numerical tree addresses, nobody is forcing you to use them. The use of numerical addresses is suitable for projects like , but it may not be appropriate for your own use-case.

Addresses in are not hierarchical: all resources are rendered at the root of the forest, no matter where their source files are kept. This limitation is intentional, but we might revisit it in the future.

2023 8 15 2024 4 25 https://www.forester-notes.org/007D/ 007D /007D/ Building and viewing your for the first time

To build your , you can run the following command of 's executable in your shell:

forester build forest.toml

The --dev flag is optional, and when activated supplies metadata to the generated website to support an “edit button” on each tree; this flag is meant to be used when developing your locally, and should not be used when building the to be uploaded to your public web host.

2023 8 15 https://www.forester-notes.org/007G/ 007G /007G/ renders each tree to an XML document

renders your to some XML files in the output/ directory; XML is, like HTML, a format for structured documents that can be displayed by web browsers. The template comes equipped with a built-in XSLT stylesheet (theme/default.xsl) which is used to instruct web browsers how to render your into a pleasing and readable format.

2023 8 15 https://www.forester-notes.org/007I/ 007I /007I/ Serving and viewing your from a local web server

To view your while editing it, you must serve it from a local web server..To do this, first ensure that you have correctly installed. Then run the following command from the root directory of your :

python3 -m http.server 1313 -d output

(You could replace 1313 with whatever port you prefer.) While this command is running, you will be able to access your by navigating to in your preferred web browser.

In the future, to avoid the dependency on external tools like Python.

2023 8 15 2024 4 25 https://www.forester-notes.org/007H/ 007H /007H/ Creating a new using forester new

Creating a new in your is as simple as adding a .tree file to the trees folder. Because it is hard to manually choose the , provides a command to do this automatically:

forester new forest.toml --dest=trees

In return, should output the location of the new tree, e.g. trees/0002.tree. If we look at the contents of this new file, we will see that it is empty except for metadata assigning a date to the tree:

You may prefer to use randomised addresses over sequential addresses; this can be particularly useful if multiple people are contributing to a . In that case, pass the --random option to forester new.

Most should have a annotation; this date is meant to be the date of the 's creation; you can have more than one date, if you like to keep track of when a tree has been updated. You should proceed by adding further metadata: the title and the ; for the latter, you will use the address of your .

titles should be given in lower case (except for proper names, etc.); these titles will be rendered by in sentence case. A can have as many declarations as it has ; these will be rendered in their order of appearance.

Now you can begin to populate the tree with its content, written in the . .

2023 8 16 https://www.forester-notes.org/007Q/ 007Q /007Q/ An complete worked example in Example

An example of a complete in the markup language can be seen below.

The code above results in the following tree:

2023 2 11 https://www.forester-notes.org/001H/ 001H /001H/ Creation of (co)limits Definition

Let be a functor and let be a category. The functor is said to create (co)limits of -figures when for any diagram such that has a (co)limit, then has a (co)limit that is both preserved and reflected by .

2023 8 16 https://www.forester-notes.org/007R/ 007R /007R/ Deploying your to a web host

Now that you have and , it is time to upload it to your web host. Many users of will have university-supplied static web hosting, and others may prefer to use GitHub pages; deploying a works the same way in either case.

  1. First, make sure your is built using .
  2. Then take the entire contents of your output directory and upload them to your preferred web host.
2023 8 16 https://www.forester-notes.org/007P/ 007P /007P/ markup: frontmatter

The frontmatter of a is a sequence of declarations that we summarize below.

Declaration Meaning
sets the title of the ; can contain markup
sets the of the to be the biographical tree at address name
sets the creation date of the ; full ISO 8601 date-times are supported.
sets the taxon of the ; example taxa include lemma, theorem, person, reference; the latter two taxa are treated specially by for tracking biographical and bibliographical respectively
defines and exports from the current a function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for
brings the functions exported by the tree address into scope
brings the functions exported by the tree address into scope, and exports them from the current tree
2023 8 16 https://www.forester-notes.org/007O/ 007O /007O/ markup: mainmatter

Below we summarize the concrete syntax of the mainmatter in a .

Function Meaning
creates a paragraph containing ...; unlike Markdown, it is mandatory to annotate paragraphs explicitly
typesets the content in italics
typesets the content in boldface
creates an ordered list
creates an unordered list
creates a list item
typesets the content in (inline) math mode using ; note that math mode is idempotent in
typesets the content in (display) math mode using
the at address address as a subsection
formats the text title as a hyperlink to address address; if address is the address of a , the link will point to that tree, and otherwise it is treated as a URL
defines a local function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for .
typesets the content in monospace
typesets the body externally using using preamble as preamble code (e.g. to set up tikz packages, etc.). It can be useful to wrap this in your own macro in order to insert your preamble code automatically.
2023 8 16 https://www.forester-notes.org/007S/ 007S /007S/ Let a hundred bloom!

I am eager to see the new that people create using . I am happy to offer personal assistance via the .

Many aspects of are in flux and not fully documented; it will often be instructive to consult the source of existings , such as .

Have fun, and be sure to send me links to your when you have made them!

2023 8 16 https://www.forester-notes.org/007N/ 007N /007N/ The markup language

A in is a single file written in a markup language designed specifically for scientific writing . A has two components: the and the .

2023 8 16 https://www.forester-notes.org/007P/ 007P /007P/ markup: frontmatter

The frontmatter of a is a sequence of declarations that we summarize below.

Declaration Meaning
sets the title of the ; can contain markup
sets the of the to be the biographical tree at address name
sets the creation date of the ; full ISO 8601 date-times are supported.
sets the taxon of the ; example taxa include lemma, theorem, person, reference; the latter two taxa are treated specially by for tracking biographical and bibliographical respectively
defines and exports from the current a function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for
brings the functions exported by the tree address into scope
brings the functions exported by the tree address into scope, and exports them from the current tree
2023 8 16 https://www.forester-notes.org/007O/ 007O /007O/ markup: mainmatter

Below we summarize the concrete syntax of the mainmatter in a .

Function Meaning
creates a paragraph containing ...; unlike Markdown, it is mandatory to annotate paragraphs explicitly
typesets the content in italics
typesets the content in boldface
creates an ordered list
creates an unordered list
creates a list item
typesets the content in (inline) math mode using ; note that math mode is idempotent in
typesets the content in (display) math mode using
the at address address as a subsection
formats the text title as a hyperlink to address address; if address is the address of a , the link will point to that tree, and otherwise it is treated as a URL
defines a local function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for .
typesets the content in monospace
typesets the body externally using using preamble as preamble code (e.g. to set up tikz packages, etc.). It can be useful to wrap this in your own macro in order to insert your preamble code automatically.
2023 8 16 https://www.forester-notes.org/007Q/ 007Q /007Q/ An complete worked example in Example

An example of a complete in the markup language can be seen below.

The code above results in the following tree:

2023 2 11 https://www.forester-notes.org/001H/ 001H /001H/ Creation of (co)limits Definition

Let be a functor and let be a category. The functor is said to create (co)limits of -figures when for any diagram such that has a (co)limit, then has a (co)limit that is both preserved and reflected by .

2023 8 15 https://www.forester-notes.org/007L/ 007L /007L/ Bottom-up hierarchy via transclusion

You may be used to writing documents, where you work from the top down: you create some section headings, put some text under those headings, make some deeper section headings, put more text, etc. work in the opposite way, from the bottom up: you start by writing independent, notes/ and then only later start to (sparingly) assemble these into a hierarchy in order to reify the emerging structure.

’s bottom-up approach to section hierarchy works via something called transclusion. The idea is that at any time, you can include (“transclude”) the full contents of another into the current tree as a subsection by adding the following code:

This is kind of like ’s command, but much better behaved: for instance, section levels are computed on the fly depending on the position in the hierarchy. This is cobbled together by transcluding many smaller , each with their own independent existence. For example, the following two sections are transcluded from an of my forest:

2022 12 27 https://www.forester-notes.org/tfmt-0009/ tfmt-0009 /tfmt-0009/ The best structure to impose is relatively flat

It is easy to make the mistake of prematurely imposing a complex hierarchical structure on a network of notes, which leads to excessive refactoring. Hierarchy should be used sparingly, and its strength is for the large-scale organization of ideas. The best structure to impose on a network of many small related ideas is a relatively flat one. I believe that this is one of the mistakes made in the writing of the foundations of relative category theory, whose hierarchical nesting was too complex and quite beholden to my experience with pre-hypertext media.

One of the immediate impacts and strengths of ’s transclusion model is that a given has no canonical “geographic” location in the . One can appear as a child of many other , which allows the same content to be incorporated into different textual and intellectual narratives.

2022 12 26 https://www.forester-notes.org/tfmt-0006/ tfmt-0006 /tfmt-0006/ Hierarchical structure as non-unique narrative

Multiple hierarchical structures can be imposed on the same associative network of nodes; a hierarchical structure amounts to a “narrative” that contextualizes a given subgraph of the network. One example could be the construction of lecture notes; another example could be a homework sheet; a further example could be a book chapter or scientific article. Although these may draw from the same body of definitions, theorems, examples, and exercises, these objects are contextualized within a different narrative, often toward fundamentally different ends.

As a result, any interface for navigating the neighbor-relation in hierarchically organized notes would need to take account of the multiplicity of parent nodes. Most hypertext tools assume that the position of a node in the hierarchy is unique, and therefore have a single “next/previous” navigation interface; we must investigate the design of interfaces that surface all parent/neighbor relations.

2023 8 15 https://www.forester-notes.org/007K/ 007K /007K/ Creating your personal biographical

The first that you should create is a biographical tree to represent your own identity; ultimately you will link to this tree when you set the of other that you create later on. It is convenient to simply use a person’s full name to address a biographical . is located at trees/people/jonmsterling.tree and contains the following source code:

Let’s break this code down to understand what it does.

  1. The declaration sets the title of the to my name.
  2. The declaration informs that the is biographical. Not ever needs to have a taxon; common taxa include Person, Theorem, Definition, Lemma, etc. You are free to use whatever you want, but some taxa are treated specially by .
  3. The subsequent declarations attach additional information to the tree that can be used during rendering. These declarations are optional, and you are free to put whatever metadata you want.
  4. Like in HTML, paragraphs must be wrapped in .

Do not hard-wrap your text, as this can have visible impact on how are rendered; it is recommended that you use a text editor with good support for soft-wrapping, like .

You can see that the looks superficially like a combination of and Markdown; Markdown-style links are used both for links to other trees and for links to external URLs. 's concrete syntax is not fully documented, but it is less ambiguous than both and Markdown.

2023 8 15 https://www.forester-notes.org/007G/ 007G /007G/ renders each tree to an XML document

renders your to some XML files in the output/ directory; XML is, like HTML, a format for structured documents that can be displayed by web browsers. The template comes equipped with a built-in XSLT stylesheet (theme/default.xsl) which is used to instruct web browsers how to render your into a pleasing and readable format.

2023 8 15 https://www.forester-notes.org/007I/ 007I /007I/ Serving and viewing your from a local web server

To view your while editing it, you must serve it from a local web server..To do this, first ensure that you have correctly installed. Then run the following command from the root directory of your :

python3 -m http.server 1313 -d output

(You could replace 1313 with whatever port you prefer.) While this command is running, you will be able to access your by navigating to in your preferred web browser.

In the future, to avoid the dependency on external tools like Python.

2023 8 14 https://www.forester-notes.org/0074/ 0074 /0074/ Base-36 identifiers in

Base-36 numbers are encoded in using the alphabet 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. For example, the base-10 number can be written 007I in the encoding. The purpose of using base-36 rather than a more familiar counting base is that a great many distinct numbers can be fit into a very small number of digits: in just four digits, base-36 can count to — which is far higher than the anticipated number of in any .

2023 8 14 https://www.forester-notes.org/006Y/ 006Y /006Y/ The distributed version control system Requirement

It is best practice to maintain your inside of . This serves not only as a way to prevent data loss (because you will be pushing frequently to a remote repository); it also allows you to easily roll back to an earlier version of your , or to create “branches” in which you prepare that are not yet ready to be integrated into the .

The recommended system is , which comes preinstalled on many unix-based systems and is easy to install otherwise. is not the most user-friendly piece of software, unfortunately, but it is ubiquitous. It is possible (but not recommended) to use without version control, but note that the simplest way to involves cloning a repository.

2023 8 13 https://www.forester-notes.org/006T/ 006T /006T/ A unix-based system Requirement

requires a unix-based system to run; it has been tested on both macOS and Linux. Windows support is , but there are no concrete plans to implement it at this time.

2023 8 13 https://www.forester-notes.org/006U/ 006U /006U/ A working OCaml 5 installation Requirement

is written in the programming language, and makes use of the latest features of OCaml 5. Most users should install through OCaml's package manager; instructions to install opam and OCaml simultaneously can be found .

2023 8 13 https://www.forester-notes.org/006W/ 006W /006W/ Installing the software

Once you have met the , installing requires only a single shell command:

To verify that is installed, please run forester --version in your shell.

2023 8 13 https://www.forester-notes.org/006R/ 006R /006R/ Preparing to run the software

In this section, we will walk through the installation of the software.

2023 8 13 https://www.forester-notes.org/006S/ 006S /006S/ System requirements of 2023 8 13 https://www.forester-notes.org/006T/ 006T /006T/ A unix-based system Requirement

requires a unix-based system to run; it has been tested on both macOS and Linux. Windows support is , but there are no concrete plans to implement it at this time.

2023 8 13 https://www.forester-notes.org/006U/ 006U /006U/ A working OCaml 5 installation Requirement

is written in the programming language, and makes use of the latest features of OCaml 5. Most users should install through OCaml's package manager; instructions to install opam and OCaml simultaneously can be found .

2023 8 13 https://www.forester-notes.org/006V/ 006V /006V/ A working installation Requirement

If you intend to in your , you will need to have a working installation of installed, such as . If all your mathematical expressions are supported by , this is not necessary.

2023 8 14 https://www.forester-notes.org/006Y/ 006Y /006Y/ The distributed version control system Requirement

It is best practice to maintain your inside of . This serves not only as a way to prevent data loss (because you will be pushing frequently to a remote repository); it also allows you to easily roll back to an earlier version of your , or to create “branches” in which you prepare that are not yet ready to be integrated into the .

The recommended system is , which comes preinstalled on many unix-based systems and is easy to install otherwise. is not the most user-friendly piece of software, unfortunately, but it is ubiquitous. It is possible (but not recommended) to use without version control, but note that the simplest way to involves cloning a repository.

2023 8 13 https://www.forester-notes.org/006W/ 006W /006W/ Installing the software

Once you have met the , installing requires only a single shell command:

To verify that is installed, please run forester --version in your shell.

2023 8 13 https://www.forester-notes.org/006S/ 006S /006S/ System requirements of 2023 8 13 https://www.forester-notes.org/006T/ 006T /006T/ A unix-based system Requirement

requires a unix-based system to run; it has been tested on both macOS and Linux. Windows support is , but there are no concrete plans to implement it at this time.

2023 8 13 https://www.forester-notes.org/006U/ 006U /006U/ A working OCaml 5 installation Requirement

is written in the programming language, and makes use of the latest features of OCaml 5. Most users should install through OCaml's package manager; instructions to install opam and OCaml simultaneously can be found .

2023 8 13 https://www.forester-notes.org/006V/ 006V /006V/ A working installation Requirement

If you intend to in your , you will need to have a working installation of installed, such as . If all your mathematical expressions are supported by , this is not necessary.

2023 8 14 https://www.forester-notes.org/006Y/ 006Y /006Y/ The distributed version control system Requirement

It is best practice to maintain your inside of . This serves not only as a way to prevent data loss (because you will be pushing frequently to a remote repository); it also allows you to easily roll back to an earlier version of your , or to create “branches” in which you prepare that are not yet ready to be integrated into the .

The recommended system is , which comes preinstalled on many unix-based systems and is easy to install otherwise. is not the most user-friendly piece of software, unfortunately, but it is ubiquitous. It is possible (but not recommended) to use without version control, but note that the simplest way to involves cloning a repository.

2023 5 14 https://www.forester-notes.org/0053/ 0053 /0053/ Introducing : a

After spending two years exploring the that meet the unique needs of real, scalable scientific writing in hypertext, I have created a tool called which has the following benefits:

  1. is tag-based like , and can therefore power large-scale generational projects like and .
  2. produces static content that without needing to run or install any serverside software.
  3. is on your own machine.
  4. To prevent bitrot, is a single tool rather than a composition of several tools.
  5. satisfies all the , including sophisticated notational macros, typesetting of diagrams, etc.

combines networks of (called “trees”) into hypertext sites called “forests”.

2023 3 4 https://www.forester-notes.org/tfmt-000R/ tfmt-000R /tfmt-000R/ Forests and trees of evergreen notes Definition

A forest of (or a forest for short) is loosely defined to be a collection of in which multiple are allowed to emerge and evolve over time. Concretely, one note may contextualize several other notes via transclusion within its textual structure; in the context of a forest, we refer to an individual note as a tree. Of course, a tree can be viewed as a forest that has a root node.

Trees correspond roughly to what are referred to as “tags” in the .

2023 1 7 https://www.forester-notes.org/tfmt-000L/ tfmt-000L /tfmt-000L/ Generating images statically using LaTeX

Because of the the other available tools, most authors of hypertext mathematics with diagramming needs tend to rely on the static generation of images from LaTeX code using a local LaTeX toolchain. It is not difficult to instrument with a .

There are also a variety of other tools that do something similar, which tend to be employed in static site generation:

  • by is used by as well as , both via .
  • by is used by the present web site.

The basic architecture of such a tool is to scan for LaTeX blocks, and then identify them by a hash of their contents. This hash is used as a filename for files, which are compiled to and thence to using the tool; the resulting file is then embedded in HTML using an ]]> tag. Alternatively, is also possible to transclude the resulting ]]> element directly, but then , as it is possible for two different ]]> elements on a single page to interfere one each other.

Both and support passing a macro library to be used when rendering. Both and set their macro libraries on a page-local basis.

A serious downside of generating images from LaTeX code is the negative impact on accessibility tools. This seems only slightly mitigated by the transclusion of the ]]> element as opposed to using ]]>. Ultimately accessibility for mathematical diagrams remains an unsolved problem, and it does not seem that the existing discussion on accessibility of hypertext mathematics has much to say about this problem.

https://www.forester-notes.org/sterling-2024-cl-forester/ sterling-2024-cl-forester /sterling-2024-cl-forester/ : networked science in hypertext Reference Related 2024 11 27 https://www.forester-notes.org/5CDY/ 5CDY /5CDY/ Presentations https://www.forester-notes.org/sterling-2024-cl-forester/ sterling-2024-cl-forester /sterling-2024-cl-forester/ : networked science in hypertext Reference 2024 10 23 https://www.forester-notes.org/30FM/ 30FM /30FM/ Forester Blog 2025 3 25 https://www.forester-notes.org/JVIT/ JVIT /JVIT/ Towards II: a design for canonical URLs

One of the goals of is lightweight federation—the ability to have two forests participate in the same graph and therefore provide backlinks, etc. In a previous post (), I talked about some of the difficulties that arise when dealing with identities of people and references that have global scope but could nonetheless be described by trees in many forests. I proposed that such things should be addressed by canonical URIs (e.g. DIDs, DOIs, etc.) and that Forester should grow the ability to bind a canonical URI to multiple trees, which are then gathered into a disambiguation page.

Today I want to broaden the discussion to cover the difficulties of addressing trees themselves (as opposed to the global entities they may describe). This is a proposal and I welcome feedback.

2025 3 25 https://www.forester-notes.org/JVIU/ JVIU /JVIU/ Forester must become part of the Web

I have been working on developing the prerequisites for Forester to emit RSS and Atom feeds for blogs, and I realised that the problem I was trying to solve is a more multifaceted than I originally thought. It comes down to analysing what is needed for Forester to be a good citizen of the World Wide Web: in particular, if we emit an RSS feed that has hyperlinks to some trees in it, those links must refer to an actual page on the actual web rather than something specific to Forester’s ontology.

This may seem downright obvious in hindsight, but you must understand that for the longest time I was not thinking of Forester as a tool for progressively enhancing the Web, but rather as a tool for building fully-local life-wikis or Zettelkästen; I no longer believe that my former viewpoint is reasonable, and I have concluded that we must integrate Forester into the Web or else we will be buried under friction. This post is the start of a design for how to do this.

Forget what you know about how either or previous versions currently work; in order to solve these problems in a reasonable way, we cannot be bound by the past versions of an experimental tool. What we are bound by is the architecture of the World Wide Web, and that will be reflected in the design.

2025 3 25 https://www.forester-notes.org/JVIV/ JVIV /JVIV/ What is the proposal?

Here is the essence of the proposal:

  1. We get rid of the forest://host/addr scheme. Instead, trees are globally addressed by a canonical URL.
  2. The canonical URL of a tree can in principle be arbitrary, but in practice you will want it to be a place where that tree can be viewed — e.g. the place to which it will be uploaded and served via HTTP(S). Indeed, a default scheme will be provided so as to enable files to be rendered with names and relative locations consistent with the intended global addressing scheme; it is also possible to imagine customisation of this without disturbing the overall design.
  3. The canonical URLs are now the vertices of the graph.
  4. In Forester source code, a hyperlink like would be resolved right away to or something, using information supplied in the user’s forest; the same goes for transclusion.
  5. Links to trees in foreign forests must, for now, be totally explicit (but we can imagine relaxing this in the future). Importantly, this approach does not require knowing what is in the forest at evaluation-time.
2025 3 25 https://www.forester-notes.org/JVIW/ JVIW /JVIW/ What about replication and mirroring?

It may seem annoying to have canonical URLs. For example, a forest that contains vital information might need to be published in multiple places. That much is true, but the fact that the physical publication of a forest is replicated should not allowed to impact the graph or fill it with redundant vertices and edges (e.g. should two mirrors become federated). So the only problem with replication is that hyperlinks might take you to the original forest instead of keeping you in the mirror, but I think this should be resolved by some kind of middleware that rewrites links, just as the rewrites links in its snapshots. That can be handled outside of Forester.

2025 3 25 https://www.forester-notes.org/JVIX/ JVIX /JVIX/ What about viewing my forest locally?

Most of the time, an author is working with their forest on their own machine rather than on the web. It is important that links and transclusions point to the local content rather than whatever (if anything) is stored in the “global” canonical URL. I believe this is not actually a problem: although things like RSS feeds and perhaps even published websites would have all the hyperlinks point to the canonical URLs, there is no reason that this should be required for all renderers. It is easy to imagine making this a configurable flag for the default renderer, and for the upcoming “dynamic”/interactive HTML server we would emit links back to the local server rather than to the canonical URLs.

Similarly, there may be projects where there is no intention at all of online publication. In such cases, the scheme for assigning canonical URLs can be arbitrary.

2025 3 25 https://www.forester-notes.org/JVIY/ JVIY /JVIY/ What about access control?

Forester does not currently support any kind of access control, but this is indeed an important area that we are considering carefully in order to enable institutional use of Forester, and ease the burden of collaboration in the usual case of a forest that contains a mixture of data with varying levels of confidentiality. I believe that the current design is compatible with essentially any approach to access control that we might adopt, but I am interested in feedback to the contrary.

2025 3 8 https://www.forester-notes.org/OYOJ/ OYOJ /OYOJ/ Towards : a design for global identity

As we move closer to , which rudimentary federation capabilities, we must address new problems that did not arise in the days when no two interacted or linked to each other. The most immediate issue is that trees describing entities with “global” identity (including actual people as well as bibliographic references) will naturally be duplicated across many forests. For example, this happens when one person authors trees in multiple forests, and it happens even more often with bibliographic entries (both for the entries themselves and their author attributions). It is very important to handle this problem properly now in a way that (1) minimises friction and (2) enables us to quietly evolve toward .

Below, I survey some existing approaches to identity that we would hope to be compatible with at some level. If you want to skip to my concrete proposal, see .

2025 3 8 https://www.forester-notes.org/OYOL/ OYOL /OYOL/ Survey of global identification schemes

There are several extant schemes for identifying individuals, organisations, and artefacts. Some are centralised, and others are decentralised. Centralisation of identity is not necessarily a bad thing, but it is most viable when nearly everyone agrees on the central authority; on the other hand, decentralisation can help in situations where a single central authority has not accumulated enough trust or prestige to be viable.

2025 3 8 https://www.forester-notes.org/OYOM/ OYOM /OYOM/ Centralised identification via DOIs and ORCIDs

Nearly every scholarly paper and book published has a Digital Object Identifier (DOI) assigned to it, which are managed by a single authority (); this applies to both traditional publishers and eprint servers like the arXiv. Services like allow individuals to mint their own DOIs and pin resources and artefacts to them. Due to their widespread adoption, DOIs are a completely viable way to identify published papers and books—and I would argue that any attempt to replace DOIs with a decentralised identifier is likely to be counterproductive as the goal should not not be decentralisation per se but rather to have a reliable, universal way to refer to scholarly content and artefacts.

What DOIs do for artefacts, the Open Researcher and Contributor ID (ORCID) aims to do for people acting within the framework of open science. ORCIDs seem to do their job well, but not everyone has or should have an ORCID—nor would every person who does have one voluntarily choose to pin their entire identity to it. Therefore, although I happily use them, I think ORCIDs are likely to face more of an uphill battle than the DOI—which needed buy-in only from major publishers and eprint servers to reach hegemony.

2025 3 8 https://www.forester-notes.org/OYOK/ OYOK /OYOK/ Informal decentralised identification via web addresses

A particularly simple way to identify a single person or organisation is by means of a web domain or an email address. Although not everyone has a domain name, many people have email addresses. On the other hand, people often have many domain names and their email address may change over time; and when people die, their presence on the web is often erased or lost. Therefore, although widespread, this approach may create difficulties with longevity and stability.

2025 3 8 https://www.forester-notes.org/OYON/ OYON /OYON/ General-purpose decentralised identification via DIDs

When reading about the paper of outlining Bluesky’s AT Protocol, I learned of . In essence, DIDs are URIs of the form did:method:path where method identifies how the DID is intended to be resolved and path is a colon-separated path that should be resolved by means of that method. In either case, a DID is intended to be resolved to a JSON document that contains information about the resource or entity being described, as well as various methods (like public keys) for verifying the integrity of that information. The methods are somewhat open-ended, but two important methods have emerged.

2025 3 8 https://www.forester-notes.org/OYOO/ OYOO /OYOO/ W3C’s did:web method

, which in which the path is intended to be a web domain. Simplifying somewhat, a DID like did:web:jonmsterling.com would be substantiated by responding to the HTTPS request https://jonmsterling.com/.well-known/did.json with a document in the appropriate format. The upside is that the owner of a web domain is their own identity authority; in this sense did:web is a truly decentralised identification scheme. The downside is that you have to have a web domain, and you also can never change it ever—the .

2025 3 8 https://www.forester-notes.org/OYOP/ OYOP /OYOP/ Bluesky’s did:plc method

For a social network like Bluesky, it is critical that users be able to migrate their identity from one domain to another. Obviously users may change or lose their domain over time, but it is important to keep in mind that the vast majority of users will never have their own domain and so they will over the course of their lives jump from one subsidiary domain that they don’t control to the next—just as Mastodon users are constantly migrating from instance to instance, driven to wander endlessly by either the petty tyranny of instance maintainers who think they know best, or by the natural quiescence of instances caused by lack of funds or time, or (in many cases) a combination of the two.

It seems that there is no way to address this problem without introducing some central authority—a directory of permanent identifiers that are then resolved to documents that establish cryptographically verified bidirectional links with more ephemeral and human-readable forms of identification (such as web domains). This is essentially the design of Bluesky’s did:plc method, as explained by :

  1. On your own domain, which serves as your (ephemeral) handle, you place a DNS TXT record or file that contains a DID like did:plc:asdlkfh9q8034baliufhbcailurb.
  2. Someone resolves this DID to a document by querying a central directory server (such as ). This document contains a link back to the domain; signatures are used to ensure that every update to the document has been authorised by whoever signed it when it was first minted.

Although some centralisation is required here, the use of cryptographic proof ensures that the central authority does not need to be trusted (to a certain extent).

2025 3 8 https://www.forester-notes.org/OYOQ/ OYOQ /OYOQ/ Analysis of global identity in Forester

Although Forester aims to become a better citizen of the Web and integrate with emerging protocols, it is a non-negotiable design constraint that Forester still remain usable by people who don’t control a domain name, cannot run software on their web host, cannot set DNS records, and could not care less what a is. I also have a feeling that there will not be a single protocol that fits all use cases; what I am noticing, however, is that there are commonalities to all the protocols, and that we ought to be informed by these commonalities. For example, in every case an identity is resolved from a URI of some kind—for example, DIDs and DOIs and ORCIDs all have canonical URIs.

Therefore, it strikes me that Forester’s approach to global identity must rest on the axiom that an identity is nothing more or less than a URI; we can place no constraints whatsoever on what form this URI takes, and we should also remain flexible as to compatibility with future replacements of URIs (whether in the form of IRIs, or the , etc.).

If we start from that point of view, there some problems to address:

  1. Even if an identity is not canonically addressed by a tree in a forest, an identity still often needs to have a tree in the forest. One wants to store biographical and bibliographic information, and maybe even personal notes, etc., and at the very least it is very important to be able to browse backlinks on a biographical page even if the page itself has no content of its own.
  2. Not only must we be able to attach a tree to an identity: we must be able to attach many trees to an identity. This is a requirement of federation.
2025 3 8 https://www.forester-notes.org/OYOR/ OYOR /OYOR/ A plan for global identity in Forester

Building on my , I propose that Forester allow any tree to declare that it “describes” a given global identity in the form of a URI. At a first cut this can be done via datalog (but we would probably hide this behind something):

Now it remains to explain how we shall surface the fact that a given entity is described by some tree.

  1. For any identity in this relation, we should automatically create a “disambiguation page” that transcludes all the attached trees.
  2. When a hyperlink points to a URI that lies in this relation, it should be directed to the disambiguation page.

There are further implications for such a feature—for instance, in the future we might automatically populate bibliographic information, etc. (But we have to be careful due to the near-universal unusably low quality of bibliographic databases keyed by DOIs, etc.)

We will need to provide guidance as to how identities should be assigned to (e.g.) people who don’t control an online identity, etc. The rule of thumb should be that we always defer to the preferences of the described person, and to the version of record in the case of an artefact. When there is no canonical choice, users of Forester should do what they like, but they should be willing to update their references in the future should a canonical global entity emerge.

2025 3 8 https://www.forester-notes.org/OYOS/ OYOS /OYOS/ Request for comment

I am hoping to hear other people’s thoughts on this proposal, including any constructive criticisms or suggestions for how we might go about implementing it. You can write to me or the with your feedback.

2023 5 14 2024 4 25 2025 5 26 https://www.forester-notes.org/0052/ 0052 /0052/ Build your own in 10 minutes

is the most successful scientific hypertext project in history. Its goal is to lay the foundations for the theory of algebraic stacks; to facilitate its scalable and sustainable development, several important innovations have been introduced, with the tags system being the most striking.

Each tag refers to a unique item (section, lemma, theorem, etc.) in order for this project to be referenceable. These tags don't change even if the item moves within the text. (, ).

Many working scientists, students, and hobbyists have wished to create their own tag-based hypertext knowledge base, but the combination of tools historically required to make this happen are extremely daunting. Both the and use a cluster of software called , but bitrot has set in and it is to build its dependencies on a modern environment without significant difficulty, raising questions of longevity.

Moreover, ’s deployment involves running a database on a server (in spite of the fact that almost the entire functionality is static HTML), an architecture that is incompatible with the constraints of the everyday working scientist or student who knows at most how to upload static files to their university-provided public storage. The recent experience of the ’s pandemic-era hiatus and near death experience has demonstrated with some urgency the pracarity faced by any project relying heavily on volunteer system administrators.

2023 5 14 https://www.forester-notes.org/0053/ 0053 /0053/ Introducing : a

After spending two years exploring the that meet the unique needs of real, scalable scientific writing in hypertext, I have created a tool called which has the following benefits:

  1. is tag-based like , and can therefore power large-scale generational projects like and .
  2. produces static content that without needing to run or install any serverside software.
  3. is on your own machine.
  4. To prevent bitrot, is a single tool rather than a composition of several tools.
  5. satisfies all the , including sophisticated notational macros, typesetting of diagrams, etc.

combines networks of (called “trees”) into hypertext sites called “forests”.

2023 3 4 https://www.forester-notes.org/tfmt-000R/ tfmt-000R /tfmt-000R/ Forests and trees of evergreen notes Definition

A forest of (or a forest for short) is loosely defined to be a collection of in which multiple are allowed to emerge and evolve over time. Concretely, one note may contextualize several other notes via transclusion within its textual structure; in the context of a forest, we refer to an individual note as a tree. Of course, a tree can be viewed as a forest that has a root node.

Trees correspond roughly to what are referred to as “tags” in the .

In this article, I will show you how to set up your own using the software. These instructions pertain to the version.

2023 8 13 https://www.forester-notes.org/006R/ 006R /006R/ Preparing to run the software

In this section, we will walk through the installation of the software.

2023 8 13 https://www.forester-notes.org/006S/ 006S /006S/ System requirements of 2023 8 13 https://www.forester-notes.org/006T/ 006T /006T/ A unix-based system Requirement

requires a unix-based system to run; it has been tested on both macOS and Linux. Windows support is , but there are no concrete plans to implement it at this time.

2023 8 13 https://www.forester-notes.org/006U/ 006U /006U/ A working OCaml 5 installation Requirement

is written in the programming language, and makes use of the latest features of OCaml 5. Most users should install through OCaml's package manager; instructions to install opam and OCaml simultaneously can be found .

2023 8 13 https://www.forester-notes.org/006V/ 006V /006V/ A working installation Requirement

If you intend to in your , you will need to have a working installation of installed, such as . If all your mathematical expressions are supported by , this is not necessary.

2023 8 14 https://www.forester-notes.org/006Y/ 006Y /006Y/ The distributed version control system Requirement

It is best practice to maintain your inside of . This serves not only as a way to prevent data loss (because you will be pushing frequently to a remote repository); it also allows you to easily roll back to an earlier version of your , or to create “branches” in which you prepare that are not yet ready to be integrated into the .

The recommended system is , which comes preinstalled on many unix-based systems and is easy to install otherwise. is not the most user-friendly piece of software, unfortunately, but it is ubiquitous. It is possible (but not recommended) to use without version control, but note that the simplest way to involves cloning a repository.

2023 8 13 https://www.forester-notes.org/006W/ 006W /006W/ Installing the software

Once you have met the , installing requires only a single shell command:

To verify that is installed, please run forester --version in your shell.

2023 8 14 2024 4 25 2024 6 17 https://www.forester-notes.org/006X/ 006X /006X/ Setting up your from the template

Now that you have the software, it is time to set up your . provides a simple command to initialise a fresh within a folder. We’ll call our folder forest, but you can call it anything you want.

Now that we are inside our new directory, we can instruct to initialise a .

forester init

This command initialises a repository with the skeleton of a , which contains a configuration file named forest.toml; this file specifies the locations of your trees, assets, etc. There is also a submodule bound to the theme/ directory (pointing to the repository) that contains the stylesheets that web browsers will need in order to render your as HTML.

2023 8 14 2024 6 17 https://www.forester-notes.org/0073/ 0073 /0073/ Tree addresses in a

A in is usually associated to an address of the form NNNN is a four-digit . The purpose of the code is to uniquely identify a within your in such a way that you are not tempted to rename it, as you might be when titles or dates are embedded into filenames. A tree with address NNNN is stored in a file named NNNN.tree (unless it is emitted from inside another tree by means of the feature).

Note that the format of addresses is purely a matter of convention, and is not forced by the tool. Users are free to use their own naming convention for tree addresses, and in some cases alternative (human-readable) formats may be desirable: this includes trees representing bibliographic references, as well as biographical trees. If you don’t like numerical tree addresses, nobody is forcing you to use them. The use of numerical addresses is suitable for projects like , but it may not be appropriate for your own use-case.

Addresses in are not hierarchical: all resources are rendered at the root of the forest, no matter where their source files are kept. This limitation is intentional, but we might revisit it in the future.

2023 8 15 2024 4 25 https://www.forester-notes.org/007D/ 007D /007D/ Building and viewing your for the first time

To build your , you can run the following command of 's executable in your shell:

forester build forest.toml

The --dev flag is optional, and when activated supplies metadata to the generated website to support an “edit button” on each tree; this flag is meant to be used when developing your locally, and should not be used when building the to be uploaded to your public web host.

2023 8 15 https://www.forester-notes.org/007G/ 007G /007G/ renders each tree to an XML document

renders your to some XML files in the output/ directory; XML is, like HTML, a format for structured documents that can be displayed by web browsers. The template comes equipped with a built-in XSLT stylesheet (theme/default.xsl) which is used to instruct web browsers how to render your into a pleasing and readable format.

2023 8 15 https://www.forester-notes.org/007I/ 007I /007I/ Serving and viewing your from a local web server

To view your while editing it, you must serve it from a local web server..To do this, first ensure that you have correctly installed. Then run the following command from the root directory of your :

python3 -m http.server 1313 -d output

(You could replace 1313 with whatever port you prefer.) While this command is running, you will be able to access your by navigating to in your preferred web browser.

In the future, to avoid the dependency on external tools like Python.

2023 8 15 https://www.forester-notes.org/007K/ 007K /007K/ Creating your personal biographical

The first that you should create is a biographical tree to represent your own identity; ultimately you will link to this tree when you set the of other that you create later on. It is convenient to simply use a person’s full name to address a biographical . is located at trees/people/jonmsterling.tree and contains the following source code:

Let’s break this code down to understand what it does.

  1. The declaration sets the title of the to my name.
  2. The declaration informs that the is biographical. Not ever needs to have a taxon; common taxa include Person, Theorem, Definition, Lemma, etc. You are free to use whatever you want, but some taxa are treated specially by .
  3. The subsequent declarations attach additional information to the tree that can be used during rendering. These declarations are optional, and you are free to put whatever metadata you want.
  4. Like in HTML, paragraphs must be wrapped in .

Do not hard-wrap your text, as this can have visible impact on how are rendered; it is recommended that you use a text editor with good support for soft-wrapping, like .

You can see that the looks superficially like a combination of and Markdown; Markdown-style links are used both for links to other trees and for links to external URLs. 's concrete syntax is not fully documented, but it is less ambiguous than both and Markdown.

2023 8 15 2024 4 25 https://www.forester-notes.org/007H/ 007H /007H/ Creating a new using forester new

Creating a new in your is as simple as adding a .tree file to the trees folder. Because it is hard to manually choose the , provides a command to do this automatically:

forester new forest.toml --dest=trees

In return, should output the location of the new tree, e.g. trees/0002.tree. If we look at the contents of this new file, we will see that it is empty except for metadata assigning a date to the tree:

You may prefer to use randomised addresses over sequential addresses; this can be particularly useful if multiple people are contributing to a . In that case, pass the --random option to forester new.

Most should have a annotation; this date is meant to be the date of the 's creation; you can have more than one date, if you like to keep track of when a tree has been updated. You should proceed by adding further metadata: the title and the ; for the latter, you will use the address of your .

titles should be given in lower case (except for proper names, etc.); these titles will be rendered by in sentence case. A can have as many declarations as it has ; these will be rendered in their order of appearance.

Now you can begin to populate the tree with its content, written in the . .

2023 8 15 https://www.forester-notes.org/007L/ 007L /007L/ Bottom-up hierarchy via transclusion

You may be used to writing documents, where you work from the top down: you create some section headings, put some text under those headings, make some deeper section headings, put more text, etc. work in the opposite way, from the bottom up: you start by writing independent, notes/ and then only later start to (sparingly) assemble these into a hierarchy in order to reify the emerging structure.

’s bottom-up approach to section hierarchy works via something called transclusion. The idea is that at any time, you can include (“transclude”) the full contents of another into the current tree as a subsection by adding the following code:

This is kind of like ’s command, but much better behaved: for instance, section levels are computed on the fly depending on the position in the hierarchy. This is cobbled together by transcluding many smaller , each with their own independent existence. For example, the following two sections are transcluded from an of my forest:

2022 12 27 https://www.forester-notes.org/tfmt-0009/ tfmt-0009 /tfmt-0009/ The best structure to impose is relatively flat

It is easy to make the mistake of prematurely imposing a complex hierarchical structure on a network of notes, which leads to excessive refactoring. Hierarchy should be used sparingly, and its strength is for the large-scale organization of ideas. The best structure to impose on a network of many small related ideas is a relatively flat one. I believe that this is one of the mistakes made in the writing of the foundations of relative category theory, whose hierarchical nesting was too complex and quite beholden to my experience with pre-hypertext media.

One of the immediate impacts and strengths of ’s transclusion model is that a given has no canonical “geographic” location in the . One can appear as a child of many other , which allows the same content to be incorporated into different textual and intellectual narratives.

2022 12 26 https://www.forester-notes.org/tfmt-0006/ tfmt-0006 /tfmt-0006/ Hierarchical structure as non-unique narrative

Multiple hierarchical structures can be imposed on the same associative network of nodes; a hierarchical structure amounts to a “narrative” that contextualizes a given subgraph of the network. One example could be the construction of lecture notes; another example could be a homework sheet; a further example could be a book chapter or scientific article. Although these may draw from the same body of definitions, theorems, examples, and exercises, these objects are contextualized within a different narrative, often toward fundamentally different ends.

As a result, any interface for navigating the neighbor-relation in hierarchically organized notes would need to take account of the multiplicity of parent nodes. Most hypertext tools assume that the position of a node in the hierarchy is unique, and therefore have a single “next/previous” navigation interface; we must investigate the design of interfaces that surface all parent/neighbor relations.

2023 8 16 https://www.forester-notes.org/007N/ 007N /007N/ The markup language

A in is a single file written in a markup language designed specifically for scientific writing . A has two components: the and the .

2023 8 16 https://www.forester-notes.org/007P/ 007P /007P/ markup: frontmatter

The frontmatter of a is a sequence of declarations that we summarize below.

Declaration Meaning
sets the title of the ; can contain markup
sets the of the to be the biographical tree at address name
sets the creation date of the ; full ISO 8601 date-times are supported.
sets the taxon of the ; example taxa include lemma, theorem, person, reference; the latter two taxa are treated specially by for tracking biographical and bibliographical respectively
defines and exports from the current a function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for
brings the functions exported by the tree address into scope
brings the functions exported by the tree address into scope, and exports them from the current tree
2023 8 16 https://www.forester-notes.org/007O/ 007O /007O/ markup: mainmatter

Below we summarize the concrete syntax of the mainmatter in a .

Function Meaning
creates a paragraph containing ...; unlike Markdown, it is mandatory to annotate paragraphs explicitly
typesets the content in italics
typesets the content in boldface
creates an ordered list
creates an unordered list
creates a list item
typesets the content in (inline) math mode using ; note that math mode is idempotent in
typesets the content in (display) math mode using
the at address address as a subsection
formats the text title as a hyperlink to address address; if address is the address of a , the link will point to that tree, and otherwise it is treated as a URL
defines a local function named with two arguments; subsequently, the expression would expand to body with the values of u,v substituted for .
typesets the content in monospace
typesets the body externally using using preamble as preamble code (e.g. to set up tikz packages, etc.). It can be useful to wrap this in your own macro in order to insert your preamble code automatically.
2023 8 16 https://www.forester-notes.org/007Q/ 007Q /007Q/ An complete worked example in Example

An example of a complete in the markup language can be seen below.

The code above results in the following tree:

2023 2 11 https://www.forester-notes.org/001H/ 001H /001H/ Creation of (co)limits Definition

Let be a functor and let be a category. The functor is said to create (co)limits of -figures when for any diagram such that has a (co)limit, then has a (co)limit that is both preserved and reflected by .

2023 8 16 https://www.forester-notes.org/007R/ 007R /007R/ Deploying your to a web host

Now that you have and , it is time to upload it to your web host. Many users of will have university-supplied static web hosting, and others may prefer to use GitHub pages; deploying a works the same way in either case.

  1. First, make sure your is built using .
  2. Then take the entire contents of your output directory and upload them to your preferred web host.
2023 8 16 https://www.forester-notes.org/007S/ 007S /007S/ Let a hundred bloom!

I am eager to see the new that people create using . I am happy to offer personal assistance via the .

Many aspects of are in flux and not fully documented; it will often be instructive to consult the source of existings , such as .

Have fun, and be sure to send me links to your when you have made them!

https://www.forester-notes.org/jonmsterling/ jonmsterling /jonmsterling/ Jon Sterling Person https://www.forester-notes.org/kentookura/ kentookura /kentookura/ Kento Okura Person 2023 6 20 https://www.forester-notes.org/0065/ 0065 /0065/ › Project information
code forge:
ticket tracker:
mailing lists:
opam package:
tutorial:
2023 6 1 https://www.forester-notes.org/005P/ 005P /005P/ › Release notes

A tool for tending .

2023620https://www.forester-notes.org/0065/0065/0065/ › Project information
code forge:
ticket tracker:
mailing lists:
opam package:
tutorial:

20241020https://www.forester-notes.org/011P/011P/011P/Forester 5.0Prerelease

This is a major release of Forester that includes many changes under the hood, as well as breaking changes that will require manual adjustments to existing forests. We are sorry for the frustration that these changes may cause to existing users, but we strongly believe that this is necessary for Forester to reach its potential as a tool that enhances rather than replaces the World Wide Web; we also strongly believe that these changes will make Forester more useful for existing users as well as the next thousand users.

Our thanks to and for conversations leading to the design of this release. We are grateful for initiative for helping us get to 5.0.

Many of the changes included here are meant to support the future of Forester as an authoring tool for a new kind of Internet of Science that will enable the federation of many different forests by extending existing protocols with new hypermedia controls for content transclusion applicable to scientific authoring.

20241020https://www.forester-notes.org/0126/0126/0126/Tl;dr: migration guide

To migrate your forest to , do the following:

  1. Update your configuration file ().
  2. Remove all usage of and (see ).
  3. Move all declarations to the top-level of any .tree files, as these can no longer occur in subtrees (see ).
  4. Any or attributions must take a tree address as their argument; when you wish to attribute a resource to a person who is not represented by a tree, you can use or (see ).
  5. Rewrite any queries to use the new datalog engine (see ), as the legacy query engine has been removed.
  6. Take into account the renaming of several built-in relations (see ).
  7. View your forest locally using an HTTP server rather than directly through the file system (see ).
  8. Begin dialing back your use of custom XML stylesheets (see ). It is possible that support for customisation at this level will be removed in a future release; if you have innovative customisations that are very important for your use of Forester, consider discussing them on the so that maintainers can better understand the problems you are solving.
20241020https://www.forester-notes.org/0SOW/0SOW/0SOW/An implementation of the

Forester now ships with an implementation of the . See for more information and configuration examples for various editors. Its status is still experimental. If you encounter crashes or other issues, please let the us know by or by writing to the

20241020https://www.forester-notes.org/0125/0125/0125/Changes to forest.toml format

Several changes have been made to the forest.toml configuration format.

  1. forest.root is renamed to forest.home.
  2. The forest.theme key has been removed; from now on, your theme must be located in the theme directory.
  3. A new field forest.foreign has been added; this is the entry-point for the experimental forest syndication feature discussed in .
20241020https://www.forester-notes.org/011Q/011Q/011Q/Canonical URLs for tree addresses

Up until this release, Forester’s trees were addressed by short strings — which, by convention, might be of the form xxx-NNNN or NNNN or some arbitrary string like sterling-2021-thesis. In order to prepare for the future in which multiple forests can be glued together, we replace Forester’s short names with fully qualified URLs that point to the location on the World Wide Web where a given tree would be published (if you choose to publish it). By default, all local trees will be resolved against http://forest.local/, which you should change if you choose to publish your forest on the Web. In your forest.toml configuration, first set a base URL for your forest like the following:

Within this forest, a tree named foo is then associated to the canonical URL https://www.forester-notes.com/foo/. Forester’s renderer will produce the correct directory structure so that if you were to upload the contents of the output directory to https://www.forester-notes.com/, a link to https://www.forester-notes.com/foo/ would bring you to the foo tree.

Hyperlinks in Forester source code to trees within your own forest will automatically expand the short name foo to the canonical URL https://www.forester-notes.com/foo/. Canonical URLs are used as vertices in the .

20241020https://www.forester-notes.org/011R/011R/011R/What do we mean by “URL”?

Today, “URLs” are a mostly implementation-defined concept that can only be understood by looking at the source code of major web browsers; in the future, this may congeal into an actual standard but today is not that day (nor is tomorrow, if the state of the is any indication). It is best to think of Forester’s approach to URLs as provisional and subject to evolution as the Web continues to mature.

20241020https://www.forester-notes.org/OYOT/OYOT/OYOT/Simplifications to the source language20241020https://www.forester-notes.org/OYOU/OYOU/OYOU/Removal of imports within subtrees

It is no longer permitted to have an declaration within a subtree: these can occur only at the top level of a file and therefore have file-level scope.

20241020https://www.forester-notes.org/011T/011T/011T/Removing transclusion overrides

In prior versions of Forester, it was possible to override the title and the taxon of a transcluded tree using the fluid bindings and respectively. This feature is no longer supported in , and existing users are encouraged to purge their use of it prior to upgrading to .

In short, supporting this feature was greatly complicating the planned transition to a genuine hypermedia format; it could also be argued that it might have led to scenarios where an original author’s intentions are violated at the transclusion site.

Please note that transclusion options, such as , etc., are still supported.

20241020https://www.forester-notes.org/OYOV/OYOV/OYOV/Removal of autocapitalisation

Titles and taxa will no longer be autocapitalised: this feature biases Forester toward specific languages and is annoyingly complex to maintain. Therefore, you must rename all your titles and taxa to be capitalised by hand. This can be done in VS Code using the following regexp: replace with , etc.

20241020https://www.forester-notes.org/012N/012N/012N/Changes to attribution links

In prior versions, the and command would detect whether its contents were the address of a tree; if so, it would create a wikilink to the tree and otherwise, the included text would appear directly. This feature was convenient for smoothly handling the case that an author of a given resource is not represented in the forest by a biographical tree; the downside is that it makes the assumption that at compiletime we shall know the entire contents of the forest (and, thus, whether a given address shall be bound to a tree).

To simplify the handling of author links and make it compatible with the open-world future of Forester, the behaviour is changed as follows:

  1. The argument to and must be a (possibly relative) . Thus, on my own forest, it would be OK to have either or but it would not be OK to have .
  2. To make an unlinked attribution containing, use .
20241020https://www.forester-notes.org/013A/013A/013A/New datalog-based query engine

As the query engine has evolved, it has become a bit unwieldy and misshapen. In order to prevent further churn and facilitate the long-term development and use of Forester, we are replacing the query engine and graph analysis with a more general tool: datalog. With this change comes the ability to introduce arbitrary relations of any arity; this is a powerful and dangerous tool, so use it wisely.

20241020https://www.forester-notes.org/013B/013B/013B/On performance trade-offs

Switching to datalog makes forests that make heavy use of queries a bit slower to render. We considered this trade-off carefully, but believe that for the long-term health of Forester, this is acceptable. In the near future, Forester will render trees on demand rather than all at once (except when you are preparing a static archive for upload/deployment); in this mode of use, Forester will be faster than ever.

20241020https://www.forester-notes.org/013C/013C/013C/Renamed built-in relations

Forester’s built-in binary relations have been accessible via macros like , etc. In this release, these relations are being renamed to make them more pleasant and consistent to use with datalog.

Old name New name
rel/tags rel/has-tag
rel/taxa rel/has-taxon
rel/authors rel/has-author
rel/contributors rel/has-direct-contributor
rel/transclusion rel/transcludes
rel/links rel/links-to
20241020https://www.forester-notes.org/013D/013D/013D/New built-in relations

A few new built-in relations have been added.

  • rel/is-node ?X is a unary relation that holds for any tree address ?X. This is needed when specifying reflexive binary relations: the clause R ?X ?X -: is not allowed by datalog, so one must use .
  • rel/transcludes/transitive-closure is the transitive closure of rel/transcludes.
  • rel/transcludes/reflexive-transitive-closure is the reflexive transitive closure of rel/transcludes.
  • rel/is-reference ?X holds when ?X is designated as a reference/bibliographical tree. Currently, the built-in rules of the database deduce rel/is-reference ?X for any tree ?X with taxon reference. The purpose of abstracting from the taxon is to enable non-English users of Forester to benefit from the computation of bibliographies.
  • Similarly, rel/is-person ?X holds when ?X is designated as a personal/biographical tree. Currently, the built-in rules of the database deduce rel/is-reference ?X for any tree ?X with taxon person.
  • rel/in-bundle-closure ?X ?Y is the reflexive transitive closure of the union of the transclusion relation with the relation of ?X requiring the asset ?Y. The purpose of this relation is to easily bundle up fragments of a forest (see ).

All of these built-in relations can be defined in Forester’s dialect of datalog; they are predefined for convenience, and because they are used in the computation of backmatter.

20241020https://www.forester-notes.org/013E/013E/013E/An example datalog queryExample

In order to illustrate the use of the datalog engine, I will show how to construct a query that will find all the trees with taxon reference written by jonmsterling that are tagged either accepted or refereed. The first thing we must do is define the smallest relation containing all trees tagged accepted or refereed; this is done by adding clauses to the database as follows.

First we define the name of a relation. In the current release, relations are global strings and there is no facility to generate a “fresh” one; that may change in the future.

Next, we add two defining clauses for our relation. In what follows, simply delimits content that should be parsed as a datalog expression, and instructs Forester to execute the datalog expression.

The left-hand side of the reversed turnstile -: is a proposition representing the goal; the right hand side is given by propositions representing the premises, each surrounded in braces and separated by whitespace. Metavariables are written with a question mark sigil. Literal content is embedded into a datalog proposition by surrounding it in '{...}; we will see that literal content is one kind of vertex in the graph database.

Now that we have actually defined the relation that we will use, we can run a query:

The structure of a query identifies the metavariable being solved behind the turnstile, and then lists the clauses that must hold. Whereas a content vertex is addressed via '{...}, a is addressed using @{...}.

20241020https://www.forester-notes.org/30FO/30FO/30FO/Atom syndication support

It is now possible to syndicate a given tree as an Atom feed; for example, if you have a tree for your blog and its subtrees/transclusions are your blog posts, you can include the following code to generate an Atom feed for this blog:

If your blog is located at https://www.my-great-forest.net/my-blog/, then there will be an atom feed placed at https://www.my-great-forest.net/my-blog/atom.xml.

This feature is experimental and has some limitations.

20241020https://www.forester-notes.org/30FN/30FN/30FN/Publishing and implanting forests

Forester now includes an experimental feature to “publish” a portion of your forest to a JSON blob that can be read by Forester and implanted into another forest. For example, if you include the following code in a tree within your forest, then a file will be emitted at output/my-forest.json containing the compiled content of your entire forest, together with all the assets:

Of course, more sophisticated queries can be used. For example, you can emit all the items tagged public together as follows:

To implant the resulting JSON file into another forest, simply copy over the file and add the following line to your configuration file:

By default, implanted trees will be rendered to your output folder underneath a foreign/ directory; if you wish to instead that links to implanted trees be routed directly to their canonical URLs (which will likely be the case if you implant a public forest), then you may configure that as follows:

This feature is highly experimental and has many limitations; it will change in breaking ways in the near future. Although we are very interested to learn about the limitations of this feature, we will be taking a hands-off approach to support until the feature has taken a more stable form.

20241020https://www.forester-notes.org/VNQ8/VNQ8/VNQ8/Changes to how forests are viewed locally and deployed

In the past, Forester’s XML output used relative URLs for all links. This was tractable because the output had no directory structure, but this is increasingly becoming problematic—for example, are going to be rendered to a subdirectory, but this breaks all the relative URLs. I have come to the conclusion that the only way forward is to use absolute URLs for everything, but this assumes that the output is being served from the root directory of some host. As a result, users must fire up an HTTP server in order to view their forest locally. With this release we will (TODO) include a built-in HTTP server, but early adopters can simply run python3 -m http.server 8000 from the output directory and open localhost:8000 in their browser.

Some users may wish to deploy their forest somewhere other than the root directory of a given (sub)domain. To achieve this and have all your links work correctly, enter the following configuration:

20241020https://www.forester-notes.org/P9BN/P9BN/P9BN/Changes to handling of assets

Assets in compiled forests are content-addressed by their hash; a new primitive is provided for generating the correct URL of an asset that is stored in a designated assets directory. For example, to embed an image that is stored in assets/images/my-great-illustration.jpg, you would write the following code:

[src]{\route-asset{assets/images/my-great-illustration.jpg}}{}]]>20241020https://www.forester-notes.org/0127/0127/0127/The future of Forester’s XML format

Forester currently emits archival-quality output in a custom XML format that is then interpreted using an XSLT stylesheet (as part of the ). This format has served us well, enabling users to customise the presentation of their forests to a great degree. An added benefit of the XML format is to be able to easily convert a tree to LaTeX using another stylesheet.

However, the constantly changing XML format has been an equally frustrating source of churn for users of Forester, and I have for some time now been warning users who customise their theme that these customisations are technically possible but not supported (i.e. we make no promise not to break them).

The time is coming when Forester’s interaction model and output format will be changed drastically; rest assured that the core principles behind Forester (including the ability to generate static archival output that can be hosted anywhere) will be retained. We aim to become a better citizen of the World Wide Web by moving toward a more standard hypermedia format.

One possiblity is to extend HTML with just the hypermedia controls and embedded microformats needed for Forester’s operation. This re-coupling of presentation and data would, paradoxically, facilitate Forester to evolve more rapidly over time while simultaneously increasing the longevity of forests that have been compiled using older versions of the tool.

2024810https://www.forester-notes.org/0109/0109/0109/Forester 4.3Release

This is a smaller release that contains a few changes to how Forester works under the hood. As usual, you must upgrade your theme submodule to the 4.3.0 tag.

2024810https://www.forester-notes.org/010A/010A/010A/Changes to external LaTeX rendering

Previously, the construct would generate a .tex file, convert it to an SVG file, and then copy it into output/resources/; this file would then be referenced in the resulting XML using the <forester:embeddex-tex> element, which was rendered by the theme to <html:img>.

Now, the contents of the SVG file are embedded directly into the resulting document as an <html:img> element with a base64-encoded data-url. The <forester:embedded-tex> element is no longer used.

The goal of this change is to make the output files more self-contained and less reliant on surrounding files. A downside of the present change is that it makes the output files a bit larger, as base64-encoded SVGs are not exactly small. In the future, we might instead embed the SVG code into the DOM (which could have some benefits for accessibility), but if we do this, we will have to massage the SVG output to remove duplicate @id attributes.

2024810https://www.forester-notes.org/010B/010B/010B/Static builds for linux

A build-static-linux.sh script has been added which can be used, in connection with Docker, to build a static binary that can be run on Linux.

2024620https://www.forester-notes.org/00WK/00WK/00WK/Forester 4.2Release

This release brings several internal changes that are meant to facilitate the further improvement of Forester, as well as some user-facing changes (most notably a ). These are breaking changes: existing queries will need to be translated, and you will need to upgrade your theme.

2024620https://www.forester-notes.org/00YF/00YF/00YF/First-class functions and lazy arguments

This release adds λ-abstraction, which can be written like so:

In addition, lazy arguments are now supported. In any place that a function argument can be bound (e.g. in , , or ), an argument marked with a tilde is automatically wrapped in a thunk when it is passed. For example, consider the following code:

In the above, the argument x is strict and y is a thunk that must be forced before being used—hence the application to {}; note that the results are not memoised. The code above is functionally equivalent to the following:

Of course, when your code is pure, passing by name vs. by value does not make a difference. The purpose of this feature is, however, to enable more expressive macros that make use of fluid bindings.

2024620https://www.forester-notes.org/00YG/00YG/00YG/Combining fluid bindings and lazy argumentsExample

makes it possible (see ) to write MathML directly as an alternative to using Forester’s TeX-like math mode via KaTeX. For example, we can write the following wrappers for some basic MathML elements:

{\body}} \def\mrow[body]{\{\body}} \def\mi[x]{\{\x}} \def\mo[o]{\{\o}} \def\mn[n]{\{\n}}]]>

With this in hand, we can write prose involving MathML content, like so:

The above is a bit messy. We can clean it up with some function definitions:

It is annoying that we have to always wrap things in . By combining first-class functions, lazy arguments, and fluid bindings, we can lift this requirement:

element. \def\ensure-math[~body]{% \scope{% % Set a default value for \math-wrapper (no-op if already set). \put?\math-wrapper{\fun[x]{\{\x}}}% % % Apply the current function bound to \math-wrapper. \get\math-wrapper{% % Bind \math-wrapper to the identity function in the current scope so that % we do not get redundant nodes. \put\math-wrapper{\fun[x]{\x}}% % % Force the \body thunk to evaluate the body within the wrapper. \body{}% }% }% }]]>

We now re-define our macro library to use the :

{\x{}}}} \def\mi[~x]{\ensure-math{\{\x{}}}} \def\mo[~x]{\ensure-math{\{\x{}}}} \def\mn[~x]{\ensure-math{\{\x{}}}} \def\plus[~x][~y]{\mrow{\x{} \mo{+} \y{}}} \def\equals[~x][~y]{\mrow{\x{} \mo{=} \y{}}}]]>

Now, we can put MathML content freely into prose without needing to wrap it each time.

2024620https://www.forester-notes.org/00YH/00YH/00YH/Lazy arguments are experimentalWarning

Please note that these features are experimental and subject to change—only build large macro libraries relying on them at your own risk.

2024620https://www.forester-notes.org/00WS/00WS/00WS/New query language

The existing querying feature, , has been replaced by something much better — at the cost of a breaking change that will require existing queries to be rewritten.

2024620https://www.forester-notes.org/00WU/00WU/00WU/New syntax for set operations

Intersections of queries are formed using a variadic constructor . For example, the following computes the intersection of the queries q1, q2, and q3:

Unions of queries are formed similarly using the variadic constructor. The complement of a query q is written .

Note: as before, to render the results of a query you must use the command; for example:

2024620https://www.forester-notes.org/00WV/00WV/00WV/Query operations are first-class values

Previously, the built-in query operations were written like , etc.; these names, however, were hard-coded into the lexer which meant that they did not work in the expected way with Forester’s hierarchical namespacing. This hardcoding has been removed, and query operations are treated as first-class values that are resolved from primitive names in the namespace. As such, the following code is equivalent to :

A further consequence of this change is that queries can be defined compositionally by macros.

2024620https://www.forester-notes.org/00WW/00WW/00WW/Relational queries

The most significant user-facing change to the query language is the ability to form basic relational queries along several ; in fact, the built-in query constructors , , and are all expressible in these terms.

2024620https://www.forester-notes.org/00WX/00WX/00WX/Built-in relation symbols

Forester includes several built-in relation symbols, maintained as graphs that are accumulated during evaluation:

  • contains an edge from x to y when x directly transcludes y, i.e. contains .
  • contains an edge from x to y when x links to y, i.e. contains something like or .
  • contains an edge from x to y when x has taxon y, i.e. contains .
  • contains an edge from x to y when x has tag y, i.e. contains .
  • contains an edge from x to y when x has author y, i.e. contains .
  • contains an edge from x to y when x is a tree with contributor y, i.e. contains .

The implementation supports arbitrarily many relation symbols; this is not yet exposed to the user, but could in the future be employed by advanced users of Forester to support the development of sophisticated ontologies.

2024620https://www.forester-notes.org/00WZ/00WZ/00WZ/Query modes and polarities

Given an address x and a relation symbol r, there are several useful queries that we might wish to make:

  1. We might wish to find all incoming edges to x in r, or we may wish to find all outgoing edges from x in r. We shall refer to the differenec between incoming and outgoing edges is referred to as a polarity.
  2. Rather than searching for edges, we may wish to search for paths — which corresponds to passing from a relation to its preorder reflection. We will refer to this distinction as a mode.

Forester supports both polarities and modes for relational queries via the following built-in constants:

  1. and denote the two polarities.
  2. and represent the two modes.
2024620https://www.forester-notes.org/00WY/00WY/00WY/The syntax of a relational query

A relational query takes the following form:

In the above, mode and polarity must evaluate to mode and polarity constants as in ; relation must evaluate to a relation symbol as in .

2024620https://www.forester-notes.org/00X0/00X0/00X0/Expressing built-in queriesExample

The built-in basic queries can be expressed in terms of in the following way:

2024620https://www.forester-notes.org/00X2/00X2/00X2/Querying the (back)links and context a given treeExample

Both the backlinks and (forward) links of a given tree can be computed using a query to the relation, and the context (immediate parents) of a given tree can be obatined from the relation:

2024620https://www.forester-notes.org/00X4/00X4/00X4/Querying a coslice of the transclusion preorderExample

We can also write a query to compute the set of trees underneath a given tree in the transclusion preorder (including the original tree) — in other words, the coslice.

2024620https://www.forester-notes.org/00X1/00X1/00X1/Unions and intersections of families of queries

A further primitive query-former is the union or intersection of a certain family of queries indexed in the results of a fixed query. These are written as follows:

In the above, q is a query expression and qfam is a that takes an address and returns a query expression. There are a couple built-in instantiations of and for the specific case where qfam is a family of relational queries; for example:

is equivalent to the following more verbose code:

2024620https://www.forester-notes.org/00X3/00X3/00X3/Querying the bibliography of a given treeExample

We can define a macro to compute the bibliography of a given tree, making use of from .

The above code first accumulates all the outgoing links from the given tree and any of its children, and then restricts (by intersection) to those with taxon reference.

2024620https://www.forester-notes.org/00X5/00X5/00X5/Querying all hereditary contributors to a treeExample

We can use the union of families of relational queries to compute the set of (proper) to a given tree. This is slightly subtle, because if a bibliographic tree is transcluded, we do not want its contributors to be included.

In the future, the support for query-indexed families of queries might be generalised to allow arbitrary queries in the components rather than only relational ones. The current version of the feature should be viewed as somewhat provisional.

2024620https://www.forester-notes.org/00WT/00WT/00WT/Queries are experimentalWarning

It is strongly recommended that inexperienced users of Forester continue to limit their usage of queries until the feature has reached a stable interface.

2024620https://www.forester-notes.org/00WL/00WL/00WL/Intermediate representation of the XML format

Forester’s primary output format is XML, rendered live in the browser to HTML using an XSLT stylesheet. Although this will continue to be the main output format, together with as well as our friends from the Topos Institute I am hoping to explore richer interfaces for that could transcend the limitations of static HTML output.

In order to support multiple backends without creating a log of code churn, I have created an OCaml abstraction of the XML format that will serve as a “source of truth” for Forester’s output — which can be serialised directly to XML, or rendered in a different way (e.g. as HTML or emitted by a hypermedia server).

With this change, I would expect Forester’s XML format to begin to change less and less over time, perhaps culminating in a versioned schema. I do not, however, guarantee that I will not make breaking changes to the format going forward.

2024620https://www.forester-notes.org/00WM/00WM/00WM/Generalised backmatter

Currently, the backmatter of a tree is not customisable; although the default backmatter sections are useful for most trees, it is likely that some of the sections are less relevant at times, and that other kinds of queries would be useful to be able to include on a tree-by-tree basis.

In order to facilitate such a feature in the future, this release changes the representation of backmatter to support arbitrary content and queries. This is a breaking change to the XML format: the <backmatter> element now contains arbitrary <tree> elements that encode the backmatter sections. By virtue of the , all default backmatter sections are computed from queries.

2024620https://www.forester-notes.org/00WN/00WN/00WN/HTML figures and captions; embedded TeX

This release adds figure and figcaption primitives that are interpreted by the XSLT stylesheet as HTML’s <figure> and <figcaption> elements.

The stylesheet no longer emits the images corresponding to embedded inside a <center> tag, as this is deprecated in HTML. Users are encouraged to wrap Forester’s tex primitive in a macro that embeds a diagram in a figure. For example, the following code comes from my own macro preamble:

2024620https://www.forester-notes.org/00ZF/00ZF/00ZF/Performance improvements in graph analysis

The has been replaced with (at the cost of space). Computing the transclusion preorder (or, more generally, the reflexive-transitive closure of relations) is orders of magnitude faster; ultimately compiles in twice the speed.

2024615https://www.forester-notes.org/00S9/00S9/00S9/Forester 4.1Release

Special thanks to , , and for their contributions to this release.

2024615https://www.forester-notes.org/00U0/00U0/00U0/New forester init command

To make it easier to set up a new forest, we have added a forester init command; when you run this command in an empty directory, it will initialise a git repository with a submodule for the pinned to the correct release, and a .

2024615https://www.forester-notes.org/00WA/00WA/00WA/Rendering only a subset of the forest

A new option has been added to the forester build command to render only certain trees. For example, the following command will render only the trees at addresses xxx-MMMM and yyy-NNNN:

forester build forest.toml --render-only=xxx-MMMM,yyy-NNNN

Note that in order to maintain a correct graph analysis, the entire forest will nonetheless be evaluated. As rendering is the slowest part of the process, however, this option can still save a lot of time. In the future it could be useful to have a more sophisticated option that renders (e.g.) all children of a given tree, etc.

2024615https://www.forester-notes.org/00SP/00SP/00SP/Changed behaviour of queries

Forester’s has been simplified somewhat. Previously, the results of a query would be gathered and, if non-empty, placed underneath an anonymous subtree (whose title could be modified using ).

In light of the introduced in , the behaviour of queries has been simplified: the results of a query are simply transcluded directly without being enclosed in a subtree.

Although the new behaviour is simpler, it is no longer possible to have a query subtree that is hidden when it returns no results. Users should treat the querying feature as highly provisional, and subject to change and even potential removal.

2024615https://www.forester-notes.org/00SQ/00SQ/00SQ/Addresses for anonymous trees

Previously, a subtree could be emitted without any address; this greatly complicated the logic of the graph analysis, , and other things. Now, emitting an anonymous subtree generates a fresh address in a separate namespace; as a result, these trees get rendered to their own XML file. Naturally, an anonymous subtree cannot be linked to or transcluded, but it can now participate properly in the graph analysis.

2024615https://www.forester-notes.org/00SA/00SA/00SA/Incremental parsing

Menhir’s incremental parsing API is adopted in order to make the parser more resiliant to syntax errors. The goal is to support language server protocol diagnostics in a future release.

2024615https://www.forester-notes.org/00WG/00WG/00WG/Dependency audit

In recent releases, Forester has become increasingly dependent on various system packages (including openssl) via transitive dependencies. This has caused a great deal of build breakage for both our developers and users, so we decided to remove all but the most critical dependencies to avoid losing control of things. Experimental tools that rely on more system dependencies that are likely to cause build breakage can be created, but only outside the main forester package.

202445https://www.forester-notes.org/00RF/00RF/00RF/Forester 4.0Release

This is a major release of Forester that changes both the command line interface and the XML format, introducing many new features under the hood as well as quality-of-life improvements (including a 2X rendering speedup).

202445https://www.forester-notes.org/00RG/00RG/00RG/Forest configuration via TOML

Previously, the locations of trees as well as assets and theme directories were configured by means of command line arguments. As this has become a bit unwieldy, especially as many users have multiple projections of their forest, we have consolidated these options under a simple configuration file whose location is the first argument to most forester commands. Here is an example configuration file:

It is common to have multiple configurations. For example, if you have “public” trees located in a specific directory, you can have an additional configuration:

Both the assets and theme keys are displayed above with their default values, so they could be omitted. There is an additional stylesheet key that can be used to set the name of the XSL stylesheet used (the default is forest.xsl).

To build the forest, simply run: forester build forest.toml; other options can be used (see forester build --help), such as forester build forest.toml --dev.

202445https://www.forester-notes.org/00RH/00RH/00RH/Enhanced XML support202445https://www.forester-notes.org/00RI/00RI/00RI/An XML namespace for Forester

The XML format is now governed by the with URI ; as is typical of XML grammars, element names are namespaced whereas attribute names lie in no namespace. Forester emits XML with element names qualified by a prefix bound to this namespace. This change breaks existing XSL stylesheets, so you must upgrade your theme.

The new version of the contains rules to allow anything in either the http://www.w3.org/1999/xhtml or http://www.w3.org/1998/Math/MathML namespaces to be copied through to the output HTML (with namespace prefixes stripped). In combination with , this allows you to write HTML and MathML in Forester directly.

Please note that although Forester now has a namespace, it does not has a schema. Any direct integration with the XML format (e.g. by custom themes) is not supported and should be done at your own risk — several recent releases have illustrated the continued rapid evolution of the XML format with many breaking changes. I expect this evolution will continue for some time.

202445https://www.forester-notes.org/00RJ/00RJ/00RJ/Emitting XML and resolving namespaces

Since , a limited form of custom XML output by means of the command. This support was, however, somewhat unwieldy: no built-in accounting for XML namespaces was included, so correct usage of was prohibitively difficult because of the need for xmlns attributes on essentially every node.

202445https://www.forester-notes.org/00RK/00RK/00RK/XML namespace declarationFeature

Forester treats XML namespace prefixes in a way that respects -equivalence: in other words, any prefix mentioned must be bound, and it is possible for two different textually identical namespace prefixes to denote different namespaces depending on their scope. This makes it possible to compose code that emits XML without coordinating namespace prefixes, which I have found to be a major impediment to the correct use of XML for non-trivial work.

An XML namespace prefix is bound by a declaration like the following:

This declaration has the same scoping rules as .

202445https://www.forester-notes.org/00RM/00RM/00RM/XML literalsFeature

The old syntax has been replaced with a new convenient notation for XML literals that supports . The grammar of XML literals is summarised below:

[qname]{expr}...{expr}]]>

For example, if the prefix html: is bound to as in , the expression [class]{highlight}{some highlighted text}]]> will emit the following XML:

some highlighted text ]]>

In reality, the appropriate @xmlns:html attribute will be attached only where it is needed in keeping with the hierarchical structure of the XML tree. Note that when the same textual prefix is bound to two different namespaces, one of them will be automatically -renamed so as to result in correct XML with the intended semantics.

202445https://www.forester-notes.org/00RL/00RL/00RL/A worked exampleExample

The following code causes MathML to be emitted (in the correct namespace), combining and :

[display]{block}{ \{ \{ \{x} \{2} } \{+} \{x} } }]]>

The above displays as follows:

x 2 + x 202439https://www.forester-notes.org/00HY/00HY/00HY/Forester 3.1Release

To use this release, you will need to and you may also need to edit your forest itself (please write to the if you encounter difficulties). Remember that this includes not only the XSLT stylesheet, but also the CSS stylesheet and the JavaScripts.

The is now : if you are using , you can confidently use the 3.1.0 tag. The head of the main branch of the theme may at times include changes that are compatible with only the main branch of Forester itself.

202439202428https://www.forester-notes.org/00O3/00O3/00O3/Designated parentsFeature

In keeping with the , hierarchical structure in Forester has always been introduced by transclusion of independent trees; in this model, a has no canonical parent because . Experience using Forester suggests that this is the right idea the vast majority of the time, but use-cases have emerged that challenge these assumptions: there do indeed arise natural subtrees that are exceedingly awkward to “decontextualise”.

For example, the features described in a changelog (such as the present one) are awkward to decontextualise because they refer to knowledge that is temporary in its applicability. Likewise, the subtrees of one’s daily notes or journal are likely to be fleeting in nature and may have little insight that can be decontextualised — and in spite of this, these notes remain important for restoring mental context on long-running projects, etc.

For these reasons, I have (reluctantly) added a new frontmatter directive , which designates the tree at address xxx-NNNN as “the” context-providing parent of the current tree. This feature is experimental and under-theorised; it should be used sparingly.

When a given tree appears transcluded within its “designated” parent, it will be shown with the title that has been specified; however, when the tree appears outside of this context, its title will appear with the parent’s title prepended to it: “parent › child”.

202439202428https://www.forester-notes.org/00O4/00O4/00O4/Inline subtreesFeature

Previously, there was a one-to-one mapping between trees and files. After discussion on the mailing list with , I have added support for defining new subtrees inline to an existing tree. The current behavior is that an inline subtree has its automatically assigned; author and date metadata is inherited (this may change in the future).

To emit (and transclude) a subtree at address xxx-NNNN, you can write the following:

It is also possible to have an anonymous inline subtree, one that has no address of its own. In this case, write:

An anonymous inline subtree will, naturally, not have its own page emitted and cannot be linked to. In the graph analysis (for computing backlinks, etc.), an anonymous inline subtree will be identified with its parent.

Inline subtrees should not be overrused; but they may make the process of daily journalling and other activities more lightweight.

One consequence of breaking the one-to-one relationship between trees and files is that commands like forester new need to actually fully evaluate the forest, whereas in the past it was possible to merely scan the file system. This is a trade-off: if your forest contains fatal errors, you cannot use forester new or related querying commands. You should never leave your forest with fatal errors long enough to notice this.

This feature is experimental and its behaviour may change. Use it at your own risk.

2024112https://www.forester-notes.org/00HZ/00HZ/00HZ/cleveref-style referencingFeature

You can now write to produce a link to the tree at address xxx-NNNN labeled by its taxon. After the taxon, the textual format and destination of the link depends on whether xxx-NNNN lies in the present context. If the linked tree is present, then link will refer to the first transclusion of the tree into the present context; otherwise, the link will refer to the tree’s stable address. For example:

  1. A reference to this very tree: .
  2. A reference to a parent of this tree: .
  3. A reference to a cousin of this tree: .

The behavior of references within one tree naturally depends on the transclusion context in which you are viewing that tree. It is instructive to examine the examples above by viewing this tree from its or on its .

202439https://www.forester-notes.org/00O5/00O5/00O5/New forester query commandFeature

has implemented a new forester query command that may be useful for creating external editor tooling; currently it is possible to query for lists of all prefixes (the xxx in xxx-NNNN), tags, and taxa. Please run forester query --help for more information.

202439https://www.forester-notes.org/00O6/00O6/00O6/Random vs. sequential generation of addressesFeature

By default, Forester generates tree addresses sequentially within a given prefix; has implemented forester new --random, which instead generates random tree identifiers. Although this option is not recommended for most users, it can be used to mitigate the problem of multiple collaborators creating trees within the same prefix. Please run forester new --help for more information.

202439https://www.forester-notes.org/00Q6/00Q6/00Q6/Manual numbering for digital editionsFeature

Numbering of trees in Forester is by default relative and determined by position in the current view. When creating translations or digital editions, the numbering from the source material is what is important. For this reason, I have added a new frontmatter directive to impose a manual numbering on a given tree.

This numbering will be used in the table of contents, headings, and by .

202439https://www.forester-notes.org/00OH/00OH/00OH/Improvements to verbatim lexerChange

Forester includes a special lexing mode for quoting source code, delimited by startverb and stopverb. This mode was never implemented properly and so it did not work well in practice; for example, previously the line comment lexer could be activated via from within vebatim mode, which made it very difficult to quote code that has comments. The lexer has been revamped and the behavior of verbatim mode is a bit different from before.

Between the delimiters (startverb,stopverb), text now is taken precisely as-written, except that newlines are stripped from the beginning and the end of the quoted text. Previously, the strange behavior of comments noted above could be used to manually avoid an initial line break from appearing in the quoted text. So in a prior version of Forester, you may have written something like this:

Now, you should instead write:

2024125https://www.forester-notes.org/00LR/00LR/00LR/Removal of and changes to Change

In , the frontmatter command was added in order to accumulate a list of packages that are then used automatically when rendering . From , this feature is removed and to embed code, you must explicitly specify the preamble as follows:

Of course, within a single project (or even ), you may have a relatively stable set of packages that you need. In this case, it is recommended to wrap in your own macro:

An even more sophisticated approach might use fluid bindings to allow local customisation of packages in use:

202439202428https://www.forester-notes.org/00O2/00O2/00O2/Removal of undocumented outputChange

Previously, Forester would emit .tex files for each of your trees in the latex directory. This feature has been removed, as can be generated more reliably using XSLT. Please see the repository for an example stylesheet.

2024125https://www.forester-notes.org/00LS/00LS/00LS/Breaking changes to the XML formatChange

makes some breaking changes to the XML format; if you are using the , just update it to the latest version to migrate your forest. The main change is that “trails” for subtrees (like “1.4.2”) are no longer computed ahead of time and stored in XML, but are instead computed on the fly in the XSLT stylesheet using <xsl:number>.

A further change is that embedded is no longer emitted using the <img> element: instead, there is a new <embedded-tex> element with an attribute @hash containing the name (without extension) of the appropriate SVG file, and with children elements <embedded-tex-preamble> and <embedded-tex-body>. These are meant to facilitate generation of documents from Forester’s XML output in combination with the filecontents environment.

2023113https://www.forester-notes.org/00CW/00CW/00CW/Forester 3.0Release

This is a major breaking release; some surgery may be required on existing . Thanks to Favonia, , , and for their contributions to this release. Thanks also to Adrien Guatto for bug reports.

2023113https://www.forester-notes.org/00CX/00CX/00CX/Proper diagnostics with source locationsFeature

adds proper diagnostics and error messages, via the excellent library maintained by . When something goes wrong in your forest, the terminal output should expain what happened while displaying the precise location in your source file.

20231119https://www.forester-notes.org/00EY/00EY/00EY/Experimental support for objectsFeature

To facilitate the development of extensible macro libraries for diagramming and other tasks, introduces experimental support for objects — which should be thought of as combination of records/structs, closures, and general recursion. An object is created like so:

The variable self is explicitly bound, and can be bound to any name you like. Methods currently are not allowed to take any arguments, but this may change in the future. A primitive form of inheritance is supported, using :

The support for objects in is extremely experimental and preliminary: users are discouraged from relying on it.

20231120https://www.forester-notes.org/00F0/00F0/00F0/Improvements to date handlingFeature

improves support for journaling with date-specific trees. When a tree is dated YYYY-MM-DD and there exists a tree at address YYYY-MM-DD, the date field will be hyperlinked to the latter. This involves changes to both the executable and the XSL stylesheet of the . The purpose of this change is to better facilitate daily notes / journaling.

Additionally, Forester’s data model now allows multiple dates to be assigned to a single tree simultaneously.

20231122https://www.forester-notes.org/00FI/00FI/00FI/Nix supportFeature

comes with a for easy integration with nix-based systems. Users of nix can try forester without installing the ocaml toolchain by running nix run sourcehut:~jonsterling/ocaml-forester.

To create a development shell with forester and LaTeX dependencies, create a file named flake.nix with the following content:

and run nix develop.

The now ships with a flake and an . If you created your forest using this template and would like to use direnv, simply copy flake.nix and .envrc to your forest base directory.

2023122https://www.forester-notes.org/00G7/00G7/00G7/Lightweight templating in forester newFeature

adds a new --template option to the forester new command. Running forester new --template xxx-0001 will create a new tree with the contents of the existing tree xxx-0001.

20231213https://www.forester-notes.org/00GG/00GG/00GG/Support for randomised tree identifiers in forester newFeature

The forester new has a new --random flag; when activated, the new tree will be allocated with a randomised unused tree identifier rather than the usual sequential tree identifier. This can be useful for projects that have multiple collaborators, although in this case, users are generally advised to claim their own namespaces.

20231215https://www.forester-notes.org/00GL/00GL/00GL/Custom static assets directoriesFeature

A new --assets-dirs option has been added to the forester build command, which can be used to supply multiple directories containing static assets that should be copied into the forest. By default, the option is set to assets.

2023113https://www.forester-notes.org/00CY/00CY/00CY/Breaking changes

introduces a number of breaking changes to the source language in order to facilitate maintainability, diagnostic support, and extensibility of both the Forester tool and your individual .

2023113https://www.forester-notes.org/00CZ/00CZ/00CZ/Fall-through of undefined identifiersChange

The fall-through for undefined identifiers in XML mode is removed in : previously when an identifier was undefined, it was possible to write and have this be rendered in XML to body]]>.

This behavior has been removed, but you can nonetheless write to achieve the same. For content that is being rendered by either LaTeX or KaTeX, simple fallthrough (naturally without attributes or arguments) is supported; therefore will render to .

2023113https://www.forester-notes.org/00D0/00D0/00D0/Primitive formatting commandsChange

As a consequence of the , several new primitives have been added to the source language, including , , , , , , , and .

You can add further commands to your primitives using a combination of , , and .

2023927https://www.forester-notes.org/009Q/009Q/009Q/Forester 2.5Release

Thanks to and Vikraman Choudhury for their suggestions and bug reports on the .

  • A new command has been added, following a suggestion of Vikraman Choudhury; this can be used to control the behavior of macros, depending on whether they are being rendered by or by the browser. For example, will become foo when passed to the tool, but will be reated as bar when rendering for the browser.
  • A new has been added to the , which can be used to locally change the taxon of a transcluded tree. Thanks to for implementing this.
  • In order to support more modular development of , a new theme directory is expected to contain all the XSL, CSS, font, etc. assets that pertain to the presentation of your ; the assets directory is meant to store things like images, PDFs, etc. that pertain to the content of your . The simplest way to take advantage of this new feature is to bind your theme directory to a pointing to the repository. Your existing will still work fine for now even if you do not migrate to the new directory structure. I’m grateful to for conversations that motivated me to make this change.
2023922https://www.forester-notes.org/007M/007M/007M/Forester 2.4Release

Thanks to and for their suggestions which have influenced this release. In addition to the major changes detailed below, there are a few minor improvements:

  • The evaluator for Markdown-style links now allows destination to contain expressions other than text, so long as they evaluate to text.
  • The introduced in has been amended so that attributes appear in square brackets, e.g.
  • The forester new command now has a --dest option, which is used to specify the directory in which to deposit the new tree (independently of the --dir option, which specifies the directory to scan for existing trees). Please run forester new --help for details.
2023819https://www.forester-notes.org/007Y/007Y/007Y/Rudimentary support for RSS feedsFeature

Each tree generates an RSS feed containing its immediate children; if a tree is located at xxx-NNNN.xml, then the corresponding RSS file will be located at xxx-NNNN.rss.xml. Currently no content is placed in the RSS feed items, but in the future we may add some best-effort plain text linearization of the first paragraph of the tree or something. .

2023913https://www.forester-notes.org/008Z/008Z/008Z/Wikilinks supportFeature

This release adds support for “wikilinks” in the form ; this will be rendered as a link whose title is given by the title of the tree at address destination. Users are discouraged from using wikilinks heavily, as it is better for your mind to “work a link into a sentence” naturally; but this can be very useful for linking to or daily notes.

2023819https://www.forester-notes.org/007X/007X/007X/Breaking changes to XML formatChange

This release contains several breaking changes to the XML format that can break custom XSLT stylesheets.

  1. Taxa used to be attributes of tree, but they are now child elements of tree/frontmatter. Therefore, what previously was written as <tree taxon="lemma"> <frontmatter> <!-- ... --> </frontmatter> <!-- ... --> </tree> is now written as follows: <tree> <frontmatter> <taxon>lemma</taxon> <!-- ... --> </frontmatter> <!-- ... --> </tree>
  2. Dates are now stored in machine-readable format. For example, what used to be written <date>August 16, 2023</date> is now written as follows:

    <date> <year>2023</year> <month>8</month> <day>16</day> </date>

    It is the responsibility of the XSLT stylesheet to format dates appropriately. Thanks to for suggesting this change.

  3. All identifiers in the XML format have been regularized to use snake-case; for instance, sourcePath is now source-path and show_heading is now show-heading.
2023814https://www.forester-notes.org/006Z/006Z/006Z/Forester 2.3Release

, , and contributed code to this major release. Thanks also to for that made it into this release.

This release adds some new features to the command line interface. The original behavior of the forester command is now obtained by calling forester build. Please browse forester --help for more information.

2023814https://www.forester-notes.org/0070/0070/0070/Create new trees from the command lineFeature

A new command has been added in to simplify the creation of new trees with the correct base-36 identifier. If your personal namespace prefix is xxx, you may run the following command to create a new tree in the trees directory:

If the last tree in this directory was xxx-0039, a new tree will be generated at xxx-003A. The new tree will be populated with a correct declaration.

2023814https://www.forester-notes.org/0071/0071/0071/Tree title completion for tool supportFeature

A new forester complete command has been added to search for trees by their title; the purpose of this command is to facilitate external tool support, such as this . Please browse forester complete --help for more information about this command.

Current limitations: the command is currently case sensitive and only searches prefixes; in the future, it would be desirable to support more flexible .

Thanks to for implementing this feature.

2023814https://www.forester-notes.org/0072/0072/0072/Rudimentary support for XML attributesFeature

When Forester encounters an undefined function, it automatically passes through to the XML output. For instance, if the function is not defined, then the Forester code will render to the XML code hello]]>. The extends this fall-through behavior to support XML attributes.

In particular, if you write , Forester will render the following XML code:

hello ]]>

Thanks to for suggesting this feature, and welcome to the !.

In addition to the major changes above, the following minor changes are included in this release:

  1. A title attribute attribute has been added to the XML output of internal links, in order to facilitate tooltips and other affordances in rendered forests. Thanks to for implementing this feature.
  2. Subdirectories of input directories will now be traversed automatically; note that the tree address model remains flat, and subdirectories are present only for convenience.
  3. Added a nicer command line interface with --help documentation.
  4. I have migrated much of the system code to use the experimental for improved portability.
  5. The example forest has been removed from the main repository, and moved into a separate .
2023717https://www.forester-notes.org/005V/005V/005V/Forester 2.2Release2023720https://www.forester-notes.org/0067/0067/0067/Flexible transclusion optionsFeature

This release replaces the old , commands with a more flexible transclusion configuration mechanism using the support for fluid binding introduced in . A basic transclusion with the default options is done in the same way as before:

The behavior of transclusion is, however, configurable by several globally allocated fluid bindings as depicted in the .

https://www.forester-notes.org/0069/0069/0069/Transclusion optionsTable Fluid Binding Default Meaning
title (none) To override the tree's title during transclusion.
toc true Show the tree in the table of contents.
expanded true Whether the tree is expanded or not.
heading true If set to false, the tree's contents will be inlined.
metadata false Show in a tree's heading.
numbered true Whether the tree is displayed with a number or not, transitively on subtrees.

It is possible to achieve undesirable results by combining these options in undesirable ways; it is up to you to use them correctly.

2023720https://www.forester-notes.org/0068/0068/0068/A configured transclusionExample

The following code produces an unnumbered transclusion that nonetheless appears in the table of context, with an overridden title.

2023720https://www.forester-notes.org/0066/0066/0066/QueriesFeature

This release adds support for generating subsections from transclusions obtained by a query the forest; this can be used to produce topical bibliographies.

2023720https://www.forester-notes.org/006A/006A/006A/A conjunctive query nodeExample

The following code will generate a subsection containing my “featured talks” as collapsed subtrees:

Under the hood, a query node is an “anonymous transclusion” and can therefore be .

A minor change is that the assets directly does not need to be flat anymore.

As always, existing forests can be upgraded by copying forest.xsl and style.css into their assets directory.

202361https://www.forester-notes.org/005O/005O/005O/Forester 2.1Release

This is a major release that breaks compatibility of the XML format for trees; existing forests can be upgraded by copying forest.xsl and style.css into their assets directory.

  • Development mode and edit button. A --dev option has been added to the forester executable; when this option is enabled, absolute paths will be embedded into tree metadata and an edit button is added to the top of the command palette.
  • Your own TeX preamble. There is no longer a hardcoded LaTeX preamble used for compiling graphics; instead, you can store your own .sty files in the assets directory and import them locally in a specific tree using the new frontmatter command.
  • Fluid binding constructs. Macros in the Forester language have functional semantics, which means that they capture their environment at the time of definition; this differs from the stacks of dynamic scopes that are familiar from the TeX model. This release adds support for fluid bindings via in order to simulate this behavior of TeX where desired; a scope can be delimited using . This can be useful for providing flexible configurations to macros.
  • Tables of contents. Tables of contents are now rendered by the default forest.xsl stylesheet.
  • LaTeX output. LaTeX output with full bibliography support is now available; this feature is still experimental, and may not work properly with some constructs (e.g. code blocks, etc.).
  • Name resolution. The behavior of name resolution was highly erratic in the prior release, and this has been corrected by adopting the library. This change may break trees that depended on the prior behavior.
  • Namespaces and hierarchical identifiers. Identifiers in the Forester language are now hierarchical, with components delimited by /. Namespaces can be created using , outside which all exported identifiers are prefixed by foo/. Namespaces can be opened into the current scope using .
Contributions
Read Entire Article