Skip to main content

Documentation Index

Fetch the complete documentation index at: https://tally.wharflab.com/llms.txt

Use this file to discover all available pages before exploring further.

tally supports configuration via TOML config files, environment variables, and CLI flags. Sources cascade in a predictable order so you can set project defaults while allowing per-run overrides.

Priority order

Configuration sources are applied highest-priority first:
  1. CLI flags--fail-level error
  2. Environment variablesTALLY_OUTPUT_FAIL_LEVEL=error
  3. Config file.tally.toml or tally.toml
  4. Built-in defaults

Config file

File names

tally looks for these config file names, in order:
  1. .tally.toml (hidden file, recommended)
  2. tally.toml

Discovery

tally uses cascading config discovery similar to Ruff:
  1. Starting from the Dockerfile’s directory, walks up the filesystem.
  2. Stops at the first .tally.toml or tally.toml found.
  3. Uses that config — no merging with parent configs.
This allows monorepo setups with per-directory configurations:
monorepo/
├── .tally.toml              # Default config for most services
├── services/
│   ├── api/
│   │   └── Dockerfile       # Uses monorepo/.tally.toml
│   └── legacy/
│       ├── .tally.toml      # Override for legacy service
│       └── Dockerfile       # Uses services/legacy/.tally.toml

Explicit config path

Override discovery with --config:
tally lint --config /path/to/.tally.toml Dockerfile

Config file reference

Controls how tally reports violations.
[output]
format = "text"           # text, json, sarif, github-actions, markdown
path = "stdout"           # stdout, stderr, or a file path
show-source = true        # Show source code snippets
fail-level = "style"      # Minimum severity for exit code 1
OptionDefaultDescription
format"text"Output format: text, json, sarif, github-actions, markdown
path"stdout"Output destination: stdout, stderr, or a file path
show-sourcetrueShow source code snippets alongside violations
fail-level"style"Minimum severity that produces exit code 1: error, warning, info, style, none

Environment variables

VariableDescription
TALLY_OUTPUT_FORMATOutput format: text, json, sarif, github-actions, markdown
TALLY_FORMATAlias for TALLY_OUTPUT_FORMAT
TALLY_OUTPUT_PATHOutput destination: stdout, stderr, or file path
TALLY_OUTPUT_SHOW_SOURCEShow source snippets: true / false
TALLY_OUTPUT_FAIL_LEVELMinimum severity for non-zero exit
NO_COLORDisable colored output (standard env var)

CLI flags

FlagDescription
--config, -cPath to config file (overrides discovery)
--no-configSkip config file discovery and use defaults plus env/CLI overrides
--excludeGlob pattern(s) to exclude files (repeatable)
--contextBuild context directory for direct Dockerfile linting
--targetBake target or group to lint (repeatable; Bake entrypoints only)
--serviceCompose service to lint (repeatable; Compose entrypoints only)
--selectEnable specific rules (repeatable)
--ignoreDisable specific rules (repeatable)

Build context and invocation flags

--context applies only when you lint Dockerfiles directly:
tally lint --context . Dockerfile
When you pass a Bake or Compose file, tally reads the build context from the selected target or service instead:
tally lint docker-bake.hcl --target api
tally lint compose.yaml --service api
Do not combine --context with a Bake or Compose entrypoint. Use --target only with Bake, and --service only with Compose. See Build invocations for the full entrypoint behavior.

Inline directives

Suppress specific violations using inline comment directives directly in your Dockerfile.
Suppress violations on the next line:
# tally ignore=StageNameCasing
FROM alpine AS Build
Suppress multiple rules with comma-separated values:
# tally ignore=StageNameCasing,DL3006
FROM Ubuntu AS Build
Suppress all rules on a line:
# tally ignore=all
FROM Ubuntu AS Build
Suppress violations throughout the entire file:
# tally global ignore=max-lines
FROM alpine
# ... rest of file is not checked for max-lines
Document why a rule is suppressed using ;reason=:
# tally ignore=DL3006;reason=Using older base image for compatibility
FROM ubuntu:16.04

# tally global ignore=max-lines;reason=Generated file, size is expected
Use --require-reason (or require-reason = true in .tally.toml) to enforce that all ignore directives include an explanation.
tally supports directive formats from other linters, making migration easy:
# hadolint ignore=DL3006
FROM ubuntu

# hadolint global ignore=DL3008
FROM alpine

# check=skip=StageNameCasing
FROM alpine AS Build

Example configurations

Strict CI

# .tally.toml - Strict settings for CI
[output]
format = "sarif"
path = "tally-results.sarif"
fail-level = "warning"

[rules]
include = ["buildkit/*", "tally/*", "hadolint/*"]

[rules.tally.max-lines]
max = 50
skip-blank-lines = true
skip-comments = true

[inline-directives]
require-reason = true
warn-unused = true

Relaxed development

# .tally.toml - Relaxed settings for development
[output]
format = "text"
show-source = true
fail-level = "error"

[rules]
include = ["buildkit/*", "tally/*"]
exclude = ["buildkit/MaintainerDeprecated"]

[rules.tally.max-lines]
severity = "warning"
max = 200

Monorepo setup

Place a root .tally.toml with shared defaults, then override for specific services:
monorepo/
├── .tally.toml              # Shared defaults
├── services/
│   ├── api/
│   │   └── Dockerfile       # Inherits root config
│   └── legacy/
│       ├── .tally.toml      # Legacy overrides
│       └── Dockerfile
# services/legacy/.tally.toml - Gradual migration from hadolint
[output]
format = "text"
fail-level = "error"

[rules]
# Start with just BuildKit rules; add hadolint rules gradually
include = ["buildkit/*"]

[rules.buildkit.StageNameCasing]
severity = "info"  # Downgrade during migration