The build tool uses a concept called "Chains", which are comparable to Maven lifecycles. They are however meant to be a bit more intuitive, which is done by providing proper documentation through documents such as this one.
(SL-)Brachyura only has a concept of Tasks, which can only be invoked once at a single time. This means that a Task cannot run after a given Task, unless the first Task is explicitly running the second task. However such a system is not very extensible, as there are circumstances where a Task needs to be necessarily run after or before a given Task, even though neither Tasks were meant for such a purpose. The resulting workaround, which is to create a "uber-Task" that is calling all the sub-tasks is not very developer friendly, as it results in there being a wide disparity across projects as each project uses their own systems.
Gradle also has the concept of Tasks, however solves above Problem by specifing which Tasks need to be run before and after a given Task. Such a system is adequate, but leaves room for improvement when it comes to have multiple Task "flows". For example it might be benificial to skip certain tasks while working towards a special task.
Maven solves such an issue by providing lifecycles - each MOJO (The equivalent of a task) is put on a goal of a lifecycle. Goals are worked on in a set order within the lifecycle. However beyond that Maven gets confusing fast as defining execution order and lifecycles is a complicated affair and does requires intervention on the developer's side within the pom.xml in order to work without flaws. This means that the maven-shade-plugin will not run it's "shade" MOJO after "jar" by default.
In order to address all of the above shortcomings a two-layer system is used. In the first layer a system of "links" (which are the equivalent of Tasks) is employed, which only specify what needs to be executed. They have names, but no inherent order.
The second layer is a system of "chains", which specify the links that need to be executed and in which order they are run. A link cannot be executed as-is, a chain can be executed in it's entirety - at which point all links are executed, or up until a given link. Further constratins of a chain is that each link may only be present once within it and as such each link may only be executed once per the chain's execution. This is caused by the registering mechanism of a chain, where when a link is inserted within the chain the previous link(s) and the following link(s) need to be defined. Having a link be present twice may lead to ambigouity when it comes to ordering the links. Do note that it is possible for a link to have no previous and/or no following links - this is because there needs to be at least one starting and ending point. But there is also likely a "root" element. For example the "javaJar" chain might have the "compileJava" link be the root element, where as any other links are relative to the given link.
In OOP world abstraction is common-place behaviour and as the users of the build tool are naturally likely to be familiar with OOP languages (since this is aimed at java developers), mirrioring this concept is only natural. This furthermore has signficance in other issues noted later on.
The easiest part of providing abstraction on links. Examples on that front would be a "compile" link. The name of the link only implies that something is compiled - but there are no specifications made on what exactly is compiled. This means that kotlin code could be compiled or java code could get compiled - what exactly gets compiled shouldn't matter for ordering links.
This means that if the "shade" link depends on "compile", and "compileJava" extends (i.e. is an implementation of) "compile", then the "compileJava" link will run at the same place as the "compile" link as all references of the "compile" link are going to be upgraded to the currently used implementation of the link - which is "compileJava". This upgrade is non-recursive, that is if another link provides "compileJava" too, then it also needs to provide "compile" in order for there to be no hickups. This flaw is sortof inevitable due to there being no name -> link lookup which is allow a recursive lookup. Furthermore the ability for a link to provide multiple "abstract" links means that ordering can be a bit confusing. Should any link depend on an abstracted out link as a run-before dependency while also depending on another abstracted out link whose concrete implementation is the same as the previous abstracted out link in a run-after manner, an error needs to be emitted. In brief an unpredictable state is not allowed under any circumstances.
Should a link depend (either as run-before or run-after) on another link that is not provided at execution time, then the chain should not execute. If a link provides a link that is supplied at execution time, then the chain may not execute and should provide and adequately well formulated error message.
Chains can be invoked as subroutines within another chain, where as the subroutine is implemented as a link and can be used as one. However such subroutines need to be explicitly registered and implemented as links in order to avoid incompatibilities. It is generally recommended to not make them recursive in order to avoid doing many thinds twice - although that is technically valid.