"This will do what you want 99% of the time. It will run mymodule:myfunc(), then it will run init:stop() without ever starting a shell."

I am the Erlang one percent!

That approach is exactly how I'd initially set up calling Heads-I-Lose from the command line. Despite my best efforts at error handling though I still kept generating crash dump files if the Met Office API happened to be down and I finally twigged it was nothing to do with my script, but the use of init stop on the command line: I think this is because if my script has errored out, then init stop is effectively trying to stop something that is already no longer running, which itself then leads to a crash.

So I decided to "fix" this by including init stop directly in my code rather than on the command line. But then quickly realised although this solved the problem on the command line, it meant developing and debugging in the Erlang shell was now tricky as I'd exit out my shell every time I called the function.

So the solution I came up with was to define a maybe_quit() function I called in an after block:

maybe_quit() ->
    Args = init:get_arguments(), 
    Found = lists:keyfind(noshell, 1, Args),
    if Found =:= false ->
        dont_quit;
    true -> init:stop()
    end.    

This checks whether it's running in a shell or not (as evidenced by the command line arguments and relying on noshell being specified on the command line) and if it is it does nothing, but otherwise calls init:stop().