vscode-tendr
is a vscode extension that transforms a collection of markdown files into a jungle gym for thought with an API for the mind. It's a personal knowledge management (PKM) system that's got [[wikirefs]]
, semantic trees, and graphs that you can visualize on screens, in headets, or map to embeddings!
🧑🌾 🚰 ✂️ Tend your 🎋 WikiBonsai digital garden from vscode.
Checkout one of the garden-beds for starter digital gardens.
The first and foremost reason to use vscode-tendr
is that each component has been modularized and released as a separate package. So by submitting issues or feature requests for this vscode extension, the changes and updates that result will percolate out to the other open source packages, thereby improving the open source PKM tool chain for everyone.
For example, if you want to use the same [[wikiref]]
syntax for your notes from this extension in a personal blog, you can use the markdown-it plugin with eleventy, or the remark plugin with astro, etc. Then, any bugs or features added to the wikiref syntax for vscode-tendr
will also be applied to the frameworks that power your blog.
For more details about the parent project, head to the WikiBonsai repo. Otherwise, keep scrolling!
- Config File
- Doctypes
- Markdown Syntax
- Semantic Tree
- Graph
- Workflows
- Treeviews
- VSCode Commands
- VSCode Configs
- Embeddings
- Index
There is a local config file to configure some aspects of your digital garden, such as what attr engine to use. Config file syncs with vscode extension configurations.
Supported file formats:
Defaults to configs.toml
-- here is a sample:
[garden]
title = "wikibonsai"
root = "i.bonsai"
attrs = "caml"
[doc]
[doc.kind]
[doc.kind.doc]
path = "/"
color = "#3e5c50"
[doc.kind.zombie]
emoji = "🧟"
color = "#959DA5"
[doc.kind.template]
path = "/template/"
prefix = "t."
emoji = "🧩"
color = "#F8F0E3"
attrs
determines which attr engine to use for file metadata.doc.kind
defines the doctype properties for the special WikiBonsaidockinds
.root
defines the root filename for the bonsai. It should be anindex
doctype.
WikiBonsai provides an optional type system for your markdown files. Types are fundamental in adding semantic information to the web and facilitates the beginning of semantic spatial mapping.
Doctype properties may be defined in the doctype declaration file. Supported file formats:
Defaults to t.doc.toml
-- which looks like:
[default]
path = "/"
color = "#3e5c50"
[index]
path = "/index/"
prefix = "i."
emoji = "🗄"
color = "#F0C61F"
# emoji = "🪵"
root = "bonsai" # index-specific property
[entry]
path = "/entry/"
emoji = "🏷"
color = "#31AF31"
# emoji = "🍃"
The following is an example
doctype that illustrates the possible properties:
# doctype resolution: path < attr < prefix
[example]
# 'path' defines the relative path in vault to what files should map to this doctype
path = "relative/path/to/docs/"
# 'attr' defines what attribute key should map to this doc type -- defaults to the name of this type entry which is 'example' here
attr = "example-key"
# 'prefix' defines what filename prefix may trigger this type (useful for cmd/ctrl+click to create new doc from template)
prefix = "prefix."
# 'suffix' to append to new doc (useful for appending unique ids)
suffix = "-suffix"
# name of the type's template (defaults to 't.<typename>')
template = "template-name"
# 'emoji' to apply in treeviews and list formats
emoji = "🤓"
# 'color' to apply in [[wikilinks]], graph nodes, and other color-coded identifiers
color = "#FFF"
attr
: Defines what:caml::attribute
key should map to this doc type -- defaults to the name of this type entry which is 'example' herecolor
: Color to apply to[[wikilinks]]
, graph nodes, and other color-coded identifiers.emoji
: Emoji to apply in treeviews and list formats.path
: Relative path within the vault directory, should map to this doc type (similar to jekyll).prefix
: Defines the filename prefix for this type. It is automatically generated upon file creation and allows for the creation of a particular doctype from a[[zombie-wikiref]]
if the prefix is included in the wikitext (ex: clicking on[[prefix.zombie-wikiref]]
will produce a new file of the doctype that has the given prefix "prefix.
"). Also supports some affix vars.suffix
: Defines the filename suffix for this type and gets automatically generated upon file creation. Also supports some affix vars.template
: Name of the type's template (defaults to 't.')
- Type resolution by precedence (similar to how jekyll collections works: by defining a
collections
directory with the ability to override it with thecollections
frontmatter var):- Filename prefix.
- Metadata (caml or yaml)
type
definition. - Directory location.
These variables can be used in prefix
and suffix
doctype properties:
:id
: Generate an id from nanoid.:date
: Generate the current date (format:YYYY-MM-DD
).:year
: Generate the current year (format:YYYY
).:month
: Generate the current month (format:MM
).:day
: Generate the current day (format:DD
).:hour
: Generate the current hour (format:HH
).:minute
: Generate the current minute (format:mm
).
The semantic tree/knowledge bonsai expects the following doctypes to exist:
index
: files with markdown-style list outlines of[[wikilinks]]
to (primarily)index
andentry
docs. These type of documents are used to build the trunk and branches of the bonsai.entry
: Wikipedia-style entries that build the leafs of the bonsai. Each one is meant to map to a particular sense of a word using wikipedia-style-(disambiguation-parens).
Doctypes are distinct from "dockinds
" -- or "kinds" of documents. DocKinds have very specific behaviors in WikiBonsai. The built-in kinds are doc
, media
, template
, and zombie
:
- Doc is the generic kind of document and will subsequently look for the correct doctype when a file is this kind of document.
- Media corresponds to file types (
.png
,.mp3
,.mp4
, etc.) that are render-able in![[wikiembeds]]
. - Templates are skeleton documents whose contents are pasted into new files of that particular doctype.
- Zombies are various entities that represent a document that does not exist.
[[WikiLinks]]
without a document or a node in the graph without a document are examples of zombie entities.
WikiBonsai adds [[wikirefs]]
, :caml::attributes
, #tags
, and optionally other markdown extensions for all your note-taking and semantic spatial mapping needs.
Also, don't forget to check against vscode's built-in markdown support.
Uses the wikirefs project.
- wikiattrs:
:attribute::[[wikiattr]]
- wikilinks:
[[wikilink]]
- wikiembeds:
![[wikiembed]]
See wikirefs-spec for full syntax specification.
Default metadata looks like this (which is overidable in the default
doc template):
let attrData: any = {
"id": "<a-nanoid-id>",
"ctime": "YYYY-MM-DD HH:MM +/-TZ",
"mtime": "YYYY-MM-DD HH:MM +/-TZ",
"vtime": "YYYY-MM-DD HH:MM +/-TZ",
"title": "unslugified file name",
"tldr": "\"\"",
};
The following file metadata / attribute formats are supported:
Uses the caml project.
(:compatible-with::[[wikiattrs]]
)
: id :: <a-nanoid-id>
: ctime :: YYYY-MM-DD HH:MM +/-TZ
: mtime :: YYYY-MM-DD HH:MM +/-TZ
: vtime :: YYYY-MM-DD HH:MM +/-TZ
: title :: unslugified file name
: tldr :: ""
See caml-spec for fyll syntax specification.
---
id: <a-nanoid-id>
ctime: YYYY-MM-DD HH:MM +/-TZ
mtime: YYYY-MM-DD HH:MM +/-TZ
vtime: YYYY-MM-DD HH:MM +/-TZ
title: YYYY-MM-DD HH:MM +/-TZ
tldr: ""
---
See YAML for more.
#tags
in WikiBonsai have a particular meaning: The tag text maps to a (slugified) filename and clicking on the tag takes you to the file's location in the semantic tree, which is the wikilink (e.g. [[tag]]
) of the same name that appears in an index
document. (Though this can be configured to act more like Roam Research style #tags
and take you to the file itself instead)
- ❌ abcjs
- ❌ argdown
- ✅ critic markup
- ✅ ditaa
- ✅ DOT
- ✅ highlightjs
- ✅ katex
- ❌ markviz
- ❌ mermaid (install via vscode-markdown-mermaid)
- ✅ PlantUML
- ❌ vextab
Uses the semtree project.
Orient yourself within your WikiBonsai digital garden by cultivating a semantic tree. The tree is built from index
doctypes, whose markdown files should be composed of metadata attributes and a markdown list outline, which should look something like this:
// i.bonsai.md
: title :: knowledge bonsai
// ⚠️ Make sure each indentation level uses the same spacing!
// (2, 4, 6, etc. whitespaces or a single tab).
- [[branch-1]]
- [[branch-2]]
- [[leaf-2a]]
- [[branch-3]]
- [[leaf-3a]]
- [[leaf-3b]]
- [[leaf-3c]]
This file will build a tree that looks like this:
graph TD;
id1[i.bonsai]-->id2[branch-1];
id1[i.bonsai]-->id3[branch-2];
id1[i.bonsai]-->id4[branch-3];
id3[branch-2]-->id5[leaf-2a];
id4[branch-3]-->id6[leaf-3a];
id4[branch-3]-->id7[leaf-3b];
id4[branch-3]-->id8[leaf-3c];
You can also split the tree up into multiple files.
// i.bonsai.md
: title :: knowledge bonsai
- [[branch-1]]
- [[branch-2]]
- [[leaf-2a]]
- [[i.branch-3]]
// i.branch-3.md
: title :: third branch
- [[leaf-3a]]
- [[leaf-3b]]
- [[leaf-3c]]
This file will build a tree that looks like this:
graph TD;
id1[i.bonsai]-->id2[branch-1];
id1[i.bonsai]-->id3[branch-2];
id1[i.bonsai]-->id4[i.branch-3];
id3[branch-2]-->id5[leaf-2a];
id4[i.branch-3]-->id6[leaf-3a];
id4[i.branch-3]-->id7[leaf-3b];
id4[i.branch-3]-->id8[leaf-3c];
style id4 stroke:#66FF00;
You can force a re-sync between the semantic tree in markdown and the index in vscode, just use the tendr: sync bonsai
command. There is also a sync button on the semantic tree treeview panel.
Uses the treehouze project.
Open the tree graph with the tendr: open tree graph
and the web graph with the tendr: open web graph
commands or via the buttons the bonsai treeview panel.
The graph may be converted to several different dimensions and will maintain its integrity (the same shape, etc.) throughout each transformation.
- ✅ 2d
- ✅ 3d
- ✅ vr
- ❌ ar (code is there, but not functional)
There are two kinds of graphs (that may be opened simultaneously):
- 🕸 Web graph built from
[[wikirefs]]
.
- 🌳 Tree graph built from the semantic tree.
- Hover on node to highlight it and its relationships or on a link to highlight it and the connected nodes.
- Click on node to center node in graph.
- Cmd/Ctrl + Click to open node in editor.
- Shift + Click + Drag to select a group of nodes (to drag).
- Click on the background to de-select all nodes.
- Drag selected node or group of nodes. If
fix
option is on, nodes will fix in-place it was dragged to.
- Save node coordinates to
.json
file (separate file fortree
andweb
). (Useful if you're interested in playing with embeddings)
- Sync graph data with files manually.
- Dynamic node coloration based on doctype.
- Filter nodes (doc, media, template, zombie) and links (wikiattr, wikilink, wikiembed) by
kind
.
- Fix nodes to dragged coordinates.
- Flip the tree along the y-axis.
- Follow node in the graph that corresponds to the active editor's document.
- Highlight node in the graph that corresponds to the active editor's document.
- Toggle auto-syncing with markdown files.
The following are VSCode workflow features.
Auto-update Attribute Metadata
- The following metadata attributes will auto-update...:
ctime
/cdate
: ...when a file is created.mtime
/mdate
: ...when a file is modified.vtime
/vdate
: ...when a file is viewed (e.g. is focused on in the active editor):
- Formats:
time
format:YYY-MM-DD HH:MM:SS +/-TZ:TZ
date
format:YYY-MM-DD
- Note: Document metadata is not updated when changes are made outside of vscode.
-
Cmd/Ctrl + Click
... -
...when file exists, follow
[[wikirefs]]
to file.
- ...when file does to exist, use text from
[[wikiref]]
to create new file calledwikiref.md
.
- ...when file does to exist, use text from
[[wikiref]]
to create new file calledwikiref.md
-- if it matches adoctype
prefix, it will create a new document from the template of thatdoctype
.
- ...follow
#tag
to either its location in the bonsai (e.g. openindex
doc that contains[[tag]]
wikilink) or the file that matches the tag text (e.g. opentag.md
).
- ...for
[[wikirefs]]
.
- ...for
[[wikirefs]]
. - ...for
:caml::attributes
.
This project was careful with internal uris, so it should be possible to use this extension with remote development and codespaces.
- Rename corresponding
[[wikirefs]]
on filename change.
- Rename references and filename from
[[wikirefs]]
.
- Rename
zombie
references and filename from[[wikirefs]]
.
- Rename reftype and reftypes (includes both wikiattr and wikilink types) of same name from type text. (Note: Does not work for caml attributes)
-
Defaults:
yellow
forindex
doctypesgreen
forentry
doctypesgrey
forzombie
s.bright green
for media files and miscillaneous.
-
...for
[[wikirefs]]
. -
...for
:caml::attributes
. -
...for
#tags
.
- ...for
[[wikirefs]]
tab completion. (Tab completion includes zombies -- if there is a[[wikiref]]
with no corresponding file it is added to the possible completions)
- ...for
:reftype::
tab completion for:reftype::[[wikiattrs]]
.
Trigger with ctrl/cmd + k
by default:
- Create document (from doctype template).
- Search documents.
VSCode Treeviews to help you to navigate your digital garden and visualize relationships, especially with regard to the document currently open in the active text editor.
- Displays emoji of the document's given
doctype
. - Colorized bullet point that matches the document's doctype.
⚠️ only works fordefault
andzombie
dockinds.
Hit the refresh button to refresh the treeview's data from the underlying index.
Click on a treeview item to navigate to its file if it exists.
Click the plus symbol if there is no file (zombie) to create a new file from the doc default.
Click the plus symbol in a circle if there is no file (zombie) to create from a template -- you will be prompted to edit the filename before finally creating the file.
- Bonsai: Display the full bonsai.
- The bonsai treeview also has some action buttons:
- Open web graph.
- Open tree graph.
- Sync bonsai with index files.
- The standard refresh bonsai treeview.
- The bonsai treeview also has some action buttons:
- Ancestry: Display the ancestral path from the root of the bonsai to the current document.
- Children: Display the children of the current document in the bonsai.
- ForeRefs: Display all forward references, which includes subsections for forward facing (wiki)attrs, (wiki)links, and (wiki)embeds. (
attrs
will list types, which further list the files themselves.) - BackRefs: Display all backward references, which includes subsections for back facing (wiki)attrs, (wiki)links, and (wiki)embeds. (
attrs
will list types, which further list the files themselves.)
- Orphans and Floaters: Documents that are not connected to the tree (orphan) and/or the web (floater). Each are denoted by a tree and web emoji.
- Zombie:
[[WikiRefs]]
without a corresponding document; also lists the documents the reference appears in.
To see all possible commands, open the VSCode command palette and type "tendr". But keep in mind that there are several vscode commands in the extension that are not meant for manual use in VSCode. They are called by internal functions and should probably be left alone.
Target commands are listed here:
- Graph:
tendr: open tree graph
: Open the tree graph.tendr: open web graph
: Open the web graph.tendr: toggle on/off active doc following in graph
: toggle whether the graph should center on the node of the document in the active editor.tendr: toggle on/off fixed nodes in graph
: toggle whether nodes should used fixed coordinates in the graph or not.
- Semantic Tree:
tendr: sync bonsai
: Sync the semantic tree with the index documents/files.
- Treeviews:
tendr: refresh bonsai panel
: Refresh the Bonsai Treeview Panel.tendr: refresh ancestors panel
: Refresh the Ancestor Treeview Panel.tendr: refresh children panel
: Refresh the Children Treeview Panel.tendr: refresh forerefs panel
: Refresh the ForeRefs Treeview Panel.tendr: refresh backrefs panel
: Refresh the BackRefs Treeview Panel.tendr: refresh orphans panel
: Refresh the Orphans Treeview Panel.tendr: refresh zombies panel
: Refresh the Zombies Treeview Panel.
- Wizard:
tendr: search and create files from the wikibonsai wizard
(also available viactrl/cmd + k
):- Begin typing to search documents.
- Select a doctype/template to create a new file and then after selection type in the target filename.
If you are experiencing issues, you can try using these debug commands:
- Debug:
tendr: dump bonsai to .json file
tendr: dump index to .json file
tendr: print link index in console
tendr: print bonsai in console
tendr: clear index and rebuild from files
To see the available configurations, open your workspace settings and type "wikibonsai".
Since the graph supports fixed node coordinates, it is possible to play around with visualizing your markdown notes alongside word embeddings if those note filenames correspond to words or word senses.
Just generate a json file called coords-web.json
(or coords-tree.json
if you have coordinates for a hierarchical tree structure), place it at the root of your project.
The data payload should look like the following:
// coords-web.json
{
"fname-a": [0, 1, 2], // [x, y, z] coordinates
"fname-b": [0, -1], // [x, y] coordinates ; z can be left off if desired
// ...
}
Uses the caudex project.
There is an internal index to speed things up so that larger gardens may be supported. Precise size support is yet to be determined.
- Initialization may still be a touch slow for large gardens (hundreds or thousands of files) when first activating the extension.
- The index relies on the
id
attribute of each document and will lose track of relationships ifid
s are manually edited in files (rather than just letting the extension handle them). This can be fixed simply by restarting the plugin.
Feature requests, bugs, and suggestions can be filed in the issue tracker.
If you want to try tracking down issues yourself, you can check the logs by opening the "WikiBonsai" output channel.
just keep tending...🪴