Well, let's see. I am going to exaggerate a touch here but here is what I see at my workplace:
a. They will write an inline script. Solution: Rip it out into a file.
b. Each Job is using a different container. Solution: use Docker with mapped volumes or we all have the same machines (this might not be possible for some workloads) and only use a single container. Why not run the shell directly you may ask?
b.1 Each container has a different environment and my machine has one.
b.2 Some things do not run natively on my machine that do on theirs.
c. Variables are defined in the yaml instead of the scripts. Solution: Make a local .env file see b.
So sure, a local gitlab runner us probably best patch here. But I am imagine if someone made a container runtime specifically for this then wrapped that in a CI config it could be very ergonomic. Which is what I would explore if I where to write a IC today. I am sure some build system today already does this...
Things outside (kindof) of Gitlab's control that I might as well complain about while I am here:
d. And regardless, there are transient dependencies everywhere (which I blame the all language creators for really, mfs :P ). So everything gets fucked eventually anyhow. Wouldn't it be nice if you could whip out a three year old project, run the build, and its exactly as you left it?
e. People thinks all right to allow for mutable versions so I have to asdjnasdaskdjasdlasjdl;askjd;asldkj = asdasdljkdasl;kdjlaskdjaslkjd some non-human readable hash if I am feeling paranoid.
d. and e. are firmly in the language creators hand I believe. But Gitlab does offer artifact repositories (which are non-portable and could also easily could be). Gitlab could also save dependency trees in different languages. But really I would gripe to the tool/language creators.