Technically one could argue that it is idempotent. Running it twice does not result in different things: build(build(x)) == build(x).
However, I see the complication you're encountering when trying to extend a plugin; I've run into the same issues myself. The reason the build directory is removed at the beginning of the build step is in the case of a previously failed build. We're working toward being able to resume such builds, but it requires some other things to happen first.
Technically one could argue that it is idempotent. Running it twice does not result in different things: build(build(x)) == build(x).
However, I see the complication you're encountering when trying to extend a plugin; I've run into the same issues myself. The reason the build directory is removed at the beginning of the build step is in the case of a previously failed build. We're working toward being able to resume such builds, but it requires some other things to happen first.