Skip to content

Instantly share code, notes, and snippets.

@garyblankenship
Created April 11, 2025 14:45
Show Gist options
  • Save garyblankenship/88ed1aa7256746766c42e28a41da4bc1 to your computer and use it in GitHub Desktop.
Save garyblankenship/88ed1aa7256746766c42e28a41da4bc1 to your computer and use it in GitHub Desktop.
Taskfile llms.txt

Taskfile (go-task) Documentation Summary for LLMs

Introduction

Task (also known as go-task) is a task runner and build tool written in Go. Its primary goal is to be simpler and easier to use than alternatives like GNU Make. It uses YAML files (typically Taskfile.yml or Taskfile.yaml) to define tasks, making it more readable and modern compared to Makefile syntax. Being a single binary written in Go, it has no runtime dependencies (other than the binary itself) and is cross-platform (Linux, macOS, Windows).

Core Concepts

  • Taskfile: A YAML file (default: Taskfile.yml or Taskfile.yaml in the current directory) that defines the configuration and tasks.
  • Tasks: Named sets of commands or actions defined within the Taskfile under the tasks: key.
  • Commands (cmds): The actual shell commands or actions a task executes. Can be single commands, multi-line scripts (using |), or calls to other tasks (task: other-task-name).
  • Running Tasks: Use the task command followed by the task name (e.g., task build). If no task name is provided, it runs the task named default.
  • YAML Syntax: Taskfiles use standard YAML syntax. Indentation (typically 2 spaces) is significant.

Key Taskfile Structure & Keywords

version: '3' # Specifies the Taskfile schema version (required)

# Optional global configurations
includes: # Include tasks from other files/directories
  # namespace: path/to/another/Taskfile.yml
  # another: ./DockerTasks.yml
  # remote: # Experimental feature
  #   taskfile: https://.../Taskfile.yml

dotenv: ['.env', '.env.local'] # Load environment variables from .env files

env: # Define global environment variables available to all tasks
  GLOBAL_VAR: value

vars: # Define global variables accessible via Go templating ({{.VAR_NAME}})
  OUTPUT_DIR: bin/
  DYNAMIC_VAR: # Can be dynamic based on a shell command
    sh: git rev-parse HEAD

output: prefixed # Global output style (interleaved, group, prefixed)
method: timestamp # Default method for up-to-date checks (timestamp, checksum)
run: always # Default run behavior (always, once, when_changed)

tasks:
  # --- Task Definition ---
  build: # Name of the task (use kebab-case recommended)
    desc: "Builds the application binary" # Optional: Description shown in `task --list`
    summary: | # Optional: Longer description shown in `task --summary build`
      This task compiles the Go source code
      and places the binary in the {{.OUTPUT_DIR}} directory.
    dir: backend/ # Optional: Execute commands in this directory
    env: # Task-specific environment variables (override global)
      CGO_ENABLED: 0
    vars: # Task-specific variables (override global)
      TARGET_OS: linux
    cmds: # List of commands to execute sequentially
      # Simple command
      - go build -o {{.OUTPUT_DIR}}myapp -ldflags="-s -w" ./cmd/myapp
      # Multi-line command
      - |
        echo "Building for {{.TARGET_OS}}..."
        GOOS={{.TARGET_OS}} go build -o {{.OUTPUT_DIR}}myapp-{{.TARGET_OS}} ./cmd/myapp
      # Calling another task sequentially
      - task: generate-assets
      # Call another task with specific variables
      - task: notify
        vars: { MESSAGE: "Build complete!" }
      # Deferred command (runs after task completes, even on error)
      - cmd: echo "Cleanup..."
        defer: true
    deps: # List of task dependencies (run BEFORE cmds, potentially in parallel)
      - clean
      - setup-tools
    preconditions: # Optional: Checks before running deps/cmds. Fail if any fail.
      - sh: "[ -f main.go ]"
        msg: "main.go not found!"
      - sh: "which go"
        msg: "Go compiler not found in PATH"
    status: # Optional: Check if task is up-to-date (alternative to sources/generates)
      # Run task only if this command exits non-zero
      - test -f {{.OUTPUT_DIR}}myapp
    sources: # Optional: Files/globs to check for changes
      - '**/*.go'
      - 'go.mod'
      - 'go.sum'
    generates: # Optional: Files/globs generated by the task
      - '{{.OUTPUT_DIR}}myapp' # Used with sources for up-to-date checks (timestamp/checksum)
    silent: false # Optional: If true, don't print task name/command before execution
    interactive: false # Optional: If true, allocates a TTY for interactive commands
    ignore_error: false # Optional: If true, continue execution even if a command fails
    run: default # Task-specific run behavior (always, once, when_changed)

  # --- Other Tasks ---
  clean:
    desc: "Remove build artifacts"
    cmds:
      - rm -rf {{.OUTPUT_DIR}}

  generate-assets:
    # ... commands to generate assets ...

  notify:
    internal: true # Optional: Hide from `task --list` unless `--list-all` is used
    cmds:
      - echo "{{.MESSAGE}}"

  setup-tools:
    # ... commands ...

  default: # Special task run when `task` is called without arguments
    desc: "Default task: lists available tasks"
    cmds:
      - task --list # A common default task pattern

  # Task using wildcard for dynamic arguments
  # Run like: task benchmark:my_module
  benchmark:*:
    vars:
      MODULE_NAME: "{{index .MATCH 0}}"
    cmds:
      - python -m {{.MODULE_NAME}}

# --- End of Taskfile ---

Variables

  • Definition (vars): Can be defined globally or per-task. Global vars are accessible in all tasks. Task vars override global vars.
  • Syntax: Use Go's template syntax {{.VAR_NAME}} to reference variables within cmds, deps, vars, etc.
  • Dynamic Variables: Can be set based on the output of a shell command using sh: "command".
  • Environment Variables (env):
    • Can be defined globally or per-task using the env: key.
    • Can be loaded from .env files using the dotenv: key.
    • Can be accessed within commands using standard shell syntax ($VARNAME or %VARNAME% on Windows).
    • Can be passed on the command line before the task name: MYVAR=value task mytask.
  • Task-Specific Variables: Variables passed when calling another task (task: other-task vars: {KEY: VAL}).
  • CLI Arguments (.CLI_ARGS): A special variable capturing arguments passed after -- on the command line (task mytask -- arg1 arg2).
  • Wildcard Matches (.MATCH): In tasks with * in their name, .MATCH is an array containing the matched wildcard parts. {{index .MATCH 0}} gets the first match.
  • Built-in Variables: .TASK (current task name), .OS, .ARCH, .ROOT_DIR (Taskfile directory), .USER_WORKING_DIR (directory where task was invoked, useful with -g).

Dependencies (deps)

  • Tasks listed under deps: are executed before the cmds: of the current task.
  • Dependencies are run in parallel by default for performance. They should generally not depend on each other's side effects within the same deps block.
  • If serial execution is needed, use sequential task: calls within the cmds: block instead of deps.

Up-to-Date Checks (Skipping Unnecessary Work)

  • Purpose: Avoid re-running tasks (like builds) if inputs haven't changed and outputs exist.
  • Methods:
    1. Timestamp: Define sources (inputs) and generates (outputs). Task runs if any source is newer than any generated file, or if generated files don't exist. Set method: timestamp.
    2. Checksum: Define sources. Task calculates a checksum of sources. Task runs if the checksum differs from the last successful run. Set method: checksum (often the default).
    3. Status (status): Define shell commands under status:. The task is considered up-to-date if all status commands exit with code 0. Task runs if any status command exits non-zero. This overrides sources/generates.
  • Forcing Execution: Use the --force (or -f) flag to run a task regardless of its up-to-date status.

Includes

  • Purpose: Organize tasks by splitting them into multiple files or directories.
  • Syntax: Use the includes: key at the top level.
    includes:
      # Assigns tasks from ./docker/Taskfile.yml to the 'docker' namespace
      # Run tasks like: task docker:build
      docker: ./docker/Taskfile.yml
      # Can also point to a directory, Task looks for Taskfile.yml inside
      docs: ./documentation
      # Can specify a different Taskfile name
      utils:
        taskfile: ./common/Utils.yaml
        # Optional: Change the working directory for included tasks
        # dir: ./common
  • Namespacing: Included tasks are typically accessed via <namespace>:<taskname>.
  • Flattening: Use flatten: true within an include definition to add tasks directly to the main namespace (use with caution to avoid name clashes).
  • Internal Includes: Advanced feature for embedding Taskfiles within Go binaries.

CLI Usage

  • task <task-name>: Run a specific task.
  • task: Run the default task.
  • task --list / task -l: List tasks with descriptions.
  • task --list-all / task -a: List all tasks, including internal ones or those without descriptions.
  • task --init / task -i: Create a basic Taskfile.yml in the current directory.
  • task --watch / task -w <task-name>: Run a task and re-run it whenever source files change.
  • task --force / task -f: Force task execution, ignoring up-to-date checks.
  • task --dry: Show what commands would run without executing them.
  • task --parallel / task -p task1 task2: Run specified tasks concurrently.
  • task --dir <path> / task -d <path>: Specify the directory containing the Taskfile.
  • task --taskfile <path> / task -t <path>: Specify a Taskfile name/path other than the default.
  • task --global / task -g: Look for and run $HOME/Taskfile.yml.
  • task --summary <task-name>: Show detailed summary/documentation for a task.
  • task -- <args...>: Pass arguments after -- to the .CLI_ARGS variable inside the task.
  • task <task-name> VAR=value OTHER='some value': Pass variables directly to a task (alternative to env vars).

Style Guide Recommendations

  • Use version: '3'.
  • Use 2 spaces for indentation.
  • Separate top-level sections (version, includes, vars, tasks, etc.) with blank lines.
  • Separate individual tasks within tasks: with blank lines.
  • Use uppercase for vars names (e.g., {{.OUTPUT_DIR}}).
  • Use kebab-case for task names (e.g., build-image).
  • Use : for namespace separation (docker:build).
  • Prefer external scripts for complex multi-line logic over embedding large scripts in cmds.
  • Provide desc for tasks intended for users.

Conclusion

Taskfile provides a powerful yet simple way to automate development workflows using readable YAML. Its features like dependency management, variables, includes, and up-to-date checks make it a compelling alternative to Makefiles, especially in Go projects and cross-platform environments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment