packages/omo-codex/plugin/skills/programming/references/go/one-liners.md
Production hygiene with throwaway ergonomics. Go scripts get the same strict lints, the same type discipline, the same 250 LOC ceiling. The difference: they live as single .go files invoked via go run, not as full modules.
Python has PEP 723 + uv run. Rust has rust-script. Go has go run directly — no extra tooling needed.
go runA .go file with a main package, run directly:
//go:build ignore
// fetch.go — fetch a URL and print body length.
//
// Usage:
// go run fetch.go <url>
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func main() {
if len(os.Args) < 2 {
log.Fatal("usage: go run fetch.go <url>")
}
resp, err := http.Get(os.Args[1])
if err != nil { log.Fatal(err) }
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil { log.Fatal(err) }
fmt.Printf("%d bytes\n", len(body))
}
Run: go run fetch.go https://example.com.
The //go:build ignore directive keeps this file out of go build ./... — it is a script, not part of the module. Without that line, every .go file in the package gets compiled into your binary.
scripts/myproject/
├── go.mod
├── internal/...
└── scripts/
├── seed/
│ └── main.go # `go run ./scripts/seed`
├── migrate/
│ └── main.go
└── one-time-fix/
└── main.go
Each scripts/<name>/main.go is its own main package. Invoke as go run ./scripts/seed/. Dependencies are shared with the parent module — no separate go.mod.
This is the right pattern when:
go run from shellgo run -mod=mod <(cat <<'EOF'
package main
import "fmt"
func main() { fmt.Println("hello") }
EOF
)
Rare, but useful for one-shot terminal experiments. The <(...) is process substitution; go run -mod=mod reads from stdin.
Even a 30-line script follows the philosophy:
Typed flags via flag or pflag, not os.Args string parsing past 2 args.
var (
url = flag.String("url", "", "URL to fetch")
limit = flag.Int("limit", 100, "max bytes")
)
flag.Parse()
if *url == "" { log.Fatal("--url required") }
context.Context propagation wherever I/O happens.
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", *url, nil)
log.Fatal is fine in main() of a script (programmer error / fatal path), but never inside any function the script imports. Library code returns errors.
Errors get wrapped. Same rule as production code:
if err != nil { return fmt.Errorf("fetch %s: %w", *url, err) }
Resources released via defer. No "I'll fix it later".
slog for output if it must be parseable. fmt.Println for one-shot terminal output is fine.
No more than 250 pure LOC. If it grows, it stops being a script and becomes a subcommand of your CLI tool.
Some scripts need deps the parent module does not have. Two options:
mkdir /tmp/migrate-tool && cd $_
go mod init scratch.local/migrate-tool
go get github.com/pressly/goose/v3
cat > main.go <<'EOF'
package main
import ... // use goose
func main() { ... }
EOF
go run .
Run, then delete /tmp/migrate-tool. Throwaway.
gorun (community tool)go install github.com/erning/gorun@latest
cat > script.go <<'EOF'
//usr/bin/env gorun "$0" "$@"; exit
// /// go.mod
// module scratch
// go 1.23
// require github.com/spf13/cobra v1.8.0
// ///
package main
...
EOF
chmod +x script.go
./script.go
gorun parses the inline go.mod block, materializes a temp module, runs the script. Niche tool — only if you want the executable-script experience.
If your script needs:
... promote it to a real CLI tool via cobra — see cobra-stack.md. The boundary is fuzzy; trust your judgment, but a 500-line "script" is not a script.
| Bad | Why | Good |
|---|---|---|
os.Args[1] indexing without length check | Panics on missing arg | flag.Parse() with explicit checks |
log.Fatal inside a function the script imports | Crashes caller's process | Return error |
panic(err) for expected failures | Same as above | log.Fatal in main, error return elsewhere |
Skipping defer resp.Body.Close() because "it's a script" | Leaks fd | Always close |
One 800-LOC main.go "to keep it simple" | Now harder to read than a real CLI | Promote to cmd/<name>/ with subcommands |
// TODO: handle error | Production-grade hygiene means production-grade hygiene | Handle now or document why ignored |
go run docs: https://pkg.go.dev/cmd/go#hdr-Compile_and_run_Go_program//go:build constraints: https://pkg.go.dev/cmd/go#hdr-Build_constraintssignal.NotifyContext: https://pkg.go.dev/os/signal#NotifyContext