Tips¶
Short, practical advice gathered from using asgard day to day. Each tip stands on its own; skim the bold phrases and read the ones that fit your project. Where a tip touches a feature in depth, it links to the page that covers it.
Getting Started¶
-
Start from working files. The task files at the repository root (
.loki,quality.loki,gem_tasks.loki,git.loki,doc_tasks.loki) are a real multi-file project: quality gates that return:passor:fail, a background job, a subcommand group, ahelperfeeding theheader, and a deliberate override for--doctor. Copy what fits. See The asgard Repository Itself. -
More examples. MadBomber/dev holds shared
.lokilibraries used across many repos: gem, git, Rails quality, schedule, status report and iTerm tasks. The Examples page walks through the repository'sexamples/directory, one small file per feature. -
One setup for every project. Put the tasks, shells and helpers you want everywhere in
~/.loki, then start each project's.lokiwithimport "~/.loki". Outside any project the same file is found by the walk up the tree, so those tasks work in any directory. See Task Files.
Naming and Running Tasks¶
-
Give busy tasks a short name with
map.map "t" => "test"stays stable when a later task would otherwise make the prefixtambiguous. Thor's prefix matching is handy; an alias is dependable. See Defining Tasks. -
Make bare
asgarddo the common thing.default_task :test(or:quality, as this repository does) saves typing on the task you run most. -
Flags go after the task name.
asgard build --verboseruns the task;asgard --verbose buildprints the help forbuild. Only--versionand--doctorgo first. See Options & Flags.
Organizing Many Tasks¶
-
One command group per file, named for the file. When a project outgrows a flat list of tasks, give each area its own
<name>.lokithat defines exactly one top-level command with its tasks as subcommands:box.lokiends withsubcommand "box", BoxCommandsand gives youasgard box up,asgard box logs,asgard box console;prod.lokigives youasgard prod info; and so on fordb,jira,stage,branch. The bare.lokiis the marker, starts withimport "*.loki", and keeps only the tasks that have to stay top-level: awatchtarget (a watcher can only run a top-level task) and*_checkgates thatqualityfinds by name.asgard helpthen lists a dozen groups instead of a hundred tasks, andasgard box helpshows one area at a time. Write the convention down in a comment at the top of.lokiso the next file follows it. See Subcommands Across Files. -
Put a one-word wrapper for each group in
bin/. Two lines of shell drop theasgardfrom every command you type all day:#!/usr/bin/env sh # Shortcut for `asgard box ...` — passes every argument and option through. exec asgard box "$@"Now
box up,box logs,prod info --webandjira 166are complete commands; every argument and flag passes straight through, sobox helpstill works. A wrapper can go one level deeper for the thing you do most:bin/workisexec asgard branch working "$@", sowork 168points the working clone at a ticket's branch. Put the wrappers onPATHonly inside the project with direnv (brew install direnv): it reads a.envrcin the project root as youcdin and undoes everything as you leave, so one line,PATH_add bin, makesboxmean this project's box here and nothing (or something else) in the next directory over. The same.envrcis the natural home for the project's environment variables, and asgard's watchers and schedules load it too; see.envrcand direnv.bin/stays an ordinarybin/, so a real script, such as a report generator, lives there beside the wrappers. -
Alias inside a group, too. Thor's prefix matching works on subcommands, so
box corunsconsoleuntil acommittask arrives;box stis already ambiguous betweenstart,statusandstop. Inside the group class,map "start" => "up", "c" => "console"gives the subcommands you type most a name that cannot drift. See Command Aliases.
Seeing What You Have¶
-
See the tasks by file with
asgard --doctor. It lists every.lokifile that loaded and, under each, the tasks that file defines with their line numbers, plus which.lokiwon the walk up the tree, what everyimportloaded, tasks hidden because they lack adesc, and definitions silently replaced by a later one. It works even when the.lokiwill not load. See The Doctor Report. -
See the commands as a tree with
asgard tree. Every command with its description, each subcommand group expanded under its own heading, header and footer included.helpshows what you can type;treeshows how it is organised. Seeasgard tree. -
Trace loading when something is missing.
RUBYOPT=-w asgard helpprints each file asimportloads it;ASGARD_TRACE=1turns a one-line load error into the full backtrace with Ruby's "Did you mean?" hint. See Tracing Imports and Load Errors.
Helpers and Dependencies¶
-
Keep helpers out of the command list. A public method without a
descis a hidden task: it runs from the command line and as a dependency. Make helpersprivate, wrap them inno_commands, or define them withhelper. See Helper Methods. -
Pass results, not instance variables. Parallel dependencies each run on their own copy of the task object, so an
@ivarset in one never reaches the task that depends on it. Return a value and read it withdep_result(:name)ordep_results;bad.lokishows the trap. See Dependencies. -
Let gates report, let guards stop. A quality gate returns
:failso every gate runs and the summary shows all failures at once. A guard such asconfirm.lokiraisesAsgard::Errorso nothing after it runs. A dependency's return value never stops its dependent; only an exit,abortorraisedoes. -
Import conditionally.
.lokiis plain Ruby:import "quality_rails.loki" if ENV["RAILS_ROOT"]keeps Rails-only gates out of non-Rails projects, and a block-formdepends_onpicks up whatever*_checktasks are loaded. See Loading Patterns.
Shells and Processes¶
-
Name shell configurations, not shells. The name you give
shellis yours:shell :strict, "bash -eu -o pipefail"names a bash configuration that stops at the first failing line, andshell :uv, "uv run --script", ext: ".py"names a way of running Python.shandshebangtake a name as an optional first argument (sh :strict, "..."); without one they run thedefault_shell, sodefault_shell :strictmakes every plainshfail fast. See TheshellsRegistry. -
An AI agent is just another shell. Register a coding agent's CLI with
shelland a heredoc becomes the prompt:examples/robots/.lokiwires upclaude -pin one line, and itsasktask sends a prompt with a plainsh :claude, <<~PROMPT. Any agent that reads a prompt from stdin fits the same way, so a task can review a diff, draft release notes or explain a failing test alongside the tasks that run them. -
Prefer
background: trueto a trailing&. A managed job gets a name, a log andasgard jobs stop; a process detached with&leaves no record and must be found withps. See Background Jobs.