Skip to content

zettelkasten

The Process of Making a Quality Zettel

A quality Zettel is made by capturing the core idea, expanding one layer deep into the idea with text, video, audio, adding external Zettelkasten system links, and adding a summary/excerpt to distill the idea.

Audio Companion

audio-thumbnail
Recording 20230225170709
0:00
/3:20

Written Idea

  1. Capture the Core Idea
  2. Expand one layer deep into the idea with text, video, audio
    1. Any further layers should be their own Zettel and be backlinked
    2. Too much energy[1] spent on depth in this step will cause overly tight ideas that can't be unpacked without a ton of context.
  3. Add external Zettelkasten system links. I use AI to assist me with this step. But the idea that I usually adhere to is: one obvious link, one surprising one. If you do only obvious links, you get trapped in confirmation bias.[2] If you only do surprising links, the path of reasoning becomes to difficult to follow, and the idea loses fluency.[3]
  4. Add a summary/excerpt to distill the idea

bramadams.dev is a reader-supported published Zettelkasten. Both free and paid subscriptions are available. If you want to support my work, the best way is by taking out a paid subscription.


  1. 202301102356

  2. 202301082259

  3. Killua is worried about that when he thinks people only like him because he is hard to read

    https://bram-adams.ghost.io/content/images/2023/02/killua-interesting.png
    killua interesting.png

Can AI Save My Zettelkasten?

TL;DR

The author is discussing the challenges they face with their personal Zettelkasten, a system of note-taking and knowledge management. The process of creating unique ID notes, writing single condensed ideas, and linking notes with tags and references can become overwhelming as the number of notes grows. The art of linking also becomes more difficult as the system scales. The author argues that current AI apps built into Zettelkasten systems are not useful for solving these problems and may even cause harm by creating an echo chamber. Instead, the author proposes using AI as a computational assistant for each independent note, creating computations from the notes that can run on their own and continue to generate new output. The author dreams of a world where everyone maintains a Zettelkasten and where Zettelkastens power themselves.

As my personal Zettelkasten (202301111303) grows beyond 400 Zettels,[1] I've noticed a few recurring problems arise that I imagine anyone in my shoes would face:

  1. The task of working on a Zettelkasten is nearly infinite -- every Zettel created spawns more Zettels
  2. As the raw number of Zettels increase, the linking process causes stress from choice overload
  3. Even though a zettelkasten can scale infinitely, the human mind can't

Let's take a look at these one by one and see if AI can throw us a life line.

The Sisyphean Task of a Zettelkasten

The Zettelkasten process is as follows:

  1. Create a unique ID note
  2. Write a single condensed idea on the card along with a title
  3. Link the card with tags (e.g. biology, woodworking, cooking, etc.) and/or references to other internal IDs within the Zettelkasten (e.g. 123456, 2231121, etc.) along with any citations for external resources

This process is enticing due to its simplicity, but in reality it's anything but. Under the calm surface lay the deep dark depths of infinite Zettels to be created, infinite links to be connected, infinite edits and tweaks to be…tweaked. Outdated knowledge and ideas get pruned, some Zettels merge into one, others yet split into other atomic Zettels.

This goes on and on and on and on and…

Linking is more of an art than a science. A creative link will add to the Zettel being worked on, providing helpful context or a new dimension of thought. A really creative link will mutually benefit both sides of the link. Inversely, a bad link will subtract from the Zettel, and in the worst case, damage the entire system.

Links are required because they are the veins and arteries of the Zettelkasten. It falls to the maintainer to make the (sometimes impossible) judgement call of where a new Zettel should embed itself in an existing Zettelkasten.[2]

As the Zettelkasten scales, the problem of linking scales as well. Eventually, so many options present themselves for linking that no one would be blamed for running off with their tail in between their legs.

As a thought experiment here are three links that I think relate to this section. Of the three, would you link any of them? One? All? None? This experiment will visualize the subjectivity of this craft

  1. 202301071346 (title: One Zettel, One Objective) (author reasoning: the ideal Zettel serves a single purpose, making good linking critical to connect disparate islands of thought)
  2. 202212162359 (title: Data Outlives Codebases) (author reasoning: Zettels can be spliced from their parent system and imported into others, much like genetic base pairs. This means individual data can outlive the original context it was created in)
  3. 202301032152 (title: Feng Shui Does Makes Sense!…) (author reasoning: Feng Shui emphasizes the function of a home by the pathing of its inhabitants. Spaces are clearly cordoned off by function. A Zettelkasten can function similarly)

And speaking of scale…

Scale Sucks

The two problems above are only exacerbated by scale. The right link becomes harder to find, ideas duplicated or lost, and the work of a Zettelkasten becomes more of a daily grind than an expression of creativity. The system eventually reaches a point where the knowledge becomes a burden on its maintainer, much like a mansion that needs to be constantly dusted or a giant library with books that will never be read, the system's berth affects its ability to maneuver gracefully.

NB: A trick to manage the problem of scale: One In, One Out: When linking choose one item to link from within a tag, and one item to link from outside the tags. The first link will be a much smaller set to search through, the second larger set is more about creative play and finding something clever.

Yikes, these problems are ominous. Can AI save us Zettelkasten maintainers from ourselves?

AI to the Rescue?

The AI apps I have seen others build into Zettelkasten systems like Obsidian have largely been readonly, with the cardinal goal of surfacing similar objects from the large set (mainly using embeddings). This is useful, to be sure, but I would argue that this may actually be the worst use case for AI in a Zettelkasten. Why?

One, correct tagging does most of the heavy lifting of surfacing similar notes. All knowledge that enters a Zettelkasten is subjective and the taxonomy is emergent. Tags are the UN in which individual Zettels engage with each other and as such need translators to make sure that important concepts don't get lost in translation.

Just because two Zettels are semantically similar does not mean that an explicit link should be formed between them. In fact, this goes counter to the highest aspiration of a Zettelkasten, where the goal is to join diverse ideas.

Two, this creates internal pressure in the system, increasing the likelihood that the system will become an echo chamber. This pressure creates more dense collections which might be visually appealing in graph view, but the heavy handed nature of the the AI links can cause nasty things like self-referential loops. In the long term, letting AI go haywire (in its current 2023 incarnation) over your system may cause more harm than good.

In a way, smart surfacing is only useful to consumers of a Zettelkasten, and may actually cause harm to producers. If the goal is to create a Google-like or ChatGPT-like experience in a Zettelkasten, that is readily achievable -- but it does not solve the problems of a growing Zettelkasten for the creator.

So what can?

Yin and Yang

As a reminder, the problem of scale is largely a product of overwhelm. With a large quantity of Zettels to search through, the value of time spent on any individual Zettel goes down drastically. Intuitively, one may build a system similar to the one above with one commandment: ignore anything that is not similar to what I am looking at, pre sort the list for anything that fits the bill.

While I agree that sorting is a useful task, I think that returning the opposite Zettels from the list is much more useful. By orienting your argument against the opposite items in your Zettelkasten, the boundaries of your Zettel become clear. From a list of 1…n, the most helpful items live at n-3…n. There is no subject without an object to compare itself against.

Adding more of the same color to a canvas does little, while adding a contrasting color reveals a brand new image.

Tiny Little Turing Machines

Another potentially powerful solution is one that I learned from a deep conversation with un1crom -- use AI as a computational assistant for each independent Zettel.

To do this, we assume that each Zettel is or is not a computable thought. A computable thought embeds an algorithm inside of it.

Imagine each Zettel as a seed. This seed represents an idea. Traditionally, ideas need to be consumed by a machine that computes. My dear reader, as you consume these very words on the page, your mind is the machine that is hard at work processing the validity of each sentence, weighing the concepts, sorting them and ranking them based on previous knowledge you have consumed, etc.

The broad concept is to have a GPT model write code based off the Zettel's contents (see 202302100037, 202302111242, and 202302111309 "Computation" titles for live examples.[3]

The task of creating computations from Zettels opens the possibility of using them like any other block of code -- a composable element that can run on its own. No longer would a Zettel be inert until some intelligent being comes and reads it, it will continue to pop out microscopic widgets from its computational factory. In fact, once Zettels get linked manually their computations can also be joined, creating mega structures and giving the second brain a job to do outside of being consumed.

This creates an exit route from the pressure of creating knowledge. Much like investing, the more computational thoughts there are, the more they power the system and create new output, which begets new computational seeds, and on and on….[4]

Conclusion

It will be at the very least entertaining to see how AI shapes up against the second brain/Zettelkasten space. I'm excited to build tools that push the boundaries of this space, all the while maintaining the living breathing Zettelkasten you see in front of you.

I dream of a world where everyone maintains a Zettelkasten, where Zettelkastens make people better, more knowledgable and happier, and a world where Zettelkastens begin to power themselves. Perhaps AGI is actually AZI (Artificial Zettelkasten Intelligence)?


If you like what you read, please hit that Subscribe button in the corner to join other thinkers in this community! I send out multiple think pieces or Maps of Content a week as well as many notes that can only be seen by subscribing to the RSS feed above.


  1. a Zettel is an individual note in a Zettelkasten

  2. should I tag this a or b… or neither? Damn.

  3. all of the code in those sections was written by ChatGPT!

  4. in the positive direction this time!

The Danger of Journaling IS Introspection

I was having an off-day a few months ago. To try and lift my spirits, I decided to take advantage of the fact that I have the ability to time travel.

Not literally, of course, but figuratively in the one direction of the past (which is almost as good as not at all, admittedly).

By maintaining a daily journaling habit for ~5 years now, I can "revisit" any day in that timeframe, remember the people I interacted with, the thoughts I was thinking, and the admire the seeds of ideas that incubated in the interim of then and now.

On this particular day, June 21, I "visited" 2018, 2019, 2020, and 2021.

And holy shit. So much has changed…but nothing has changed.

Physically, I am a different person. My location is different. My age is different. My finances are different. My crushes, my friends, my job, all radically different.

But what has stayed the same, disappointingly, is the shape of my goals. The mountain I set out to climb nearly 1500 days ago is still looming, and I am still at base camp.

Sure, I've made "progress" towards the summit of self actualization, but in reality, I've written a lot more about what I want to do as opposed to what I have done over the past five years.

In a way, introspection has held me back. It has made me viscerally aware of my shortcomings in the financial, professional, romantic, and physical realms. Introspection has reminded me of dropped promises, awkward encounters, unfounded concerns. It reminds me of just how naked and vulnerable in the cold of space and time I really am.

But on the other hand it's kind of… really fucking funny?

The raison d'etre of the exercise of daily journaling is to step outside of the stream of time, to crystallize thoughts and emotion, to view oneself from as detached a perspective that can be mustered.

I'm looking from now, from "above", in 2022, at this gelatinous creature in 2018 with desires and pains, likes and dislikes, thoughts that amounted to being nothing or more often entirely incorrect. I'm watching him lament, I'm watching him try to problem solve, I'm watching him cope, and build, and destroy, and dream, and panic. It's hard to not examine this creature with pity, with a dose of concern for his mental well-being.

And yet… he's kind of cute. His persistence is admirable. He gets up every day in pursuit of his goals, even though I know as the future reader that in many ways, he has failed. I find myself cheering for this man stuck in the page, go you fighter, go! Continue to strive out the mud. Continue day in and day out to climb this unforgiving fucking cliff face, and if your fingers are bloody at the end of it, and you sit breathless at the bottom, staring up as the snowy wind pelts your face, you can rest easy knowing that you've tried.

I know you've done your best.

There's proof.

Criticism, Conjecture and Nen Vows

Conjecture = Guesswork/Hypothesis/Reality Free
Criticism = Judgement/Tied To Reality

Let's imagine conjecture and criticism as being two sides of a hypothetical spectrum.

The closer one is to the criticism side, the more they are likely to act realistically, conservative, rigid.

The closer one is to the conjecture side, they are more likely to apply open-mindedness and imaginative creativity.

The very act of thinking is a form of conjecture. Every thought is an idea, a potential action presented by the mind as a path to pursue. Thoughts flood in from the "monkey mind", and the critical mind is forced to come up with justification as to why that thought is indeed the case -- or to reject it. ^945c1a, 202301082259

Conjecture can only happen in the mind of an individual.

Editing is a form of criticism. Editing can be described as alignment to shared reality, the aim of reducing the creative space of a thought -- to bring it in line with reality.

Editing can happen in the mind of an individual, but it is actually driven by society. 202301082233 Customs that feel natural to you feel foreign to another. Editing also happens against the laws of the universe: physics, biology, chemistry, etc. If something breaks the laws of the universe, it ceases to exist.

Criticism can happen within an individual, but criticism is the result of a composite network of rules and engagements from individual objects colliding & seeing each other as subjects.

Sparta or Athens?

HERMES: Not at all, Athenian. As I said, I honour you. Now, let us consider what would happen if, instead of legalizing thievery, their error had been to ban debate. And to ban philosophy and politics and elections and that whole constellation of activities, and to consider them shameful.
SOCRATES: I see. That would have the effect of banning persuasion. And hence it would block off that path to salvation that we have discussed. This is a rare and deadly sort of error: it prevents itself from being undone.
HERMES: Or at least it makes salvation immensely more difficult, yes. This is what Sparta looks like, to me. (Location 4077)

If a system banishes debate, the rigid and currently fallible ideas never get deposed. New ideas have no chance to flourish. To use conjecture is to imagine alternatives, to have fair and honest debate is to decide which conjecture is most likely to be a good explanation.

Strive to be Athenian, not Spartan. Societies and cultures that protect the individual right to make conjecture continue to grow. Cultures (and subcultures and families and groups of friends and classrooms and…) that stifle and smother new ideas get trapped in stasis, and when they are threatened by physical reality, break due to their rigidity.

Nen Contracts

Being a product of the mind, Nen responds to the goals, strengths, and desires of individual users. As a result, a student of Nen can increase the overall power of an individual skill by stating a self-imposed restriction that forces even more conditions on it.
For example, if one consciously decides something along the lines of "I will only use this skill on Thursdays" or "I will only use this skill against short people" and manages to abide by that rule, that particular skill will become stronger. These restrictions are called "limitations" (制(せい)約(やく), Seiyaku, or 制約(ルール), lit. "rule"), and the act of swearing to respect them "vows" (誓(せい)約(やく), Seiyaku) or "contracts".
The stricter the limitation, the stronger the user's resolve, and thus the more their ability is strengthened. Limitations seem to strengthen an ability to a greater degree than Conditions. However, limitations are also considered liabilities, since the power they grant is not consistent. (View Highlight)
Limitations that contain some sort of punishment (e.g., "I will die if I break this rule") will strengthen the ability even further (View Highlight)

In Hunter x Hunter, characters can make contracts against their Nen. They increase with power the stricter the criticism.

Because Nen is a product of the mind, Nen is a conjecture for the user. Combat against other Nen users is where people are forced to determine the usefulness of their ability choice (Gon's Jajanken is insanely simple for example, but that very simplicity gives it a broad use case in reality -- despite this Gon actually has one of the most rigid mindsets in the entire series 202301071340, 202301092316).

Societal Customs

The ideology, world outlook, and sense of right and wrong of the ability's creator plays a fundamental role in determining the exact circumstances and boundaries of a condition. The Manipulation ability, Order Stamp only works on puppets, which the ability's creator defined as "non-living objects with a discernible head"; vice versa, this means that if the puppet’s head is removed, it ceases to be counted as such and the ability terminates. Additionally, since the creator did not view human corpses as mere objects, despite them otherwise fitting the definition of a puppet. Chrollo, who stole the ability, had no such views and considered corpses perfectly acceptable as objects, however he was still unable to manipulate corpses with Order Stamp. Although the ability could still be used on artificial replicas of corpses. (View Highlight)

Even in the world of HxH, customs and world views shape criticism. Chrollo's perception of reality is fundamentally different than the original user of the Order Stamp. This changes the rules of how Order Stamp is used. Suddenly, the same conjecture in a different context has a completely different outcome.

The creator of a Nen ability can include conditions (条(じょう)件(けん), jōken) in it to increase its power or to make the ability feasible in the first place, whether because the user lacks the degree of skill otherwise required, or because the effects of the ability exceed what can be achieved with Nen without a trade-off. Conditions are based on the principle of equivalent exchange, but may occasionally be rendered redundant by high proficiency in Nen. The three categories at the bottom of the Nen chart—Conjuration, Specialization, and Manipulation—are the ones that appear to rely on conditions the most. It does not appear to be possible to violate the conditions of an ability. (View Highlight)

Strangely enough, the more imaginative Nen affinities (conjuration, manipulation, specialization) are farther from reality and require stricter conditions to be put in place. Compare this to enhancement or transmutation, where the goal is to modify an aspect of reality, instead of creating brand new concepts.

Why I Migrated 300+ Posts From Obsidian Publish to Ghost

303.

303 posts manually backfilled one by one from Obsidian Publish to Ghost, with great effort and mental + physical expense. But why?

https://bram-adams.ghost.io/content/images/2023/02/303-issues-ghost.png
303 issues ghost.png

The Goal of a Zettelkasten

For the uninitiated, a zettelkasten is a form of a personal knowledge management system (PKM). The Zettelkasten method prioritizes small pieces of information (i.e. the information that could fit on one flashcard) linked together in a web like format by using IDs.

These two simple features together create emergence, as different notes influence the system in unique ways (A is linked to B, B is linked to C, meaning it possible to get to C from A despite no direct link).

"Wholly new forms of encyclopedias will appear, ready-made with a mesh of associative trails running through them, ready to be dropped into the memex and there amplified."
https://en.wikipedia.org/wiki/As_We_May_Think

In the 2020s, the Zettelkasten has come back into vogue thanks to software like Obsidian and Roam Research. Everyone from academics to business professionals drowning in information deluges have sought the refuge of systems that can scale flexibly without breaking under their own weight.

The New Native

The Zettelkasten, in my belief, is a pivotal piece in the future of information creation and consumption. The system allows for healthy consumption (easy to jump into the graph and easy to jump out), updating of stale information when it is revisited, and most importantly implicit dense forests of linking.

But there is a problem. How do we share this information on the web, the closest technology we have to a global communication layer, a platform that works on a Hypertext layer, but displays information linearly? (think of a Twitter feed, information is delivered in LTR and top to bottom) How can we create a graph like experience when information is hidden behind links?

Obsidian + Publish

This is where Obsidian comes in.

Obsidian is beautiful software. In fact, I like it so much, I wrote a 10,000+ word guide on how to use it to its full potential.

Obsidian offers an official plugin named Publish. Publish functions exactly how you might imagine. It publishes markdown notes from Obsidian onto the web.

Publish, much like Obsidian, is a solid piece of software. For a lightweight hosting solution for Obsidian notes, it is fast, reliable, and intuitive. It functionally operates as a CRUD uploader with options to change custom domains, upload custom JS and CSS files, etc.

https://bram-adams.ghost.io/content/images/2023/02/obsidian-publish-settings.png
obsidian publish settings.png

Unfortunately, the current version of Publish didn't fit the full laundry list of features I needed to make the Zettelkasten in my head a reality. But what are these features anyway? And why can't I live without them?

The Deal Breakers

I had a list of non negotiable elements I wanted to achieve in this build. I have some pretty strong opinions about the logos, ethos, and pathos of a working & published Zettelkasten, and I wasn't really willing to compromise on anything from this list.

It HAS To Be Fun

First and foremost, my cardinal belief is that writing and reading the Zettelkasten should be fun. I as the writer and you as the reader should feel ideally feel no friction moving from note to note.

Topics should merely be a slight change of context instead of a drastic pivot from one field of expertise to another. The non linear path should be a sandbox for the mind to discover concepts that are surprising -- akin to a pleasant midday walk through the garden of the mind.
"Oh, the hydrangeas look nice today! Or perhaps I'll spend time amongst the cherry blossoms. I think I'll take this tulip home with me."

If it is not fun to garden, if it is not fun to walk the garden -- then the whole enterprise should be abandoned from the outset.

Lazy Utils

In service of making writing an enjoyable and fun process, the work around publishing a piece should be minimized. My goals were as follows:

  • Spend minimal time on tedious dev work: this includes maintenance, required features, annoying work like targeting different browsers/optimizing for mobile, SEO, etc.
  • Do 100% of the writing process within Obsidian
  • One Button Sharing

All three of these allow for me to focus on the act of writing, while being to maintain a high quality visual and tactile experience for the reader as well.

Reader Engagement

Speaking of the reader, I wanted a blog that could engage with the audience on a level past just reading. For better or worse, social media has become the human bazaar of communication. This causes a lot of problems, since most people have a lot of emotional baggage attached to their social profiles, not to mention the patterns of addiction and harm caused from subtraction of context + hostile territory.

For years, I've been looking for a way to solve this problem. I think there are four reliable, solid tools to manage reader-author interactions on the web: self-hosting, email newsletters, RSS, and in-place comments. All of these technologies are tried and true, last years, and many have protocols built into the very fabric of the web.

Having access to all four greatly increases the longevity of a website, as well as the utility the owner can provide to the visitors.

Customizability

Being able to get my hands dirty with the source code allows me to build spirit into the garden. As I evolve as a writer and developer, and as I learn new skills, customizability is paramount to creating a fun experience for the reader.

In fact, the need to have customization is what initially chased me away from Substack, I didn't like how limited I felt by the tools Substack offered (they don't even offer an API!).

https://bram-adams.ghost.io/content/images/2023/02/substack-no-api.png
substack-no-api.png

Why (Not) Ghost?

Of the dealbreakers listed above Ghost offers a lot, but also misses a few things that I had to try my hand at building manually. From the above list, Ghost provides built-in:

  • Minimal dev work for features like fast mobile loading, image optimization, routing, etc. built-in
  • Comments built in
  • Full text search built in
  • RSS built in
  • Email newsletters built in
  • Admin dashboards built in
  • Admin and Content API built in
  • Mainstream CSS themes to start from built in
  • An official way to make money through Stripe built in (this is uber important for people who want to go full time with their work!)
  • Option to self host or host through Ghost's platform

Thanks to Ghost being open source, I don't (probably) have to worry about situations like the below happening (which it did, and because I didn't see the email, I was blindsided and lost access to all the newsletters I wrote on Revue -- like totally locked out)

https://bram-adams.ghost.io/content/images/2023/02/revue.png
revue.png

The deal breakers that had yet to be built:

  • One button publish from Obsidian
  • Writing in Obsidian and converting Markdown to a published post -- seamless CRUD workflow
  • Elements of fun and exploration
  • Internal Hover Links

The Obsidian Ghost Plugin

The first and most important extension to Ghost's base offerings was to build an Obsidian plugin that would automatically interface with Ghost without leaving Obsidian.

One button publish was built off a great open source plugin by jaynguyens, which converts Obsidian markdown into HTML and uploads it directly to Ghost using the Ghost API. I forked it and added a number of features including:

  • automatically checks if slug exists; if so updates instead of creating a new post
  • converts [[ links into a.href and maintains canonical name
  • inserts image placeholder cards that match names of local files for easy discovery while uploading
  • removes title H1 from notes to prevent duplicate titles
  • auto sizes YouTube embeds and auto centers them in the middle of the page
  • opens automatically in preferred browser after uploading with the API

For example, here's the wikilink to a.href converter feature code:

// converting <a href="https://bram-adams.ghost.io/link">link</a> to <a href="BASE_URL/id" class="link-previews">Internal Micro</a>for Ghost
	const content = data.content.replace(
		/!*\[\[(.*?)\]\]/g,
		(match: any, p1: string) => {
			if (p1.toLowerCase().includes(".png") || p1.toLowerCase().includes(".jpg") || p1.toLowerCase().includes(".jpeg") || p1.toLowerCase().includes(".gif")) {
				try {
					// get the year
					const year = new Date().getFullYear();
					// get the month
					const monthNum = new Date().getMonth() + 1;
					let month = monthNum.toString();
					if (monthNum < 10) {
						month = `0${monthNum}`;
					}

					return `<figure class="kg-card kg-image-card"><img src="${BASE_URL}/content/images/${year}/${month}/${p1.replace(/ /g, "-").replace(/%20/g, "-")}" alt="${BASE_URL}/content/images/${year}/${month}/${p1.replace(/ /g, "-").replace(/%20/g, "-")}"></img><figcaption>${p1}</figcaption></figure>`;
				} catch (err) {
					console.log(err);
				}
			}

			const [link, text] = p1.split("|");
			const [id, slug] = link.split("#");
			const url = `${BASE_URL}/${id}`;
			const linkText = text || slug || link;
			const linkHTML = `<a href="${url}">${linkText}</a>`;
			return linkHTML;
		}
	);

Fun and Exploration

To make the process of traversing the published Zettelkasten fun, I thought about what I liked about note discovery in Obsidian. The first thoughts that came to mind were tags and internal hover links.

All topics are available at the bottom of each post in addition to read later from items within the same tag. This gives the reader an option to laterally move within a tag or to jump back to the top level of another tag and explore there instead.

jump to a top level search -- a new tag with completely new ideas to explore

https://bram-adams.ghost.io/content/images/2023/02/tags-and-topics-ghost.png
tags and topics ghost.png

or explore within the same tag

https://bram-adams.ghost.io/content/images/2023/02/within-same-tag-ghost-1.png
within same tag ghost 1.png
https://bram-adams.ghost.io/content/images/2023/02/within-same-tag-ghost-2.png
within same tag ghost 2.png

To implement these, I edited the code in my Ghost theme to show the posts I wanted to surface for users:

{{!-- https://github.com/TryGhost/Themes/blob/6f71fe0f1b10e9b81678bb7e0fde12489dfc995f/packages/journal/index.hbs#L111-L126 --}}

{{#get "tags" include="count.posts" limit="all" as |topic|}}
    {{!-- <section class="gh-section"> --}}
    <div class="gh-read-next gh-canvas">
        <section class="gh-pagehead">
            <h4 class="gh-pagehead-title">Topics</h4>
        </section>

        <div class="gh-topic">
            {{#foreach topic}}
                <a class="gh-topic-item" href="{{url}}">
                    <h3 class="gh-topic-name">{{name}}</h3>
                    <span class="gh-topic-count">
                        {{plural count.posts empty="0 issues" singular="% issue" plural="% issues"}}
                    </span>
                </a>
            {{/foreach}}
        </div>
    </div>
{{/get}}

Show Me What You GOT

For internal hover links, I used the Microlink API and code injection to create a block in the footer of my Ghost pages that would give all internal links on my site the ability to be hovered (if you are on desktop -- hover this link for an example may take a second to load! 202212181947)

<!-- https://microlink.io/docs/sdk/getting-started/styling --> <style> :root { --microlink-background-color: #1A1A1A; --microlink-color: white; --microlink-border-color: #666; --microlink-hover-border-color: #999; } </style>  <!-- load @microlink/hover-vanilla --> <script src="https://cdn.jsdelivr.net/combine/npm/react@16/umd/react.production.min.js,npm/react-dom@16/umd/react-dom.production.min.js,npm/react-is@16/umd/react-is.production.min.js,npm/styled-components@5/dist/styled-components.min.js,npm/@microlink/mql@latest/dist/mql.min.js,npm/@microlink/hover-vanilla@latest/dist/microlink.min.js"></script>  <!-- intialize `microlinkHover` --> <script> document.addEventListener('DOMContentLoaded', function (event) { microlinkHover('.link-previews') }) </script>
<script defer>
    const BASE_PATH = "https://bram-adams.ghost.io"
	const EXCLUDED_PATHS = ['/', '/about/']
    const EXCLUDED_PATTERNS = ['#/portal/', '/author/', '/tag/', '#fn']
	document.querySelectorAll("a").forEach((a) => {
    	if(
            a.href.includes("https://bram-adams.ghost.io") // only match internal links
           && EXCLUDED_PATHS.filter(path => a.href !== BASE_PATH + path).length == EXCLUDED_PATHS.length // skip exact paths
           && EXCLUDED_PATTERNS.filter(epattern => !a.href.includes(epattern)).length == EXCLUDED_PATTERNS.length // skip paths including a pattern
           && (!a.classList.contains("gh-card-link") && !a.classList.contains("gh-topic-item") && !a.classList.contains("gh-navigation-link"))) // homepage bug
        {
       		a.classList.add("link-previews");
    	}
	});
</script>

Was it Worth It?

I had to add many features to Ghost to "catch up" with Publish, but the stuff I would've had to add to Publish (full text search, mainstream CSS, newsletter, comments, admin pages, Stripe integrations, etc.) would be nigh impossible, so I'm glad overall that I made the move.

The overall UX of Ghost is much more polished than Obsidian Publish currently (though that may one day change!).

If you want to have a blog that could pass as a high quality standalone blog, check out Ghost. The ease of connecting to Obsidian really sealed the deal for me, as I would be able to maintain my writing habits while gaining a new venue to publish in.

What's Next?

I want to continue to make this site more fun as I come across new ideas and techniques along my journey. I'm excited to play with new themes and new visual ways to tell stories.

Concretely, I'd like to add some form of Obsidian block support for Ghost. Being able to link within specific blocks within Obsidian pages is such a treat, it's hard to not have that on my website.

More pressingly, I'm using this time to write. At the top of this post I mentioned I manually uploaded 300+ posts one by one. This is true. What I failed to mention is that my #to-process tag (where all my zettels are sourced from) has over 4000 (oof) items to go through. Some of these will be quick, others will take days to fully process.

https://bram-adams.ghost.io/content/images/2023/02/to-process-vs-zettel.png
to-process-vs-zettel.png

In other words, I have a lot of writing to do.

*me right after I rebuild my site from scratch*

If you read this far into this post, I'm gonna assume you're into Zettelkasten stuff. If you want to learn about the process of building a Zettelkasten by watching one be built from the bottom up, do be sure to subscribe!

Thank you for reading, and I hope to walk past you in the garden one day!


Edit 2023-02-03

A comment on Reddit from /u/johnlunney mentioned that it would be helpful to call out the features Publish is missing, so I'd like to carve a little space to do that here.

https://bram-adams.ghost.io/content/images/2023/02/missing-features.png
missing features.png

Here are some things that caused me to move away from Publish.

Limited Control Over Full Feel

Publish gives an option to upload a custom publish.css file, but unfortunately it is up to the user to find the correct CSS classes and reverse engineer them. For example, I added this feature on mobile to be able to swipe to open the sidebar, but I had to inspect the element itself and take a leap of faith that the CSS class I was toggling would control what I hoped. It worked, but the whole thing was honestly a shot in the dark since there is very minimal documentation floating about the web.

// swipe left on mobile to open menu
let touchstartX = 0;
let touchendX = 0;

function checkDirection() {
  // check if greater than 100px
  // if swipe right close menu
    if (touchendX < touchstartX && touchstartX - touchendX > 100) {
    document
        .querySelector(".published-container")
        .classList.remove("is-left-column-open");
    }

  if (touchendX > touchstartX && touchendX - touchstartX > 100) {
    document
      .querySelector(".published-container")
      .classList.add("is-left-column-open");
  }
}

document.addEventListener("touchstart", (e) => {
  touchstartX = e.changedTouches[0].screenX;
});

document.addEventListener("touchend", (e) => {
  touchendX = e.changedTouches[0].screenX;
  checkDirection();
});

There are many other examples like this, but off the top of my head:

  • No control over the way the sidebar displays file order
  • No way to add onClick() events
  • Adding comments and other features is hard due to loading order (onLoad() didn't work since I think Publish is a SPA app?)
  • Hard to anticipate how publish.css/js changes will propagate to mobile
  • Unnecessarily large gutters for content
  • Full Text Search
  • Limited Space (4GB) for everything

Unfortunately all this adds up to a novel (read: kinda weird) UX for both the developer and readers to learn.

I think Zettelkastens across the web would be a lot more popular if SEO was better and they adhered to more mainstream principles.

Gitignore

The "gitignore" feature in Publish is awesome. It makes uploading changed and new files a breeze, as well as deleting them. Unfortunately, this also causes all the files in Obsidian to be tracked, which is pretty annoying.

To combat this, the Obsidian devs added an option to ignore folders/files. This works great…until you locally move the files. Then the whole game starts over again. This is pretty annoying if you uploaded something, changed its path and then need to do the whole upload process from scratch.

Limited Communication Around Updates

With the core team hard at work on the app of Obsidian, I felt at times Publish was passed over as a side offering instead of a main project. As I said earlier in the essay: this is fine if you need an immediate readonly hosted solution. But the second you want to scale the public offer, Publish can no longer provide utility, imo.

You can find more of my thoughts on whether or not Obsidian Publish makes for a remarkable venue here: 202301240135

Data Outlives Codebases

Your data is the most important part of your system
I’ve seen a lot of systems where hope was the primary mechanism of data integrity. In systems like this, anything that happens off the golden path creates partial or dirty data. Dealing with this data in the future can become a nightmare. Just remember, your data will likely long outlive your codebase. Spend energy keeping it orderly and clean, it’ll pay off well in the long run. (View Highlight)

raw data is the stuff programs work against, the static 1s and 0s that represent patterns. functions are basically just giant orms. i do wonder the effect this logic has on the functional programming zealots though.

The act of building and maintaining a Zettelkasten is similar work. It is focused on the content of individual notes, and how dense their local neighborhoods are through connection.

The Manic Zettelkasten Mood

closed mode “most of the time when we’re at work. We have inside us a feeling that there’s lots to be done and we have to get on with it if we’re going to get through it all. It’s an active, probably slightly anxious mode, although the anxiety can be exciting and pleasurable . . . It’s a mode in which we’re very purposeful and it’s a mode in which we can get very stressed and even a bit manic.” (Location 2205)

omg i'm in this manic mood at this exact moment.[1] the anxiety of having infinite zettels to create (a mt everest sized pile in my #to-process)[2] but the output of each zetttel being atomic in scope has a satisfying finality. the creativity of some of these zettels is blowing me away like "fondong" 202212192046 or the ying-yang narcolepsy screenplay 202212192225


  1. ^xa9thp

  2. it's coming along! 202301111303

So Much to Process - So Little Time

Don’t forget that the “needs attention” box ought to be empty. If there are papers in it, be aware that this means you have left things undone in your life that require your attention. (Location 1132)

My #to-process folder is going off rn. The act of going through the inbox is an organizational unto itself to find the ideas you love and discard the ones you don't (202212281202)

The trick is not to overcategorize. Divide your clothes roughly into “cotton-like” and “wool-like” materials when you put them in the drawer. (Location 979)

Tags work for real items as well as digital ones!

If you release and let the energy pass through, then it will go away. If you relax when the pain comes up inside your heart, and actually dare to face it, it will pass. Every single time you relax and release, a piece of the pain leaves forever. Yet every time you resist and close, you are building up the pain inside. It’s like damming up a stream. (Location 1521)

or adding it to the pile of items to process