Teodor’s public journal


Q: Hey! Should I read this?

A: Perhaps not. Perhaps. I use this page as a low-filter, low-threshold way to get ideas out. Capture ideas, incomplete as they are. Growth and nurturing is a separate process. Filtering, curating, organizing — that’s for later. The reading experience might feel like a stream-of-consciousness endeavor — with less flow, less feelings, less poetic content. In other words, messy, without the good sides of messy. Still, I choose to make this public, because I believe public should be the norm, not the exception.



On product and indirection.

I feel shackled by pressure for specificity. Always be specific. Specific is better. Don’t be vague.

Specificity expels indirection. Indirection is core to design.

If we lazer-focus on the specific, we’ll ignore problems with a longer feedback cycle time than some arbitrary limit.

Emacs ⟂ Product

Statement: “don’t build something for yourself – you’ll ignore users”

Response: “no – DO build product for yourself – but design in the flexibility as indirection. Don’t force your users into your workflow. Doing it for yourself is not workflow design - it’s capability design.”

By building in flexibility — indirection — at the right layer, we decouple the product, and give ourselves leverage.

On fun

I’m better when I have fun.

I have fun when I build stuff for myself and others.

∴ I should build stuff for myself.

Fully integrated feedback loops

Commonly discussed feedback loops:

  1. Cycle time for recompilation
  2. Cycle time for running the tests
  3. Cycle time for a deploy

Uncommonly discussed feedback loops:

  1. Idea-to-sharable-paper
  2. Idea-to-team


Pandoc code blocks

(moved from separate page)

We explore how Pandoc supports embedded code.

We can write Clojure:

(defn act [& commands]
  ;; code

Or Python:

def act(*commands):
    # code

Or even javascript:

function act(commands...) {
    // code


Another morning.

I want trailing whitespace.

Possible solutions:

  1. Find org-mode native solution
  2. Lol, I can just use a big verse. Problem solved. See the bottom of this file.

What about tags?

Outcome - less messy front page.

Right now we’ve got this:

Intent: bring ideas to life. Discuss, sharpen, play.

Status: very much work in progress. Please advance at your own peril.


Possible next steps:

Possible improvements:

  1. Get real title out, don’t use file name as link name.
  2. Separate into sections with tags
    1. “Quite finished stuff” up top
    2. Then categorized content
    3. Then “draft” content
    4. Then untagged pages.
  3. Considerations
    1. Perhaps hide untagged content
    2. Perhaps introduce a tag for content that should not be indexed
      1. Or just ignore content without a play.edn file?

Migration path - opt in.

Backwards compatible path - existing behavior prevails, title is “settable” from play.edn.

Concern - performance.

The root HTML file will now depend on all the play.edn files. Perhaps use SQLite for caching? Not now. I want good performance under scale. Performance is important. I can just opt for manual indexing if the need arises.

Implementation path

Outcome - better titles. Order. First create a play.edn file manually. Then create the proper title for that file. Run index.clj by hand.

On reactivity, speed and whole-system changes


  1. Having a fast Makefile is super nice for when I’m working on a single piece of content.
  2. Just rerunning the whole system is preferable when I’m changing the system. Also keeping track of changes at the same time is probably not required.
  3. When I’m changing the whole system, I don’t really want a file watcher. I’d rather apply the change manually.

So …

I’d like a teod/apply-on-save-mode.

Perhaps I made it work?


Nope. Back to manual teod/apply it is.


Morning / afternoon / whatever.


Retrospective - play.teod.eu

How are we coming along?

  1. I like working with Babashka
  2. But the current process of multiple “thingies” is getting painful
    1. Perhaps I need to consolidate into a single play.clj script with a CLI.
  3. Tags are nice
    1. It’s nice to always think outcome. What do we want to achieve right now?

Next steps?

  1. Have the page command automatically categorize stuff as “don’t mind me”
  2. Group the remaining English content
  3. I kinda wanna explore SQLite
  4. I wanna try out portal
  5. Do I want to be able to run my stuff with both JVM Clojure and Babashka?

Current pages

Page Category aka
https://play.teod.eu/emacs/ Rambling
https://play.teod.eu/aphorisms/ Page
https://play.teod.eu/feedback-loops-api-design-how-it-works/ Article draft
https://play.teod.eu/hourglass-architecture/ Ideas & capture Narrow waist
https://play.teod.eu/opt-in-hierarchies/ Ideas & capture
https://play.teod.eu/orthogonality-enables-optionality/ Article draft
https://play.teod.eu/product-for-developers/ Article draft
https://play.teod.eu/journal/ Rambling
https://play.teod.eu/unix-signals-crash-course/ Article draft
https://play.teod.eu/knowledge-worker/ Article draft

How do we tag?

By form:

:form :rambling
:form :article
:form :explore
:form :unknown

By readiness:

:readiness :in-progress
:readiness :published

By language:

:lang :no
:lang :en

Batch editing tags?

Dump -

distributed ${ARTICLE}/play.edn files are “near” to the article (nice), but tedious to batch edit

batch editing is nice in a table

A normalized model is EAV.

EAV example:

:id "emacs" :title "(Doom) Emacs learning journal"
:id "emacs" :form :rambling
:id "emacs" :readiness :in-progress

What are nice ways of batch editing?

One big text file Excel table SQLite?

How should lines be deleted?

In Dired, simply d the line, then x to apply with confirmation In Magit, c c to commit, C-c C-c to apply

I could simply try dumping all the data into SQLite and see how that works out.

I have:

Metadata per page some pages

So - simple, flat model.

I could build

Files -> SQLite SQLite -> files

Do I want “apply everything” or “apply partial”?

I could implement “apply everything” in terms of “apply partial”

First delete all the play.edn files Then apply partial And confirm changes in Git.

    play.edn is a module declaration
    it declares dependencies
       And binds them to targets
        Maps to root.
    Challenge - link resolution.
        Do I need a redirect “service”?
            Yeah, perhaps I can use redirects.
        I thought I needed magic to rewrite links to target
            But I can generate a companion link site
                    ?link=LINK_ID that redirects

./play API draft

$ ./play2.clj relations :from :files :to :lines
:id "emacs" :title "(Doom) Emacs learning journal" :form :rambling :readiness :in-progress
:id "feedback-design-impl" :title "Feedback loops, API design and how stuff works"


Created the lines mode - and more.

Mode Read? Write? Purpose
:files y y play.edn files is the main storage
:lines y y lines give a concise overview
:table y y table is great for batch editing
:pretty n y :to :pretty is great when devleoping a reader

This almost looks like an hourglass architecture :)

relations interface in the middle.

I’m happy with the design.


Possible talk - dynamic programming

idea - dynaimc programming isn’t lack of types. Dynamic programming is options to do flexible stuff.

Option - work on data structures rather than types. XML - static types for everything, or a dynamic tree? JSON - types for everything? Alternative formulation - serialization for free

Option - dynamic runtime. Dynamic languages often support interpretation / dynamic recompilation

Option - extend language when required. Embedded DSLs are just data (Or macros, but macros can be complex)

Option - use schemas directly for validation rather than types

Examples? Hmm Python? Clojure? Javascript?


Braindump / thought stack

I want to give Ole Jacob a big JSON file he can build UIs on top of


rich entity semantics - “url” “title”

& filter on tags

I want to get more info when I generate pages. This should be possible:

./play.clj page compuational-engineering :title “Computational Engineering”

And it should also write :author-url and :created-at.

I’d like to avoid the watchbuild files

Are they even required any more?

I haven’t used any of them in a long time

Makefile works well

Action: delete em.

I deleted the watchbuild files


Docs fanout factor

For me:

Written for myself 10
Shared with others 1


Working on my own ideas / perception / intent is something I’d like to do with an internal feedback loop.


Hmm, good question.

Well, easy answer. Because I don’t get anywhere as fast ahead through conversation with others.


No, actually, that’s not it.

And amount of written text is the wrong metric

Effort is the right metric

For effort, it’s perhaps 50/50

50 % internal

50 % external.

I prefer writing to thinking when iterating internally.

I prefer speaking to writing in conversation

I think? I’m not quite sure.

I dislike IDEs because in IDEs, plain text and prose is second class

That basically means they are missing Org-mode.

So perhaps “I dislike anything that doesn’t have Org-mode” is better.


Observation: sometimes vague and general is required

I feel shackled by pressure for specificity. Always be specific. Specific is better. Don’t be vague.

This feels like a statement that sometimes a bad abstraction is required to get to a good abstraction. Also, I hate being forced to do stuff.

Emacs is a tool for research that happens to work for code too


refers to https://www.ingentaconnect.com/content/matthey/jmtr/2022/00000066/00000002/art00002;jsessionid=2tqj0na4wh7rw.x-ic-live-01

and https://pubs.acs.org/doi/10.1021/acscatal.5b00538

and https://www.technology.matthey.com/article/66/2/122-129/

And “which is the first subset of Org-mode that should be supported?” https://gitlab.com/publicvoit/orgdown/-/tree/master


Actionable - SQLite as a file system

Should be worthy of a page on its own.

Also paves the way for what I can do with play.teod.eu.

Also perhaps worthy of publishing to the Clojurians Slack? Hmm.


Driving in Troms, with Tjerand and Torstein.

Problem - npx doesn’t work offline

npx seems to look for new versions on each invocation. I can’t use the following offline:

$ cat preview.sh
#!/usr/bin/env bash

npx live-server --no-browser --port=3000

So … what do I want? Just having the dependencies available offline would be nice, really.


  1. Something NPM based. Probably means I need node_modules, package.json and package-lock.json.
  2. Something Clojure-JVM-based.
  3. Something Babashka-based.
  4. Just serving raw HTML in firefox, and triggering a hook to refresh on a keystroke - like I’m doing with Clerk


Discussing note taking systems on the Clojurians Slack

ag is using Org-Roam quite heavily. He separates between:

And says that there’s no semantic difference between those three categories and:

Hmm, I think I’ve actually landed on that same structure myself in Roam. Fleeting notes go on the Daily Notes page. Permanent notes are entities. Project notes are one big hierarchy.

How does that map to play.teod.eu?

Fleeting notes go into the journal. No new entities. Permanent notes get their own page. It should be possible to link to permanent notes! Project notes get a page per project. That page is deleteable or “removable from index”.

Question: “in what context do I want to re-discover this piece later”. Then – establish links to all those contexts.


I really don’t like UPS.

Better editing of play.edn files

I could create some simple Emacs lisp commands for that which shell out to babashka.

How do I split my Emacs lisp code into packages?


How do others do it? I tried looking at the Doom Emacs creator dotfiles, but I didn’t find any Emacs config. https://github.com/hlissner/dotfiles/tree/0df9027010b424410a4622eba54b979c256f0efb/./ I guess his Emacs config is just Doom. What about https://github.com/tecosaur/? He just has a big org-mode file. What about https://github.com/org-roam/? Good. Toplevel org-roam.el. Then (require 'org-id') and others.

I want to learn how to create an Emacs minor mode.


It’s the next step, I think. I know how to do basic stuff, I don’t know how to do interactive stuff. I love how magit works. How dired works. Dired’s view over the file system, the ease of moving around.

So … I probably want a major mode too. Haha.



How can git tell me when a folder was last changed?

Git knows this.

I would like: input folder path, output last changed timestamp.

Purpose: sort, enrich :relations.

Treat :changed the same way as I’m treating :id now. It’s a special tag, and should not be written down. When writing lines back to files, dissoc the :changed property.

Note categories

named ideas have a deeper meaning. They have an URL, and can be linked to.

project journal is temporally indexed. Date up top, topic below. Project-scope rambling.

project problems is a mutable approach to attention design. It does not function as a ledger. Rather, it is meant to be changed. Problem-scope attention design.

journal is the temporally indexed global catch-all thing. Put things here when in doubt. Global-scope rambling.

problems is a global list of things that want attention. Global scope attention design.


How to get nice-to-copy terminal output with GRML ZSH config

teodorlu@teod-t490s ~/tmp/temp-2022-07-15/prompt % prompt off
% PROMPT="$ "
$ echo hello there
hello there


I’m afraid to stop learning

I don’t want to end up stuck. In a context where there’s no novelty. Where there’s nothing I can learn.

What does such a context look like?

Is it closer to a research lab than a product company? Can there be both?

Reading Elements of Clojure

ec Nextcloud/store/elementsofclojure.pdf

“Indirection is abstraction”

Indirection, also sometimes called abstraction, is the foundation of the software we write. Layers of indirection can be peeled away incrementally, allowing us to work withint a codebase without understanding its entrirety. Without indrection, we’d be unable to write software longer than a few hundred lines.

Huh, this names something I’ve seen. Python scripts written by civil engineers. One big for loop, with some clauses.

Advantage: straightforward. Disadvantage: Inflexible. Lesson: use indirection / abstraction to make code flexible.

SJ train Wifi allows SSH traffic




Participating in public

I wrote something I thought was of value:

  1. Make sure your note taking system supports your goals. My goals: (A) assist my learning, (B) easily share content and get feedback from others.
  1. When you produce content, consider (A) what you want to achieve by producing the content, and (B) how you want to find the content later.

  2. Use one global namespace for named concepts. Category / taxonomy / tags belongs in metadata.

Why the goals? If your system supports your goals, you will continue to use it and get value from it. If your system doesn’t support your goals, it becomes tedious to use, and you’ll abandon your notes.

I encourage you to put your notes publicly on the web. Public notes have URLs, and there’s no easier way to read content. You’re going to remember notes.yourname.com/THING, or just go via notes.yourname.com to list / search.

My information architecture consists of named concepts, journals and metadata.

Named concepts is the top level. Wikipedia uses this structure. There’s one global namespace with sufficiently qualified names. You are going to remember your note by this name. Disambiguate in your global names.

Journals are organized by date. The advantage of journals is that you don’t have to name anything. In general, it’s nice to start with a journal, and collect named concepts on demand. Journals don’t have to be discoverable.

Metadata helps you discover and index your notes. Categories and tags go here. But don’t go nuts on categorization, think about what those categories should achieve. Remember the fact boxes on Wikipedia? Those are driven by concept metadata. Sometimes it’s better to embed a table or a nested list on a concept page than introduce metadata. “Is this helpful to understand the concept?” - put it on the page. “Is this helpful to find/index your content?” - it’s metadata.

Let’s say you want to learn FUSE (https://en.wikipedia.org/wiki/Filesystem_in_Userspace). Create a journal page for learning FUSE, and tag it as “open problem”. Make sure you can list open problems. Each time you’ve got some time, open your FUSE journal, and work to understand something. Read the man page. Read wikipedia. Read the source. But annotate! Take notes in your journal as you go. When you revisit your FUSE journal, you can easily rediscover where you were last time, and decide where you want to go next.

Didn’t get any comments.

Am I dissatisfied? Doesn’t feel that way. Am I surprised? Yes, perhaps. That’s imprecise. Yes, I’m surprised. This is something I believe strongly in.

Am I disappointed? No.

Got the dots working

  1. create dots
  2. realize build system wasn’t yet configurable
  3. try to go for perfect
  4. ditch perfect, go for achievable instead
  5. Be happy.




bimodal strategies

deep work, tactical initiatives, strategic initiatives

Applying bimodal strategies to the design of the daily effort.

produce documents

Squirreltime – topic of stuff :)

Burnout, meaning and deep work. Reflecting on the last half year.

A perfect day

How is a perfect day structured?

copied from Roam notes

How do I want to work?

Principles to prevent burnout, mess and loss of the strategic picture.

copied from Roam notes



I want Live.js to work on this site

Live.js: https://livejs.com/

I’m hosting with Cloudflare.

Problem: there’s no live-reload.

Diagnosis: Cloudlfare sends the same headers on each request. That’s meant to disallow caching. But in my case, it causes cache invalidation to never happen – opposite of the intended effect. I could fork live.js if I want, it’s small.

To get Live.js working with Cloudflare, I need Cloudflare to produce correct etag headers. That means I need to disable some Cloudflare stuff.

General Cloudflare Etag docs: https://support.cloudflare.com/hc/en-us/articles/218505467-Using-ETag-Headers-with-Cloudflare

Cloudflare pages dog, mentions etags: https://developers.cloudflare.com/pages/platform/serving-pages/

Do I have live reload in production now?

Pretty pleeeease


Still no etag header on the responses.

Another fix

is it automatic or not?????

It’s actually automatic. It works!!!




How do contribute when you don’t know what you’re doing

Also, “how to help”.

From Aphorisms:

10 - When in doubt, do that which builds trust.

11 - When still in doubt, do that which reifies and distributes intent.

12 - When still in doubt, reduce WIP.

13 - When STILL in doubt, improve your specific & general feedback loops.


Target audience: xxx

When taking notes, why not just copy-paste from wikipedia?

Because taking notes is 90 % for the process, and only 10 % for the resulting artifact.

Because simply copying does not help you reify your taste. It does not help you to cultivate your taste.


wanna code



se Terminalen: Hvordan løpe med motorsag. Jeg har lyst til å bruke dingsen til Magnus. Det hadde vært fint. Men … hvor var det vi gjorde det? Vi flyttet det til et Iterate-repo, vi.


On the bitter aftertaste of cultivated aesthetics

“Cultivate your aesthetic”, visa said. I wanted answers. I wanted a preference. So I figured, Okay, let’s try that. Let’s dig in.

I had no idea what that little germ of an idea would do to me.

Now, it has changed how I think. I find more joy, meaning, purpose and connection in each day. I enjoy doing my work. I’m not doing it for somebody else, I’m doing it for me.

Yet — at times, the devil in me shows his face. His strikes are more powerful. His tongue sharper, his arguments bear more conviction than before.

I realize that I cannot be only kind.

As I started to write today, I expected to want to explore bitterness. Bitterness at lack of quality. Bitterness when those around me don’t care.

I had a lang walk+talk with Sindre today. We talked about things I’m frustrated with. (and we bumped into Ida, which was fun)

I have this model of human relationships. Your relationship with someone has three attributes:

  1. Trust
  2. Shared sense of quality
  3. Shared intent

I find that trust and shared intent can be built. And building those are sort of … easy. Well, it’s not exactly easy. But it’s soluable, in the words of David Deutsch. It’s work. It’s something you can do. Improve trust and shared intent every day, and you’ll succeed. (or figure out that this is someone you don’t want to work with)

I digress.

I don’t think shared sense of quality can be built. I think shared sense of quality is discovered. You figure out what someone likes, explore their kneejerk reactions. What do they deliver, when given freedom? Is it any good?

Making an explicit effort to cultivate my own aesthetic has sharpened my inner critic. I see clearly what I like and what I despise. And my reaction to content without substance is bitterness and disgust.

Is this my new normal? Is disgust the price to pay for joy? Does a tree with branches reaching to heaven necessarily need roots anchored to hell?

We’ll see.

Oh, we’re not quite done. The eagles have come, saved the day, and we wake up in Rivendell.

I actually feel good now. Being dead serious, actually honest about that sense of quality. I felt like an ass when I was in the heat of the moment. Now I feel … relief. I feel good. I didn’t expect that.

I bet there’s a lesson in here somewhere.

Until next time,


we wake up again, this time in the Shire. Yet Another End That’s Not An End.

I read this:

feeling proud of your work is critical for any ambitious/high-achieving person. for this type, it’s not about the hours put in, it’s about the *feeling they get out* of doing the work. and if they’re not interested in the work, it’s hard to make it phenomenal and be proud of it.

— Isabel⚡️ (@isabelunraveled) November 7, 2022

The War of Art introduces “territorial orientation”. Here’s a quote from the chapter The Definition of a Hack:

In other words, the hack writes hierarchically. He writes what he imagines will play well in the eyes of others. He does not ask himself, “What do I want to write? What do I think is important?” Instead, he asks “What’s hot, what can I make a deal for?”

The hack is like a politician who consults the polls before he takes a position. He’s a demagogue. He panders.

“so what?”

Yeah, that’s the feeling of quality and lack thereof. The joy of doing something worthwhile, and the disgust of wading through swamps.

“so what, you feel like complaining?”

No. I like where I am. I like where I’m going.

And I like that I don’t like everything I see.

bitter can be good. Ginger. A good beer. Grapefruit.

👋 talk to you later,


We had some snow! Now we have some gray stuff.

cond-> confusion

I expect the following to evaluate without crashing.

(cond-> (list 1 2 3)
  number? inc)

Do you know what? It crashes! Who would have thought.

1. Unhandled java.lang.ClassCastException
   class clojure.lang.PersistentList cannot be cast to class java.lang.Number
   (clojure.lang.PersistentList is in unnamed module of loader 'app';
   java.lang.Number is in module java.base of loader 'bootstrap')

I thought

(cond-> form condition transform)

was equivalent to

(if (condition form)
  (transform form)

, but it appears I was wrong. Not sure why.



How to ask for stuff: in public or in private?

Proposed principle: don’t ask people for stuff in public.

Why? I was in an E-mail chain with five other people. I don’t like those E-mail chains.

Proposed principle:

  1. Provide information and invitations in public
  2. Ask for stuff in private.

Why? It decouples “is this disrespectful” from other questions as “what is good?” and “what is practical?”.


but why?

Why bother with all this collective knowledge management stuff?

Watching a video where Werner Hetzog discusses Mike Tyson’s interest in old dead french rulers, I get the urge to write, to model, to map out.

but why?

Because it means something. I’m not interested in making Wikipedia 2. I’m interested in a curated, subset of the knowledge, values and culture of the world. And I want that subset do do something.

Not just describe some facts. The knowledge should have a function. A purpose. The knowledge should be a source of good questions.

I don’t just want to put all of history on play.teod.eu. I want interesting things. Documents can be interesting. Art can be interesting. Programs can be interesting.

If you will, we get stuck in a tautology. Interesting things are interesting. No shit!

But perhaps the systems thinking and quality aspects are less common. A way to surface interest is to provide a thread of interest. Therefore, I want threaded interest on this site. 🤔


Electric UI for always-live content sites

Electric: https://github.com/hyperfiddle/electric

With Electric, I can write a backend and stream updates to a frontend. I could use that to serve & stream updates.

How? I could use a babashka file watcher to trigger signals for reloading a specific page. Then Electric just makes the rest work.


Competence - Quality - Aesthetics - Taste — it’s a scale

Competence Quality Aesthetics Taste
Skills Outcome effectiveness what’s the right outcome? why are we even here - where do we want to be?

Left: Objective, specific. Right: general, vague.


Idea: file explorer on bb

codename filebbrowser

  1. Navigate around quickly - be like dired with Doom’s (:evil +everywhere)
  2. Support jumping from/to a normal CLI
  3. Support some Clojure
    1. REPL expressions
    2. Put tap> to good use, perhaps persist
    3. Dynamic vars for current directory


Consider having a “process stack” – start filebbrowser from the terminal, and put terminals “on top”, then start filebbrowser on top of that (again)

Support FZF UIs natively

Idea 2: use a client/server model instead

  1. Use a persistent JVM
  2. Connect multiple clients
  3. Keep the clients as light as required
  4. Automatically start a server when required – like Emacs w/client & server

Idea 2.1: JVM server, bb clients. 🤔

Criticism: this is just reinventing Emacs, Dired and vterm/eshell


But building on Clojure (bb/jvm) gives a different set of tradeoffs.

Idea 3: JVM server, Emacs Lisp client


Then I don’t have to reinvent Emacs. Aaaand I can “move around” more quickly.

Observation: hierarchy depth 3

date project / option theme

This way of dividing is sufficient for lots of stuff.

organization project initiative

Sword of truth, shield of virtue

Truth slices up what’s wrong. Virtue keeps you in check, lets you avoid harming yourself and others.

Write about something important

That’s right!

  1. Reflect on what’s important
  2. Write about that
  3. Reflect on your writing and whether it’s important


Aesthetics is hard.

Do you dare be the judge of quality?


Leveranser, mål, kvalitet, tekst, surr og ergonomisk arbeidsflyt

Har du egentlig gjort noe fornuftig i dag? Jobber vi egentlig på det som betyr noe? Når du uttrykker skepsis til struktur du ikke ønsker, er det fordi strukturen er dårlig, eller fordi du ikke gidder?

  1. Leveranser er til for å få noe ned på papiret. Hvis du misliker leveranser, kan det generaliseres til at du ikke ønsker at noen skal dømme deg for noe, og at du heller vil ha fri.
  2. Mål. Grunnen til at vi har leveranser i det hele tatt, er for å nå mål.
  3. Vi kan nå mål så fort som overhodet mulig, eller vi kan nå mål uten å kompromittere kvaliteten vi leverer. Jeg har ikke tro på å “nå mål så fort som overhodet mulig”. Det er ekvivalent til å dra for å ta knebøy, for så å ta ett lett sett og sitte på mobilen. Gjør det skikkelig. Og hvis det er vanskelig? Perfekt. Da har vi faktisk et verdig mål å oppnå. Et skikkelig problem, som ikke er trivielt å nå.
  4. Tekst. Tekst er magisk. Tekst gjør det mulig å lage leveranser av alt. Det er en sannhet mennesker har kjent så lenge vi har hatt kultur. Hulemaleriene lot oss heve oss over instinkt og dele noe syntetisk, noe vi har laget. Hulemalerier er tekst. Bokstaver og litteratur er tekst. Og du klarer alltid å skrive noe. Og når du har skrevet det ned, kommuniserer det noe til andre mennesker. Bruk tekst. Tekst lar deg lage leveranser av alt. Tekst lar deg gjøre mål konkrete. Tekst lar deg levere kvalitet.
  5. Hvis vi ignorerer leveranser, mål, kvalitet og tekst, hva gjenstår? Surr. Sirkus. Det kan godt være koselig, og lekent. Men vi tar ikke oss selv seriøst. Vi kunne levert så uendelig mye bedre.
  6. Tekst har en plass for å lage ergonomisk arbeidsflyt. For lite, og vi har surr. For mye, og vi har byråkrati. Bruk tekst til å peke deg selv framover. Bruk tekst til å definere “framover”. Bruk tekst. Bruk tekst til å ta kontroll. Ikke gå i søvne, tenk.

“it’s rich” – “it has texture”

if you look at the lives of individual creators, it’s so rich!

– Mark, Metamuse (podcast), episode 40

So … wealth is texture? Wealth is rich in texture? Variability, details, individuation?

Rather than boxed, bland, plain, smooth?


we either create theory or apply theory

we either construct language or apply language to gain value in context.

See Software architecture as langauge construction or Capability, feature and assembly.

In Norwegian, we don’t distinguish between “good” and “great”.

There’s one word: “bra”. And its meaning depends on who you’re asking.

But there’s a difference between “bra” and “bra”. We rarely emphasize the word in relation to the other words in the sentence.

The corpus of the Clojure newsletter is interesting.

Every week, Alex Miller brings together content from the Clojure community in Clojure Deref – the Clojure newsletter. This is an interesting corpus of free resources. Perhaps something can be done for discovery.

List of lists

List of things I find good. List of things I find bad. List of things I want to stay the same. List of things I want to change.


List of good

List of bad

Time to be bad?


Bad, for whom?

For myself. For my self respect. For my team. For my organization. For my customer.


as a programmer, I want to skim a git commit log and get something.

at least let me know easily whether the change was “fix bug” “add stuff” or “move things around”

f fix: fix stuff things were broken, now we’re good
a add: add stuff TOOL handles some PROBLEM better now.
r refactor: move stuff around internals, no observable changes.
d doc: doc doc changes only

your movement is limited, use is wisely

If everything is moving all the time, you cannot move yourself. If nothing around you can ever move, you’re stuck.

In other words, it’s bad for you if everything moves, and if nothing moves!

your personal workflow. You have a finite amount of attention you can spend each day. You can use that attention to follow movement, or to cause movement.

follow movement consume
cause movement create

How do you want to spend your day?

cohesive movement

Fragmented movement is when everybody is waving their arms faster and faster and faster, but the things that matter stay the same.

In cohesive movement, internal structure enables the desired outwards movement. For example, car frames or aircraft bodies are stiff, but move fast.

move yourself, help others move.

move yourself Support, challenge, carry carry
help others move Support, challenge, carry support

the corpus of the Clojure newsletter is still interesting

making that … thing … explorable would be good.


  1. Just follow HTTP
  2. Provide it through redirects

Can I provide HTTP redirects with javascript? I’d like to.


Isn’t that how the DOI thing works? Or perhaps I should have a small redirect service that does the right thing on the HTTP level?

I want full width tables for play.teod.eu

.. and I might want to just generate the HTML and CSS myself.

But I’m not able to!


At least not right now, within my current skill ceiling and available time. And I’m also hesitant to fork away from Pandoc.

wait …

what about … forking pandoc? starting from pandoc and building?



  1. haskell

but .. I could I extract the current pandoc html writer and work only with that? Use the rest of pandoc as a binary, and write only the json->html piece?

Perhaps “transpile” from haskell to clojure?



Good code is scale dependent

I’ve sometimes felt annoyed working on code bases, seeing stuff that can be improved everywhere. Then, later I’ve realized that I was focusing too intently on stuff that doesn’t matter.

The right layer to focus on was 2 or 3, I was stuck on 1.


charity, grace, joy

The last words of Learning to play support. I feel like they carry meaning. Or carry something that I don’t quite know yet.

charity. Take the first step. Reach out your hand.

grace. Accept error. We are not perfect.

joy. Live, let live. Love. (“I want to know what love is” or “All you need is love”?)

innsats og effekt

hva: skal vi fokusere på innsatsen vi legger ned, eller effekten den innsatsen har?

produkt: outcome over output. Hvis vi ikke fokuserer på produktet, blir alt bare tull.

team: innsats OG outcome. Jobben vår er å lage bra ting, da må vi vite om tingen er bra. Men fra dag til dag er jobben vår å legge ned en innsats som gjør tingene bedre. Vi kommer på jobb, skal legge ned en dags innsats, så skal vi gå hjem.

teamprosess: innsatsen er alt. Hvordan vi jobber er ufattelig viktig!

the memex is here: it is the world wide web

  1. information deserves to be free
  2. put knowledge in bite-sized definitions (theories) + motivation about why one should care about this
  3. compose bite-sized definitions with playlists – a playlist is an ordered list of links


Q: what’s the right interface for making microtheories?

Q: what’s the right interface for making knowledge playlists?

Microtheories need to be good explanations. Examples of good explanations:

it’s worthwhile to build your own little memex

a “little memex” is your own corner of knowledge. you curate the index. you create and link your nodes. you can refer to and build on other memexes, but the act building the memex is the reward in itself.

your memex should live on the web

microtheories deserve its own URL. others should be able to leverage your little memex.

your memex is composed of microtheories and knowledge playlists

a microtheory is a bite-sided deinfition, and motivation for why it matters.

a knowledge playlist is an ordered list of microtheories.

the act of building your own little memex is to explore your curiosity and journal about your experience.

  1. what are you curious about?
    1. write that question down.
    2. Breathe!
  2. find an answer
    1. write that answer down.
    2. Breathe!
  3. and an action
    1. write that action down.
    2. Breathe!
  4. Listen to yourself.
    1. Breathe.
    2. Do you want to do the action?
    3. if yes, consider doing it.


build your own little memex with babashka



OLORM: lag en subkommando, få ting gjort

Flyttet: https://serve.olorm.app.iterate.no/o/olorm-7/

Norvig and Pitman on good programming style, via Jack Rusher:

Source: https://twitter.com/jackrusher/status/1623367128635084802


Jeg leser Homesteading av Jack Rusher.

I dette asnittet blir jeg sittende å tenke:

I managed to sidestep the worst of those concerns by practicing something I think of as “attention hygiene”:

Jeg har tenkt mye på oppmerksomhet mens jeg har laget denne siden. Se feks attention design.

Jeg tror det er grunnen til at jeg liker å holde på med disse greiene. Jeg tar kontroll over min egen oppmerksomhet.



datomic was open sourced

wanna code




Electric Clojure, Datomic and Quil. And nextjournal/clojure-mode. Done right, this could work for kids!

But local setup & installation is too complex. So I’m kind of curiuos about trying this myself.

This would essentially be a cheap maria.cloud clone. So … why?

  1. Because it’s a worthwhile challenge, and I’d love to be able to build something like that.
  2. Because my overwhelming experience teaching kids to code (Lessons learned teaching Elm to kids) has been that being able to control (A) the subject matter, and (B) the learning experience is essential. So even if there is a “good tool” it’s not necessarily the best tool for teaching what you aim to teach.


  1. I could make an introduction to Clojure that I’m interested in giving with this material.
  2. I could teach more kids to code – this time Clojure rather than Elm (because why not)
  3. The quil-system itself
    1. I wanna learn Quil
    2. I wanna learn Electric Clojure
    3. I wanna learn Datomic
    4. I wanna experience writing a moldable systems (see for instance Hypertext: The medium is the message and Build Your Own Little Memex with Babashka, both drafts)


dynamic runtime, high performance, instant startup, pick two?

thing dynamic runtime high performance instant startup
Clojure 1 0.8 0.2
Go (programming language) 0.4 0.8 1
Rust (programming language) 0.1 0.95 1
Javascript 0.8 0.5 0.8
Babashka 1 0.4 0.9

clojurians slack post

Idea: of “dynamic runtime”, “high performance” and “instant startup”, you can only pick two. I rated (very subjectively, hand-waving) some runtimes from 0 (bad) to 1 (good).

Would you agree? Are there counter-examples? Does this have to be the case?

How would you score runtimes you use on the three axes?

My speculation:

I know borkdude has experimented with starting up Sci and JVM Clojure simultaneously, using Sci for instant startup, and moving over to JVM Clojure for JVM optimizations / compilation, but I don’t think that effort got further than experimentation. Another challenge is that sci isn’t exactly the same as JVM Clojure, so I suspect one could get nasty bugs if the two runtimes “diverge in execution”.

I also wonder if Common Lisp might score high on all three. But I haven’t used CL in anger, so won’t blindly guess a score. Common Lisp hacker opinions welcome! I’m also curious if Clojure is better than Common Lisp on any of these axes. Which further begs the question about why some of us prefer Clojure over Common Lisp, and if that merits a fourth axis.

10:31 teodorlu:

I also wonder if Common Lisp might score high on all three.

Perhaps this is more a matter of effort than anything else. If we had infinite resources, perhaps we could “just” invent a JVM that worked like this. Start out with a simple statically compiled interpreter, then move to compile & JIT optimize stuff. But I’m speculation, I’ve never written anything like the JVM or Sci.

Related, perhaps “jvm bytecode” is a better target for this than “Clojure”. So that there are different JVM bytecode interpretation strategies with different performance characteristics.

updated table

I had to shorten the column names to make it fit:

column name short column name
dynamic runtime dynamic
high performance performance
instant startup startup
instant build build
ecosystem ecosystem
thing runtime performance startup build ecosystem
Clojure 1 0.8 0.2 1 Maven
Go 0.4 0.8 1 0.7 ?
Rust 0.1 0.95 1 0.1 ?
Javascript 0.8 0.5 0.8 1 NPM
Babashka 1 0.4 0.9 1 Graal
Cherry “no” “as JS” “yes” 0.9 NPM
Nbb “good” 0.9 1 NPM
Fennel “good” “as luaJIT” “good” “good” Lua+C FFI
Zig Zig+C ABI



moved to own page: execution for developers.

are the overall priorities right? are we doing the right things to hit the overall priorities?

execution for developers

what things should I be making progress on today? have I made progress on the things I should today?

a process has a job to be done

if you don’t know a process’s job to be done, you

  1. Either haven’t done your job as a leader understanding why things are being done,
  2. or the process should not be done.

As a leader, you need to know why things are being done.

This is a burden, but also a fine way to judge everything. If you know why initiatives are worked on, you can judge whether the initiative works as it should

the job to be done for a meeting

the job to be done for XX

prompts for learning

Easy mode (awareness):

Hard mode (awareness + actionable):


  1. Find someone you trust.
  2. Write three or six answers, your choice.
  3. Share your answers with the person you trust.


  1. Build trust
  2. Exercise growth mindset
  3. Exercise coachability

13:06: moved this into prompts for learning.


not even wrong

I want to write something about product management and good theory. Tie David Deutsch and Marty Cagan together.

Core: the skills of a good product manager is theory building in practice.


paulus asks about time

Teodor says “yeah, lots of time.”

remember to look at federated wikis


Watching Maria: A beginner-friendly coding environment for Clojure

by Dave Liepmann.

I liked this part:

Why learn to code?

#{:create :play :explore :share}

Create. Play. Explore. Share.

That’s right. Matches the name of my site (play.teod.eu).

baby steps comprehensible and tangible


Is this all there is?

Effort required. Consumption and learning conflated.

I want a Pandoc benchmark

How much of the time spent is process startup? How much is actual document conversion?


Not even wrong

I feel like this is the problem every XXX time. Lack of theory causes confusion. Conflicting theories cause communication to break down.

Though—as I write this, I realize how often it works well, but then theory (shared intent) is implicit. When theory works, it is invisible. When theory works, it is the structure of our communication.

When theory works, it is the structure of our communication

deps.edn cheat sheet

Context: I’ve previously struggled with running tests on Michiel Borkent’s projects. Neil, Babashka.


  1. How do I get a proper REPL with the right aliases here?
  2. How do I run certain tests from the command line?
  3. How do I run all the tests from the command line?
  4. How do I run tests from a REPL?

I want to fix this by getting more familiar with the `clj` command line interface. So here is a selection of commands.

Run a specific var from the command line

$ clj -A:test -X cognitect.test-runner.api/test :vars '[babashka.neil.dep-upgrade-test/dep-upgrade-test]'

Test runner source



(defn test
  "Invoke the test-runner with the following options:

  * :dirs - coll of directories containing tests, default= [\"test\"]
  * :nses - coll of namespace symbols to test
  * :patterns - coll of regex strings to match namespaces
  * :vars - coll of fully qualified symbols to run tests on
  * :includes - coll of test metadata keywords to include
  * :excludes - coll of test metadata keywords to exclude

  If neither :nses nor :patterns is supplied, use `:patterns [\".*-test$\"]`."
  (let [{:keys [fail error]} (do-test opts)]
    (when (> (+ fail error) 0)
      (throw (ex-info "Test failures or errors occurred." {})))))

Open question: do I need to specify -X even though it’s in the alias??

Yes! Here’s how:

$ clj -X:test :vars '[babashka.neil.dep-upgrade-test/dep-upgrade-test]'

Can I run that from a REPL?



  1. Fikk god tilbakemelding på mikrobloggeriet.no. Prøvde å jobbe litt med det, ba om innspill. Fikk innspill. Gjorde endringer basert på innspill.
  2. Fant You are in a maze of deeply nested maps, all alike (av Eric Normand) etter litt hjelp fra en trivelig fyr på Clojurians Slack.
  3. Har lyst til å komme videre på Memex-sporet. Men jeg tror nå er tiden for å bygge—ikke tiden for å snakke om bygging. Jeg har noe bra på vei flere steder. Her på play.teod.eu. På mikrobloggeriet.no. Og på det interne kunnskapsssytemet til Unicad.
  4. Hypotese: ferie er urettet nettverkssøk. Jobb er rettet arbeid mot mål og milestener. Ferie er å kunne navigere fritt over et nettverk.
  5. Læring krever innsats. Jeg bryr meg om at folk skal kunne lære ting. Men jeg gidder ikke bruke tid og innsats hvis jeg ikke får noe tilbake. Gjør noe! Ta initiativ! Demonstrér at du tar dette seriøst! Ikke bare sett deg på ræva og vent på at gode ting skal skje med deg. Det er ikke noe demonstrasjon på nysgjerrighet. Tvert imot, det er nøyaktig det motsatte.


Judge the quality of the part for its contribution to the whole

When you’re in the weeds, you’ll have to regularly step back to see what you’re doing. In which bigger game are you playing a part? How will your part be used? How will your part interact with other parts? Make some examples. Then jump back and forth between the examples and the weeds.

Doing this, you’ll jump between the roles of “maker” and “critic”.

A “read it later” strategy that works - another take

I suspect I want to keep a reading reference log.

  1. Temporally organized - dates.
  2. Can be enriched with attributes and values.
  3. Has a notion of “effort” / “significance” built in. For example, today I spent some time looking into https://julian.digital, which covers topics I care about in a tasteful way. I spent some time browsing and reading. That effort means something. How much time has I spent on this resource? effort-on-resource avoids cheap signaling. (proof of work)


referencelog? readlog? remotelog?

I’m not quite sure.

Browsing experience: Must be possible to “collapse” views. Collapse into days, collapse in other ways.

flog flog.teod.eu

flog—a tool for remixing


Three libraries for writing


Memexes - a status update

Hi, everyone!

I’m super excited to see that so many people choose to join this channel. I expected to be able to spend more time on memex tooling for people who like to write babashka scripts, but I’ve been busy with work. So here’s a status update.

motivation: a better way to build knowledge, applicable to real-world projects. I’m sick of trello. Sick of churning out tasks before we really know what we’re doing. I’m also sick of running full speed ahead with no idea where the team is going. Is there an alternative? I believe we need:

  1. To treat building knowledge as seriously as we treat building software. It pains me to see the effort that goes into writing source code, while at the same time documentation is viewed as an afterthought.
  2. Better tools for building knowledge. With source code, I can jump into a project, make an improvement, and push it. With knowledge, I don’t feel like I’m able to do the same when I’m working with others. I can quickly take notes for myself, but I cannot easily use those notes to work with the rest of my team.

collective knowledge management in practice: does using a memex work? I want to build tools for managing knowledge as I’m using them day to day. My deliverable this far has been text in hyperlinked documents. I’ve been able to get teammates to contribute text to hyperlinked documents in two cases: for our planning system in the startup I’m working on (private), and in an initiative for technical blogging with colleagues (public, source code, live site, all in Norwegian).

the first pain point: converting documents from various formats to HTML. In both cases, I’ve had to write some kind of system to convert text from plaintext formats like markdown and org-mode to HTML. So far, I’ve based all that conversion on Pandoc. I’ve approached the pandoc conversion in a few different ways. Pandoc can convert files directly, with commands like pandoc -i document.md -o document.html. Pandoc can also work on markup as strings directly:

$ echo 'hi, _there_!' | pandoc -f markdown -t html
<p>hi, <em>there</em>!</p>

Though Pandoc usage through shelling out has its limitations. For a small document conversion, I typically get a response in ~30 ms. For a large document, I it takes 200-300 ms to get a response. For my use, that has necessitated some caching. Especially when the amount of documents grows large. On play.teod.eu, I currently have 351 documents.

a pandoc wrapper for babashka scripts. So I’ve written a pandoc wrapper. Nothing serious, yet. But I’m gradually able to reuse more code each new time I need to convert documents. If you’re interested in helping out, I’d greatly appreciate feedback from real usage! Example usage of the current iteration:

(require '[teodorlu.pandoc.alpha1 :as pandoc])

(-> "Hi, _there_!"
;; => "<p>Hi, <em>there</em>!</p>\n"

next steps? So, where does the journey lead? Right now, I’m thinking links. I’ve been able to get 7 colleagues to start writing content to learn things and plan projects. That means we’ve produced a little body of work. We’re starting to feel the weight of that content. What have we actually written? I think we can improve that with better tools for linking. A first step could be a FZF-powered command line interface. Something like this:

$ link --format markdown
# ... select Simple Made Easy with FZF ...
# Then this is printed:
[Simple Made Easy](https://www.youtube.com/watch?v=LKtk3HCgTa8)

That’s all for today. Hope you all have a great day!


Trust vs evil

Wrote a text and moved it over to its own page: Trust vs Evil.



Got a nice comment from @PEZ about my thouhgts on Trust vs Evil. Evil, not being constrained by honor and moral, has a larger pool of possible actions.

Wrote some more titles, but I’m leaving those for now:


“testing” er feil ord

Det er feil modell. Det gir feil assosiasjoner. Det er ikke det som skjer.

Så hva er det som skjer? Vi lærer. Steg for steg. Vi lærer hvordan bibliotekene vi bruker fungerer. Vi lærer om programmeringsspråket vi bruker. Vi lærer om mønstre for å organisere kode som fungerer godt eller dårlig.

Vi bygger teori og praksis. Teorien handler om denotasjon og definisjon. Teorien er hva vi ser. Teorien er språket vi bruker. I praksis må vi velge hva vi ønsker å gjøre. Vi må velge teori som passer problemet. Og vi må gjennomføre. Teori uten handling er verdiløst.

“Gjør noen greier, kast det ut! Nå tester vi, dere.”

Nei nei nei! Poenget er ikke å bruke testing til å kunne la være å ta stilling til kvaliteten av det vi har laget. Vi er fagfolk. Hvis vi ikke bryr oss om kvaliteten på produktet vi lager, kommer ingen til å gjøre det. Dette er teori. Teorien velger vi å tro på eller ikke. Vi får ikke “testet” om vi er gode på programmering når brukere bruker produktet. Brukerene jobber med produktet, ikke med koden. Vi får ikke “testet” om vi er gode designere når brukeren bruker produktet. Vi får sjekket om brukeren oppnår de målene brukeren har.

Målet med å sette produktet foran folk som skal bruke det er ikke å vurdere hvor gode vi er på programmering og design. Det toget har gått. Målet er å se om produktet lar brukeren oppnå det brukeren vil!


Coding for fun? Or not?

I like creating stuff. Programming is a nice tool, but it’s not necessarily a goal in itself.

Create music Overtone
Create visuals Quil

Perhaps I should challenge myself on creating new kinds of things.


I asked Clojurians Slack for reading recommendations

Thread: https://clojurians.slack.com/archives/CBJ5CGE0G/p1711268565351239


“looking for books or papers?” Both I guess? I’m not a heavy reader (yet).

Recommendation: Hyperion cantos (by Dan Simmons).


Three Body Problem, Book Of The New Sun. Malazan Book of The Fallen. Dune.

From 40k, consider Ciaphas Cain or Eisenhorn. Elric of Melniboné.