# RustFS Agent Instructions

This file contains repository-wide rules. Use the nearest subdirectory
`AGENTS.md` for path-specific invariants.

## Precedence

1. System/developer instructions.
2. The current user request.
3. The nearest `AGENTS.md`.
4. This file.

## Operating Model

- Inquiry, diagnosis, review, and planning tasks are read-only unless the user
  explicitly requests changes.
- For implementation, read the relevant code, tests, and local guidance, then
  make the smallest change that satisfies the request.
- State assumptions only when they affect behavior or verification. Ask only
  when a wrong assumption would materially change the result.
- Do not load every skill or inspect unrelated modules preemptively. Select a
  skill only when its description directly matches the request or changed
  surface.
- Avoid repeated reads and equivalent verification commands once enough
  evidence exists.

## Worktree and Disk Hygiene

- Start implementation from the latest `origin/main` and confirm the requested
  change is not already present.
- An existing clean, isolated task worktree is sufficient. Create another
  worktree only when the current checkout is shared, dirty with unrelated work,
  or belongs to another task.
- Never commit from a shared checkout.
- Use a task-specific branch named `<type>/<topic>`, such as `fix/...`,
  `feat/...`, `test/...`, or `docs/...`, unless the user specifies a name.
- Do not include agent, tool, contributor, account, or organization names in
  branch names.
- Push to the user-requested remote or the repository's configured push remote.
  Do not hard-code or infer a remote from an account name.
- Check free space before artifact-heavy builds, tests, coverage, or downloads.
  Re-check before a broad gate when space is tight.
- Remove only task-owned temporary/build artifacts. Never delete another task's
  worktree or uncommitted data.
- At handoff, mention disk or cleanup details only when they affected execution
  or artifacts/worktrees remain intentionally.

## Change Style

- Preserve existing control flow unless changing it is required for correctness.
- Prefer a direct local edit over new files, wrappers, managers, or speculative
  abstractions.
- Add a helper only when it removes current duplication, names a real domain
  boundary, or isolates a non-trivial invariant.
- Remove an in-scope path superseded by the change. If compatibility requires it,
  adapt at the boundary to one canonical core and use the repository's
  `RUSTFS_COMPAT_TODO` policy.
- Comments explain non-obvious invariants or reasons. Do not narrate code or
  record change history.
- Mention unrelated problems when useful; do not fix them in a narrow task.

## Reuse and Boundary Rules

- Before adding helpers, constants, fixtures, or wrappers, search the touched
  crate, the domain-owning crate, `crates/utils`, `crates/common`, and relevant
  direct dependencies.
- Reuse requires matching semantics: normalization, error types, deadlines,
  durability, and compatibility must fit the call site. A narrowly named local
  helper is better than forced reuse with different semantics.
- Validate untrusted input at its trust boundary, then trust the validated type.
  Values crossing disk, RPC, persistence, or version boundaries remain
  untrusted at every consumer.
- Re-check boundary values immediately before destructive actions such as
  delete, overwrite, or quorum decisions.
- Every new branch needs a concrete triggering input/state. For decoded or peer
  data, corruption and mixed-version input are valid triggers.
- Required values must return a typed error when absent or corrupt; do not use a
  default that converts corruption into a plausible result.
- Attach error context once where it is actionable. Do not erase typed errors
  below aggregation or quorum layers.

## Sources of Truth

- Workspace membership: `Cargo.toml`.
- Local gates: `Makefile` and `.config/make/`.
- CI gates: `.github/workflows/ci.yml`.
- PR format: `.github/pull_request_template.md`.
- Architecture routing: `ARCHITECTURE.md` and `docs/architecture/README.md`.
- Knowledge-base index and documentation rules: `docs/architecture/README.md`.
- Agent skills: `.agents/skills/*/SKILL.md`.

Do not commit one-shot plans, trackers, migration ledgers, benchmark snapshots,
or agent scratch notes. Durable architecture belongs under `docs/architecture/`,
operations under `docs/operations/`, and testing references under
`docs/testing/`. `scripts/check_no_planning_docs.sh` enforces this boundary.

## Verification

Select checks from the final task-owned diff. Scoped `AGENTS.md` files may add a
concrete path-specific check, but must not replace this tiering with a generic
full-workspace gate.

### Documentation and Instructions

For prose, comments, agent instructions, and skill metadata that cannot affect
runtime/build output:

- Run `git diff --check`.
- Run the relevant documentation guard or skill validator when applicable.
- Skip Cargo formatting, compilation, Clippy, tests, `make pre-commit`, and
  `make pre-pr`.

### Non-Behavioral Source Changes

- Run the formatter/validator for the changed language.
- Add compilation or doctests only when syntax or executable examples changed.

### Localized Behavior Changes

- Run `cargo fmt --all --check` for Rust changes.
- Run the narrowest test that exercises the changed behavior.
- Add package-scoped `cargo check` or Clippy only for targets, features, public
  APIs, error handling, or control flow not compiled by the focused test.
- Use `make pre-commit` only when its repository-wide fast checks add confidence
  beyond the focused checks.

### Broad Cross-Module Changes

Do not run `make pre-pr` by default before opening a PR. Consider it only when
the final diff is broad, spans multiple modules, and targeted checks cannot
bound the impact. Decide dynamically from the affected boundaries and risks;
otherwise use the scoped formatting, linting, compilation, and test checks
above.

`make pre-pr` includes `make pre-commit`; never run both for the same unchanged
diff. Do not repeat a check already covered by a successful umbrella gate.
Rerun only checks affected by later edits.

Never weaken a gate to get green: do not add baselines/allowances, suppress
lints, ignore tests, or relax assertions unless changing that policy is itself
the reviewed task. Follow `docs/testing/README.md` for flaky tests.

## Adversarial Validation

Adversarial validation applies to final implementation diffs, explicitly
requested adversarial/design reviews, and agent-instruction changes that alter
execution. Ordinary questions, diagnoses, status reports, non-adversarial code
reviews, and low-risk planning do not trigger it.

Risk and review shape:

- **Exempt:** documentation, comments, formatting, or typos with no runtime,
  build, test, or agent-execution effect.
- **Mechanical:** renames, moves, test/tooling-only changes, and agent-rule
  changes. Run correctness and simplicity lenses.
- **Standard:** localized behavior changes. Run one integrated final-diff pass
  covering correctness, simplicity, and test coverage; add only domain lenses
  matched by the diff.
- **High risk / substantial PR review:** high risk includes locking,
  erasure/quorum/heal, replication, multipart, RPC, lifecycle/tiering,
  persistence/fsync, IAM/KMS/auth, cryptography, on-disk/on-wire formats, and
  S3-visible semantics. Cover all applicable lenses using exactly two
  independent reviewers when delegation is explicitly authorized. Split the
  lenses between them. Otherwise perform two fresh sequential passes.
- **Outbound client defaults:** what `TargetClient`, `PutObjectOptions`, or
  the remote SDK configuration sends to every replication or migration target
  is high risk for every target class even when the change fixes one. Follow
  the SOP in `docs/postmortems/2026-09-03-replication-checksum-default-regression.md`:
  run the outbound target matrix, document each new env knob in the same PR,
  and list verified and unverified target classes in the PR Impact section.

Available domain lenses are security, concurrency/durability, compatibility,
and performance. Select `.agents/skills/adversarial-validation/SKILL.md` for an
explicit adversarial request, a high-risk change, or a substantial PR review;
then read only its matching role references. A routine standard pass does not
load the playbook unless the reviewer needs a RustFS-specific probe.

A finding must name a concrete input/state/interleaving and wrong outcome, or a
specific missing regression check, with `file:line`. Resolve it by fixing the
diff or rebutting it with code-path/test/invariant evidence. After a non-trivial
fix, rerun only affected lenses.

For high-risk PRs, record one concise verdict per covered lens in the PR body.

## Pull Request Lifecycle

- Creating or updating a PR includes one immediate snapshot of checks,
  mergeability, reviews, and unresolved threads.
- Unless the user explicitly requests monitoring, a release workflow requires
  it, or an automation already owns it, hand off after the PR is open with the
  current state and next event to watch. Do not delay ordinary handoff with
  fixed quiet-period sleeps.
- For requested monitoring, use event-driven or bounded waits. Report only state
  changes, actionable failures, or a meaningful prolonged delay.
- Investigate failures/comments before changing code. Fix task-attributable
  issues, rerun affected verification, push, reply or resolve the thread, then
  resume the requested monitor.
- Never merge without required reviewer approval or explicit authority.
- After an observed merge, verify the commit reached the base, then clean the
  task worktree/branch when safe. Preserve unmerged work for closed PRs unless
  deletion was explicitly authorized.

## Git and PR Baseline

- Follow Conventional Commits; keep the subject at most 72 characters.
- Source comments, commits, PR titles, and PR bodies are in English.
- Keep every heading from `.github/pull_request_template.md`; use `N/A` where
  needed and include commands actually run.
- Use `--body-file` for multiline `gh pr create`/`gh pr edit` content.
- PR/issue/discussion content must not contain the literal sequence `\n` or
  hard-wrapped prose paragraphs.
- Do not include local absolute paths or tool-specific labels/prefixes in GitHub
  content.
- Resolve review threads after the underlying issue is fixed. If declining a
  suggestion, reply with a short evidence-based reason.

## Security Baseline

- Never commit secrets, credentials, or key material.
- Use environment variables or vault tooling for sensitive configuration.
- For localhost-sensitive tests, bypass proxies explicitly.
- Untrusted S3 XML/JSON, lifecycle, policy, replication, and RPC structures use
  strict deserialization where compatibility permits. Security-critical
  defaults require explicit validation.

## Logging

For every added or edited `tracing` call:

- Reuse the module's `EVENT_*`, `LOG_COMPONENT_*`, and `LOG_SUBSYSTEM_*`
  constants and field shape.
- Put fields first and a short label last.
- Use `error` for behavior/security failure, `warn` for degradation/fallback,
  `info` for low-frequency lifecycle, `debug` for diagnostics, and `trace` for
  repetitive request/object success paths.
- Never log secrets, credential payloads, or merged configs.

Use `.agents/skills/rustfs-logging-governance/SKILL.md` for logging changes.

## Cross-Cutting Storage Invariants

- Write internal object metadata under both `x-rustfs-internal-<suffix>` and
  `x-minio-internal-<suffix>` using
  `crates/utils/src/http/metadata_compat.rs` helpers.
- Read binary UUID metadata with
  `.and_then(|v| Uuid::from_slice(&v).ok()).filter(|u| !u.is_nil())`; absent,
  empty, and nil all mean no value.
- Remote-tier version `None` or `""` means an unversioned bucket; send no
  `versionId` on tier GET/DELETE.
- `DataUsageCacheInfo` and `DataUsageEntry` keep their hand-written map
  serialization and new fields remain `#[serde(default)]` for older readers.

## Naming

Use Rust API naming: `SCREAMING_SNAKE_CASE` constants/statics, `snake_case`
functions/variables, and `PascalCase` types. Do not rename unrelated existing
violations.

## Scoped Guidance

Before editing, locate the nearest instructions with:

```bash
git ls-files '*AGENTS.md'
```

The nearest file wins for domain invariants. Keep generic workflow and
validation policy in this root file.
