Extensible shape API

Step 1 to full extensibility.

I plan to split the shape definitions out into separate files later, but for now I want the diff to be meaningful.

We should probably standardize all the constructors to take dicts instead of arg lists.