The parser gets to the code which constructs the module, and interprets I as sqrt(-1) before the interpreter runs it.
So, in the session in which you construct your module, you could call interface(imaginaryunit=ii) before the code that constructs the module.
I think I see what you intended. You invoked ModuleLoad(), which makes the `interface` call, inside the module's code. This would work for some actions (that you desired to occur even in the session which did not read the module from archive file) but not for what amounts to an adjustment in how the parser interprets the code up front.
interface(imaginaryunit=ii): # ..won't need this in new sessions where Q is read from archive
export `*`, Qdef, Qrand, Qreal, Qimag, Qconj, Qnorm, Qinv, eval, LagP, M;
M(I,I)=-1, M(I,J)=K, M(I,K)=-J,
M(J,I)=-K, M(J,J)=-1, M(J,K)=I,
M(K,I)=J, M(K,J)=-I, M(K,K)=-1);
M(a+b*x*I + c*x^2*J, d*I + x*K);
2 2 3
d a I + x a K - b x d - b x J - c x d K + c x I
If you savelib that module to a personal Library archive, then you shouldn't need to make the separate `interface` call in subsequent sessions which load it from archive. It would get done by the ModuleLoad.