essays
Long form opinion pieces about any topic under the sun, yuh!
Thoughts While Building an IKEA Alex File Cabinet
I spent two hours building two IKEA Alex drawers and had a lot of thoughts along the way, from questioning the instruction manuals to wondering why they don't tell you to batch things.
Audio Companion
Total time building two Alex drawers: ~2hours
15 minutes in: Whoever is the motherfucker who makes instruction manuals[1] for IKEA is a sadist of the highest order. Who are these Keith Haring looking motherfuckers? Why are they so condescending?
19 minutes in: Nothing like some particleboard in the lungs to wake you up. I probably should've wore a mask for this…
34 minutes in: Fuck it I’ll just hit it with a hammer
38 minutes in: If you’re going to make such a small distinction about screws that look the exact same, why put them in the same fucking bag???[2]
44 minutes in: The instruction to put it upside down was a great call. Author's note: This brief joy was
immediately canceled out by having to turn the weird screw from the bottom.
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.
44 minutes in: Why don’t instruction manuals tell you to batch things, do the honestly expect people to do these one by one? Looks like someone got stuck on bubble sort at school ;)
IKEA Engineers Should Unionize
A newspaper in Sweden described Ikea [furniture assembly] as something between civil engineering and captaining a submarine, and I think that’s a good description,” says Allan Dickner, Ikea’s deputy packaging manager. (View Highlight)
there’s one foolproof method for turning Ikea rage into grudging respect: assembling almost any other brand of furniture. After an hour spent comparing piles of ambiguous components against an assembly diagram that looked like a misfiled mimeograph from Area 51, I somehow produced a HomeGoods end table—as well as a surging curiosity about how Ikea designs its own packaging and instructions, which now seemed positively Eamesian in comparison. To adapt Winston Churchill’s famous quip, Ikea may be the worst form of ready-to-assemble product design we have—except for all the others. (View Highlight)
According to Allan Dickner, whatever your most frustrating Ikea experience is, it could have been worse—and most likely was for the packaging engineer who test-assembled even more complicated versions of the product before arriving at the optimized design that you unboxed on your living room floor. “We had one furniture piece, a type of wardrobe, which originally had over 400 fittings and screws to hold it together,” Dickner says. (View Highlight)
For 400 screws that wardrobe better open straight to Narnia, shit.
Continuity, meanwhile, is what separates Ikea’s instructions—even the maddening ones—from those of other brands. The Lego-like, frame-by-frame illustrations are based on construction drawings, digital snapshots, 3-D models, and videos of test assemblies. Designers take pains to render each successive picture from a single, unchanging point-of-view (mimicking that of the customer), so that confusing rotations or perspective changes are minimized and the customer can stay oriented more easily as he or she moves back and forth between the booklet and the parts. (View Highlight)
*Turns on isometric view mode in Blender once*
They may not be pleasant, but they are at least rational and comprehensible—even sympathetic—by design. Think of that big-nosed “Ikea man” who’s shown calling the company when he gets stuck. He’s not mocking or condescending. If anything, he represents some designer at Ikea who has already gone through exactly what you’re going through now on your living room floor: half-quizzically glancing from instruction booklet to pile-of-parts and back, hoping for the best, but trusting that it will all, at the very least, make sense. (View Highlight)
I disagree.
The Moving Sofa Problem
“It would be quite stupid to design a package that’s flat and efficient but won’t fit into a small elevator or staircase,” Dickner explains. “It sounds ridiculous, but in the United Kingdom, that was one of the most frequent reasons for a customer returning a product.” He adds that global package designs are tested in Japan and South Korea “because those are the customers who live in the smallest spaces.” (View Highlight)
The Europeans get math(s)ed by their hella small flats.
the moving sofa problem or sofa problem is a two-dimensional idealisation of real-life furniture-moving problems and asks for the rigid two-dimensional shape of largest area that can be maneuvered through an L-shaped planar region with legs of unit width.The area thus obtained is referred to as the sofa constant. The exact value of the sofa constant is an open problem (View Highlight)
He's made quite the compelling career for himself…202301051907
products like these make me appreciate well made tech products even more, tbh 202301130214
Reader (by Readwise) is Goated
I am impressed with the Readwise team for creating a great app with a solid AI integration that provides a world class reading experience on mobile and web clipper experience.
Intro
As I've discussed[1] multiple[2] times, creating a solid app that leverages GPT is a difficult challenge. LLMs have a steep learning curve. Even after the summit of learning is crested there are still major problems (features -- not bugs) that are (currently) unsolvable. These "features" include, but are not limited to: model hallucination, context window size, and fine tuning unfreezing for transfer learning.[3]
These domain specific problems are in addition to the regular problems of building an app, including UX, data integrity, marketing, pricing strategy, data storage, dev ops pipelines, privacy, yada yada yada.
There is a reason I say that building my own E2E app Stenography took multiple years off of my lifespan.[4] Shit was tough.
With this difficulty in mind, I want to give major props to the Readwise team for knocking it out of the park with the Reader App. They succeeded not just in the domain of building a great app, but also having a solid AI integration. This app provides a world class reading experience on mobile, in addition to a world class web clipper experience. The double tap to highlight a paragraph functionality is something I didn't know I needed so badly until I had it.
On top of all of that, the Ghost Reader Extension is actually really good.
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.
Ghostreader is easily accessible from the menu.
There are only a few options. Counterintuitively, limiting options with an AI app is the correct play.
Feels like a part of the app (crazy to say that I know, but you'd be shocked how many AI apps feel distinct from the parent app)
Human in the loop editing
Two Actually Useful GPT-3.5 Prompts for Zettelkasten Schreibers
I have been using two GPT-3.5 prompts to help me save time and improve my writing as a Zettelkasten Schreiber. The Outline to Complete Sentence English Prompt transforms outlines into complete sentence English, while the Summary Generator takes complex text and distills it into a blurb.
Audio Companion
Intro
These past few months have been a whirlwind of nothing-burger AI companies,[1] random social media (and regular media -- which in recent times have seemed to collapse in on each other w.r.t messaging about technical topics) hive-minding about whatever new model is vogue[2] -- alongside valid concerns about ML technology and the pace that it is introducing itself into the fabric of society.
This post isn't about any of that -- in fact I'd like to do the opposite of making some wild claim about how AI will do this or won't do that. I just want to talk about small W's I've been able to achieve in my daily life with this cool tech.
Here's two prompts that I've been using as a Zettelkasten Schreiber that have saved me a ton of time and have been a joy to use.
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.
Prompt 1: Outline to Complete Sentence English
The Outline to Complete Sentence English Prompt transforms outlines into complete sentence English. This useful for a multitude of reasons.
NB: look at the bottom of this piece for raw results from the model
Utility
The purpose of a first draft is to get ideas down on paper and examine relationships.[3] The first draft is the optimal time for the writer to do relevant research and compile external ideas.[4]
In other words, the draft state is the pouring out of thought, creating as much raw material to work with as possible, since most of it will be shaved away during the edit.
Because the drafting state is so impactful to the shape and feel of the result of the final piece, it is critical to get the totality of the idea space on paper ASAP.
Faster Writing
The Outline to Complete Sentence English Prompt allows for lower case, casual writing, which means faster writing. Faster writing means a closer orbit to the core of a thought, and without the ligaments and tendons needed for grammatical writing that are beaten into our brains during schooling it is easier to see if an idea is good by itself or if the writing is window dressing that makes it "look" good.
On Ramp to the Flow State
Outlining is also great for low energy writing, allowing the writer to get into the writing mood without needing to be at peak energy, essentially creating a slow ramping into the flow state. Analogous to exercise, jumping right in to heavy lifting without warming up is just asking for injury. Writing without warming up is a recipe for silly mistakes, or missed conceptual gold.
Wait on the Judge
Finally, by writing in outline format, the critical side of the brain is less likely to be invoked, making it easier to have more wild ideas. This means that the idea space has greater breadth, and creativity is more likely to appear in surprising places.[5]
It's Still 2023
The major downside of this prompt is that it whitewashes the author's voice; however, this can be fixed during the edit phase or during the outline phase with more "complete" outlines that leave less room for model hallucination.[6] In addition, writing in outline feels a bit awkward, but that may be more adaptation than anything. Finally, some outlines perform better than others.
This form of writing is also a form of prompt engineering, along with all of the baggage that comes with that.
With all that said, here's the prompt:
const sentencesPrompt = `Convert this bulleted outline into complete sentence English (maintain the voice and styling (use bold, links, headers and italics Markdown where appropriate)). Each top level bullet is a new paragraph/section. Sub bullets go within the same paragraph. Convert shorthand words into full words.\n\nOutline:\n${text}\n\nComplete Sentences Format:\n`;
And here is the entire command in my GPT plugin I built into Obsidian:
this.addCommand({
id: "outline-to-complete-sentences",
name: "Outline to Complete Sentences",
editorCallback: async (editor: Editor, view: MarkdownView) => {
const text = editor.getSelection(); // get selected text
const sentencesPrompt = `Convert this bulleted outline into complete sentence English (maintain the voice and styling (use bold, links, headers and italics Markdown where appropriate)). Each top level bullet is a new paragraph/section. Sub bullets go within the same paragraph. Convert shorthand words into full words.\n\nOutline:\n${text}\n\nComplete Sentences Format:\n`;
const loading = this.addStatusBarItem(); // alert user of http fetch
loading.setText("Loading...");
const sentences = await this.callOpenAIAPI(
sentencesPrompt,
engine,
1000,
0.7
);
editor.replaceSelection(
`${
this.settings.keepOriginal
? `${editor.getSelection()}`
: ""
}\n\n${sentences}`
); // replace outline with result (with option to keep outline above)
loading.setText("");
},
});
Prompt 2: Summary Generator
The Summary Generator works in the opposite direction of the Outline to Complete Sentence English Prompt. It takes a huge block of complex text and distills it into a blurb. This prompt is functionally easier to edit since the resulting text is approximately 300 to 400 characters. Additionally, since it is more referential to the source material, it is less likely to hallucinate -- the Outline to Complete Sentences Prompt has to hallucinate to come up with punctuation, pacing, words for acronyms, etc.
In terms of implementation, it is very similar programmatically to the Outline to Complete Sentence English Prompt. It uses Metadata Menu to insert it as a key-value for excerpt
into YAML. From there, this excerpt can be surfaced with Dataview or a Content Management System (CMS) like Ghost.[7]
Here is the prompt:
const summaryPrompt = `Summarize this text into one or two sentences in first person format (using "I"):.\n\nText:\n${text}\n\nSummary:\n`;
And here is the full Obsidian implementation:
this.addCommand({
id: "summarize-to-frontmatter",
name: "Add Excerpt to Frontmatter",
editorCallback: async (editor: Editor, view: MarkdownView) => {
const metadataMenuPlugin =
this.app.plugins.plugins["metadata-menu"].api;
if (!metadataMenuPlugin) {
new Notice("Metadata Menu plugin not found");
return;
}
const activeFile = view.file;
if (!activeFile) {
new Notice("No file open");
return;
}
const { postValues } = app.plugins.plugins["metadata-menu"].api;
const editField = async (file: any, yamlKey: any, newValue: any) => {
const fieldsPayload = [
{
name: yamlKey,
payload: {
value: newValue,
},
},
];
postValues(file, fieldsPayload);
}; // post to key with value
const loading = this.addStatusBarItem();
loading.setText("Loading...");
const text = editor.getSelection();
const summaryPrompt = `Summarize this text into one or two sentences in first person format (using "I"):.\n\nText:\n${text}\n\nSummary:\n`;
const summary = await this.callOpenAIAPI(summaryPrompt, engine, 100);
await editField(activeFile, "excerpt", summary.trim());
loading.setText("");
},
});
Conclusion
Amidst the tornado of AI conversation on the global stage, there are minor wins to be had by just making prompts that help people do stuff. The summary prompt and the outline to complete sentence prompt have provided me a ton of utility and I'm excited to continue to refine them as time goes on. NLU has come such a long way, and being able to alleviate tedium all the while increasing the value of a piece of work is a wonderful addition to anyone's toolset.
ADDENDUM: Raw GPT-3.5 Results (READ AT YOUR OWN CAUTION/CURIOSITY!!)
Outline to Complete Sentence English
Input Outline
- first prompt: an outline to complete sentence english prompt
- the outline to complete sentence english prompt transforms lower case outlines into complete sentence english
- why is it useful?
- the purpose of a first draft is to get ideas down on paper and examine their relationships, space they take up next to each other, how complete they are
- also to do relevant research, and compile external ideas
- recommendation use shorthand for tasks for research, e.g. {research: this topic} in the outline
- also to do relevant research, and compile external ideas
- the outline to complete sentence english prompt allows for lower case writing, which means faster writing
- faster writing means stricter adherence to the core of thought
- without the ligaments and tendons needed for grammatical writing it is easier to see if an idea is good or if the writing is window dressing
- great for low energy writing -allows you to get into the writing mood without needing to be at peak energy
- a slow ramping into the flow state
- increases velocity of how much can be written in a day
- you can switch back and forth between the two as you please
- can potentially make you a better texter/short form communicator
- the purpose of a first draft is to get ideas down on paper and examine their relationships, space they take up next to each other, how complete they are
- less likely to invoke the critical side of the brain
- easier to look over and edit when it is time to edit
- thanks to outliner,
cmd-shift-⬇️
andcmd-shift-⬆️
move ideas in real physical space allowing writer to play with flow or easily create parent-child relationships between ideas
- downsides
- whitewashes the author's voice
- i try to fix this during the edit
- whitewashes the author's voice
GPT-3.5 Result
The Outline to Complete Sentence English Prompt transforms lower case outlines into complete sentence English. It is useful because the purpose of a first draft is to get ideas down on paper and examine their relationships, the space they take up next to each other, and how complete they are. Additionally, it allows the writer to do relevant research and compile external ideas. I recommend using shorthand tasks for research, e.g. {research: this topic} in the outline.
The Outline to Complete Sentence English Prompt allows for lower case writing, which means faster writing. Faster writing means stricter adherence to the core of thought, and without the ligaments and tendons needed for grammatical writing it is easier to see if an idea is good or if the writing is window dressing. It is also great for low energy writing, allowing the writer to get into the writing mood without needing to be at peak energy, creating a slow ramping into the flow state. This increases the velocity of how much can be written in a day, and the writer can switch back and forth between the two as they please. It can also potentially make the writer a better texter/short form communicator.
The Outline to Complete Sentence English Prompt is less likely to invoke the critical side of the brain, making it easier to look over and edit when it is time to edit. Thanks to outliner, cmd-shift-⬇️
and cmd-shift-⬆️
move ideas in real physical space allowing writer to play with flow or easily create parent-child relationships between ideas. The downside of this prompt is that it whitewashes the author's voice; however, I try to fix this during the edit.
Here is the diff of the version GPT gave back and the final edited version above
Summary Generator
Input Outline
- a summary generator
- works in the opposite direction of the outline to complete sentence english prompt
- takes a huge block of complex text and distills it into a blurb
- this prompt is functionally easier to edit since the result is ~300-400 characters
- also since it is more referential to the source material it is less likely to hallucinate
- the outline -> complete sentences prompt has to hallucinate to come up with punctuation, pacing, words for acronyms, etc.
- h3: implementation
- very similar programmatically to outline to complete sentence english prompt
- uses metadata menu to insert it as key-value for
excerpt
into yaml- from there, this excerpt can be surfaced with Dataview or a CMS like Ghost
GPT-3.5 Result
A Summary Generator works in the opposite direction of the Outline to Complete Sentence English Prompt. It takes a huge block of complex text and distills it into a blurb. This prompt is functionally easier to edit since the result is approximately 300 to 400 characters. Additionally, since it is more referential to the source material, it is less likely to hallucinate; the Outline to Complete Sentences Prompt has to hallucinate to come up with punctuation, pacing, words for acronyms, etc.
In terms of implementation, it is very similar programmatically to the Outline to Complete Sentence English Prompt. It uses metadata menu to insert it as a key-value for excerpt
into YAML. From there, this excerpt can be surfaced with Dataview or a Content Management System (CMS) like Ghost.
Here is the diff of the version GPT gave back and the final edited version above
I can tell because there is a 1:1 increase in how many emails I get about whatever is hot at the moment, especially from VCs who are basically all social proof gamblers
Thanks to the Outliner Obsidian Plugin,
cmd-shift-⬇️
andcmd-shift-⬆️
move ideas in real physical space allowing writer to play with flow or easily create parent-child relationships between ideas. This creates really fun relationship hierarchies.NB: I recommend using shorthand tasks for research, e.g. {research: this topic} in the outline. This allows you to not have to break flow of writing to fetch something.
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:
- The task of working on a Zettelkasten is nearly infinite -- every Zettel created spawns more Zettels
- As the raw number of Zettels increase, the linking process causes stress from choice overload
- 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:
- Create a unique ID note
- Write a single condensed idea on the card along with a title
- 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…
To Link or Not to Link? That Is the Question
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
- 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)
- 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)
- 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.
a Zettel is an individual note in a Zettelkasten
should I tag this a or b… or neither? Damn.
all of the code in those sections was written by ChatGPT!
in the positive direction this time!
Conjecture
= Guesswork/Hypothesis/Reality FreeCriticism
= 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.
303.
303 posts manually backfilled one by one from Obsidian Publish to Ghost, with great effort and mental + physical expense. But why?
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.
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!).
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)
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
or explore within the same tag
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.
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.
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