I went ahead and ran your gist and all I had to do was use kAudioUnitSubType_DefaultOutput rather than kAudioUnitSubType_GenericOutput and I got a working lowpass with a render callback, you were very close! I did not set any ASBDs anywhere. And for the offline render, following christian's advice is the way to go. You don't need a graph or io unit, just AudioUnitInitialize your lowpass unit. I also checked out EZAudio.m from Haris and it has easy to read code for how to get some common ASBDs, and how to initialize the AudioBufferlist that you will need for doing the offline render. It's definitely worth a study, especially if your having trouble finding examples online.
Here I do the AudioBufferList setup and then thirty renders of 1024 frames of stereo float data:
AudioBufferList *bufferlist = malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)); //stereo bufferlist
float *left = malloc(sizeof(float) * 1024);
float *right = malloc(sizeof(float) * 1024);
bufferlist->mBuffers[0].mData = left;
bufferlist->mBuffers[1].mData = right;
AudioTimeStamp inTimeStamp;
memset(&inTimeStamp, 0, sizeof(AudioTimeStamp));
inTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
inTimeStamp.mSampleTime = 0;
AudioUnitRenderActionFlags flag = 0;
for (int i = 0; i < 30; i++) {
bufferlist->mBuffers[0].mDataByteSize = sizeof(float) * 1024;
bufferlist->mBuffers[1].mDataByteSize = sizeof(float) * 1024;
bufferlist->mNumberBuffers = 2;
AudioUnitRender(lowPass, &flag, &inTimeStamp, 0, 1024, bufferlist);
//do something with audio here
inTimeStamp.mSampleTime += 1024;
}