AGENTS.md

July 13, 2026 ยท View on GitHub

This file provides guidance to AI coding agents (e.g. Claude Code, Codex, Cursor, Gemini CLI, and similar tools) when working with code in this repository.

Rclone welcomes AI-assisted contributions, but the expectation is that you, the human submitter, understand every line you propose and have compiled and tested it against real rclone code - not just generated it. See the "AI-assisted contributions" section of CONTRIBUTING.md before opening a pull request.

Project Overview

Rclone is a command-line program to sync files and directories to and from cloud storage providers. It's written in Go and supports 70+ backends (cloud storage systems). Think "rsync for cloud storage".

General Notes

We take backwards compatibility very seriously. PRs should not change the observable behaviour of existing commands, flags or rc API without very good reason. Rclone does not try to preserve a stable Go API but try not to change it gratuitously.

Rclone operates with a lot of different backends, so compatibility is key. It is the backend integration tests which guarantee that compatibility. Changes should consider both known and unknown backends and should take care not to break functionality of existing installations.

The core parts of rclone under fs and vfs need to work with all backends and backend specific hacks won't be merged. Fixes likely need to go in the relevant backend or if new behaviour is really needed, a new Feature flag needs to be added.

Changes should be kept to the minimum. Work hard to make the most elegant, smallest change you can. Do not refactor or re-order code unless necessary as this makes review more challenging. Re-use existing test scaffolding, existing or library routines (e.g. lib) where possible.

Make sure added tests actually test the code you have written and test the intention behind the change. If you are fixing a problem, write the tests first to reproduce the problem before starting on the fix.

Build and Test Commands

# Build rclone (simple)
go build

# Build with version info (preferred)
make

# Run all unit tests (no cloud credentials needed)
make quicktest
# or equivalently:
RCLONE_CONFIG="/notfound" go test ./...

# Run tests for a specific package
cd backend/memory && go test -v
# or from root:
go test -v ./backend/memory/

# Run a single test
go test -v -run TestIntegration/FsCheckWrap ./backend/memory/

# Run tests with race detector
make racequicktest

# Lint (requires golangci-lint)
golangci-lint run ./...

# Run backend integration tests (requires configured TestRemote remote)
cd backend/drive && go test -v
# Run sync/operations integration tests against a remote
cd fs/sync && go test -v -remote TestDrive:
cd fs/operations && go test -v -remote TestDrive:

# Run integration tests via test framework
go run ./fstest/test_all -backends drive

Architecture

Entry Point and Plugin Registration

rclone.go is the main entry point. It imports backend/all and cmd/all which use Go's init() pattern to register all backends and commands. Each backend calls fs.Register() with a fs.RegInfo struct during init.

Core Interfaces (fs/)

The fs package defines the core abstractions:

  • fs.Fs (fs/types.go): The filesystem interface every backend must implement (List, NewObject, Put, Mkdir, Rmdir).
  • fs.Object (fs/types.go): Interface for a file/object (Open, Update, Remove, SetModTime).
  • fs.Features (fs/features.go): Optional capabilities a backend can declare (Purge, Copy, Move, DirMove, etc.). Backends set function pointers for operations they support; nil means not supported.
  • fs.RegInfo (fs/registry.go): Registration metadata for a backend including its name, config options, and NewFs constructor.

Backend Structure (backend/)

Each backend is a single Go package (e.g., backend/s3/, backend/drive/). Key conventions:

  • Main implementation in a single file (e.g., s3.go) - do not split into fs.go/object.go.
  • API types go in a separate api/types.go file.
  • Test file (e.g., s3_test.go) uses fstests.Run() from fstest/fstests for standardized integration tests.
  • Register in backend/all/all.go via blank import.
  • HTTP-based backends should use lib/rest for HTTP calls and fs/fshttp for the HTTP client.
  • Use lib/dircache for directory-ID-based remotes, lib/oauthutil for OAuth, lib/pacer for rate limiting.

Command Structure (cmd/)

Each command is a package under cmd/ registered in cmd/all/all.go via blank import. Commands use cobra via cmd.Main().

Key Subsystems

  • fs/operations/: Core file operations (Copy, Move, Delete, etc.)
  • fs/sync/: Directory sync logic
  • fs/march/: Parallel directory tree walker used by sync
  • fs/filter/: Include/exclude filtering
  • fs/accounting/: Transfer statistics and bandwidth limiting
  • fs/config/: Configuration file management
  • vfs/: Virtual filesystem layer (used by mount, serve)
  • librclone/: C-compatible library interface for embedding rclone
  • fstest/: Integration test framework; fstest/fstests/ has the generic backend test suite

Commit Message Convention

Prefix with the directory of the change, then a colon: drive: add team drive support - fixes #885. For cross-cutting changes use a broader prefix like fs or operations.

Make the first line of your commit message a summary of the change that a user (not a developer) of rclone would like to read. So write drive: fix server side copy of big files instead of drive: no longer set the MimeType in Move or Copy. This is important because these lines go into the change log which is read by users.

Code Commenting Style

Comments describe the code as it is now, for a future reader who has no knowledge of the change that introduced it.

Every exported type, function, field, and constant has a godoc comment that starts with its name and is phrased as a present-tense statement of what it is or does (// Mkdir makes the directory (container, bucket))

Document the contract callers need - preconditions, what's returned, which sentinel errors are returned and when, and any "shouldn't return an error if it already exists" style caveats - rather than the implementation.

Keep comments terse: a single line for most things, with extra paragraphs (separated by blank // lines) reserved for genuine subtlety.

Inline comments inside function bodies should explain why - a non-obvious API quirk, a workaround, a gotcha, or an ordering constraint - and may cite an external reference (forum thread, vendor docs, RFC) when that's what makes the behaviour non-obvious; skip comments that merely restate what the code plainly does.

Use FIXME and TODO for known shortcomings.

Do not write comments that narrate the change itself or compare against the previous behaviour (no "now we also handle...", "changed to...", "previously this returned...", or references to bug/PR numbers in the code) - that context belongs in the commit message, not in source that will outlive the change.

Code comments should only refer to current behaviour - and shouldn't describe behaviour that is trivially deducible from reading the code.

Linting Configuration

Uses golangci-lint v2 with config in .golangci.yml. Enabled linters: errcheck, govet, ineffassign, staticcheck, unused, gocritic, misspell, revive, unconvert. The goimports formatter is also enabled.

Documentation

  • Backend option docs come from Help: fields in the Go source Options structs, not from markdown files.
  • Command docs are in the command source code (e.g., cmd/ls/ls.go).
  • Don't commit autogenerated doc changes from make backenddocs or make commanddocs.
  • Website docs are in docs/content/ as markdown, built with Hugo (make serve to preview).