very simple, a controller object is just a subpatch.
in preferences give the name of a subpatch you wish to use as a controller object
(and ensure its enabled... theres a checkbox so its quick to enable/disable without having to enter the object name again)
whilst enabled, this subpatch will be wired into every patch you compile (ie. go live or put on sdcard)
it can do anything you want, but of course does not have inlets/outlets (by design, as if it did you would have to wire it in)
its normal use case is to use with a (hardware) controller (doh, hence the name ) so hence intercept the midi and then do something... this could be simple like intercept program change messages and change patches, or more complex like my Push object which intercepts all midi, applies scales, looks at parameters and displays them etc.
(you don't have to do midi it could for example use GPIO encoders)
the 'limitation' of not having outlets, means you will tend to use 'internal bus' to communicate with the main patch if necessary, or drive parameters directly... the later is more 'advanced' since its only possible via the C api.
quite likely other things are possible too, and it may be later I introduce some objects which allow controller objects to be built more easily ...
but for now Ive been using it really with my Push so that I can drive patches without having to patch the push in to each patch
tip: be careful with size/resources (e.g. preset allocation etc) a controller object uses, as its applied to all your patches, so its an 'overhead'... if a patch doesnt work with it enabled, try disabling it... if it works then probably your expecting a bit much the axoloti board, so you need to simplify your controller object
enjoy
Mark