How to create an agent that retrieves a list of books with a given tag? + some automation nice-to-haves

Last year Mark Bernstein and Michael Becker helped me create a simple “commonplace” list of books and other materials with relevant notes. It includes several prototypes, including Reference, which always consists of author and title, like this: “Bateson, Steps to an Ecology of Mind.”

They also helped me create several agents, such as a “Find Authors” agent with this query:

This returns a list of Reference notes where the Author attribute includes “Chung.” I can substitute any author I want, and the list updates. Great.

I have now added a Tags attribute. I would like to create an agent with a query that does something similar with tags, so that I can substitute any given tag in the query and get a list of all books with that tag.

For example: all books with a tag “#1” which are books I want to revisit in some way by a certain date. Or those with a tag “Gaeilge” indicating that they are written in the Irish language. Or those with the tag “formal” indicating they contain texts with formal properties currently of interest. Etc.

I am not trying to predict how else I might use tags, just trying to create a general mechanism for labeling and retrieving books with certain characteristics.

How do I do this?

I hope this is a simple question. I’m not a programmer and do not want to get into the weeds of Tinderbox, at least not yet. Just want to be able to list books with a given tag.

Thanks in advance for any suggestions!

Related question:

I am not using Bookends or Zotero (although I’ve tried the latter). I am not an academic and don’t need to generate bibiographies. Instead, when I enter a new reference, I simply type the last name of the author and the title: “Weiss, A Suite of Dances.”

Then I need to retype:

  • the author’s last name in the Author attribute (followed by the first name or any additinal author names)
  • the author’s last name in the CitiationKey attribute (after the @ symbol, and followed immediately by the year of publication)
  • the title in the Title field.
  • sometimes (this is less important) the year of publication in the PublicationYear attribute.

How I can automate some or all of these manual retyping steps?

Again: I do not want the overhead of using a third-party tool like Zotero. The vast majority of such bibliographic details are irrelevant for my purposes. In most cases I don’t even bother with the publisher information. I do generally record whether the book is my own (in my “Where” field), online (URL in the URL field), from the library (e.g. SFPL), and I have an OnAdd attribute that fills in the CitationKey for any subordinate notes or quotes I may add later.


One agent query might be:


This would find all notes that have the tag “ecology”. If you only wanted to locate Books, you might use

$Tags.contains("ecology") & $Prototype=="Book"

Let’s start with the first one. We’ve got notes with names like "Weiss, A Suite of Dances.” To get the author’s name, we want to copy everything up to the comma, and put that into $Author, a user attribute.

Rule: $Name.captureTo(',',"Author");

After that, we want to put the rest of the name into $BookTitle, a built-in string attribute. We can just extend the same rule!

Rule: $Name.captureTo(',',"Author").captureRest("BookTitle");

There are other ways to do this too. What I suggest is making a little throwaway Tinderbox document with a note or two with suitable names, and playing with these rules.

Thanks Mark. I have several Tags attributes in Reference notes that contain “Sept 2023,#1”. These are in a test file, a subset of my working file.

Side question: is it OK to leave a space between comma-separated tags, or must they be closed up as above?

Neither $Tags.contains(“#1”)

nor $Tags.contains(“Sept 2023”)

produce anything as queries in a new “Find Tasks” agent with prototype “pAgent”.

Where exactly do I put this rule? For example, in the attribute “Authors” in the Reference prototype? That doesn’t seem to work. Or somewhere else?

Here is my test file.

Sean-test.tbx (1.1 MB)

Your tags can contain anything (well, almost anything) you like, including whitespace and punctuation. As a rule, I find single words are usually best.

$Tags.contains("#1") matches the tag #1', but not that tag #1aor 'We’re #1'. That’s because.contains()` for lists asks, “Does this list contain this element?”

Tinderbox lists are semicolon-delimited.

The tutorial on Actions and Dashboards in the Help menu might be worth reading. Tinderbox offers lots of places for actions:

  • Rules are run every few seconds
  • Edicts are run occasionally
  • Agent actions are performed when a note is found by an agent
  • OnAdd actions are performed when a note is added to a container
  • Link actions are performed when you make a link of a given link type
  • Stamps are performed on the selected note(s) when you select a stamp from the Stamps menu

There are some really good videos on this stuff, by the way.

If you want to capture non-exact matches you can use $Tags.asString.contains("#1"), for instance. The .asString operator is a replacement for the .format(“l”) method reference above. Mark introduced it a while back. asString looks at the attribute as a string, rather than a set. I use it all the time.

Thanks both of you for the quick responses.

I got the tags agent working. Sort of. Here’s how.

I had created my tags agent from scratch, and at a glance it appeared to be identical to the other agents using the same prototype. Same attributes, etc. Couldn’t get it to work at all with either of your suggested queries.

But then I noticed that the furthest left icon in my outline for my new agent looked very slightly different from the icon on my existing agents. Very difficult to see for someone of my age and corrected eyesight, but the icon of my new agent had a thin gray bar across the top, whereas the icons for my old agents had a gray bar across the bottom. So I simply copied one of my existing agents and changed the query. Voila.

There are still some weird things happening, but at least now I can troubleshoot because the query actually does something. Oddly, for example, discovered by accident, $Tags…contains(“2003”) returns eight responses, which is correct. And $Tags.contains(“2003”) produces one response. If I add asString as you suggest, it returns two responses. If I precede it with an extra dot, it also works correctly: eight responses. (Sorry, the forum is doing something funny with the two dots I attempted to in this paragraph after “$Tags”. Turning it into three instead of two.)

By the way, the agent seems to take several minutes to complete its query. Will this get worse as I add more books? There are only 34 or so in my test file. This is on a brand new MacBook Air M2.

So: what’s with the crucial difference in the icon? And why do two dots work whereas one doesn’t? Bug? Feature? Something I’ve done wrong? Some complex capability I just don’t understand?

This illustrates an ongoing frustration I have with Tinderbox. Debugging for a greenhorn like me is incredibly frustrating. I need to read long articles (or watch multiple videos, or attend several wonderfully detailed meetups) about the many marvelous intricacies of the program to get a very basic set of capabilities working. What I want to do seems pretty simple, and as you’ve both suggested, it’s best to start simple and build from there. But I’m trying to focus on the books I’m reading, not the debugging involved in automating repetitive actions or using the tool to track the bits and pieces of ideas that interest me. Based on the time I’ve spent trying to figure out how to make fairly simple things happen, a more manual approach would actually have saved me many hours.

Perhaps. after years of intermittent trying (and forgetting most of the tiny scraps I manage to learn between each effort) this program just isn’t right for my purposes. And yet . . . I still feel like it has potential for my oddball use cases, and quick responses from the forum are fantastic considering my ignorant questions. But if I can’t find a way to use it easily on an ongoing basis without falling down rabbit holes, at some point I will have to give up on the promise and revert to, I don’t know – maybe pencil and paper!

So I’m giving it another try. Glutton for punishment, or is enlightenment around the next bend?

Thanks Mark. Not sure I get why a rule is useful here. I want these copying actions repeated just once, when I create the note, not every few seconds.

I took a look at Actions and Dashboards (a 67-page document), and quickly got overwhelmed. I still don’t know where to add the first rule you suggested:

What does “put that into $Author” mean (my attribute is “Authors”)? In the prototype’s “Authors” attribute? That doesn’t seem to work. Somewhere else? I can’t find any information about how to do this.

As I said in my response to Michael, I may have to face the fact that, after many tries over more than a decade, Tinderbox is just way too complicated for what I’m trying to do. Which would be a shame, because I enjoyed The Tinderbox Way very much and (after a long career in big software companies as a tech writer) am very sympathetic to the whole notion of artisan software. But if I’m spending more time trying to learn the program than actually using it for useful work, something’s wrong.

That’s the title bar of the container or agent. It’s typically not very thin or hard to see in map view — you might want to increase the magnification of your map view if you’re working in the map.

Your problem was that you didn’t create an agent — you made a new note, which became a container when you put other notes inside it. Agents are created by choosing Create Agent from the Note menu.

I cannot imagine any query, however complex, requiring more than a few second in a small document. Most documents with no more than a few thousand notes finish all agent queries in ten seconds — the interval at which Tinderbox begins a new scan for agent updates.

Thanks! Makes sense.

FYI, I am currently working in outline view only, which makes most sense so far for my simple use case.

After cleaning up all my tags, the $Tags.contains(“tagname”) query is working fine.

(And the queries now seem to be completing in ten seconds or so, as Mark indicated they should.)

1 Like

OK, after finding this video by Michael Becker (thanks for doing that Michael) and poking around a little more, I ended up creating an OnAdd action for my Commonplace container based on Mark’s code: $Name.captureTo(‘,’,“Authors”).captureRest(“Title”);

Then, as long as I create any new top-level notes under Commonplace (which are always made with the Reference prototype), I can drag it into Commonplace and presto, I get what I want. And can then add the author’s first name and any other attributes.

I tried adding this action as a Rule to my Reference prototype, but then it ended up wiping out all my author first names (since the rule keeps running.

So this seems like a reasonable solution. It would be nice to be able to create the notes directly inside the Commonplace container, but that means they all end up with the Author “Untitled” and no title.

I will keep plugging away. It’s very cool to see things working the way I want, despite the messing around required.

Thanks Mark and Michael for you patience! I’ve now got what I need for now.

1 Like

You bet! Awesome. :slight_smile:

Here’s a tiny improvement that I’d like to make (which might also be helpful in terms of learning Tinderbox syntax more generally).

When I add a new Reference note to my Commonplace folder, this OnAdd attribute (for Commonplace) adds the book author’s last name to the Authors attribute, the book’s title to the Title attribute, and the author’s last name to the CitationKey attribute:



  • How can I modify this script so the symbol"@" appears before the author’s name in the CitationKey attribute?
  • How would I find the answer to this question by myself in the Tinderbox Reference?

There are several ways to do this.

There are several ways you can do this.

  1. Add a new expression to the $OnAdd


Once you’ve created the CitationKey tell Tinderbox to add a “@”

  1. Use Split (Bonus capture publication year)
    You could do this. Note, TBX ignores linebreaks after the semicolon, having the line breaks makes it easier to read. I’ve asked Split to parse the name at the commas and create a list.
var:list vList=$Name.split(",");

If $Name=“Becker, This is a Book, 2023” then I get this:


Adding the publication year may help with your sorting and distinguishing between titles an author wrote in different years.

REMEMBER: TBX uses a 0 based for the list, so item #1 starts at 0 in the list. The brackets “[ ]” are telling TBX which items from the list to pull. Using a variable lets TBX do the parsing once.

Thanks Michael. The first solution works fine for me, for now. Good to know about Split and lists though, for future reference.

Very much appreciate the quick response and lucid explanations!

1 Like