I had used the Self command interface as my simulator's interface, just as you suggest. When you call up a new simulation it installs the top level component in a slot called simRoot*. You can then type expressions such as:
set: u1 nand out To: h After: 3. inv ntran source value. run.
This only works as long as you limit yourself to one simulation at a time which is no big deal since Self is single user for now.
I had hoped the the name inferencer would take care of the output as neatly as this trick helped with the input, but as simRoot* is an assignable slot I had to write a printString method for each type of object.
A neat side effect is that I can use the simulator interactively or place the commands in a file and _RunScript it in.