Was going to come back and suggest that you at least move the matcher stuff into a separate lib, but now see that you have removed it.
Now without the matcher stuff, there actually IMO is no need for the It interface. The only method defined on It is fail, which isn’t really needed. You can just use Assert.fail from Junit. If you really felt it was necessary you could move it to the Spec interface.
With It gone then the it function in spec just takes a () -> Unit instead of an It.() -> Unit and there really is no significance between describe, context, and it other than it is a terminal. describe, context, and it are basically just text strings put into the junit test descriptions.
So it seems to me that Context.terminal should not be a value you set on the context and instead is just:
val terminal : Boolean get() = children.isEmpty
So that any context without children is terminal.
You should then allow people to use any words they want instead of just describe, context, and it. For example, people will want the ability to use the given, when, then verbiage.
To accomplish this Spec, should have a method of this form (not sure what the best name is):
fun specBlock(term: String? = null, description: String, action: () -> Unit)
I would then move describe, context, and it from the interface to instead be inline extension functions that just call this method. If someone wants to use given-when-then they can define extension functions with these names that similarly call this method.
Note, I made term nullable so that if it is null you do not add the term, colon, and space in front of the junit description so that you get just the description.