rlibaert

Agentic coding

May 10, 2026 ⏲ 4m read

AI has definitely transformed a lot of industries and software development is not spared. While this technology is still young and changing, some standards are now emerging.

Agentic code editors

Most IDEs now make use of AI models, either directly or via extensions, to provide powerful features and enhance the development experience. VSCode has been the standard for a long time and is still extremely popular, but the rise of AI helped changing the landscape. Cursor is one of those, but to me Zed is the most innovative (several IDEs are VScode forks, this one is built from the ground up).

The most immediate interest of such tools is to reduce the distance between production code and the AI model, allowing it to directly read and write the codebase, providing context-aware code completion and refactoring suggestions.

Agent rules

Agent rules are a set of guidelines that define how an agent should behave and interact with the developer, providing a consistent behavior accross sessions and teams. This ruleset is basically a prompt loaded into the model’s context at the start of each session. This concept is shared among different providers (e.g. .cursor/rules, CLAUDE.md, GEMINI.md, …). I prefer the agnostic approach and use AGENTS.md, which seems to be rising as a standard.

As specified previously, since the rules are loaded in the model’s context, the same guidelines for good prompting apply. A good AGENTS.md file should provide clear and concise instructions to specialize the agent efficiently while keeping the context size manageable.

There exists generative tools that can help grasp the idea of what a good AGENTS.md file should look like and get you started. You can also definitely get inspiration from open-source projects.

An example for Go projects
# AGENTS.md

## Context

You are an expert Golang developer.
This repository contains a Golang API backend.

## Project structure

The project follows a hexagonal architecture with clear separation of concerns:

- **domain/** - Business logic, entities & interfaces... this is the heart of
  the application
- **domaintest/** - Reusable testing suites for domain implementations
- **datastores/** - Domain's storage interfaces implementations
- **restapi/** - An HTTP interface to drive domain: its main components are a
  service registerer wrapping a domain service to register HTTP handlers,
  presentation models with mappings to domain models and an HTTP client.
- **wrappers/** - Decorators around domain interfaces to augment behavior
  (e.g. logs & metrics production).
- **cmd/api-server/** - API server entrypoint

## Coding guidelines

- Do not write organizational or code-summary comments but do write comments to
  explain tricky code blocks
- Reserve `panic` for truly unrecoverable errors
- Never silenty discard errors; handle them ASAP with `if err != nil { ... }`
- Return `error` last in function output lists
- Use `context.Context` when available and set `ctx context.Context` first in
  function input lists
- Use Generics to implement small, generic functions:
  ```go
  func _[T comparable](a, b T) bool { return a == b } // do
  func _(a, b int) bool             { return a == b } // don't
  ```
- Use `[package.symbol]` notation in comments when referring to types,
  constants, variables, functions ...
- Specialize primitive types when relevant (e.g. `type PersonID string`)
- Define relevant sentinel domain errors to be wrapped over
  implementation-specific errors:
  ```go
  var ErrPersonUnknown = errors.New("domain: person unknown")
  func _(ctx context.Context, id PersonID) error {
    err := ...
    if errors.Is(err, errSuggestingUnknownPerson) {
      return errors.Join(ErrPersonUnknown, err)
    }
  }
  ```

## Testing guidelines

- Run `golangci-lint run ./...` to run linters ([configuration](.golangci.yaml))
- Run `go test ./...` to run all tests, with optional flags:
  - `-artifacts`: persist test artifacts
  - `-cover`: coverage analysis
  - `-race`: data races detection
  - `-bench regexp`: run matching benchmark tests
  - `-fuzz regexp`: run matching fuzz tests
- Run tests & linter and resolve issues when editing code
- If you are unable to provide a simple fix for a linter error, you may instead
  suggest to append the line with `//nolint: <linter> // <explanation>` to
  suppress the warning
- End test code files in `_test.go` and suffix test packages with `_test`
- Use `testing.TB.Context()` to fill `context.Context` arguments

## Dependency management

| Key dependency | Purpose |
| - | - |
| `log/slog` | Structured logging |

Only if necessary, you may ask to:

- Use `go get <import path>` to add a new dependency
- Use `go mod tidy` to tidy up [go.mod](go.mod)
- Use `go get -u ./...` to update modules
- Use `go mod vendor` to create or refresh [vendor](vendor) (not versioned) and
  fix vendoring issues