scryer-prolog can import libraries, but not custom modules:
$ cat test1.pl
:- module(test1, [myrel/3]).
myrel(g,h,i).
$ scryer-prolog
?- use_module(library(lists)).
?- use_module(test1).
caught: error(existence_error(procedure,use_module/1),use_module/1)
?- ^C
$
Thank you for your wonderful work, by the way, Mark!
Thank you for the kind words! I'll add this feature soon.
It has misleading error message. use_module/1 exists as a predicate.
So the error message should say that it only understands library/1 file
specifier. And not that the procedure doesn't exist.

Giving that the error message is ambivalent, I really don't know what
exactly is going on here. Whether ensure_loaded/1 is missing, or
whether it also does not understand plain file names:
If the file loaded by use_module doesn't contain a module declaration, what should be done?
Some Prolog systems throw an error, some don't. use_module/1 can be implemented similar like ensure_loaded/1. Especially if you don't throw an error. For example in my system, since I don't throw an error, they have the same implementation:
ensure_loaded(Path) :-
absolute_file_name(Path, Pin),
sys_load_file(Pin, [condition(on), sys_link(use_module)]).
use_module(Slash) :-
absolute_file_name(Slash, Pin),
sys_load_file(Pin, [condition(on), sys_link(use_module)]).
The only difference between ensure_loaded/1 () and use_module/1 (*) in my system, is that ensure_loaded/1 also understands "user". I did implement "user" as an import. ensure_loaded/1 is also what is used in []/2, so that in the end [user] works.
The =(X, user) in the code of ensure_loaded/1 to also understand "user" is something peculiar to hierarchical knowledge bases, since I have different user dynamic databases, so that the system can recognize from what context the [user] was issued.
()
https://github.com/jburse/jekejeke-devel/blob/master/jekrun/headless/jekpro/reference/bootload/load.p
(*)
https://github.com/jburse/jekejeke-devel/blob/master/jekrun/headless/jekpro/reference/bootload/module.p
"throw an error" is possibly the wrong phrasing. During consult and friends you might also consider displaying a warning instead throwing fatally an error, and aborting consult. If the end-user is in an editing phase, he might have forgotten something.
Warnings are more friendly towards a make/0, and IDEs that provide automatic build for Prolog. You can repeatedly issue make/0, edit away your warnings, until you are done with the many problems that your immature Prolog text had.
The built-in make/0 is from here:
https://www.swi-prolog.org/pldoc/man?predicate=make/0
Ideally, ensure_loaded/1 would be equivalent to use_module/2 with an empty import list (for module files). Otherwise, giving it the same semantics of use_module/1 becomes a mostly redundant alias. A system where ensure_loaded(F) is equivalent to use_module(F, []) is ECLiPSe. SWI-Prolog does, unfortunately and too late to change without breaking backwards compatibility, ensure_loaded(F) equivalent to use_module(F).
As a general point regarding errors: If you encounter a situation that your system cannot yet handle satisfactorily, for example because the feature is not yet implemented, or for example it is currently unclear what to do in that situation, then throwing an exception seems preferable over silent failure or success with unclear result.
An exception can be caught and inspected programmatically and allows nice clean test cases from within the Prolog system. Later, when you generalize the feature set, you can remove the exceptions.
This has been working for a while, and can be closed.