Jon Sterling https://www.forester-notes.org/jonmsterling/ 2025-03-25T13:44:56Z Forester Blog https://www.forester-notes.org/30FM/ Towards Forester 5.0 II: a design for canonical URLs 2025-03-25T13:44:56Z 2025-03-25T13:44:56Z Jon Sterling https://www.forester-notes.org/jonmsterling/ https://www.forester-notes.org/JVIT/

One of the goals of Forester 5.0 is lightweight federation—the ability to have two forests participate in the same graph and therefore provide backlinks, etc. In a previous post (Towards Forester 5.0: a design for global identity), 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.

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 earlier this month 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 Forester 5.0 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.

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.

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 Wayback machine rewrites links in its snapshots. That can be handled outside of Forester.

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.

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.

Towards Forester 5.0: a design for global identity 2025-03-08T12:17:14Z 2025-03-08T12:17:14Z Jon Sterling https://www.forester-notes.org/jonmsterling/ https://www.forester-notes.org/OYOJ/

As we move closer to Forester 5.0, which introduces rudimentary federation capabilities, we must address new problems that did not arise in the days when no two forests 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 more Web-centric approaches to identity as they emerge.

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 § OYOR/.

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.

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 (The DOI Foundation); this applies to both traditional publishers and eprint servers like the arXiv. Services like Zenodo 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.

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.

General-purpose decentralised identification via DIDs

When reading about the paper of Klepmann et al. outlining Bluesky’s AT Protocol, I learned of Decentralised Identifiers (DIDs). 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.

W3C’s did:web method

W3C have specified the 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 same disadvantage of informal decentralised identification which we have discussed.

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 Klepmann et al.:

  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 Bluesky’s own). 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).

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 DID 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 URL non-“standard”, 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.

A plan for global identity in Forester

Building on my analysis, 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.

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 mailing list with your feedback.

Build your own Stacks Project in 10 minutes 2023-05-14T00:00:00Z 2024-04-25T00:00:00Z Jon Sterling https://www.forester-notes.org/jonmsterling/ https://www.forester-notes.org/jms-0052/

The Stacks project 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. (Tags explained, The Stacks Project).

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 Stacks project and Kerodon use a cluster of software called Gerby, but bitrot has set in and it is no longer possible to build its dependencies on a modern environment without significant difficulty, raising questions of longevity.

Moreover, Gerby’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 nLab’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.

Introducing Forester: a tool for scientific thought

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

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

Forester combines associative and hierarchical networks of evergreen notes (called “trees”) into hypertext sites called “forests”.

Forests and trees of evergreen notes

A forest of evergreen notes (or a forest for short) is loosely defined to be a collection of evergreen notes in which multiple hierarchical structures 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 Stacks Project.

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

Preparing to run the Forester software

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

System requirements of Forester

A unix-based system

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

A working OCaml 5 installation

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

A working \LaTeX installation

If you intend to embed \LaTeX -rendered diagrams in your forest, you will need to have a working installation of \LaTeX installed, such as TeX Live. If all your mathematical expressions are supported by \KaTeX , this is not necessary.

The git distributed version control system

It is best practice to maintain your forest inside of distributed version control. 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 forest, or to create “branches” in which you prepare trees that are not yet ready to be integrated into the forest.

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

Installing the Forester software

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

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

Setting up your forest from the template

Now that you have installed the Forester software, it is time to set up your forest. Forester provides a simple command to initialise a fresh forest 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 Forester to initialise a forest.

forester init

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

Tree addresses in a forest

A tree in Forester is usually associated to an address of the form xxx-NNNN where xxx is your chosen “namespace” (most likely your initials) and NNNN is a four-digit base-36 number. The purpose of the namespace and the base-36 code is to uniquely identify a tree, not only within your forest but across all forests. A tree with address xxx-NNNN is stored in a file named xxx-NNNN.tree (unless it is emitted from inside another tree by means of the inline subtrees feature).

Note that the format of tree addresses is purely a matter of convention, and is not forced by the Forester tool. Users are free to use their own format 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.

Building and viewing your forest for the first time

To build your forest, you can run the following command of Forester'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 forest locally, and should not be used when building the forest to be uploaded to your public web host.

Forester renders each tree to an XML document

Forester renders your forest 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 forest template comes equipped with a built-in XSLT stylesheet (theme/default.xsl) which is used to instruct web browsers how to render your forest into a pleasing and readable format.

Serving and viewing your forest from a local web server

The recommended and most secure way to view your forest while editing it is to serve it from a local web server. To do this, first ensure that you have Python 3 correctly installed. Then run the following command from the root directory of your forest:

python3 -m http.server 1313 -d output

While this command is running, you will be able to access your forest by navigating to localhost:1313/index.xml in your preferred web browser.

In the future, Forester may be able to run its own local server to avoid the dependency on external tools like Python.

Viewing your forest locally without a local web server

It is also possible to open the generated file output/index.xml directly in your web browser. Unfortunately, modern web browsers by default prevent the use of XSLT stylesheets on the local file system for security reasons. Because Forester's output format is XML, the output cannot be viewed directly in your web browser without disabling this security feature (at your own risk). Users who do not understand the risks involved should turn back and use a local web server instead, which is more secure; if you understand and are willing to accept the risks, you may proceed as follows depending on your browser.

Configuring Firefox for viewing a local forest

To configure Firefox for viewing your local forest, navigate to about:config in your address bar.

  1. Firefox will present a page warning you to “Proceed with Caution”: you must “Accept the Risk and Continue”.
  2. In the “Search preference name” box, search for security.fileuri.strict_origin_policy.
  3. Most likely, the security.fileuri.strict_origin_policy will appear set to true. Double click on the word true to toggle it to false.
Configuring Safari for viewing a local forest

To configure Safari for viewing your local forest, you must activate the Develop menu and then toggle one setting.

  1. Open Safari's settings window.
  2. In the Advanced tab, check the “Show Develop menu in menu bar” checkbox at the bottom.
  3. Open the Develop menu in the menubar, and select “Disable Local File Restrictions”.

Creating your personal biographical tree

The first tree that you should create is a biographical tree to represent your own identity; ultimately you will link to this tree when you set the authors of other trees that you create later on. Although most trees will be addressed by identifiers of the form xxx-NNNN, it is convenient to simply use a person’s full name to address a biographical tree. My own biographical tree 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 tree to my name.
  2. The declaration informs Forester that the tree is biographical. Not ever tree needs to have a taxon; common taxa include person, theorem, definition, lemma, blog, etc. You are free to use whatever you want, but some taxa are treated specially by Forester.
  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 trees are rendered; it is recommended that you use a text editor with good support for soft-wrapping, like Visual Studio Code.

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

Creating a new tree using forester new

Creating a new tree in your forest is as simple as adding a .tree file to the trees folder. Because it is hard to manually choose the next incremental tree address, Forester provides a command to do this automatically. If your chosen namespace prefix is xxx, then you should use the following command in your shell to create a new tree:

forester new forest.toml --dest=trees --prefix=xxx

In return, Forester should output the location of the new tree, e.g. trees/xxx-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:

Most trees should have a annotation; this date is meant to be the date of the tree's creation. You should proceed by adding further metadata: the title and the author; for the latter, you will use the address of your personal biographical tree.

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

Now you can begin to populate the tree with its content, written in the Forester markup language. Think carefully about keeping each tree relatively independent and atomic.

Bottom-up hierarchy via transclusion

You may be used to writing \LaTeX 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. Forests work in the opposite way, from the bottom up: you start by writing independent, atomic notes/trees and then only later start to (sparingly) assemble these into a hierarchy in order to reify the emerging structure.

Forester’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 tree into the current tree as a subsection by adding the following code:

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

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 Forester’s transclusion model is that a given tree has no canonical “geographic” location in the forest. One tree can appear as a child of many other trees, which allows the same content to be incorporated into different textual and intellectual narratives.

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.

The Forester markup language

A tree in Forester is a single file written in a markup language designed specifically for scientific writing with bottom-up hierarchy via transclusion. A tree has two components: the frontmatter and the mainmatter.

Forester markup: frontmatter

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

Declaration Meaning
sets the title of the tree; can contain mainmatter markup
sets the author of the tree to be the biographical tree at address name
sets the creation date of the tree
sets the taxon of the tree; example taxa include lemma, theorem, person, reference; the latter two taxa are treated specially by Forester for tracking biographical and bibliographical trees respectively
defines and exports from the current tree 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 xxx-NNNN into scope
brings the functions exported by the tree xxx-NNNN into scope, and exports them from the current tree

Forester markup: mainmatter

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

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 \KaTeX ; note that math mode is idempotent in Forester
typesets the content in (display) math mode using \KaTeX
transcludes the tree at address xxx-NNNN as a subsection
formats the text title as a hyperlink to address address; if address is the address of a tree, 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 \LaTeX 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.

An complete worked example tree in Forester

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

The code above results in the following tree:

Creation of (co)limits

Let {\mathcal {C}}\xrightarrow {U}{\mathcal {D}} be a functor and let \mathcal {I} be a category. The functor U is said to create (co)limits of \mathcal {I}-figures when for any diagram {\mathcal {I}}\xrightarrow {C_\bullet }{\mathcal {C}} such that \mathcal {I}\xrightarrow {C_\bullet }\mathcal {C}\xrightarrow {F}\mathcal {D} has a (co)limit, then C_\bullet has a (co)limit that is both preserved and reflected by F.

Deploying your forest to a web host

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

  1. First, make sure your forest is built using the earlier instructions.
  2. Then take the entire contents of your output directory and upload them to your preferred web host.

Let a hundred forests bloom!

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

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

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