A Tinderbox solution to organising a Zettelkasten?

Thanks for the analysis, @eastgate. Your third solution may work for some, but doesn’t really replicate Luhmann: the branching could go many more places deep (21/3d26g53 was apparently a real card, discussing Habermas). And while it solves sorting (the original problem of the other thread), it precludes the other benefit of using a computer and software that allows for reordering the notes without breaking links since there is a permanent ID—one would need to manually change all subsequent cards if the order was changed.

Not sure if I understood #2, but if I did, then again it goes against the Luhmann approach: you don’t want to be making a Table of Contents for the whole collection because related and linkable notes are often dispersed. The point of the address is to provide a door in to the collection using the Keywords Index, and then exploring via note sequences and links thereafter. But maybe I misunderstood.

So far, it seems that #1 remains on top for purposes of export.

The table of contents can be assembled by the computer. But you know what you prefer!

It seems to me that Mark B’s solution 3 is getting you closest to what you want to do.

The following is tentative, so please ignore if you don’t find it helpful or if I’ve missed something obvious, but…

As far as can see from your other post, if you take away the commas, your numbering scheme is actually just a regular sequence of numbers and letters. If you made the following changes:

a) all numbers are given leading zeroes (the further down the hierarchy, the fewer zeroes are needed), and;
b) you translate the numbers with commas into decimal numbers, while giving the numbers without commas a .0 number, then

you’d be able to sort on the UUID.

e.g. the following numbers from your current scheme are not currently sorted properly, but if you made the translation (to the number after ->)

  • 0_11,2a5 -> 0_011.2a05
  • 0_1,3a5 -> 0_001.3a05
  • 0_1a5b7a -> 0_001.0a05b07a
  • 0_2a5f3g1 -> 0_002.0a05f03g01

and will sort in the Finder as follows

  1. 0_001.0a05b07a
  2. 0_001.3a05b3
  3. 0_002.0a05f03g01
  4. 0_011.0a05

which is what you’re after (I think)…
(If you have commas at levels below the first one, then you’d repeat the ‘make it a decimal’ trick.)

Obviously, it doesn’t matter whether you think you’ll need the ‘decimal’ numbers as 001.1 or 001.001, as long as you do the same thing every time.

The example you give from Luhmann would simply be 021/003.0d026g053, which is sortable and extensible.

If you were starting from scratch, wouldn’t this work for you? I may have missed something obvious, of course.

But you need to get there from where you are… This would be a really complicated regular expression to do in one go, but it could be done as a series of fairly simple conversions, I think, and once you’ve done the conversion, then you can simply continue with the new format. You can add new levels arbitrarily as you go on, as long as you stick to leading zeroes for numbers.

How may cards do you have now?

Sorry if I’ve missed something…

5 Likes

No, you’ve not missed anything at all, David. It is I who misunderstood what @eastgate was suggesting earlier. This is now clear, and works very well. Using periods or commas for later interpolation works exactly as it should, and the whole thing doesn’t look too bad. Here’s a dummy file demonstrating it:

My digital zettelkasten in the TBX file is not yet too extensive, so some hours of renumbering will suffice. Many thanks for the extensive and clear explanation, @brookter.

The decision now is whether using Luhmann’s numbering manually adds or takes away value in a Tinderbox-based zettelkasten. Adopting MarkB’s technique above:

  1. Manually number by Luhmann’s system & sort by it
  • Pro: Note-sequences & branches are visually represented by the alphanumeric system, which allows you to quickly recognise that notes are in a sequence and related. If you ever have to abandon cultivating the zettelkasten in TBX, you could carry on the same naming protocol in other software or even in a paper-based ZKN.
  • Con: You lose the ability to reorganise the notes at will (reorganising is one way of reflecting and understanding your note collection).
  • Rebuttal: A benefit of fixed addresses is that you don’t waste too much time worrying about where a note goes; just link to it.
  1. Sort manually in Outline view & automate numbering for purposes of export
  • Pro: You are able to reorganise the notes after having filed them, with all the cognitive benefits this brings.
  • Con: There is no numerical representation of note-sequences and branching. Automated numbering does not actually protect against the disaster of your note-sequences being destroyed if you accidentally (mis-)sort your notes, as the OutlineNumber will automatically change to reflect its new position in the outline. If you ever have to move your zettelkasten out of Tinderbox, you’d have to find some way to number every individual note in a fashion that would preserve your order.
  • Rebuttal: In TBX, you could still visually reflect branching by making branch notes ‘children’ of the parent note, and by making more links. If you ever have to move out, you’ll find a way to use a computer to renumber the notes.

(I’d normally not post my train-of-thought on something like this. But since others use TBX for their zettlkasten, I hope it might be useful. And the feedback and suggestions from all the participants is gratefully received, and any more welcome.)

1 Like

I’m very pleased it helped!

Well you could make a hybrid system that combines the sibling order of ancestors:

$MyString=;
$MyList=collect(ancestors,$Path).sort($OutlineOrder);
$MyList.each(X){
   if($MyString){
      $MyString=$MyString+"."+$SiblingOrder(X).format(0,3,"0");
   }else{
      $MyString=$SiblingOrder(X).format(0,3,"0");
   };
};
$MyString=$MyString+"."+$SiblingOrder.format(0,3,"0");
$MyStringA=$MyString;

I’ve deliberately left-padded the sibling numbers with a zero, so the each ‘segment’ of the zettel number has 3 digital - allowing 999 siblings per segment. If you think any segment might need over 1,000 siblings amend the ‘3’ to a ‘4’ in the format() code and you will get 4 digits allowing up to 9,999 per segment. Although the segments between fixed lengths are constant, the number of segments is only limited by how deeply you nest.

It seems a lot to run as a rule but sadly moving a note via drag-drop doesn’t seem to fire the Edict (which isn’t what i expected).

As people seem quite first up about the zettelkasten approach, putting this logic in an action might be useful (with a parameter allowing the user to set the number of padding digits).

1 Like

Forgot to add, for those who like things visualised, here is the above in action:

I’d also add, that I’ve used Sandbox group system attributes like ‘$MyString’ to help illustrate (assumed) data types during the process. However, for real use—especially if you tend to use Sandbox attributes—to replace those attributes with user attributes (of the same data type) but with names that make more sense to you and which won’t be used in other rules, etc.

OK, there are some immediate issues - perhaps not insurmountable:

  • The sibling numbering in a map includes adornments and although by default all adornments number after all notes, so this _ought not to be an issue. In testing the above, using ‘Got to front’/ ‘Go to back’ commands (which move the note to the end of the sibling orders (albeit shown in the map via Z-order) it seem to the sibling separation of adornments to break down. Downside, this might make you think you’d lost a zettel note due to a sequence gap.
  • The edict approach is probably flawed as if a note is moved you will need to update, at minimum, all sibling notes and more if the note has moved level in the outline.

Still, I do think it shows a way forward.

1 Like

This indeed has great potential, @mwra, thank you! Is there a way to modify this, so as to start the counting from a particular note? I’m trying to figure out how to tailor it to start counting from a specific container.

I’m grateful to everyone who has made this an educational experience beyond the issue of zettelkasten-ing.

Make the root container for the zettel the first sibling. Just sticking an offset into the code is a nasty kludge, even if you fully understand the code. Or you could test the outline level inside the loop and just ignore the root level folder. That assumes the root container of the zettel notes isn’t part of the zettelkasten, but there’s not enough information here to know if that’s possible. Please be aware that I know nothing about zettelkasten except what I’ve read here (as it’s not really something that particularly interests me). I’ll assume if something’s not described, I don’t need to take it into account as I just helping to resolve a problem expressed within Tinderbox.

In looking to tweak the numbering systems, do be aware of a law of diminishing returns. The more baroque the code gets the more scope for hard to figure errors grows. Good enough sometimes is better than perfect. :slight_smile:

I am getting lost re-reading this thread, wondering just what problems are on the board for resolution. It seems like these are the issues:

  1. How to number notes in so-called zettlekasten fashion (a la Luhmann, in other words).
  2. How to encode the path between notes into the note-numbering scheme.
  3. How to use the note-numbering scheme to reassemble notes if they need to be exported.

Is this correct? If not, please adjust – I’ve made this note into a Discourse wiki-note so others can edit it.

2 Likes

Taking my opinions out of the wiki note so they do not get edited away.

The reason I suggest enumerating the issues is to be more precise about suggestions – “this” is being suggested as the answer to “that”.

I also observe, that the existence of problems #2 and #3 are apparently limiting the answers to problem #1. Luhmann did not have the latter two problems – I believe he was more concerned with discovering relations than creating a fixed structure. But, what he wanted to do is irrelevant, really. The best approach is Tinderbox’s strength – links. So if we do not have the latter two problems, then the first problem becomes irrelevant because we have links. Is it more important to know that Note 2 comes after Note 1, or to know that Note 2 relates to Note 1?

1 Like

Sorry: it’s my imprecise language, built atop my imperfect mastery of TBX action terminology, causing the confusion. Let me clarify:

@brookter had kindly shown me how to use Luhmann’s alphanumeric system in a way that would sort correctly in TBX and upon exporting. In so doing, he was clarifying something @eastgate had suggested but I’d misunderstood.

@mwra then pointed out that a purely numerical version of a Luhmann ‘address’ could be automated in TBX (instead of my entering it manually). The action code he posted achieved this, providing a Luhmann-esque number to a note depending on where it stood in the document’s overall OutlineOrder.

In my dummy test file, this gave me the following:

My final query (which contained the offending ‘this’), was whether the action code could be modified in order to start, say, with ‘container 001’ (in my image above) having a MyStringA value of 001. In other words, for the counter to ignore anything outside of the container ‘zettels’ and only start counting children note below it.

Edit: To clarify what I’m trying to achieve using MarkA’s code:

zettels container (no number here; zettels is the root)
    001
        001.001
            001.001.001
            001.001.002
        001.002

So, yes, @mwra was helping me with 1. and 2. in your list of issues. (I think 3. is just a matter of exporting, which isn’t a problem.)

As to your opinions (which are helpful when thinking about implementing a zettelkasten in TBX):

  • You are right, one needn’t follow Luhmann’s exact numbering regime when creating a zettelkasten in TBX. In fact, if one was never going to export at all, none of this is probably necessary: just file the notes wherever you want, because the Tinderbox-issued ‘ID’ attribute will ensure links never break.
  • My initial question (which got this whole ball rolling) was how one could implement the Luhmann numbering, for purposes of exporting notes in a way that would respect the order of notes and preferably reflect the existence of note-sequences. Again, even this is not strictly necessary, so long as some numeral-based system of exporting maintains the basic order.
  • Everything else that followed was helpful suggestions for using TBX’s action for automating the process (in light of pros and cons of the manual vs automated approaches).

Apologies if I overcomplicated things! But I must admit, I found all the advice not only useful, but also instructive in tailoring TBX for my purposes.

That seems to be a live issue within the Zettelkastenwelt as far as I can tell. Some think links are enough, others that the placing of notes (behind this note rather than that) adds something.

To me it seems that a clustering of notes around a number sequence is an indicator of where your interests are evolving: if you’ve reached note 3/1b7j8n10p1a, then that is an indicator that this topic stream is occupying more of your thoughts than a sequence which finishes at 4/1a. As one of the benefits of the system is supposed to be that it does allow you to build up a map of interests from the ground up ‘in conversation with you’, that may be of value in itself, and it’s supplementary information to that you get from links or tags alone.

But I’m not an expert at all, and only the ZKn3 program seems to implement it, so I’m probably missing something.

Edit: the Dance feature in TBX does offer an interesting way of viewing such clusters though.

2 Likes

You’ve summarised it well, David. My own experience and usage puts me in the camp that values the note-sequences. Beyond the reasoning you gave (which is the main cognitive benefit), the existence of note-sequences

  • saves me from having to create a link from every note to merely ‘follow-up’ notes on the same topic (think, the view of another author on the same subject, or a note that deals with a particular point of the previous note)
  • preserves the creation of links for connecting different concepts and ideas to one another.

Why this distinction in Tinderbox particularly?

  • It means I can utilise the Outline View to provide me a quick visual overview of which note-sequences are maturing, without needing to fiddle with links for every note and without having to scroll all over my tinderbox file just to see handful of related notes.
  • It means I can utilise the Hyperbolic View to see what trails of connected but distinct concepts are developing across the whole note collection.

It goes without saying this isn’t the only way to structure or use a zettelkasten, in or out of Tinderbox. But, to my eye and in my experience, it provides a great way to actually learn from one’s note collection as a whole.

1 Like

Interesting points, thanks, Talal. At the moment I’m using Scrivener for the ‘live’ slip box, so haven’t really tried implementing it in Tinderbox in anger, rather than just testing it, but there is real food for thought there when I do.

A numbering scheme is not needed to do that.

Or, as Manfred Kuehn pithily noted

“this is an ordinary Zettelkasten:”

IMG0000004D

1 Like

@talazem - no censure intended. The confusion here is that this is like a game of whack-a-mole. There’s always one more thing, that it would have been more useful to to know about before starting. :slight_smile:

Firstly, I strongly advise use prototypes for this sort of thing, and disable the code in the prototype(s) being used to set the code. There is no gain running the code in notes that don’t need or use it. For instance, you ‘Prototypes’ container shouldn’t be using the code.

As the the precise question, I’ll table two inferred assumptions from the screen grab, though not described in text:

  • All zettel notes are descended from one container.
  • That container is at root level.
  • That container is not a zettel note.

Then try this:

$MyString=;
$MyList=collect(ancestors,$Path).sort($OutlineOrder);
$MyList.each(X){
   if($OutlineDepth(X)>1){
      if($MyString){
         $MyString=$MyString+"."+$SiblingOrder(X).format(0,3,"0");
      }else{
         $MyString=$SiblingOrder(X).format(0,3,"0");
      };
   };
};
if($MyString){
   $MyString=$MyString+"."+$SiblingOrder.format(0,3,"0");
}else{
   $MyString=$SiblingOrder.format(0,3,"0");
};
$MyStringA=$MyString;
1 Like

A numbering scheme is not needed to do that.

It’s the Little Enders v the Big Enders argument of the Zettelkastenwelt as far as I can see. Obviously some extra information is imparted: whether that additional information is worth the additional effort in a digital system is another matter.

I miss Manfred’s Taking Note blog. I had it on an RSS feed in Devonthink and then one day it stopped without explanation.

5 Likes

Further fixes to my Zettelkasten-like numbering code, including a user-configurable number of segment padding numbers. Assumptions as before:

  • All zettel notes are descended from one container per document. If you need two discrete sets either use two TBXs. This method can only support a single note hierarchy per document.
  • That container is at root level, though I’ve added a feature to let the root $OutlineDepth be below root.
  • That container is not a zettel note.

Plus:

  • Root zettelkasten note container is called Zettels, case-sensitive
  • Add a String-type user attribute, MyStringA
  • Add a List-type user attribute, MyListA
  • Add a String-type user attribute, ZettelCode
  • Add a Number-type user attribute, ZettelPadNumber, default value: 3
  • Add a Number-type user attribute,ZettelRootNumber, default value: 1
  • Set $ZettelPadNumber and $ZettelRootNumber as Key Attributes for container ‘Zettels’

The ‘My-’ prefixed attributes are used in the code and named so as to not accidentally affect Sandbox group attributes with the same name stem.

In the previous example padding was hard coded to 3 giving codes like 001.004.002. Now setting a value of 2 gives codes like 01.04.02 . The variable padding number is now set in $ZettelPadNumber in the ‘Zettels’ container. Note: the sensible range for $ZettelPadNumber is minimum 2 and up to c.4: a value of 4 allows up to 999 sibling zettel notes per containers but obviously makes for longer codes. The Value can be changed and will be applied the next time the code is run.

N.B. If you set, for example, a pad value of 2 and some containers actually have >99 notes the code still works but different segments have different numbers of digits. This will effect correct sorting using lexical sort, so set the pad value according to the maximum number of siblings-per-container you have (or foresee using soon). My hunch is most people will start on 2 and move to 3. If a need to set 4 approaches, you might want just break a current set of siblings into 2 containers (Tinderbox doesn’t really care).

The code assumes the container holding the steels is at the document root level, but pre-empting a another change, I’ve parameterised this. So, if your main container holding zettel notes is at $OutlineDepth of 2 set $ZettelRootNumber to 2. Simple!

Set this code as the rule in the prototype(s) used for zettel notes (or add to existing rule code):

$MyStringA=;
var vPad($ZettelPadNumber(/Zettels));
var vRoot($ZettelRootNumber(/Zettels));
$MyListA=collect(ancestors,$Path).sort($OutlineOrder);
$MyListA.each(X){
   if($OutlineDepth(X)>vRoot){
      if($MyStringA){
         $MyStringA=$MyStringA+"."+$SiblingOrder(X).format(0,vPad,"0");
      }else{
         $MyStringA=$SiblingOrder(X).format(0,vPad,"0");
      };
   };
};
if($OutlineDepth>vRoot){
   if($MyStringA){
      $MyStringA=$MyStringA+"."+$SiblingOrder.format(0,vPad,"0");
   }else{
      $MyStringA=$SiblingOrder.format(0,vPad,"0");
   };
};
$ZettelCode=$MyStringA;

Sorry, this took much longer than I’d imagined (checking edge cases, parameterisation of options, etc.), but here is a simple demo/test file: zettelcode-demo.tbx (115.7 KB)

I would be very interested to know if the logic of the ‘zettelcode’ mechanism is essentially feature complete. IOW, before building anything deeper off this I want to make sure we’ve not missed any obvious error or needed additional option.

I’m not wildly keen to do this as a rule, but for now it’s the best option. Discussion (elsewhere) is considering ‘featurising’ this as a an action or calculated attribute, thus the necessity to ‘freeze’ the design logic - or we’ll be at this forever. :slight_smile: So, input on this is requested!

If you want to ask about action code logic in the code above, I suggest you start a new thread and link to this one so we don’t get thread drift.

1 Like