Tinderbox Forum

Restricting agent scope to a specific path

I am looking to restrict an Agent scope to a specific path, I am looking for all the people in my tbx (eg. $Prototype==“Person”), but would like to collect only those under a specific path (of the outline).

Thank you!

Look at inside() and descendedFrom().

Thank you.

How would I use it with the item note designator ‘parent’ in order not to hardcode the path?

Not enough info! Are you saying you want to the agent to find items inside the agent’s parent container? That would be a circular reference. Can you explain the relationship of the objects a bit more - bear in mind we can’t see what you see. :slight_smile:

Node A
. . Person 6
. . Node B
. . . Agent collecting all people in node B and below
. . . Person 1
. . . Person 2
. . . . .Node C
. . . . . Person 3
. . . . . Person 4
. . . Node D
. . . . . Person 5

The agent should collect all “person” below Node B (1,2,3,4), it should exclude person (5,6)

I can do it with descendedFrom but only if hardcoding Node B in it, I am trying to avoid that.

How about a query like:

descendedFrom(parent(agent)) & $Prototype=="Person"

However, this will find Person 5 as Node D is descended from Node B. It seems odd that All nodes except Node C descend from other nodes. I’m not sure of the rules of the structure here. Here’s the result of the above query:


I’m not sure quite how you indicate Person 5 isn’t in scope. You might need to rethink your outline structure or add extra metadata.

I think my indents were wrong, I was posting from my phone and it is no easy feat , spaces are stripped, anything with more than three dots is displayed as 3 dots…

Node D was intended to be a sibling of Note B, then your solution should work (I am saying should because I am still working from the phone as of yesterday and I haven’t tried it yet).


1 Like

Great! I thought that might be the case. So, I hope that helps you once you are back at your Mac.

For later readers, it’s worth noting one thing here. The agent is in-scope of queries based on the agent’s parent. In the above case, the agent is then excluded by the query term matching a specific prototype. However, when using a scenario like this, do take care that the agent isn’t matching itself (or the aliases within it) as it could create a loop and give the app a headache and you the wrong result).

1 Like

Yep it works just fine! And yes I had taken into account recursive-ity of the query when asking.

I have decided to have one TBX file to rule them all on some work matters, but as a result I need to reduce the scope of agents (for the time being) to a specific outline branch. I will experiment a bit more with this approach, if it proves to be more painful than I thought I am going to revert to one file per major area.


1 Like

Thanks. My follow-up warning was less for you that later reader of the thread as people often take ideas for old threads and adapt them (as they are encouraged to do!). It just struck me that a new user might easily overlook the fact the agent was within its own query scope, if using only inside() or descendedFrom() as the query. :slight_smile:

Agents don’t find themselves, so that isn’t something to worry about.

I agree you want to make sure you’re not matching against the aliases within the agent, but I’ve also never run into a situation where I’ve done that (though it is possible).

With this agent query:

descendedFrom(/parent note) & !descendedFrom(/my agent)

You’ll see the agent toggling between showing child note, and then hiding it:



In context it is worth noting that inside() has a subtly different behaviour from descendedFrom(). inside(item) will match if either the original or an alias of a note is a child of (i.e. ‘inside’) item whereas descendedFrom(item) only matches originals descended from item. If you need a child-scoped original-only match you can use descendedFrom() if you know there are only children of the target container (e.g. it is an agent) or consider using using an additional &$IsAlias==false query term with inside().

See the @pat’s post below for a more accurate description.

That is incorrect. descendedFrom also matches aliases.

The subtly different behavior arises from the fact that that when you combine multiple descendedFrom expressions, it does what most people expect – but when you combine multiple inside expression, it does not do what most people expect. (why that’s the case, I’ve read multiple explanations of but still don’t quite understand)

This is precisely why descendedFrom is useful to target the children of an agent – because inside has a pretty big gotcha that prevents it from being useful in that case, but descendedFrom gets the job done.

Here’s a document showing how descendedFrom finds aliases, and comparing the difference between inside and descendedFrom. It also demonstrates an approach for achieving the goal that people are aiming for when they combine multiple inside expressions. inside vs descendedFrom.tbx (81.2 KB)

To achieve a combination of multiple inside expressions, you need to approach it from the other side: examining children of a container:

// this finds notes that are inside both container
collect(children(/container 1), $ID(original)).contains($ID(original))
  & collect(children(/container 2), $ID(original)).contains($ID(original))

// this finds notes that are inside container 1, but not container 2
collect(children(/container 1), $ID(original)).contains($ID(original))
  & !(collect(children(/container 2), $ID(original))).contains($ID(original))

Ah , yes. Note to self that if/when I get some spare time I should re-document this more clearly in aTbRef. I can attest to getting caught out by inside() behaving in a way I didn’t expect.

And I can attest that, thanks to @mwra, aTbRef has saved my bacon by telling me exactly what I needed to know in a pinch, more times than I’ll ever be able to count :tada::tada::tada:


The only reason I can do all the cool stuff I can do with Tinderbox is because of aTbRef!! I constantly have it open, and I pretty much live in Attributes / Action Codes / Export Codes / Designators pages. I’ve barely looked at the rest of it yet – including all the apparently neat things you can do in map view.

Good to hear - because that’s me too! There’s simply too much to remember. The forum is good for kicking things over. This thread, needing to loop on a list reminded my that whereas we used to have to use list.contains() instead of == for Set/List types, we now have the list.each() option to iterate the list and == test each list value. Sure it’s a little bit more code but not too complex once you’ve figured it through the first time.

A note is inside(target) if it’s a child of the target note, or if one of its aliases is a child of the target note.

The second clause lets you agents work together more easily.


is true if a note matches the agent’s query.

Yes, but as far as I can tell, that’s only true for one application of inside().

A note is not inside(target 1) & inside(target 2), even if it is a child of target 1 and one of its aliases is a child of target 2.

That’s the tricky bit.