Libraries shouldn't lie. That's not why they're called "lie-braries"...

The threadpool is an app-global resource, so you should leave the callers of your library to decide how and when they want to use it. Your library methods should not use the threadpool (Task.Run, Parallel.For, ...) internally in secret. Most of the time, they should have async signatures if and only if their internal implementations are truly async.

Slides, source code and transcript for this video are available here.

Sometimes you're forced to write a synchronous blocking method to fit into an older synchronous framework, but you still want to call new async APIs. There's no good answer here. People use Task.Wait() or Task.Result, which are bad solutions. Stephen Toub lists some less bad solutions here.

Sometimes you're trying to work in a modern asynchronous framework but you have to call legacy synchronous APIs. People use Task.Run here, but you should understand that there's simply no way to gain the scalability of async. For that you really need async all the way down. Once again, Stephen Toub fleshes out what to do here.