build: add agent docs, permissions and spec/plan layout for the fork

Fork-only. Appends a Fork Workflow section to AGENTS.md and adds
GEMINI.md, per-tool permission files and docs/ pages for agent driven
development. Not for upstream.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Fable 5.2 committed 2026-11-11 10:01:49 +01:00
1 parent 448d7361c8
commit a28ee25855
13 files changed
+306

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
{
"permissions": {
"allow": [
"Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(git show:*)",
"Bash(git rev-parse:*)", "Bash(git add:*)", "Bash(git commit:*)",
"Bash(go mod download:*)", "Bash(go build:*)", "Bash(go test:*)", "Bash(go vet:*)",
"Bash(gofmt -l:*)"
],
"ask": [
"Bash(git push:*)", "Bash(git merge:*)", "Bash(git rebase:*)", "Bash(git switch:*)",
"Bash(git restore:*)", "Bash(git commit --amend:*)", "Bash(rm:*)",
"Bash(go get:*)", "Bash(go mod tidy:*)", "Bash(go install:*)",
"Bash(make:*)", "Bash(docker:*)"
],
"deny": [
"Bash(git push --force:*)", "Bash(git push -f:*)", "Bash(git push --force-with-lease:*)",
"Bash(git reset --hard:*)", "Bash(git clean:*)", "Bash(git add -f:*)", "Bash(git add --force:*)",
"Bash(git commit --no-verify:*)", "Bash(git commit -n:*)",
"Bash(rm -r:*)", "Bash(rm -R:*)", "Bash(rm -rf:*)", "Bash(rm -fr:*)", "Bash(rm -Rf:*)",
"Bash(rm -fR:*)", "Bash(rm --recursive:*)", "Bash(sudo:*)",
"Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"
]
}
}
+2
View File
@@ -0,0 +1,2 @@
sandbox_mode = "workspace-write"
approval_policy = "on-request"
+20
View File
@@ -0,0 +1,20 @@
# Rendered from docs/PERMISSIONS.md - change both in the same commit.
# Deny
prefix_rule(pattern = ["git", "push", ["--force", "-f", "--force-with-lease"]], decision = "forbidden",
justification = "Force-push rewrites shared history.")
prefix_rule(pattern = ["git", "reset", "--hard"], decision = "forbidden", justification = "Discards work.")
prefix_rule(pattern = ["git", "clean"], decision = "forbidden", justification = "Deletes untracked files.")
prefix_rule(pattern = ["git", "add", ["-f", "--force"]], decision = "forbidden",
justification = "Stages ignored files, e.g. secrets.")
prefix_rule(pattern = ["git", "commit", ["--no-verify", "-n"]], decision = "forbidden", justification = "Skips hooks.")
prefix_rule(pattern = ["rm", ["-r", "-R", "-rf", "-fr", "-Rf", "-fR", "--recursive"]], decision = "forbidden",
justification = "Recursive delete.")
prefix_rule(pattern = ["sudo"], decision = "forbidden", justification = "No privilege escalation.")
# Ask
prefix_rule(pattern = ["git", ["push", "merge", "rebase", "switch", "restore"]], decision = "prompt")
prefix_rule(pattern = ["git", "commit", "--amend"], decision = "prompt")
prefix_rule(pattern = ["rm"], decision = "prompt")
prefix_rule(pattern = ["go", ["get", "install"]], decision = "prompt")
prefix_rule(pattern = ["go", "mod", "tidy"], decision = "prompt")
prefix_rule(pattern = ["make"], decision = "prompt")
prefix_rule(pattern = ["docker"], decision = "prompt")
+19
View File
@@ -0,0 +1,19 @@
{
"tools": {
"allowed": [
"run_shell_command(git status)", "run_shell_command(git diff)", "run_shell_command(git log)",
"run_shell_command(git show)", "run_shell_command(git branch --list)",
"run_shell_command(git add)", "run_shell_command(git commit)",
"run_shell_command(go mod download)", "run_shell_command(go build)",
"run_shell_command(go test)", "run_shell_command(go vet)", "run_shell_command(gofmt -l)"
],
"exclude": [
"run_shell_command(git push --force)", "run_shell_command(git push -f)",
"run_shell_command(git push --force-with-lease)", "run_shell_command(git reset --hard)",
"run_shell_command(git clean)", "run_shell_command(git add -f)", "run_shell_command(git add --force)",
"run_shell_command(git commit --no-verify)", "run_shell_command(git commit -n)",
"run_shell_command(rm -r)", "run_shell_command(rm -R)", "run_shell_command(rm -rf)",
"run_shell_command(rm -fr)", "run_shell_command(rm -Rf)", "run_shell_command(sudo)"
]
}
}
+5
View File
@@ -22,3 +22,8 @@ resource_windows_*.syso
/librclone.h
.devcontainer
/cmd/bisync/testdata/bisync_vscode_debuggers_launch.json
.env
.env.*
CLAUDE.local.md
.claude/settings.local.json
.worktrees/
+12
View File
@@ -134,3 +134,15 @@ Uses golangci-lint v2 with config in `.golangci.yml`. Enabled linters: errcheck,
- 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).
## Fork Workflow
This fork carries agent tooling that upstream does not. Never include `docs/specs/`, `docs/plans/`, `docs/{ARCHITECTURE,DECISIONS,TODO,PERMISSIONS}.md`, `GEMINI.md`, `.claude/`, `.codex/`, `.gemini/` or this section in a PR to rclone/rclone.
- Required skill: `superpowers` - check at session start, install if missing. There is no product UI here, so `impeccable` is not needed.
- Specs go in `docs/specs/NNN-slug.md` (permanent). Plans go in `docs/plans/NNN-slug.md` and are removed with `git rm` before merge. This overrides the superpowers default paths.
- Non-trivial work: brainstorm → spec → plan → TDD → review. For trivial fixes say "trivial, skipping spec" and proceed.
- Log things noticed but deliberately not fixed in `docs/TODO.md`, record decisions in `docs/DECISIONS.md`, and keep `docs/ARCHITECTURE.md` in step with structural changes - in the same commit as the code.
- `docs/PERMISSIONS.md` is the source for the `.claude/`, `.codex/` and `.gemini/` permission files - change them together.
- Never push, force-push or commit directly to `master`. Ask before adding or upgrading a dependency (`go get`, `go mod tidy`).
- Done means run in this session and seen passing: `go build`, `go test` on the touched packages, and `golangci-lint run` on them.
+8
View File
@@ -0,0 +1,8 @@
# GEMINI.md
**`AGENTS.md` is the single source of truth for this repository.** Read
`./AGENTS.md` before doing anything else and follow it exactly.
This file exists only so Gemini CLI finds the rules. It contains no project
rules of its own - add those to `AGENTS.md`. If anything here ever conflicts
with `AGENTS.md`, `AGENTS.md` wins.
+44
View File
@@ -0,0 +1,44 @@
# Architecture
Fork-only orientation for agents. The summary in `AGENTS.md` ("Architecture")
is upstream's and is not repeated here; this page adds what that summary
leaves out. Update in the same commit as any structural change.
## Map
| Path | Responsibility |
|---|---|
| `rclone.go` | Entry point; blank-imports `backend/all` and `cmd/all` |
| `backend/<name>/` | One storage backend per package, registered in `init()` |
| `cmd/<name>/` | One cobra command per package |
| `fs/` | Core interfaces, config, operations, sync, accounting |
| `vfs/` | Virtual filesystem used by mount and serve |
| `lib/` | Shared helpers: `rest`, `pacer`, `dircache`, `oauthutil`, `encoder` |
| `fstest/` | Test framework: `fstests` (backend contract), `test_all` (runner) |
| `docs/content/` | Hugo website source; partly autogenerated |
| `docs/specs/`, `docs/plans/` | Fork-only agent workflow artefacts |
| `bin/` | Build and docs scripts |
## Test layers
- Unit tests: `RCLONE_CONFIG=/notfound go test ./...` - no credentials.
- Backend contract: each `backend/<name>/<name>_test.go` calls
`fstests.Run()` against a remote named `Test<Name>:` in the user's rclone
config. Without that remote the test skips, so a green `go test` on a
backend package says nothing about the backend against the real service.
- Integration: `fstest/test_all` runs the backend contract plus the
`fs/operations`, `fs/sync`, `vfs` etc. suites against the backends listed in
`fstest/test_all/config.yaml`.
## Invariants
- Backwards compatibility of commands, flags, config keys and the rc API.
- `fs` and `vfs` contain no backend-specific code.
- cgo use differs per release target (the `cgo` and `build_flags` columns of
the matrix in `.github/workflows/build.yml`), so a backend cannot assume cgo.
## Known rough edges
- `backend/protondrive` depends on the forks `github.com/rclone/Proton-API-Bridge`
and `github.com/rclone/go-proton-api` (`go.mod`). See `docs/specs/`.
- See `docs/TODO.md` for host tooling gaps.
+38
View File
@@ -0,0 +1,38 @@
# Decisions
Fork-only. Append-only, newest first. Never edit or delete an entry - supersede
it with a new one that links back. One entry per decision a future maintainer
would otherwise have to reverse-engineer.
No index: `grep -n '^## ' docs/DECISIONS.md` lists every entry.
## 2026-11-11 - Fork agent tooling is appended, not merged, into upstream files
**Status:** accepted
**Context:** Upstream rclone already ships a maintainer-written `AGENTS.md`
and a `CLAUDE.md` that imports it. This fork tracks upstream and intends to
send work back, so every edit to an upstream file is a future merge conflict
and a risk of leaking fork-only material into an upstream PR.
**Decision:** Upstream's `AGENTS.md` text is kept verbatim. Fork rules are one
"Fork Workflow" section appended at the end. `CLAUDE.md` and `README.md` are
untouched. Fork-only docs live at the top of `docs/` (Hugo only builds
`docs/content/`, so they do not reach the website).
**Alternatives:** Restructuring `AGENTS.md` with the fork rules first (better
agent attention, permanent conflicts with upstream); a separate fork rules
file (two sources of truth).
**Consequences:** `AGENTS.md` sits at 148 of a 150 line budget - a new fork
rule must replace an old one. Upstream PR branches must be cut so they exclude
the paths listed in the Fork Workflow section.
## 2026-11-11 - Adopt AGENTS.md as single source of truth
**Status:** accepted
**Context:** Agents had no fork-specific workflow or permission config between
sessions.
**Decision:** `AGENTS.md` is canonical; `CLAUDE.md`/`GEMINI.md` are pointers.
Specs are permanent in `docs/specs/`. Plans live in `docs/plans/` only while
work is in progress and are removed before merge. Both override the
superpowers default paths.
**Alternatives:** Per-tool rule files (drift); no rules file (agents
re-explore the repo every session).
**Consequences:** Rule changes happen in one file; pointer files stay thin.
The spec, not the plan, is the record.
+70
View File
@@ -0,0 +1,70 @@
# Agent permissions
Fork-only. Source of truth for what AI coding agents may run here. Tool files
are renderings of this page: `.claude/settings.json`, `.codex/config.toml`,
`.codex/rules/project.rules`, `.gemini/settings.json`. Change this page and
every tool file in the same commit. Review changes to these files and to
`AGENTS.md` like CI config: one line redirects agent behaviour repo-wide.
## Verified commands
Run on 2026-11-11. The development host has **no Go toolchain**, so every `go`
row was run inside the `golang:1.26` container (go1.26.11) with the repository
mounted, using this wrapper:
```sh
docker run --rm -u "$(id -u):$(id -g)" -e HOME=/cache -e GOCACHE=/cache/build \
-e GOMODCACHE=/cache/mod -e GOFLAGS=-buildvcs=false -e RCLONE_CONFIG=/notfound \
-v "$HOME/.cache/rclone-go:/cache" -v "$PWD:/src" -w /src golang:1.26 <command>
```
Only `worked` rows may appear in a tier, a tool file, or `AGENTS.md`.
| Command | Result |
|---|---|
| `go mod download` | worked (container) |
| `go build` | worked (container) - binary reports `rclone v1.77.0-DEV` |
| `go test ./backend/memory/` | worked (container) |
| `go test -run 'TestIntegration/FsMkdir/FsPutFiles/FsCopy' ./backend/memory/` | worked (container) |
| `go test ./backend/protondrive/` | worked (container) - no `TestProtonDrive:` remote, so the integration test skips |
| `go vet ./backend/protondrive/` | worked (container) |
| `gofmt -l backend/protondrive` | worked (container) - no output |
| `RCLONE_CONFIG=/notfound go test ./...` | failed (container) - 178 packages ok, 7 fail: `backend/smb`, `cmd/gitannex`, `cmd/mount`, `cmd/mount2`, `cmd/serve/docker`, `cmd/serve/nfs`, `fs/logger`. `fs/logger` fails because the container has no `rsync`; the other six were not diagnosed |
| `make`, `make quicktest`, `make racequicktest` | not run - need Go on the host |
| `golangci-lint run ./...` | not run - not installed on the host or in the container |
| `go run ./fstest/test_all -backends protondrive` | not run - needs a configured `TestProtonDrive:` remote |
TODO(maintainer): confirm every row above that is not `worked`.
## Tiers
| Tier | Commands | Why |
|---|---|---|
| Allow | `git status`, `git diff`, `git log`, `git show`, `git branch --list`, `git rev-parse`, `git add`, `git commit`, `go mod download`, `go build`, `go test`, `go vet`, `gofmt -l` | Inspection and the verified dev loop; no prompt needed. |
| Ask | `git push`, `git merge`, `git rebase`, `git switch`, `git restore`, `git commit --amend`, `rm` (any), `go get`, `go mod tidy`, `go install`, `make` (any target), `docker` (any) | Leaves the machine, rewrites work, changes dependencies, or is unverified. |
| Deny | `git push --force` / `-f` / `--force-with-lease`, `git reset --hard`, `git clean` (any), `git add -f` / `--force`, `git commit --no-verify` / `-n`, `rm -r` / `-R` / `-rf` / `-fr` / `-Rf` / `-fR` / `--recursive`, `sudo`; reading `.env`, `.env.*`, `secrets/**` | Destroys work, skips checks, or exposes secrets. |
## Known gaps
- Allowlists save prompts; they are not a security boundary. Use the tool's
sandbox for isolation.
- While the host has no Go, the allowed `go` commands only work through the
`docker run` wrapper above, and `docker` is in Ask - so each one prompts.
Installing Go on the host removes this.
- Prefix rules are bypassable: `git -C dir push`, flags placed later
(`git push origin main --force`), `+refspec` pushes. Claude Code's `:*`
matches at a word boundary, so each flag cluster must be listed - which is
why `git clean` is denied whole and `rm` always asks.
- Allowed test and build commands run code from the repo; an agent that can
edit Go files or tests can run anything through `go test`.
- Denying reads of `.env` does not stop a program that opens it itself, and
git can print staged or committed secrets. Rclone test credentials live in
the user's rclone config, outside this repository - keep them there.
- Codex: loaded only once the project is trusted; `approval_policy` here can
loosen a stricter user setting. No `allow` rules are written because in
Codex `allow` means "run outside the sandbox". Codex cannot deny file reads.
`--force-with-lease=<ref>`, `+refspec` and late flags only match Ask.
- Gemini CLI: ignored until the folder is trusted; no Ask tier (anything not
allowed already asks); cannot deny file reads.
- Cursor and Copilot files are not written: nothing in the repository shows
the fork uses them (`.vscode` is gitignored).
+40
View File
@@ -0,0 +1,40 @@
# TODO
Fork-only durable backlog for things noticed and deliberately not fixed.
Small, specific, independently actionable. Remove only when actually done.
(In Go source, upstream's `FIXME`/`TODO` comment convention still applies.)
## Now
- [ ] Install a Go toolchain on the development host (go.mod needs 1.26; CI
builds with 1.27.x). Until then every `go` command has to run in the
`golang:1.26` container - see `docs/PERMISSIONS.md`.
- [ ] Install `golangci-lint` v2 so `golangci-lint run` can be verified and
moved into the Allow tier.
## Next
- [ ] Propose a CI check for this fork: `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`
and the `docs/` agent files exist, and `AGENTS.md` is at most 150 lines.
- [ ] Upstream CI (`.github/workflows/build.yml`) is gated on
`github.repository == 'rclone/rclone'` and the remote is Gitea, so this fork
has no CI at all. Decide whether to add a Gitea Actions workflow.
## Someday
## Recurring
- [ ] Maintain `AGENTS.md`:
- **Add a rule only in response to a real failure.** Do not pre-empt
hypothetical mistakes.
- **Update in the same commit as the convention change.**
- **Prune quarterly**, and re-check the Fork Workflow section against
upstream's `AGENTS.md` after each upstream merge.
## Known issues
- [ ] `RCLONE_CONFIG=/notfound go test ./...` in the bare `golang:1.26`
container fails 7 packages (list in `docs/PERMISSIONS.md`). `fs/logger`
needs `rsync`; the mount, serve and smb failures are undiagnosed and are
probably missing container tooling (FUSE, git-annex), not code. Confirm on a
host with Go installed before treating a full-suite failure as a regression.
+14
View File
@@ -0,0 +1,14 @@
# Plans
Fork-only. Implementation plans from the superpowers writing-plans workflow.
**Transient:** a plan lives only on its feature branch and is removed with
`git rm` before the merge request is opened. This README stays.
- Naming: `NNN-short-slug.md`, matching its spec number.
- Links back to its spec. Bite-sized checkbox tasks with exact file paths, test
commands, and commit checkpoints.
- Written for an engineer with zero context for this codebase - spell out the
obvious.
- Tick checkboxes as you go so another agent can resume an interrupted session.
- Front matter: `status: draft | approved | in-progress`. There is no `done` -
a finished plan is deleted.
+10
View File
@@ -0,0 +1,10 @@
# Specs
Fork-only. Approved specifications from the superpowers brainstorming workflow.
Nothing non-trivial gets implemented without one. Not for upstream PRs.
- Naming: `NNN-short-slug.md`, zero-padded, sequential.
- A spec states **what** and **why**, plus acceptance criteria. Not **how**.
- Front matter: `status: draft | approved | implemented | superseded`. No link
to a plan - plans are removed before merge.
- Never delete an implemented spec; it is the record of intent.