Skip to content

Latest commit

 

History

637 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gavel

Gavel

A CLI toolkit for testing, linting, AI-powered code review, and CI automation.

Install

# From source
go install github.com/flanksource/gavel/cmd/gavel@latest

# Or build locally
task build       # also: make build
task install     # installs to $GOPATH/bin

Pre-built binaries for Linux, macOS, and Windows are available on the Releases page.

For embedded and externally managed database observability, top-statement queries, and safe session-storage maintenance, see PostgreSQL performance diagnostics.

GitHub Action

Run gavel test --lint in CI, upload JSON + HTML artifacts, and post a sticky PR comment with the markdown summary.

Minimal usage

- uses: flanksource/gavel@main
  with:
    args: test --lint

Full example

jobs:
  test:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write # required when comment=true so the action can post/update the sticky PR comment
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: flanksource/gavel@main
        with:
          args: test --lint
          timeout-minutes: "20"
          version: latest
          json-file: gavel-results.json
          html-file: gavel-results.html
          summary-file: gavel-summary.md
          artifact-name: gavel-results
          comment: "true"
          comment-header: gavel
          fail-on-error: "true"

If you disable PR commenting (comment: "false"), contents: read is sufficient. Keep pull-requests: write when the action should post or update the sticky PR comment.

Inputs

Input Default Description
args test --lint Arguments passed to gavel
working-directory . Working directory for execution
timeout-minutes 20 Hard wall-clock limit; timeout diagnostics are printed before the process tree is terminated
version latest Release tag, latest, or source to use a pre-installed binary
json-file gavel-results.json Path for the JSON artifact
html-file gavel-results.html Path for the HTML artifact
summary-file gavel-summary.md Path for the compact markdown summary
artifact-name gavel-results Name of the uploaded artifact bundle
comment true Post/update a sticky PR comment with the summary
comment-header gavel Unique marker for the sticky comment (allows multiple comments per PR)
github-token ${{ github.token }} Token used to post PR comments
fail-on-error true Fail the step when gavel exits non-zero (artifacts are still uploaded)

Outputs

Output Description
exit-code Exit code from gavel
json-path Absolute path to the JSON artifact
html-path Absolute path to the HTML artifact
summary-path Absolute path to the markdown summary
log-path Absolute path to the stderr log (gavel.log) — always present, even on crash

The action is crash-resilient: if gavel exits before writing results, placeholder stubs with the exit code and log tail are written so the artifact upload and PR comment still succeed.

Commands

Testing & Linting

gavel test

Discover and run Go and Ginkgo tests with structured output, optional linting, benchmarks, fixture files, and a live browser UI.

gavel test ./pkg/...
gavel test --lint                                     # run linters in parallel with tests
gavel test --ui                                       # launch browser dashboard
gavel test --changed                                  # only packages affected by local changes
gavel test --cache                                    # skip packages unchanged since last pass
gavel test --bench .                                  # run benchmarks alongside tests
gavel test --fixtures                                 # discover and run *.fixture.md files
gavel test --format "json=out.json,html=report.html"  # write multiple output formats
gavel test --dry-run                                  # show what would run without executing
gavel test history                                    # show local test duration/pass history
gavel test ./pkg -- -run 'TestFoo'                    # focus Go test and Ginkgo by name
gavel test ./pkg -- --focus 'TestFoo'                 # equivalent native focus spelling
gavel test ginkgo ./pkg -- --label-filter smoke       # raw args for one framework

The first -run or --focus immediately after -- is normalized through each runner's focus mapping. Any other arguments after -- require exactly one selected framework, using a framework subcommand or a single --framework value.

Flag Description
[paths...] Package paths to test (e.g. ./pkg/...). If empty, all packages are discovered.
--lint Run linters in parallel with tests
--ui Launch browser with real-time test progress dashboard
--addr Interface to bind the UI server (default: 0.0.0.0, all interfaces; set localhost to restrict to this machine)
--cache Skip packages whose content fingerprint matches the last passing run
--changed Only run packages affected by staged/unstaged/untracked changes vs origin/main
--since Only run packages affected by the diff since <ref> (merge-base)
--bench Run Go benchmarks matching this regex (. runs all)
--fixtures Discover and run fixture files (also enabled via .gavel.yaml)
--fixture-files Globs for fixture discovery (default: **/*.fixture.md)
-p / --nodes Number of parallel Ginkgo nodes (0 = default, -1 = auto)
-r / --recursive Recursive test discovery (default: true)
--show-passed Show passed tests in output
--show-stdout When to show stdout: Never, OnFailure (default), Always
--show-stderr When to show stderr: Never, OnFailure (default), Always
--skip-hooks Skip .gavel.yaml pre/post hooks (default: skip locally, run in CI)
--dry-run Print test commands without executing
--auto-stop With --ui, fork a detached UI server that exits after this duration
--idle-timeout With --ui --auto-stop, exit the detached UI after no HTTP requests
--extra-args Additional arguments broadcast to every selected test runner
--work-dir Working directory to run tests in

gavel test history

Show a package/file/suite outline of executable tests from completed .gavel/run-*.json snapshots.

gavel test history
gavel test history ./pkg/foo
gavel test history pkg/foo/foo_test.go --format json

Each leaf row shows min/avg/max duration, execution count, pass rate, last passed, last failed, and the date the test first appeared in local history. Optional paths filter by package or file relative to --cwd.

gavel lint

Run linters on the project. Auto-detects which linters are installed and applicable.

Supported linters: golangci-lint, ruff, eslint, oxlint, react-doctor, pyright, tsc, markdownlint, vale, jscpd, betterleaks.

gavel lint
gavel lint --fix                            # auto-fix violations
gavel lint --triage                         # interactive mode to select violations to ignore
gavel lint --changed                        # only new issues vs origin/main
gavel lint --ui                             # view violations in browser
gavel lint --dry-run                        # show linter commands without executing
gavel lint secrets                          # run betterleaks only (alias)
gavel lint react-doctor                     # run React Doctor only
gavel lint jscpd eslint                     # run specific linters by name
Flag Description
[linters/files...] Positional args: linter names run only those linters; file paths lint only those files
--linters Comma-separated linter names or * for all (default: *)
--fix Enable auto-fixing
--triage Interactive mode to select violation types to ignore (saves to .gavel.yaml)
--changed Only report new issues vs origin/main (or $GAVEL_CHANGED_BASE)
--since Only report new issues since <ref> (merge-base with HEAD)
--ignore Glob patterns to exclude from linting
--ui Launch browser UI to view violations
--addr Interface to bind the UI server (default: 0.0.0.0, all interfaces; set localhost to restrict to this machine)
--no-cache Disable caching/debounce
--timeout Timeout per linter (default: 5m)
--dry-run Print linter commands without executing

Config-file-gated linters only run when a usable config or native project signal is discovered, unless explicitly named. For betterleaks that includes native config files (.betterleaks.toml / .gitleaks.toml) and any existing paths from secrets.configs across layered .gavel.yaml files. React Doctor runs when package.json declares React or a common React framework/plugin, and can also be enabled with doctor.config.*, legacy react-doctor.config.json, or package.json#reactDoctor. Disable betterleaks entirely via secrets.disabled: true in .gavel.yaml.

gavel test outline

Inspect every supported test source without running test bodies:

gavel test outline
gavel test outline --framework jest,playwright
gavel test outline --framework fixture --fixture-files 'examples/*.fixture.md'

The default outline includes Go test, Ginkgo, Jest, Vitest, Playwright, and Markdown fixtures. Positional paths constrain discovery, while --fixture-files overrides fixture globs from .gavel.yaml. Use gavel fixtures outline when you need fixture-specific sections, tables, AI criteria, and kind counts rather than the unified test view.

gavel fixtures

Run declarative tests defined in markdown files using tables, command blocks, or standalone code blocks.

gavel fixtures tests.md
gavel fixtures fixtures/**/*.md
gavel fixtures -v tests.md                  # verbose (stderr on pass, stdout+stderr on fail)
gavel fixtures -vv tests.md                 # more verbose
gavel fixtures --no-progress tests.md       # disable progress display
gavel fixtures outline fixtures/**/*.md     # parse and summarize without executing

Use gavel fixtures outline when you want to inspect fixture files, sections, tables, runner steps, AI checks, and source locations without running any build, daemon, command, test/lint, skip, or AI work.

The same runner can be used from Go tests. Import the default fixture types when using exec fixtures:

import (
	"testing"

	"github.com/flanksource/gavel/fixtures"
	_ "github.com/flanksource/gavel/fixtures/types"
)

func TestFixtures(t *testing.T) {
	runner, err := fixtures.NewRunner(fixtures.RunnerOptions{
		Paths: []string{"fixtures/**/*.md"},
	})
	if err != nil {
		t.Fatal(err)
	}
	runner.RunTesting(t)
}

RunTesting(t) mirrors markdown files, headings, tables, and table rows as nested t.Run nodes when passed a *testing.T. Use RunGomega(gomega.NewWithT(t)) for aggregate Gomega assertions, RunGinkgo() inside an existing Ginkgo It, or RegisterGinkgoSpecs() during Ginkgo spec registration when fixture files, sections, and rows should become Describe/It nodes.

Fixtures support three formats in a single markdown file:

Table format (preferred) — each row is a test. Custom columns become template variables in exec/args:

---
exec: bash
args: ["-c", "curl {{.flags}} {{.baseUrl}}{{.path}}"]
baseUrl: https://api.example.com
flags: "-s"
---

| Name       | path    | CEL                      |
|------------|---------|--------------------------|
| get users  | /users  | json.size() > 0          |
| get health | /health | json.status == "ok"      |

Command blocks — use when commands are multi-line or need per-test setup:

### command: my test
```yaml
exitCode: 0
env:
  KEY: value
```

```bash
echo "hello"
```

* contains: hello

Standalone code blocks — auto-detected from headings:

## Smoke Tests

```bash
echo "auto-detected"
```

* cel: stdout.contains("auto-detected")
Front-matter reference

File-level front-matter applies to all tests. Fields marked with can also be set per-test via table columns or command block YAML.

---
build: go build -o myapp           # run once before all tests
exec: ./myapp                      # † default executable (default: bash)
args: [--verbose]                  # † default arguments
env:                               # † environment variables
  LOG_LEVEL: debug
cwd: ./testdir                     # † working directory (relative to fixture file)
terminal: pty                      # † pseudo-terminal mode (merges stdout/stderr)
files: "**/*.go"                   # glob: replicate tests per matching file
codeBlocks: [bash, python]         # languages to execute (default: [bash])
timeout: 30s                       # † total timeout
os: linux                          # † skip on other OSes (prefix ! to negate: !darwin)
arch: amd64                        # † skip on other architectures
skip: "! command -v docker"        # † skip if command exits 0
---

Auto-injected variables (available as $VAR, {{.VAR}}, and env vars):

Variable Description
GIT_ROOT_DIR Nearest parent directory containing .git
GO_ROOT_DIR Nearest parent directory containing go.mod
ROOT_DIR GIT_ROOT_DIR if available, else GO_ROOT_DIR, else working directory
CWD Resolved working directory for the test
GOOS Go runtime OS (e.g. linux, darwin)
GOARCH Go runtime architecture (e.g. amd64, arm64)
GOPATH Go workspace path

CWD resolution priority: Test-level CWD → File-level CWD → SourceDir (directory of fixture file) → --cwd flag or current working directory.

See gavel fixtures --help for the full reference including CEL variables, validation shorthand, supported languages, and template syntax.

Example workflows — ready-made templates in examples/ that run against the bundled examples/sample-app; compose the yaml test / yaml lint steps and AI verification:

Run one with gavel fixtures examples/precommit.fixture.md, or copy it into your project.

gavel bench

Run Go benchmarks and compare base vs head results for regression detection.

# Run benchmarks and write JSON
gavel bench run ./pkg/... --out base.json
gavel bench run ./pkg/... --out head.json --count 10

# Compare results
gavel bench compare --base base.json --head head.json
gavel bench compare --base base.json --head head.json --threshold 15 --ui

bench run flags:

Flag Default Description
--count 6 Number of times to run each benchmark
--timeout 20m Test execution timeout
--benchtime 1s Duration per benchmark
--out stdout Write JSON results to file
--pattern . Benchmark name regex
--benchmem true Include memory allocation stats
--extra Extra flags passed through to go test

bench compare flags:

Flag Default Description
--base Path to base bench JSON (required)
--head Path to head bench JSON (required)
--base-label base Display label for the base run
--head-label head Display label for the head run
--threshold 10 Regression threshold in percent
--ui false Launch browser UI with the comparison
--addr 0.0.0.0 Interface to bind the UI server (all interfaces; set localhost to restrict to this machine)

Code Review & Commits

gavel commit

Generate a conventional commit message via LLM and run pre-commit hooks from .gavel.yaml.

gavel commit                          # LLM-generated message, staged changes
gavel commit -t                       # choose files in an interactive tree picker
gavel commit -i -s                    # stream one-line AI summaries into picker rows
gavel commit -A                       # stage everything, let the LLM split it into logical commits + a chore commit for lock/generated files
gavel commit --max-commits=3          # same as -A, capped at 3 logical commits (implies -A)
gavel commit -m "chore: bump dep"     # explicit message, still run compatibility analysis
gavel commit --stage all --dry-run    # stage everything, print message
gavel commit --force                  # skip hooks
Flag Description
--stage Which changes to commit: session (default — commits only the running agent's edits, resolving GAVEL_SESSION_ID/CLAUDE_SESSION_ID/CODEX_SESSION_ID, falling back to staged when none is set), staged, unstaged, all, or an explicit Claude/Codex session id
-t / --tree, -i / --interactive Open an interactive tree picker over changed files; press / in the picker to filter by path, status, language, or scope
-s / --summary With -i/-t, stream a one-line AI summary into each candidate file row while the picker remains interactive
-A / --commit-all Stage all changes and ask the LLM to split them into logical commit groups (plus a separate chore commit for lock files / build artifacts / generated bundles). Each group is committed as soon as its message is ready
--max-commits Cap the number of logical commits, excluding the chore commit (default 7). Setting it implies -A. Rendered into the grouping prompt's output schema as maxItems and enforced by captain's schemaStrictness=retry policy
-m / --message Explicit commit message; skips only the message-generation LLM call
--model Override LLM model for commit-message/PR generation from .gavel.yaml commit.message.model (falling back to ai.model); accepts a compact mode:model:effort selector
--group-model Override LLM model for AI grouping (-A) from .gavel.yaml commit.grouping.model (capable/sonnet-class); falls back to --model
--dry-run Print the generated message without committing
--force Skip pre-commit hooks
--no-cache Bypass the LLM response cache
--precommit How to handle gitignore + linked-dependency precommit checks: prompt, fail, skip, or false

Pre-commit hooks are configured in .gavel.yaml under commit.hooks — see Configuration. Combined precommit behavior is controlled by .gavel.yaml commit.precommit.mode.

Pull Requests

gavel pr status

Show GitHub Actions status for a pull request.

gavel pr status
gavel pr status 42
gavel pr status https://github.com/owner/repo/pull/123
gavel pr status --follow --interval 30s
gavel pr status --follow --actions 'CI / Test' --fail-fast
gavel pr status --follow --comments '@coderabbit'
gavel pr status --logs --tail-logs 50
Flag Description
-R / --repo GitHub repository (owner/repo)
--follow Keep watching until the dimensions you filtered on settle (see below)
--fail-fast With --follow, return at the first definitive failure instead of waiting for the rest
--interval Poll interval (default: 30s)
--logs Fetch and include failed job logs (uses extra API quota)
--tail-logs Number of failed log lines to show per step (default: 100)
--comments Filter review comments by MatchItem patterns over comment ID and @author/@bot tokens
--actions Filter workflow actions by MatchItem patterns over run/workflow ID, YAML path, workflow name, or job/check name

--follow gates on the dimensions you actually filtered on, ANDed together: with --actions it waits for the selected checks to complete, with --comments it waits for the selected review threads to be resolved, and with neither it waits for the whole rollup. A selector that matches nothing is an error, not a completion.

A PR GitHub reports as CONFLICTING renders a Merge conflicts section listing every conflicting path, how it conflicts, and the commands that clear it — replayed locally with git merge-tree, since no GitHub API returns the paths. The exit code is 1 whenever the PR cannot merge: a failing check, a failing job, a failing gavel shard, or a merge conflict.

gavel pr list

List pull requests with filtering, a live browser dashboard, and macOS menu bar indicator.

gavel pr list
gavel pr list --ui                            # live dashboard in browser
gavel pr list --menu-bar                      # macOS menu bar status indicator
gavel pr list --state merged --since 30d
gavel pr list --any --status                  # all authors, with check status
gavel pr list owner/repo another/repo         # specific repos
gavel pr list --all --org myorg               # all repos in org
Flag Description
--author GitHub username (default: @me)
--since Show PRs updated since (e.g. 7d, now-30d, 2024-01-01)
--state PR state: open (default), closed, merged, all
--all List PRs across all repos in the org
--any Show PRs from all authors
--bots Include bot-authored PRs
--org GitHub org for --all (auto-detected from git remote)
--limit Maximum PRs to return (default: 50)
--status Show GitHub Actions check status counts
--logs Fetch failed job log tails (requires --status -v)
--url Show PR URL instead of number
--ui Open PR dashboard in browser with live updates
--menu-bar Show macOS menu bar status indicator
--interval Poll interval for --ui/--menu-bar (default: 60s)
--addr Interface to bind the --ui/--menu-bar server (default: 0.0.0.0, all interfaces; set localhost to restrict to this machine)
--port UI port (default: 9092, 0 to auto-scan upward for a free port)

Git Analysis

gavel git history

Retrieve and filter commit history from a git repository.

gavel git history --path .
gavel git history --since 2024-01-01 --until 2024-06-01
gavel git history --author "alice" --message "feat*"
gavel git history abc1234                    # specific commit
gavel git history main..feature-branch       # commit range
Flag Description
--path Path to git repository (default: .)
--since Start date for filtering
--until End date for filtering
--author Filter by author name/email (repeatable)
--message Filter by commit message
--show-patch Include diffs

gavel git analyze

Analyze commits with scope/technology detection, Kubernetes resource change tracking, severity scoring, and optional AI-powered analysis.

gavel git analyze
gavel git analyze --ai --ai-model api:haiku
gavel git analyze --scope backend --tech kubernetes
gavel git analyze --summary --summary-window week
gavel git analyze --include bots --exclude merges --verbose
gavel git analyze --input previous-run.json   # re-analyze from JSON
Flag Description
--ai Enable AI-powered analysis
--model AI model to use
--scope Filter by scope types
--commit-types Filter by conventional commit types
--tech Filter by technologies
--summary Generate a tree-based summary
--summary-window Grouping window: day, week, month, year
--include Include named filter sets from .gitanalyze.yaml
--exclude Exclude named filter sets from .gitanalyze.yaml
--verbose Show what was skipped and why
--input Load from previous JSON output (repeatable)
--short Show condensed file-change summary

gavel git init-config

Create a .gitanalyze.yaml with sensible defaults, then optionally spawn an AI CLI to analyze the repo and recommend additional rules.

gavel git init-config                          # create defaults + AI recommendations via claude
gavel git init-config --model gemini           # use gemini instead
gavel git init-config --model codex            # use codex instead
gavel git init-config --model none             # just create the defaults file, no AI
Flag Description
--path Path to git repository (default: .)
--model AI CLI to use: claude, gemini, codex, or none (default: claude)
--debug Enable debug logging

gavel git amend-commits

Interactively improve commit messages using AI. Rewrites commits below a quality score threshold.

gavel git amend-commits
gavel git amend-commits --threshold 5.0 --base main
gavel git amend-commits --dry-run

Infrastructure

gavel ssh serve

Start an SSH server that accepts git push and runs gavel test --lint. Developers add it as a git remote for local CI-like flows with real-time streaming results.

# Start the server
gavel ssh serve --port 2222

# From any project, add as a remote and push
git remote add gavel ssh://localhost:2222/myproject
git push gavel HEAD:main

Results stream back in real-time. Push is rejected on test failure. Repos are cached for fast incremental pushes.

Flag Description
--port SSH server port (default: 2222)
--host Listen address (default: 0.0.0.0)
--host-key Path to SSH host key (default: ~/.gavel/ssh_host_key)
--repo-dir Directory for cached bare repos (default: ~/.gavel/repos)

The command run on push defaults to gavel test --lint but can be overridden via ssh.cmd in .gavel.yaml.

gavel ssh install

Install and enable a systemd unit for the SSH server (Linux only).

gavel ssh install                    # install and enable service
gavel ssh install --dry-run          # preview without making changes
gavel ssh install --port 3333 --user gavel
Flag Description
--port SSH server port (default: 2222)
--host Listen address (default: 0.0.0.0)
--user System user to run the service as (default: gavel)
--unit-path Path to write the systemd unit (default: /etc/systemd/system/gavel-ssh.service)
--data-dir Directory for host key and cached repos (default: /var/lib/gavel)
--binary Path to the gavel binary (default: current executable)
--dry-run Print actions without writing
--force Overwrite an existing unit file

gavel summary

Build a compact markdown PR-comment summary from a gavel test/lint JSON result file.

gavel summary --input gavel-results.json
gavel summary --input results.json --output summary.md
Flag Description
--input Path to gavel JSON result file
--output Path to write compact markdown (default: stdout)

gavel ui serve

Run a standalone UI server for replaying a previously captured test run.

gavel ui serve run.json
gavel ui serve run.json other-run.json --auto-stop=10m --idle-timeout=5m
Argument / Flag Description
run.json [other-run.json ...] One or more JSON snapshots to load and merge in order
--port Bind this port (0 = pick ephemeral)
--addr Interface to bind (default: 0.0.0.0, all interfaces; set localhost to restrict to this machine)
--auto-stop Hard wall-clock deadline from process start (default: 30m)
--idle-timeout Exit after this long with no HTTP requests (default: 5m)
--url-file Write the bound URL to this path for scripting

gavel repomap

View the merged architecture configuration for a repository path.

gavel repomap view .
gavel repomap get src/main.go

gavel config

View the merged .gavel.yaml for a path.

Interactive output shows merged YAML with comments for non-git-root sources. Redirected output, --yaml, and --json emit only the merged config. Pass --resolve (-r) to expand all registered AI prompts, including inline Captain specs and file-backed templates, and show both declared and effective model/backend details. With --json or --yaml, resolved output is wrapped as {config, prompts}.

gavel config
gavel config ./pkg/api
gavel config ./cmd/gavel/main.go
gavel config --yaml ./cmd/gavel/main.go
gavel config --resolve ./cmd/gavel/main.go
gavel config --resolve --json
gavel config > merged.gavel.yaml

Resolution order is: built-in defaults, ~/.gavel.yaml, <git-root>/.gavel.yaml, and <target-dir>/.gavel.yaml (or the parent directory when the target is a file).

Task Management

gavel todos

Manage and execute native PostgreSQL TODO issues with Claude or Codex.

Every todo moves through a lifecycle: an ordered set of steps, each a captain prompt reference plus a CEL when predicate (deciding whether the step applies now) and ordered outcomes (deciding which status a finished run lands the todo in). review and ask are human-facing statuses, not steps — they wait on gavel todos plan approve|reject|revise or an answer to the agent's questions. See MANUAL.md for the full model and the retired-flags table.

gavel todos list
gavel todos list --status pending
gavel todos run 3f2a1b
gavel todos steps 3f2a1b                 # which lifecycle steps apply to this todo now
gavel todos run --step plan              # propose a reviewable plan first (read-only)
gavel todos check 3f2a1b                 # run the TODO's complete definition of done

--step names the lifecycle step to run (plan, verify, run, triage, or any step the project's lifecycle declares); empty lets the lifecycle pick the next applicable step. --model selects the model, in the compact mode:model:effort form (cli:opus:high, api:sonnet).

The configured checks: test/lint suite is part of every todo's definition of done: when .gavel.yaml checks.enabled (or a todo's own checks: front matter) turns it on, the run step executes it after the agent reports done and feeds any failures back into the same session until they pass (bounded by todos.run.workflow.verify.maxIterations).

gavel todos check is the lifecycle's verify step run standalone: the same fixture/CEL definition of done used by the implementation loop — configured test/lint checks, the issue's persisted ## Verification fixture, and any acceptance-criteria checklist step.

The old --driver, --mode, --prompt, and --group-by flags on todos run no longer exist; see MANUAL.md for their replacements.

Output Formats

Many commands (test, lint, bench compare, pr status, pr list) support the --format flag for structured output:

# Single format
gavel test --format json

# Multiple formats written simultaneously
gavel test --format "json=results.json,html=report.html"

# Used by the GitHub Action internally
gavel test --lint --format "json=gavel-results.json,html=gavel-results.html"

Supported formats: json, html, text (default).

Configuration

.gavel.yaml

Project-level configuration placed at the repository root. Gavel also loads ~/.gavel.yaml for user-level defaults and merges them (repo settings win).

Use gavel config [path] to inspect the merged result for any directory or file path. A full annotated example lives in gavel.yaml.example and is also rendered in gavel config --help.

verify:
  model: claude                      # AI model for generic AI verification fixtures
  checks:
    disabled: [SEC-1, PERF-2]        # disable specific check IDs
    disabledCategories: [performance] # disable entire categories

lint:
  ignore:
    - rule: SA1000                    # ignore a specific rule
      source: golangci-lint
    - source: eslint                  # ignore all eslint violations in vendor
      file: "vendor/**"
  linters:
    jscpd:
      enabled: true                   # opt in to jscpd duplicate detection
    react-doctor:
      enabled: true                   # opt in without React detection or doctor.config.*

commit:
  message:
    model: claude-haiku-4-5          # fast model for commit-message generation
  grouping:
    model: claude-sonnet-4-5         # capable model for AI commit grouping (-A)
  hooks:                             # pre-commit hooks
    - name: lint-staged
      run: "golangci-lint run --new-from-rev=HEAD~1"
      files: ["*.go"]
  precommit:
    mode: prompt                     # prompt|fail|skip|false for gitignore + linked-deps checks
  compatibility:
    mode: prompt                     # prompt|fail|skip|false for removed-functionality / compatibility warnings

fixtures:
  enabled: true                      # auto-discover fixture files during gavel test
  files: ["tests/**/*.fixture.md"]   # override default glob (**/*.fixture.md)

checks:                              # post-completion loop inside `gavel todos run`
  enabled: true                      # run tests/lint after the agent is done, feed failures back
  test:                              # omit to skip tests
    changed: true                    # only packages affected by the agent's changes
  lint:                              # omit to skip linting
    changed: true                    # only new violations vs the base ref

ssh:
  cmd: "gavel test --lint --fixtures" # override the command run on git push

pre:                                 # hooks run before tests
  - name: generate
    run: "go generate ./..."

post:                                # hooks run after tests (non-blocking)
  - name: cleanup
    run: "rm -rf tmp/"

secrets:
  disabled: false                    # set true to disable betterleaks entirely
  configs: ["custom-leaks.toml"]     # additional betterleaks/gitleaks config files

arch.yaml

Placed at the repository root (or any directory — gavel walks up to find it). Defines scope classification, technology detection, severity rules, and build/git settings.

scopes:
  rules:
    backend:
      - path: "cmd/**"
      - path: "pkg/**"
    frontend:
      - path: "web/**"

tech:
  rules:
    kubernetes:
      - path: "deploy/*.yaml"

severity:
  default: medium
  rules:
    'kubernetes.kind == "Secret"': critical
    'change.type == "deleted"': critical
    'commit.line_changes > 500': critical

git:
  version_field_patterns:
    - "**.image"
    - "**.tag"
    - "**.version"

Embedded defaults detect common scope types (ci, dependency, docs, test) and technologies (Go, Node.js, Python, Kubernetes, Terraform, Docker, etc.).

.gitanalyze.yaml

Controls which commits, files, authors, and resources are excluded from gavel git analyze. Placed at the repository root.

# Named filter sets toggled with --include / --exclude
filter_sets:
  bots:
    ignore_authors:
      - "dependabot*"
      - "renovate*"
      - "github-actions*"

  noise:
    ignore_files:
      - "*.lock"
      - "go.sum"
      - "package-lock.json"

  generated:
    ignore_resources:
      - kind: ConfigMap
        name: "*-generated"
      - kind: Secret

# Which filter sets are active by default
includes:
  - bots
  - noise

# Top-level filters (always applied)
ignore_commits:
  - "fixup!*"
  - "squash!*"

ignore_files:
  - ".idea/*"
  - "*.svg"

ignore_commit_types:
  - "chore"
  - "ci"

# CEL expressions — skip when true
ignore_commit_rules:
  - cel: "commit.is_merge"
  - cel: "commit.line_changes > 10000"

# Kubernetes resource filters
ignore_resources:
  - kind: Secret
  - kind: ConfigMap
    name: "*-generated"
CEL variables for ignore_commit_rules
Variable Type Description
commit.author string Author name
commit.author_email string Author email
commit.subject string Commit subject line
commit.body string Commit body
commit.type string Conventional commit type
commit.scope string Conventional commit scope
commit.is_merge bool True if subject starts with "Merge "
commit.files_changed int Number of files changed
commit.line_changes int Total lines added + deleted
commit.additions int Lines added
commit.deletions int Lines deleted
commit.files list File paths changed
commit.tags list Commit tags
commit.is_tagged bool True if commit has tags

Embedded defaults skip bot authors (dependabot*, renovate*, github-actions*), lock files (*.lock, go.sum, etc.), and merge commits.

Override at the CLI:

gavel git analyze --exclude bots      # include bot commits
gavel git analyze --include generated  # activate the "generated" filter set
gavel git analyze --verbose            # show skip reasons

Agent Skills

Gavel ships Agent Skills that teach AI coding agents to reach for gavel across the workflow: writing data-driven tests, driving the everyday test+lint loop, using gavel instead of gh/git for PRs and commits, running the TODO/AI-review loop, and migrating CI pipelines onto the gavel composite action. Skills are auto-discovered from .agents/skills/ by any compatible agent (Claude Code, VS Code Copilot, Cursor, Gemini CLI, and others).

Skill What it teaches the agent
gavel-fixture-tester Author fixture-based tests in markdown — YAML front-matter, tables, command blocks, and CEL assertions for stdout/stderr/exitCode/json.
gavel-runner Run gavel test and lint — focus on a subset (--changed, --cache, framework, runner pass-through), re-run only failures (--failed defaults to .gavel/last.json), suppress noise with baselines, pull JSON / markdown / HTML out via --format, attach to live runs through the UI server's HTTP+SSE API, and tune the four-layer timeout stack.
gavel-git Use gavel over gh/gitgavel pr status for PR + CI status (replaces gh pr view/gh run view), gavel commit -p / gavel pr create to open PRs with AI-generated content, and gavel commit (session-scoped, conventional message, hooks) for commits.
gavel-todos Run the TODO loop — have a coding agent implement or plan TODOs, then execute the same fixture/CEL definition of done manually with gavel todos check.
gavel-ci-migrator Migrate CI — discover existing golangci-lint / go test / `make lint

Install

For Claude Code (marketplace):

# Add the Flanksource marketplace, then install the gavel-skills plugin
/plugin marketplace add flanksource/gavel
/plugin install gavel-skills@flanksource-gavel

After installation, all five skills become available. The agent picks gavel-fixture-tester when you ask it to write a fixture, gavel-runner when you ask it to run tests, rerun failures, or inspect results, gavel-git when you ask it to check a PR, see why CI is failing, or commit / open a PR, gavel-todos when you ask it to run the todos or verify committed work, and gavel-ci-migrator when you ask it to switch CI to gavel or replace golangci-lint-action / go test jobs with the gavel action.

For any agent (via the open Skills CLI):

npx skills add flanksource/gavel        # current project
npx skills add flanksource/gavel -g     # all projects
npx skills add flanksource/gavel -l     # preview before installing

For a local clone (auto-discovery):

Clone the repo and open it in your agent — .agents/skills/ is picked up automatically with no extra setup.

See .agents/skills/README.md for the full reference, including manual settings.json configuration and per-agent install paths.

Development

task build       # build binary (also: make build)
task test        # run all tests
task test:unit   # run unit tests only
task lint        # run linters
task fmt         # format code
task ci          # fmt + lint + test + build

License

See LICENSE for details.

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages