ci: add Duo agent environment configuration
Description
Add an agent-config.yml to configure the CI/CD execution environment for GitLab Duo coding agent flows.
Why
When Duo Developer is triggered on an issue in this project, the agent runs in a default Docker environment that lacks the Go toolchain and project-specific tooling. This means the agent cannot build, test, or lint code — it can only write files and commit them blindly.
This gap was observed in !3177 (merged), where the agent introduced an import ordering issue (gci lint error) that it could not detect on its own. A reviewer had to manually copy the CI lint output into an MR comment and ask the agent to fix it — a slow, manual feedback loop that this configuration eliminates.
This MR adds a project-specific agent-config.yml that gives the agent the same development environment a human contributor would set up by following CONTRIBUTING.md.
What this does
The configuration:
-
Uses
golang:1.26as the base image — matching our CI (default: image: golang:${GO_VERSION}). Provides Go,git, andmakeout of the box. -
**Bootstraps the full toolchain with **mise — the project's standard tool version manager.
mise installreads.tool-versionsand installs at the exact pinned versions:- Go 1.26.1
- golangci-lint 2.11.4 (includes gofumpt and goimports formatters)
- shellcheck 0.11.0
- markdownlint-cli2 0.22.0
- vale 3.13.0
- lychee 0.21.0
- Node.js 23.11.0
- lefthook 2.0.2
-
Installs commitlint dependencies so conventional commit validation works.
-
Pre-downloads Go modules (
go mod download) so the agent doesn't hit the network mid-task. -
Activates lefthook git hooks — this is the key quality gate. The agent gets automatic validation on every commit and push:
Hook stage Trigger Checks pre-commit git commitgolangci-lint --fix(auto-formats code with gofumpt/goimports), shellcheck, markdownlint--fix, auto-regenerates docs if command files changedcommit-msg git commitConventional commit format validation via commitlint pre-push git pushmake build, golangci-lint (changed files vs main),make test-changed(tests on changed packages + reverse deps), verify generated docs/code are up to date, markdownlint, vale, lychee -
Caches Go modules and mise tool installations between flow runs, keyed on
go.sumand.tool-versionsso the cache invalidates when dependencies or tool versions change.
Testing
This was tested on a local GDK instance by:
- Pushing the CLI repo (with this config on
main) to a GDK project - Creating a test issue: "Add a
glab mr statssubcommand that displays summary statistics for a merge request" - Assigning Duo Developer to the issue
Results:
- The setup script executed successfully
- The agent wrote Go code, tests, and command registration
- Lefthook pre-commit hooks fired: golangci-lint auto-fixed formatting, commitlint validated the commit message, docs regeneration check passed
- The agent caught and fixed 3 lint issues during development (named returns, unchecked error, import ordering) — exactly the kind of feedback loop we want
make build,go test,make gen-docsall passed- The agent created a working MR with a proper conventional commit
How to test locally with GDK
Prerequisites: a running GDK with a runner configured using the Docker executor and the gitlab--duo tag.
# 1. Add your GDK as a remote (one-time setup)
git remote add gdk http://root:<YOUR_TOKEN>@gdk.test:3000/<namespace>/cli.git
# 2. Push the branch with agent-config.yml to GDK
# (it must be merged to main on GDK for the config to take effect)
git push gdk add-duo-agent-config:main
# 3. Create a test issue on the GDK project — for example:
# "Add a glab mr stats subcommand that displays summary statistics
# for a merge request: number of commits, changed files, additions,
# and deletions. Output should support both text and --output json
# formats. Include unit tests following the cmdtest and gitlabtesting
# patterns."
# 4. Trigger Duo Developer on the issue (assign or use the UI)
# 5. Observe the CI job logs for:
# - mise installing all tools from .tool-versions
# - lefthook hooks firing on commit (golangci-lint, commitlint)
# - lefthook hooks firing on push (build, lint, test-changed)
# - The agent being able to run: make build, make test, make lint