diff --git a/.agents/skills/api-design/SKILL.md b/.agents/skills/api-design/SKILL.md new file mode 100644 index 00000000000..f6642cf83bd --- /dev/null +++ b/.agents/skills/api-design/SKILL.md @@ -0,0 +1,45 @@ +--- +name: api-design +description: API stability annotations, design principles, and patterns for the MongoDB Java Driver. Use when adding or modifying public API surface — new classes, methods, interfaces, or changing method signatures. +--- +# API Design + +## API Stability Annotations + +- `@Alpha` — Early development, may be removed. + Not for production use. +- `@Beta` — Subject to change or removal. + Libraries should not depend on these. +- `@Evolving` — May add abstract methods in future releases. + Safe to use, but implementing/extending bears upgrade risk. +- `@Sealed` — Must not be extended or implemented by consumers. + Safe to use, but not to subclass. +- `@Deprecated` — Supported until next major release but should be migrated away from. + +## Design Principles + +- **Deep modules:** Prefer simple interfaces with powerful implementations over shallow wrappers. +- **Information hiding:** Bury complexity behind simple interfaces. +- **Pull complexity downward:** Make the implementer work harder so callers work less. +- **General-purpose over special-case:** Fewer flexible methods over many specialized ones. +- **Define errors out of existence:** Design APIs so errors cannot happen rather than detecting and handling them. + +## Search Before Implementing + +Before writing new code, search the codebase for existing implementations: + +- Check if a utility method already exists in `com.mongodb.internal.*` +- Check if a similar pattern is established elsewhere in the module +- Reuse existing well-tested infrastructure over creating duplicates + +## Key Patterns + +- Static factory methods: `Filters.eq()`, `Updates.set()`, `Aggregates.match()` +- Fluent builders: `MongoClientSettings.builder()` is the primary entry point +- Abstract core with pluggable transports + +## Public API Rules + +- Breaking changes require a major version bump - ALWAYS warn if breaking binary compatibility +- All `com.mongodb.internal.*` / `org.bson.internal.*` is private API — never expose in public APIs +- Every public package must have a `package-info.java` diff --git a/.agents/skills/evergreen/SKILL.md b/.agents/skills/evergreen/SKILL.md new file mode 100644 index 00000000000..603beeb9c60 --- /dev/null +++ b/.agents/skills/evergreen/SKILL.md @@ -0,0 +1,34 @@ +--- +name: evergreen +description: Evergreen CI infrastructure, configuration validation. Use when modifying .evergreen/ config, preparing to submit changes or understanding the Evergreen test matrix. +--- +# Evergreen + +## Evergreen (MongoDB Internal CI) + +Primary CI runs on MongoDB’s Evergreen system. +Configuration lives in `.evergreen/`. + +- Do not modify `.evergreen/` configuration without review +- Evergreen runs the full test matrix across MongoDB versions, OS platforms, and JDK versions + +## Validating Evergreen Configuration + +After modifying `.evergreen/` files, validate the config locally: + +```bash +evergreen validate $PROJECT_PATH/.evergreen/.evg.yml +``` + +Always run this before submitting changes to `.evergreen/` to catch syntax errors and invalid task definitions. + +## Testing with a Patch Build + +To test your changes on Evergreen before merging, create a patch build: + +```bash +evergreen patch -u +``` + +This uploads your uncommitted and committed local changes as a patch build on Evergreen, allowing you to run the full CI +test matrix against your branch. diff --git a/.agents/skills/project-guide/SKILL.md b/.agents/skills/project-guide/SKILL.md new file mode 100644 index 00000000000..a068414426e --- /dev/null +++ b/.agents/skills/project-guide/SKILL.md @@ -0,0 +1,63 @@ +--- +name: project-guide +description: Project structure, dependency graph, and guide for finding the right project to work in. Use when starting a task and unsure which project owns the relevant code, or when you need to understand cross-project dependencies. +--- +# Project Guide + +## Project Structure + +| Project | Purpose | +| --- | --- | +| `bson` | BSON library (core serialization) | +| `bson-kotlin` | Kotlin BSON extensions | +| `bson-kotlinx` | Kotlin serialization BSON codec | +| `bson-record-codec` | Java record codec support | +| `bson-scala` | Scala BSON extensions | +| `driver-core` | Core driver internals (connections, protocol, operations) | +| `driver-sync` | Synchronous Java driver | +| `driver-legacy` | Legacy MongoDB Java driver API | +| `driver-reactive-streams` | Reactive Streams driver | +| `driver-kotlin-coroutine` | Kotlin Coroutines driver | +| `driver-kotlin-extensions` | Kotlin driver extensions | +| `driver-kotlin-sync` | Kotlin synchronous driver | +| `driver-scala` | Scala driver | +| `mongodb-crypt` | Client-side field-level encryption | +| `bom` | Bill of Materials for dependency management | +| `testing` | Shared test resources and MongoDB specifications | +| `buildSrc` | Gradle convention plugins and build infrastructure | +| `driver-benchmarks` | JMH and custom performance benchmarks (not published) | +| `driver-lambda` | AWS Lambda test application (not published) | +| `graalvm-native-image-app` | GraalVM Native Image compatibility testing (not published) | + +## Dependency Graph (simplified) + +``` +bson + ├── bson-kotlin + ├── bson-kotlinx + ├── bson-record-codec + ├── bson-scala + └── driver-core + ├── driver-sync + │ ├── driver-legacy + │ ├── driver-kotlin-sync + │ └── driver-lambda + ├── driver-reactive-streams + │ ├── driver-kotlin-coroutine + │ └── driver-scala + └── driver-kotlin-extensions +``` + +## Finding the Right Module + +- **BSON serialization/codecs:** `bson` (or `bson-kotlin`/`bson-kotlinx`/`bson-scala` for language-specific) +- **Query builders, filters, aggregates:** `driver-core` (`com.mongodb.client.model`) +- **Sync Java API:** `driver-sync` +- **Reactive API:** `driver-reactive-streams` +- **Kotlin coroutines:** `driver-kotlin-coroutine` +- **Kotlin DSL builders:** `driver-kotlin-extensions` +- **Scala driver:** `driver-scala` +- **Connection, protocol, auth internals:** `driver-core` (`com.mongodb.internal.*`) +- **Build plugins, formatting, test infra:** `buildSrc` + +Each module has its own `AGENTS.md` with module-specific packages, patterns, and notes. diff --git a/.agents/skills/spec-tests/SKILL.md b/.agents/skills/spec-tests/SKILL.md new file mode 100644 index 00000000000..6c07b7d7f5e --- /dev/null +++ b/.agents/skills/spec-tests/SKILL.md @@ -0,0 +1,41 @@ +--- +name: spec-tests +description: How to work with MongoDB specification tests — structure, rules, and adding new spec test support. Use when implementing or modifying behavior defined by the MongoDB Driver Specifications, or when working with the test data in testing/resources/specifications/. +--- +# MongoDB Specification Tests + +## Overview + +The driver implements the [MongoDB Driver Specifications](https://github.com/mongodb/specifications). +Specification test data files live in `testing/resources/specifications/` — a git submodule. + +## Rules + +- **Do not modify existing specification tests** unless they test incorrect behavior +- **Do not modify spec test data** — it is managed upstream +- Create new tests instead of modifying existing ones +- Update the submodule via `git submodule update` + +## Structure + +Spec test data is organized by specification area: + +- CRUD, SDAM, auth, CSFLE, retryable operations, and more +- Each spec area has JSON/YAML test data files defining inputs and expected outputs +- Driver test runners parse these files and execute against the driver + +## Test Data Location + +``` +testing/ + resources/ + specifications/ # Git submodule — do not edit directly + logback-test.xml # Shared logback configuration for tests +``` + +## Adding Spec Test Support + +1. Check `testing/resources/specifications/` for the relevant spec test data +2. Find existing test runners in the module (look for `*SpecificationTest*` or similar) +3. Extend existing patterns — each module handles spec tests slightly differently +4. Ensure tests run with `./gradlew check` or the module’s test task diff --git a/.agents/skills/style-reference/SKILL.md b/.agents/skills/style-reference/SKILL.md new file mode 100644 index 00000000000..0ac14435419 --- /dev/null +++ b/.agents/skills/style-reference/SKILL.md @@ -0,0 +1,44 @@ +--- +name: style-reference +description: Detailed code style rules for Java, Kotlin, Scala, and Groovy in the MongoDB Java Driver. Use when you need specific formatting rules beyond the basics in root AGENTS.md — e.g., line length, import ordering, brace style, or language-specific formatter configuration. Spotless auto-enforces most rules. +--- +# Style Reference + +## Java Style Rules + +- **Max line length:** 140 characters +- **Indentation:** 4 spaces (no tabs) +- **Line endings:** LF (Unix) +- **Charset:** UTF-8 +- **Star imports:** Prohibited (AvoidStarImport) +- **Final parameters:** Required (FinalParameters checkstyle rule) +- **Braces:** Required for all control structures (NeedBraces) +- **Else placement:** `} else {` on the same line (Palantir Java Format default) +- **Copyright header:** Every Java / Kotlin / Scala file must contain `Copyright 2008-present MongoDB, Inc.` +- **Formatter:** Palantir Java Format + +## Kotlin Style Rules + +- **Formatter:** ktfmt dropbox style, max width 120 +- **Static analysis:** detekt + +## Scala Style Rules + +- **Formatter:** scalafmt +- **Supported versions:** 2.11, 2.12, 2.13, 3 (default: 2.13) + +## Groovy Style Rules + +- **Static analysis:** CodeNarc + +## Prohibited Patterns + +- `System.out.println` / `System.err.println` — Use SLF4J logging +- `e.printStackTrace()` — Use proper logging/error handling + +## Formatting Commands + +```bash +./gradlew spotlessApply # Auto-fix all formatting +./gradlew spotlessCheck # Check without modifying +``` diff --git a/.agents/skills/testing-guide/SKILL.md b/.agents/skills/testing-guide/SKILL.md new file mode 100644 index 00000000000..73b7c6c4b2f --- /dev/null +++ b/.agents/skills/testing-guide/SKILL.md @@ -0,0 +1,60 @@ +--- +name: testing-guide +description: Testing frameworks, conventions, and commands for the MongoDB Java Driver. Use when writing or running tests — covers framework selection per module, test naming conventions, integration test setup, and how to run specific test subsets. +--- +# Testing Guide + +## Frameworks + +| Framework | Usage | Notes | +| --- | --- | --- | +| JUnit 5 (Jupiter) | Primary unit test framework | All new tests | +| Spock (Groovy) | Legacy tests | Do not add new Spock tests | +| Mockito | Mocking | Use `mockito-junit-jupiter` integration | +| ScalaTest | Scala module testing | FlatSpec + ShouldMatchers | +| Project Reactor | Reactive test utilities | `driver-reactive-streams` tests | + +## Writing Tests + +- Every code change must include tests +- Extend existing test patterns in the module you are modifying +- Unit tests must not require a running MongoDB instance +- Descriptive method names: `shouldReturnEmptyListWhenNoDocumentsMatch()` not `test1()` +- Use `@DisplayName` for human-readable names +- Clean up test data in `@AfterEach` / `cleanup()` to prevent pollution + +## Running Tests + +```bash +# All tests (unit + integration) +./gradlew check + +# Single module +./gradlew :driver-core:test + +# Integration tests (requires MongoDB) +./gradlew integrationTest -Dorg.mongodb.test.uri="mongodb://localhost:27017" + +# Specific test class +./gradlew :driver-core:test --tests "com.mongodb.internal.operation.FindOperationTest" + +# Alternative JDK +./gradlew test -PjavaVersion=11 + +# Scala tests (all versions) +./gradlew scalaCheck +``` + +## Module-Specific Notes + +- **driver-core:** Largest test suite — JUnit 5 + Spock + Mockito +- **driver-sync:** JUnit 5 + Spock (heavy Spock usage, but don’t add new) +- **driver-reactive-streams:** JUnit 5 + Spock + Project Reactor +- **bson-scala / driver-scala:** ScalaTest, test per Scala version +- **Kotlin modules:** JUnit 5 + mockito-kotlin + +## Integration Tests + +- Require a running MongoDB instance +- Set connection URI: `-Dorg.mongodb.test.uri="mongodb://localhost:27017"` +- Integration test source set configured via `conventions/testing-integration.gradle.kts` diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 00000000000..2b7a412b8fa --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6398e8490e8..2241cf34717 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,9 @@ local.properties # security-sensitive files *.gpg +# per-developer agent overrides +.AGENTS.md + # bin build directories **/bin diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..73572bf9223 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,71 @@ +# AGENTS.md - MongoDB Java Driver + +All changes require human review. +Breaking changes to public API require a major version bump — always warn if binary compatibility is affected. +Also consult `.AGENTS.md` / `~/.AGENTS.md` if present for local agent settings. + +See [`.agents/skills/project-guide`](.agents/skills/project-guide/SKILL.md) for module structure and dependency graph. +Each module has its own `AGENTS.md`. + +## Core Rules + +- Read before modifying. + Understand existing code and patterns first. +- Minimal changes only. + No drive-by refactoring or unrelated changes. +- Preserve existing comments. + Only remove if provably incorrect. +- No rewrites without explicit permission. +- When stuck or uncertain: stop, explain, propose alternatives, ask. + +## Build + +Gradle with Kotlin DSL. Build JDK: 17+. Source baseline: Java 8. Versions in `gradle/libs.versions.toml`. + +```bash +./gradlew check # Full validation (format + static checks + tests) +./gradlew :driver-core:test # Single module tests +./gradlew integrationTest -Dorg.mongodb.test.uri="mongodb://localhost:27017" +``` + +## Style + +`check` runs `spotlessCheck` to verify formatting — run `./gradlew spotlessApply` to auto-format when needed. +Do not reformat outside your changes. +See [`.agents/skills/style-reference`](.agents/skills/style-reference/SKILL.md) for full rules. + +- No `System.out.println` / `System.err.println` — use SLF4J +- No `e.printStackTrace()` — use proper error handling +- Copyright header required: `Copyright 2008-present MongoDB, Inc.` +- Every public package must have a `package-info.java` + +## Testing + +- Every code change must include tests. + Do not reduce coverage. +- See [`.agents/skills/testing-guide`](.agents/skills/testing-guide/SKILL.md) for framework details and running specific + tests. +- See [`.agents/skills/spec-tests`](.agents/skills/spec-tests/SKILL.md) for MongoDB specification test conventions. + +## API + +All `com.mongodb.internal.*` / `org.bson.internal.*` is private API — never expose in public APIs. +See [`.agents/skills/api-design`](.agents/skills/api-design/SKILL.md) for stability annotations and design principles. + +## Do Not Modify Without Human Approval + +- Wire protocol / authentication handshakes (`com.mongodb.internal.connection`) +- Connection pool core code (`com.mongodb.internal.connection.pool`) +- Security-critical encryption code / JNA bindings (`mongodb-crypt`) +- Public API contracts (breaking changes need major version bump) +- BSON specification compliance +- Spec test data submodule (`testing/resources/specifications/`) +- Release/versioning scripts, `.evergreen/` config, credentials/secrets + +See [`.agents/skills/evergreen`](.agents/skills/evergreen/SKILL.md) for CI validation and patch builds. + +## Before Submitting + +```bash +./gradlew spotlessApply doc check scalaCheck # formatting + Docs + static checks + all tests +``` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md index 7cf774eb9fb..8a28cd89cb2 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,18 @@ $ mongod --dbpath ./data/db --logpath ./data/mongod.log --port 27017 --logappend If you encounter `"Too many open files"` errors when running the tests then you will need to increase the number of available file descriptors prior to starting mongod as described in [https://www.mongodb.com/docs/manual/reference/ulimit/](https://www.mongodb.com/docs/manual/reference/ulimit/) +## AI Agent Configuration + +This repository uses [agentskills.io](https://agentskills.io) conventions for AI coding +agent instructions. `AGENTS.md` is the canonical source of truth — tool-specific files +like `CLAUDE.md` are generated references. + +### Adding a nested AGENTS.md + +1. Create an `AGENTS.md` in the target directory. +2. Run `scripts/symlink-claude-md.sh` to generate the companion `CLAUDE.md`. +3. Stage and commit both files. + ## IntelliJ IDEA A couple of manual configuration steps are required to run the code in IntelliJ: diff --git a/bom/AGENTS.md b/bom/AGENTS.md new file mode 100644 index 00000000000..50262893e75 --- /dev/null +++ b/bom/AGENTS.md @@ -0,0 +1,12 @@ +# AGENTS.md - bom + +Bill of Materials (BOM) POM for the MongoDB Java Driver, simplifying dependency version management. + +**Depends on:** All published driver modules (transitive version constraints only) + +## Notes + +- Java Platform plugin — no source code, only version constraints +- Automatically includes all supported Scala version variants for `bson-scala` and `driver-scala` +- Validates generated POM: all dependencies must be `org.mongodb`, no `` or `` elements +- Do not add non-MongoDB dependencies to this module diff --git a/bom/CLAUDE.md b/bom/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/bom/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/bson-kotlin/AGENTS.md b/bson-kotlin/AGENTS.md new file mode 100644 index 00000000000..1842209daf2 --- /dev/null +++ b/bson-kotlin/AGENTS.md @@ -0,0 +1,20 @@ +# AGENTS.md - bson-kotlin + +Kotlin extensions for the BSON library, providing idiomatic Kotlin codec support. + +**Depends on:** `bson` + +- Work here if: modifying Kotlin-specific BSON codecs or inline reified functions + +## Key Packages + +- `org.bson.codecs.kotlin` — Kotlin-specific codecs with inline reified functions + +## Build & Test + +```bash +./gradlew :bson-kotlin:test +./gradlew :bson-kotlin:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/bson-kotlin/CLAUDE.md b/bson-kotlin/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/bson-kotlin/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/bson-kotlinx/AGENTS.md b/bson-kotlinx/AGENTS.md new file mode 100644 index 00000000000..39035e80c7c --- /dev/null +++ b/bson-kotlinx/AGENTS.md @@ -0,0 +1,21 @@ +# AGENTS.md - bson-kotlinx + +Kotlinx serialization integration for BSON, providing a pluggable serialization format. + +**Depends on:** `bson` + +- Work here if: modifying the kotlinx-serialization BSON codec integration + +## Key Packages + +- `org.bson.codecs.kotlinx` — Kotlinx serialization BSON format support +- `org.bson.codecs.kotlinx.utils` — Helper utilities + +## Build & Test + +```bash +./gradlew :bson-kotlinx:test +./gradlew :bson-kotlinx:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/bson-kotlinx/CLAUDE.md b/bson-kotlinx/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/bson-kotlinx/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/bson-record-codec/AGENTS.md b/bson-record-codec/AGENTS.md new file mode 100644 index 00000000000..3cc0ef41262 --- /dev/null +++ b/bson-record-codec/AGENTS.md @@ -0,0 +1,21 @@ +# AGENTS.md - bson-record-codec + +Java record codec support for BSON serialization. +**Requires Java 17+.** + +**Depends on:** `bson` + +- Work here if: modifying Java record serialization support + +## Key Packages + +- `org.bson.codecs.record` — `RecordCodecProvider` and record field accessors + +## Build & Test + +```bash +./gradlew :bson-record-codec:test +./gradlew :bson-record-codec:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/bson-record-codec/CLAUDE.md b/bson-record-codec/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/bson-record-codec/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/bson-scala/AGENTS.md b/bson-scala/AGENTS.md new file mode 100644 index 00000000000..e2a3fc8e4c6 --- /dev/null +++ b/bson-scala/AGENTS.md @@ -0,0 +1,25 @@ +# AGENTS.md - bson-scala + +Scala extensions for the BSON library, providing Scala-idiomatic wrappers and macro-based codecs. + +**Depends on:** `bson` + +**Supported Scala versions:** 2.11, 2.12, 2.13, 3 (default: 2.13, configured in root `gradle.properties`). + +- Work here if: modifying Scala BSON wrappers, macro codecs, or Scala collection support + +## Key Packages + +- `org.mongodb.scala.bson` — Core Scala BSON wrappers +- `org.mongodb.scala.bson.codecs` — Macro-based codecs (Scala 2/3) + +## Build & Test + +```bash +./gradlew :bson-scala:test +./gradlew :bson-scala:scalaCheck # Static checks + tests (default Scala version) +./gradlew :bson-scala:scalaCheck -PscalaVersion= # Test specific Scala version +``` + +For global rules see [root AGENTS.md](../AGENTS.md). +See [README.md](./README.md) for directory layout details. diff --git a/bson-scala/CLAUDE.md b/bson-scala/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/bson-scala/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/bson/AGENTS.md b/bson/AGENTS.md new file mode 100644 index 00000000000..1da3b8ec9d3 --- /dev/null +++ b/bson/AGENTS.md @@ -0,0 +1,27 @@ +# AGENTS.md - bson + +Core BSON (Binary JSON) library — the foundation module. +All other modules depend on it. + +**Depends on:** None (foundation module) + +- Work here if: adding/modifying BSON types, codecs, JSON conversion, or binary I/O +- Do not: expose `org.bson.internal` types in public API + +## Key Packages + +- `org.bson` — Core types (`BsonDocument`, `BsonValue`, `BsonReader`, `BsonWriter`) +- `org.bson.codecs` — Codec framework (`Encoder`, `Decoder`, `Codec`, `CodecRegistry`) +- `org.bson.codecs.pojo` — POJO codec support +- `org.bson.json` — JSON conversion (`JsonReader`, `JsonWriter`) +- `org.bson.internal` — Private API — do not expose + +## Build & Test + +```bash +./gradlew :bson:test +./gradlew :bson:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). +For API design see [api-design skill](../.agents/skills/api-design/SKILL.md). diff --git a/bson/CLAUDE.md b/bson/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/bson/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/buildSrc/AGENTS.md b/buildSrc/AGENTS.md new file mode 100644 index 00000000000..b4812d93d77 --- /dev/null +++ b/buildSrc/AGENTS.md @@ -0,0 +1,67 @@ +# AGENTS.md - buildSrc + +Gradle build infrastructure providing convention plugins and shared configuration for all modules. + +## Key Directories + +- `src/main/kotlin/conventions/` — Convention plugins applied by modules (formatting, testing, publishing, static + analysis) +- `src/main/kotlin/project/` — Base project plugins for Java, Kotlin, and Scala modules +- `src/main/kotlin/ProjectExtensions.kt` — Shared Gradle extension utilities + +## Convention Plugins + +| Plugin | Purpose | +| --- | --- | +| `spotless` | Code formatting (Java: Palantir; Kotlin: ktfmt dropbox, max 120; Scala: scalafmt) | +| `codenarc` | Groovy static analysis | +| `detekt` | Kotlin static analysis | +| `spotbugs` | Java bug detection | +| `bnd` | OSGi bundle metadata | +| `dokka` | Kotlin documentation generation | +| `javadoc` | Java documentation generation | +| `scaladoc` | Scala documentation generation | +| `publishing` | Maven Central publishing configuration | +| `git-version` | Version derivation from git tags | +| `optional` | Optional dependency support (`optionalImplementation`) | +| `testing-base` | Shared test configuration | +| `testing-integration` | Integration test source set and tasks | +| `testing-junit` | JUnit 5 test setup | +| `testing-junit-vintage` | JUnit 4 compatibility | +| `testing-spock` | Spock framework setup | +| `testing-spock-exclude-slow` | Spock with slow test exclusion | +| `testing-mockito` | Mockito setup | +| `test-artifacts` | Test artifact sharing between modules | +| `test-artifacts-runtime-dependencies` | Runtime dependency sharing for tests | +| `test-include-optionals` | Include optional dependencies in tests | + +## Project Plugins + +| Plugin | Purpose | +| --- | --- | +| `project/base` | Common settings for all modules | +| `project/java` | Java module conventions (source compatibility, checkstyle) | +| `project/kotlin` | Kotlin module conventions | +| `project/scala` | Scala module conventions (multi-version support) | + +## Notes + +- Formatting: ktfmt dropbox style, max width 120 (for buildSrc’s own code) +- `check` depends on `spotlessCheck` in buildSrc itself +- Java toolchain is set to Java 17 + +## Keeping AGENTS.md and Skills in Sync + +When modifying buildSrc, you **must** update the relevant AGENTS.md files and skills (in `.agents/skills/`) if your +changes affect: + +- **Formatting conventions** (e.g., changes to `spotless.gradle.kts`) — update the root `AGENTS.md` “Formatting” + section, the `style-reference` skill, and any module AGENTS.md files that reference formatting rules +- **Convention plugins added or removed** — update this file’s plugin table and the root `AGENTS.md` if the change + affects build commands or developer workflow +- **Testing conventions** (e.g., changes to `testing-*.gradle.kts`) — update the root `AGENTS.md` “Testing” section, the + `testing-guide` skill, and affected module AGENTS.md files +- **Project plugins added or removed** — update this file’s project plugin table +- **Build commands or task names changed** — update the root `AGENTS.md` “Build” and “Before Submitting” sections, the + `evergreen` skill, and any module “Before Submitting” sections +- **CI/CD or publishing changes** — update the `evergreen` skill diff --git a/buildSrc/CLAUDE.md b/buildSrc/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/buildSrc/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-benchmarks/AGENTS.md b/driver-benchmarks/AGENTS.md new file mode 100644 index 00000000000..75c9ff42c87 --- /dev/null +++ b/driver-benchmarks/AGENTS.md @@ -0,0 +1,21 @@ +# AGENTS.md - driver-benchmarks + +Performance benchmarks for the MongoDB Java Driver using JMH and a custom benchmark framework. + +**Depends on:** `driver-sync`, `mongodb-crypt` + +## Key Packages + +- `com.mongodb.benchmark.benchmarks` — Benchmark suite and individual benchmarks (BSON, single/multi-doc, bulk + operations) +- `com.mongodb.benchmark.benchmarks.bulk` — Bulk write benchmarks +- `com.mongodb.benchmark.benchmarks.netty` — Netty transport benchmarks +- `com.mongodb.benchmark.framework` — Custom benchmark harness +- `com.mongodb.benchmark.jmh` — JMH microbenchmarks + +## Notes + +- Not published — internal testing only +- Non-standard source layout: `src/main` (no `java` subdirectory) +- Run benchmarks: `./gradlew :driver-benchmarks:run` or `./gradlew :driver-benchmarks:jmh` +- Requires `-Dorg.mongodb.benchmarks.data` and `-Dorg.mongodb.benchmarks.output` system properties diff --git a/driver-benchmarks/CLAUDE.md b/driver-benchmarks/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-benchmarks/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-core/AGENTS.md b/driver-core/AGENTS.md new file mode 100644 index 00000000000..72839e445e8 --- /dev/null +++ b/driver-core/AGENTS.md @@ -0,0 +1,34 @@ +# AGENTS.md - driver-core + +Core driver internals shared by all driver variants (sync, reactive, Kotlin, Scala). +Largest and most complex module. + +**Depends on:** `bson`, `bson-record-codec`, optionally `bson-kotlin`, `bson-kotlinx`, `mongodb-crypt` + +- Work here if: modifying query builders (`Filters`, `Updates`, `Aggregates`), connection handling, wire protocol, + server selection, or operation execution +- Do not: block in async code paths, modify wire protocol or auth without human approval + +## Key Packages + +- `com.mongodb.client.model` — `Filters`, `Updates`, `Projections`, `Aggregates`, `Sorts`, `Indexes` +- `com.mongodb.internal.connection` — Wire protocol, command execution (safety-critical) +- `com.mongodb.internal.operation` — Concrete operations (find, insert, aggregate) +- `com.mongodb.internal.authentication` — SASL, SCRAM, X.509, OIDC (safety-critical) + +## Build & Test + +```bash +./gradlew :driver-core:test +./gradlew :driver-core:check +./gradlew :driver-core:generateMongoDriverVersion # If MongoDriverVersion is missing +``` + +## Notes + +- Most extensive test suite — JUnit 5 + Spock + Mockito. + Match surrounding patterns carefully. +- `MongoDriverVersion` is auto-generated by the `com.github.gmazzo.buildconfig` plugin + +For global rules see [root AGENTS.md](../AGENTS.md). +For API design see [api-design skill](../.agents/skills/api-design/SKILL.md). diff --git a/driver-core/CLAUDE.md b/driver-core/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-core/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-kotlin-coroutine/AGENTS.md b/driver-kotlin-coroutine/AGENTS.md new file mode 100644 index 00000000000..471ee61fde2 --- /dev/null +++ b/driver-kotlin-coroutine/AGENTS.md @@ -0,0 +1,21 @@ +# AGENTS.md - driver-kotlin-coroutine + +Kotlin Coroutines driver providing `suspend` function-based async API. + +**Depends on:** `bson`, `driver-reactive-streams`, `bson-kotlin` + +- Work here if: modifying the Kotlin coroutine-based driver API +- Do not: block in any code path — all suspend functions wrap `driver-reactive-streams` + +## Key Packages + +- `com.mongodb.kotlin.client.coroutine` — Coroutine-based driver API (`MongoClient`, `MongoDatabase`, `MongoCollection`) + +## Build & Test + +```bash +./gradlew :driver-kotlin-coroutine:test +./gradlew :driver-kotlin-coroutine:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/driver-kotlin-coroutine/CLAUDE.md b/driver-kotlin-coroutine/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-kotlin-coroutine/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-kotlin-extensions/AGENTS.md b/driver-kotlin-extensions/AGENTS.md new file mode 100644 index 00000000000..009b49e45c8 --- /dev/null +++ b/driver-kotlin-extensions/AGENTS.md @@ -0,0 +1,22 @@ +# AGENTS.md - driver-kotlin-extensions + +Kotlin extensions providing type-safe DSLs for query and update construction. + +**Depends on:** `driver-core`, optionally `driver-kotlin-sync`, `driver-kotlin-coroutine` + +- Work here if: adding or modifying Kotlin type-safe DSL builders for `Filters`, `Updates`, `Aggregates`, etc. +- Works with both `driver-kotlin-sync` and `driver-kotlin-coroutine` + +## Key Packages + +- `com.mongodb.kotlin.client.model` — Type-safe DSL builders +- `com.mongodb.kotlin.client.property` — `KPropertyPath` for property-based queries + +## Build & Test + +```bash +./gradlew :driver-kotlin-extensions:test +./gradlew :driver-kotlin-extensions:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/driver-kotlin-extensions/CLAUDE.md b/driver-kotlin-extensions/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-kotlin-extensions/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-kotlin-sync/AGENTS.md b/driver-kotlin-sync/AGENTS.md new file mode 100644 index 00000000000..5f6d7ef32b0 --- /dev/null +++ b/driver-kotlin-sync/AGENTS.md @@ -0,0 +1,21 @@ +# AGENTS.md - driver-kotlin-sync + +Kotlin synchronous (blocking) driver — idiomatic Kotlin wrapper over `driver-sync`. + +**Depends on:** `bson`, `driver-sync`, `bson-kotlin` + +- Work here if: modifying the Kotlin blocking API surface +- Do not: add internal connection/protocol code (that belongs in `driver-core`) + +## Key Packages + +- `com.mongodb.kotlin.client` — Blocking sync API (`MongoClient`, `MongoDatabase`, `MongoCollection`) + +## Build & Test + +```bash +./gradlew :driver-kotlin-sync:test +./gradlew :driver-kotlin-sync:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/driver-kotlin-sync/CLAUDE.md b/driver-kotlin-sync/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-kotlin-sync/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-lambda/AGENTS.md b/driver-lambda/AGENTS.md new file mode 100644 index 00000000000..29a83c6ed4d --- /dev/null +++ b/driver-lambda/AGENTS.md @@ -0,0 +1,16 @@ +# AGENTS.md - driver-lambda + +AWS Lambda test application for validating the MongoDB Java Driver in Lambda environments. + +**Depends on:** `bson`, `driver-sync` + +## Key Packages + +- `com.mongodb.lambdatest` — Lambda test application entry point + +## Notes + +- Not published — internal testing only +- Java 11 source/target compatibility +- Built as a shadow JAR for Lambda deployment +- Non-standard source layout: `src/main` (no `java` subdirectory) diff --git a/driver-lambda/CLAUDE.md b/driver-lambda/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-lambda/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-legacy/AGENTS.md b/driver-legacy/AGENTS.md new file mode 100644 index 00000000000..16c142ac1c4 --- /dev/null +++ b/driver-legacy/AGENTS.md @@ -0,0 +1,24 @@ +# AGENTS.md - driver-legacy + +Legacy MongoDB Java driver API — backwards compatibility facade for the 3.x API. + +**Depends on:** `bson`, `driver-core`, `driver-sync` + +- Work here if: fixing bugs in the legacy 3.x API compatibility layer +- Do not: add new features (new functionality goes in `driver-sync` or `driver-core`) +- Do not: add new Spock tests + +## Key Packages + +- `com.mongodb` — Legacy API (`MongoClient`, `DB`, `DBCollection`, `DBCursor`) — distinct from `driver-core` classes in + the same namespace +- `com.mongodb.gridfs` — Legacy GridFS + +## Build & Test + +```bash +./gradlew :driver-legacy:test +./gradlew :driver-legacy:check +``` + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/driver-legacy/CLAUDE.md b/driver-legacy/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-legacy/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-reactive-streams/AGENTS.md b/driver-reactive-streams/AGENTS.md new file mode 100644 index 00000000000..15e452358ac --- /dev/null +++ b/driver-reactive-streams/AGENTS.md @@ -0,0 +1,26 @@ +# AGENTS.md - driver-reactive-streams + +Reactive Streams driver implementing the [Reactive Streams specification](https://www.reactive-streams.org/). + +**Depends on:** `bson`, `driver-core` + +- Work here if: modifying the Publisher-based async API +- Do not: block in any code path, break backpressure contracts + +## Key Packages + +- `com.mongodb.reactivestreams.client` — Publisher-based API (`MongoClient`, `MongoDatabase`, `MongoCollection`) + +## Build & Test + +```bash +./gradlew :driver-reactive-streams:test +./gradlew :driver-reactive-streams:check +``` + +## Notes + +- All operations return `Publisher` — never block +- `driver-kotlin-coroutine` and `driver-scala` both build on top of this module + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/driver-reactive-streams/CLAUDE.md b/driver-reactive-streams/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-reactive-streams/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-scala/AGENTS.md b/driver-scala/AGENTS.md new file mode 100644 index 00000000000..b71b7e2c4de --- /dev/null +++ b/driver-scala/AGENTS.md @@ -0,0 +1,26 @@ +# AGENTS.md - driver-scala + +Scala async driver providing Observable-based API wrapping `driver-reactive-streams`. + +**Depends on:** `bson-scala`, `driver-reactive-streams` + +**Supported Scala versions:** 2.11, 2.12, 2.13, 3 (default: 2.13, configured in root `gradle.properties`). + +- Work here if: modifying the Scala Observable-based driver API or Scala model wrappers +- Do not: block in any code path + +## Key Packages + +- `org.mongodb.scala` — Scala async driver (`MongoClient`, `MongoDatabase`, `MongoCollection`) +- `org.mongodb.scala.model` — Scala wrappers around filter/update builders + +## Build & Test + +```bash +./gradlew :driver-scala:test +./gradlew :driver-scala:scalaCheck # Static checks + tests (default Scala version) +./gradlew :driver-scala:scalaCheck -PscalaVersion= # Test specific Scala version +``` + +For global rules see [root AGENTS.md](../AGENTS.md). +See [README.md](./README.md) for directory layout details. diff --git a/driver-scala/CLAUDE.md b/driver-scala/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-scala/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/driver-sync/AGENTS.md b/driver-sync/AGENTS.md new file mode 100644 index 00000000000..a02ad511c64 --- /dev/null +++ b/driver-sync/AGENTS.md @@ -0,0 +1,26 @@ +# AGENTS.md - driver-sync + +Synchronous (blocking) Java driver — the most commonly used entry point for Java applications. + +**Depends on:** `bson`, `driver-core` + +- Work here if: modifying the blocking Java API surface (`MongoClient`, `MongoDatabase`, `MongoCollection`), GridFS, or + CSFLE vault client +- Do not: add new Spock tests (legacy only), add internal connection/protocol code (that belongs in `driver-core`) + +## Key Packages + +- `com.mongodb.client` — Public sync API +- `com.mongodb.client.gridfs` — GridFS sync implementation +- `com.mongodb.client.vault` — Client-side field-level encryption client + +## Build & Test + +```bash +./gradlew :driver-sync:test +./gradlew :driver-sync:check +``` + +Primary entry point: `MongoClients.create()` or `MongoClients.create(MongoClientSettings)`. + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/driver-sync/CLAUDE.md b/driver-sync/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/driver-sync/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/graalvm-native-image-app/AGENTS.md b/graalvm-native-image-app/AGENTS.md new file mode 100644 index 00000000000..40de264de12 --- /dev/null +++ b/graalvm-native-image-app/AGENTS.md @@ -0,0 +1,17 @@ +# AGENTS.md - graalvm-native-image-app + +GraalVM Native Image test application verifying driver compatibility with native compilation. + +**Depends on:** `bson`, `driver-core`, `driver-sync`, `driver-legacy`, `driver-reactive-streams`, `mongodb-crypt` + +## Key Packages + +- `com.mongodb.internal.graalvm` — Native image test app, GraalVM substitutions, and custom DNS support + +## Notes + +- Not published — internal testing only +- Requires `-PincludeGraalvm` Gradle property to be included in the build +- Requires GraalVM JDK 21+ installed and detected by Gradle toolchains +- Reachability metadata in `src/main/resources/META-INF/native-image/` +- Non-standard source layout: `src/main` (no `java` subdirectory) diff --git a/graalvm-native-image-app/CLAUDE.md b/graalvm-native-image-app/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/graalvm-native-image-app/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/gradle/AGENTS.md b/gradle/AGENTS.md new file mode 100644 index 00000000000..7bdb8910d0f --- /dev/null +++ b/gradle/AGENTS.md @@ -0,0 +1,20 @@ +# AGENTS.md - gradle + +Gradle configuration and infrastructure for the build system. + +## Key Files + +- `libs.versions.toml` — Central version catalog defining all dependency versions, library coordinates, bundles, and + plugin versions +- `wrapper/` — Gradle wrapper JAR and properties (do not modify manually — use + `./gradlew wrapper --gradle-version=`) +- `scala/lib/` — Bundled Scala Ant JAR for Scala compilation support + +## Notes + +- All dependency versions are managed in `libs.versions.toml` — never declare versions inline in `build.gradle.kts` + files +- Never add dependencies without justification +- The version catalog defines `[versions]`, `[libraries]`, `[bundles]`, and `[plugins]` sections +- Scala test libraries are declared per Scala version (v3, v2-v13, v2-v12, v2-v11) +- When adding or updating dependencies, modify `libs.versions.toml` and reference via `libs.` in build scripts diff --git a/gradle/CLAUDE.md b/gradle/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/gradle/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/mongodb-crypt/AGENTS.md b/mongodb-crypt/AGENTS.md new file mode 100644 index 00000000000..7d7323b3a7c --- /dev/null +++ b/mongodb-crypt/AGENTS.md @@ -0,0 +1,28 @@ +# AGENTS.md - mongodb-crypt + +Client-side field-level encryption (CSFLE) support via JNA bindings to libmongocrypt. + +**Depends on:** `bson` + +- Work here if: modifying CSFLE encryption/decryption logic or JNA bindings +- Do not: move, re-expose, or refactor JNA/libmongocrypt bindings without human approval — this is security-critical + code +- Do not: modify the C API binding layer without understanding the libmongocrypt contract + +## Key Packages + +- `com.mongodb.crypt.capi` — mongocryptd C API bindings (JNA) — **security-critical, do not modify without human + review** +- `com.mongodb.internal.crypt.capi` — Internal encryption state management + +## Build & Test + +```bash +./gradlew :mongodb-crypt:test +./gradlew :mongodb-crypt:check +``` + +Tests are primarily integration tests requiring libmongocrypt native libraries. +Build downloads JNA libs for multiple platforms, embedded in the JAR. + +For global rules see [root AGENTS.md](../AGENTS.md). diff --git a/mongodb-crypt/CLAUDE.md b/mongodb-crypt/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/mongodb-crypt/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/scripts/symlink-claude-md.sh b/scripts/symlink-claude-md.sh new file mode 100755 index 00000000000..95a060eaf41 --- /dev/null +++ b/scripts/symlink-claude-md.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# 1. Ensure every staged AGENTS.md has a companion CLAUDE.md containing +# "@AGENTS.md" (a Claude Code import reference). +# 2. Ensure .claude/skills is a symlink to .agents/skills. + +set -euo pipefail + +claude_file_for_agents() { + local agents_file="$1" + local dir + + dir=$(dirname "$agents_file") + + if [ "$dir" = "." ]; then + printf 'CLAUDE.md\n' + else + printf '%s/CLAUDE.md\n' "$dir" + fi +} + +remove_generated_file() { + local generated_file="$1" + + if git ls-files --error-unmatch -- "$generated_file" > /dev/null 2>&1 || [ -e "$generated_file" ]; then + rm -f "$generated_file" + git add -u -- "$generated_file" + echo "auto-removed: $generated_file" + fi +} + +sync_claude_skills_dir() { + local claude_skills_dir=".claude/skills" + local expected_target="../.agents/skills" + local current_target + + if [ -L "$claude_skills_dir" ]; then + current_target=$(readlink "$claude_skills_dir") + if [ "$current_target" = "$expected_target" ]; then + return + fi + + rm -f "$claude_skills_dir" + elif [ -e "$claude_skills_dir" ]; then + rm -rf "$claude_skills_dir" + fi + + mkdir -p .claude + ln -s "$expected_target" "$claude_skills_dir" + git add "$claude_skills_dir" + echo "auto-synced: $claude_skills_dir -> $expected_target" +} + +sync_claude_skills_dir + +staged_agents=() +deleted_agents=() + +while IFS=$'\t ' read -r status first_path second_path; do + [ -n "$status" ] || continue + + case "$status" in + R*) + if [[ "$first_path" =~ (^|/)AGENTS\.md$ ]]; then + deleted_agents+=("$first_path") + fi + if [[ "$second_path" =~ (^|/)AGENTS\.md$ ]]; then + staged_agents+=("$second_path") + fi + ;; + D) + if [[ "$first_path" =~ (^|/)AGENTS\.md$ ]]; then + deleted_agents+=("$first_path") + fi + ;; + *) + if [[ "$first_path" =~ (^|/)AGENTS\.md$ ]]; then + staged_agents+=("$first_path") + fi + ;; + esac +done < <(git diff --cached --name-status --find-renames --diff-filter=ADMR) + +# --- CLAUDE.md sync --- +if [ "${#staged_agents[@]}" -gt 0 ]; then + for agents_file in "${staged_agents[@]}"; do + claude_file=$(claude_file_for_agents "$agents_file") + + # Skip if already a regular file with the correct content + if [ -f "$claude_file" ] && ! [ -L "$claude_file" ] && [ "$(cat "$claude_file")" = "@AGENTS.md" ]; then + continue + fi + + # Remove symlink if present, then write the reference file + rm -f "$claude_file" + printf '@AGENTS.md\n' > "$claude_file" + git add "$claude_file" + echo "auto-created: $claude_file with @AGENTS.md reference" + done +fi + +if [ "${#deleted_agents[@]}" -gt 0 ]; then + for agents_file in "${deleted_agents[@]}"; do + remove_generated_file "$(claude_file_for_agents "$agents_file")" + done +fi diff --git a/testing/AGENTS.md b/testing/AGENTS.md new file mode 100644 index 00000000000..ea168df20ac --- /dev/null +++ b/testing/AGENTS.md @@ -0,0 +1,11 @@ +# AGENTS.md - testing + +Shared test resources and MongoDB specification test data. + +## Notes + +- `resources/specifications/` — Git submodule containing MongoDB specification test data (CRUD, SDAM, auth, CSFLE, + retryable ops, etc.) +- `resources/logback-test.xml` — Shared logback configuration for tests +- **Do not modify spec test data** — managed upstream. + Update via `git submodule update`. diff --git a/testing/CLAUDE.md b/testing/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/testing/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md