Tinderbox Forum

AgentQuery to identify notes with no value for any attribute out of several or no text?

After fiddling with TB for knowledge management (Zettelkasten) on my own for a year or so (thanks for everybody here helping me along the way), I just went through @satikusala 's excellent video tutorials and realized immediately that I have not been harnessing almost any of the software’s real powers. I feel I am taking leaps forward, but got stuck on this:

I want an agent to identify notes that I have missed to assign values to all attributes for or not filled in any text yet. My limited knowledge tells me that an AgentQuery could be the way to go, but I do not find enough detailed info on how to do that neither on this Forum nor in the Tinderbox Reference File (I am sure there is, though). Perhaps there are other ways? Please help!

This is the easier part. If the there is no text then the $Text attribute is empty. This query will find such notes:


You can even use the short-form test version of the same:

[Edit - code error!]


I’d use the first until you understand the process but do read the link about the latter as it helps you write more succinct code once you’ve more experience with action code queries.

Do bear in mind that the above matches every note with no $Text. It may be you only really want to match ‘content’ notes in your zettelkasten. Let’s assume—by way of example—that all such notes have a common prototype. For this example I’ll call it ‘pZettel’. Now we can restrict the scope of the notes tested for having text:

$Prototype=="pZettel" & $Text==""

The order is important. First we match only notes with the desired prototype (ignoring all other notes) then we test only those already-matched notes for their text. If you can, it always helps to test as few notes as possible when using operators employing regular expressions like .contains(). In the above examples, were we using as $Text.contains() type argument the last, pre-filtered version would be snappier.

This is a good reason not to use a root-level map. If all your work/content is under a single root container, then querying using descendedFrom() on that container means all back-of house stuff like prototypes, templates, etc., are automatically excluded from the rest of the query. I often use a prototype in some projects just so I can address only those notes in a query.

This is a bit harder as you need to test each of the attributes. Let’s assume you have $StringA, $StringB and $StringC that you need to test. We’ll cement good practice here by using a prototype as an initial filter, but you don’t have to do this. You could test them one at a time:

$Prototype=="pZettel" & $StringA==""

Then repeat for $StringB, etc. As you fix incomplete $String A do check the other two attributes (e…g. ass Displayed Attributes) so the subsequent queries will return fewer items as you’ll already have fixed some notes. Tip: if you know there are more errors for, say, $StringB, test that one first and you may find you’ve pretty much fixed all 3 attribute via that first agent. I’d not make 3 agents, but one, fix all the errors, then change the query, etc. When done delete the last agent which should now be empty as all the attribute values are now fixed.

Or, you could do one query:

$Prototype=="pZettel" & ($StringA=="" | $StringB=="" | $StringC=="")

The \ means an ‘OR’ join and the parentheses means these are all processed and the result is then added to the query. The OR means that a note matches this second part of the query if any one or more of the 3 attributes has an empty value. So it only takes any nee of the three attributes to be wrong for the note to match the query.

You can use either approach. Depending on the task, the best fit may differ. For instance if the edits to the 3 attributes are different in nature it may make sense to work though just one at at time, and so on. Either way, there is a solution for you.

Does that help?

1 Like

Yes! That’s exactly what I was trying to accomplish! Thanks @mwra! You have done it again. I followed your lead and put everything in one AgentQuery row:

$Prototype==“pZettel” & $Text=="" | ($Domain=="" | $Type=="" | $Keywords=="")

I have tried all combinations of missing text or attributes and it works like a charm. I also like how you anticipated the challenge of checking all kind of notes and provided a solution for that right away. You are a star!

Thanks again!

Oh, it somehow picked up notes that are not assigned the Prototype “pZettel”. Strange… Any thoughts?

Looking at your posted code, and though it may be forum auto-formatting, the first query term (prototype) uses curly quotes and not straight quotes. I’m afraid that small distinction matters in action code & queries.

By the way, to make sure core doesn’t get mangled by the forum software, put a back-tick (i.e. ` ) character immediately before after your sample. Thus $MyString="Hello" not $MyString=“Hello”. For longer samples, put 3 x back-ticks (nothing else!) on a separate line before and after your code sample, to get a result like this:


I’m learning new things here all the time. Here’s the code again, with the back-ticks:

$Prototype=="pZettel" & $Text=="" | ($Domain=="" | $Type=="" | $Keywords=="");

It seems like the quotes are correct, but thanks for the heads up about the curly ones (also pointed out by @satikusala in one of the video tutorials). Isn’t it strange that my AgentQuery still picks up other notes not assigned the prototype pZettel , when that comes first in the code? Everything else works fine.

It is picking up everything, a lot because it is grabbing the prototype and text elements and the failing on the other parts of the expression. TBX is trying to do what you’re asking, and then is failing because it is getting confused.

What I think you want here is "Get me all my notes that have a prototype of Zettle and no text, or no value in domain, type, or keyword.

Try it without the ( ), I believe this is where is it failing. You’d use the ( ) in other expressions, like conditional finds and dot operators.

$Prototype=="pZettel" & $Text=="";$Prototype=="pZettel" & | $Domain=="";$Prototype=="pZettel" & | $Type=="";$Prototype=="pZettel" & | $Keywords=="";

You need the and agrument with each of the other or statemetns, “|”, operators otherwise it will just pickup notes no value in those other attributes.

The original code I posted ought to work - parentheteses are allowed in queries - see here. Indeed sometimes there are needed, though arguably not in my original suggested code.

semi colons aren’t used in queries. I think the above is possibly meant to show a series of discrete queries:

$Prototype=="pZettel" & $Text==""
$Prototype=="pZettel" & | $Domain==""
$Prototype=="pZettel" & | $Type==""
$Prototype=="pZettel" & | $Keywords==""

but even that makes no sense as there is no & | syntax. A notional linguistic ‘and or’ is an OR join as the OR trumps the AND as it widens the pool of matches.

So, I’m not sure what the above example mean.

OK, @mwra and @satikusala. I tried these things in order:

  1. I simply removed the parentheses (my own desperate and uninformed solution):
    $Prototype=="pZettel" & $Text=="" | $Domain=="" | $Type=="" | $Keywords=="";
    RESULT: Still the same problem.

  2. Then I tried @satikusala 's suggestion:
    $Prototype==“pZettel” & $Text=="";$Prototype==“pZettel” & | $Domain=="";$Prototype==“pZettel” & | $Type=="";$Prototype==“pZettel” & | $Keywords=="";
    RESULT: No notes identified instead.

  3. Then I tried a version in which I removed the “|” in the string:
    $Prototype=="pZettel" & $Text=="";$Prototype=="pZettel" & $Domain=="";$Prototype=="pZettel" & $Type=="";$Prototype=="pZettel" & $Keywords=="";
    RESULT: Only notes with no data for text and the three attributes identified.

  4. Then I tried @mwra 's suggestion with a series of discrete queries

$Prototype=="pZettel" & | $Domain==""
$Prototype=="pZettel" & | $Type==""
$Prototype=="pZettel" & | $Keywords==""```
RESULT: Now, notes with no text are identified, regardless of values or not for the attributes. Like if it is only the first row that is doing something. 

What I need is to somehow connect these queries with an "OR" / "|" of some kind.

Um, if you read carefully I said (extra empahsis added here):

but even that makes no sense as there is no “& |” syntax.

… i.e. I didn’t think that these were valid queries. Buried in a work at present. Can you post a small test TBX we can use as a common reference (and show code (not) working. You need enough test notes to test each of the cases you need to tease out - i.e. possibles and potential false positives. This far into the topic it’s easier to work with a common example.

I think the problem here is that the order of evaluation is not clear. I think you probably mean:

$Prototype=="pZettel" & ($Text=="" | ($Domain=="" | $Type=="" | $Keywords==""))

That is, “find zettels with either no text or where domain, type, and keywords are all empty”

But Tinderbox may be evaluating this is

($Prototype=="pZettel" & $Text=="") | ($Domain=="" | $Type=="" | $Keywords=="")

That is, "find zettels with no text, or any note where the domain, type, and keywords are all empty.

1 Like

Sorry @mwra , I didn’t want to make it look like you suggested that as a solution. I just tried everything (including a lot more variations that I didn’t post to look too dumb concerning TB). Thank you, @mwra and @satikusala , for helping out so far!

Following @mwra 's suggestion, I hereby upload a small test TBX in which I have recreated the context and issue I have in my larger Zettelkasten. In it, you find the agent that assigns the “warning” badge to all Zettels (notes with prototype “pZettel”) lacking text or any of the three attributes, but unfortunately also do the same to notes not assigned to the “pZettel” prototype.

I am very grateful for any assistance in solving this issue. My goal is to have agents assigning different colors to notes related to different scientific domains (social science, natural science, engineering, etc) and badges for three types of Zettels (content, interpretation, synthesis), as well as a “warning” badge to notes lacking text or any of the three attributes (Domain, Type, Keywords).

Test of AgentQuery to identify notes with no value for any attribute out of several or no text.tbx (127.9 KB)

1 Like

Serious, no worries here! Just concerned at you spinning your wheels on the wrong stuff.

Also, really appreciate the through demo, off to give a try

1 Like

@eastgate just solved it! See above.

1 Like

@eastgate’s second example works (in your lovely sample TBX - thanks again)

$Prototype=="pZettel" & ($Text=="" | ($Domain=="" | $Type=="" | $Keywords==""))

But this simpler code does the same, using a single pair of parentheses. Above, the latter pair are not needed - the last 4 terms are all an OR join.:

$Prototype=="pZettel" & ($Text=="" | $Domain=="" | $Type=="" | $Keywords=="") 

I get eleven results. Oddly, “Note 4, no text” is found twice, which should not be possible but it won’t affect your task.

1 Like

I think you solved it! The code you suggest seems to do what I want it to do, which is to “find zettels with either no text or no domain or no type or no keywords”, so I can identify them easily to complete them.

$Prototype=="pZettel" & ($Text=="" | ($Domain=="" | $Type=="" | $Keywords==""))

It seems to do just that, but I will continue to test throughout the evening over here (Sweden). Thanks @eastgate !

1 Like

I’ve reported the odd duplicate result with the agent (mentioned above) elsewhere so no need to follow up on that. It seems to be transient issue anyway.

1 Like

Yes, it seems like both @eastgate 's code and @mwra 's slightly simpler code work. Also in my larger Zettelkasten. I guess it may be a bad idea to assign badges for both type and this warning for empty fields (text and attributes), or what do you both think? I have found nice badges for each purpose, so if there are no direct issues with it, I like to try it. A good thing with Tinderbox is that it is possible to change later, without too much hassle…

These AgentQueries are a real test of logical reasoning… I may be a university professor, but this I need to practice :blush:

Thanks again for all help!

Thanks for the summary. Each note can only have one $Badge value. So use as many different badges as you like as long as the groups they imply don’t overlap. You can do the latter but you end up having to do lots of if work.

However, if the badges are single to type but the warning is only for incomplete notes of any type, you just need to test it isn’t set to ‘warning’., i.e. a ‘warning’ badge beats all others.

In your current demo, the ‘warning’ $Badge wins out as it runs_last_ (by Outline order) in the agent cycle. Unless you put the agent there deliberately, you may see badges change each cycle. A safer way to do this is that where you have an action like:


do this instead


This way, whatever order the agents run, the ‘memo’ agent will only set the badge for this type if the current badge is none (i.e. no badge) or any value other than ‘memo’.

Pedantic point, if the badge is “memo” it will still (re-)set it but that has no bad effect so don’t worry about it.

To set badges, if all each one does is set a per $Type, then you only need one agent:

Query: $Type (i.e. Type has a value)

Action (note the nested if() calls:


Indeed, you could fix $Color at the same time with additional query term and actions:


$Type | $Domain


if($Type=="Domain2"){$Color ="green";};

Now, 4 agents have become 1 agent doing all the same work!

The latter shows how incremental formalism, i.e. adding/improving structure as needed or discovered is both powerful and—in Tinderbox—easy. If you make the change above, the same result occurs but with much less agent activity.

Over time and use, you will get better at spotting these improvements in advance, but don’t worry about them. Let them emerge, saving your concentration for the real work you are doing with the content.

1 Like