Writing .gl scripts
.gl files turn a chain of gapline commands into a single, committable artifact. They are the right tool when a cleanup is worth re-running weekly, shipping in a repo, or handing to a colleague as a reproducible pipeline.
This guide builds a weekly-fix script from scratch: validate, patch a few known issues, re-validate, save.
Anatomy of a .gl file
Section titled “Anatomy of a .gl file”A .gl file is plain text:
# Comments start with '#'. They can be on their own line or at the end of one.
feed ./data/gtfs.zip # First directive — load the feed into memory.
validate --min-severity error # Any gapline command, without the -f flag.
save ./data/gtfs-patched.zip # Atomic write. Without a path, rewrites the source.Three things to know up front:
feedalways comes first. It loads the archive once; every subsequent command works against that in-memory copy.saveis explicit. Nothing reaches disk untilsaveruns — if the script crashes in the middle, the source feed is untouched.- Stop-on-error. The first failing command halts the script. Combined with the point above, this makes
.glfiles safe to re-run.
The full grammar is documented on .gl syntax; the runtime semantics are in concepts / .gl session model.
A weekly-fix script
Section titled “A weekly-fix script”The goal: every Monday morning, validate the production feed, apply the known cleanups, and hand the team a fresh JSON report.
# Load the latest feed dropped by the nightly sync.feed ./data/gtfs.zip
# Prune the retired line and everything that references it.delete trips --where "route_id=OLD_LINE" --confirmdelete routes --where "route_id=OLD_LINE" --confirm
# Normalize the mis-coded bus routes.update routes --where "route_type=700" --set route_type=3 --confirm
# Snapshot the post-cleanup report for the team.validate --format json -o ./reports/weekly.json
# Atomic write. Only reached if every step above succeeded.save ./data/gtfs-patched.zipRun it:
gapline run weekly-fix.glIf any command fails, the run halts, save is skipped, and ./data/gtfs.zip on disk is unchanged. Fix the reported issue and re-run.
Command flags inside a script
Section titled “Command flags inside a script”Every flag the CLI accepts works inside a .gl file, with one exception: -f / --feed is supplied by the feed directive, so you omit it on every subsequent command. --output still works if you want to dump an intermediate report to a different path than the one save will use.
feed ./data/gtfs.zip
# The feed flag is implicit — validate operates on the in-memory copy.validate --min-severity warning --format json -o pre-cleanup.json
update stops --where "stop_id=S01" --set stop_name="Gare Centrale" --confirm
validate --min-severity warning --format json -o post-cleanup.json
saveCalling save without a path rewrites the source file — in this case ./data/gtfs.zip. Pass a path to preserve the original.
What .gl cannot do
Section titled “What .gl cannot do”- No variables, no substitution. Paths and values are literal.
- No conditionals, no loops, no error-handling blocks. Execution is strictly linear.
- No nested
run. You cannot call a.glfile from another.glfile.
If your workflow needs branching or templating, drive gapline from a shell script and keep the .gl file small. .gl is a declarative format on purpose — readable at a glance, safe to version-control, no hidden control flow.
Running from CI
Section titled “Running from CI”- run: gapline run weekly-fix.gl- uses: actions/upload-artifact@v4 with: { name: weekly-reports, path: reports/ }- run: | case $? in 0) ;; # Script completed, save succeeded. 1) echo "A step failed — source feed unchanged." ; exit 1 ;; *) exit 1 ;; esacExit codes mirror the first failing sub-command’s code. See concepts / exit codes.
See also
Section titled “See also”gapline run— the command reference..glsyntax reference — directive grammar.- Concepts /
.glsession model — in-memory state, save semantics. - Guides / CI integration.