diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml
index 3dffae9..8ec9ce1 100644
--- a/.github/workflows/claude-code-review.yml
+++ b/.github/workflows/claude-code-review.yml
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 1
diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml
index 5a84dc8..e1d300c 100644
--- a/.github/workflows/claude.yml
+++ b/.github/workflows/claude.yml
@@ -27,7 +27,7 @@ jobs:
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 1
diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml
index 561def3..cd03836 100644
--- a/.github/workflows/integration-test.yml
+++ b/.github/workflows/integration-test.yml
@@ -13,9 +13,9 @@ jobs:
chroma-version: [0.4.24, 0.5.0, 0.5.5, 0.5.15 ]
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v5
- name: Set up JDK 8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v5
with:
java-version: '8'
distribution: 'adopt'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8c2a669..2362aa7 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,9 +9,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v5
- name: Set up JDK 8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v5
with:
java-version: '8'
distribution: 'adopt'
diff --git a/.github/workflows/v2-api-nightly.yml b/.github/workflows/v2-api-nightly.yml
new file mode 100644
index 0000000..8d39639
--- /dev/null
+++ b/.github/workflows/v2-api-nightly.yml
@@ -0,0 +1,225 @@
+name: V2 API Nightly Tests
+
+on:
+ schedule:
+ # Run at 2 AM UTC every day
+ - cron: '0 2 * * *'
+ workflow_dispatch:
+ inputs:
+ test_experimental:
+ description: 'Test experimental ChromaDB features'
+ required: false
+ type: boolean
+ default: false
+
+env:
+ MAVEN_OPTS: -Xmx4096m -Xms1024m
+
+jobs:
+ comprehensive-v2-tests:
+ name: Comprehensive V2 API Tests
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ chroma-version:
+ - '1.0.0' # Minimum supported version
+ - '1.0.1'
+ - '1.0.2'
+ - '1.0.3'
+ - '1.0.4'
+ - '1.1.0'
+ - 'latest'
+ java-version: [8, 11, 17, 21]
+ exclude:
+ # Java 8 only with older ChromaDB versions (no exclusions needed for 1.x)
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Java ${{ matrix.java-version }}
+ uses: actions/setup-java@v4
+ with:
+ java-version: ${{ matrix.java-version }}
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Start ChromaDB container
+ run: |
+ docker run -d \
+ --name chroma-${{ matrix.chroma-version }} \
+ -p 8000:8000 \
+ -e ALLOW_RESET=TRUE \
+ -e IS_PERSISTENT=FALSE \
+ chromadb/chroma:${{ matrix.chroma-version }}
+
+ # Wait for ChromaDB to be ready
+ echo "Waiting for ChromaDB to start..."
+ for i in {1..60}; do
+ if curl -f http://localhost:8000/api/v1 > /dev/null 2>&1; then
+ echo "ChromaDB is ready!"
+ break
+ fi
+ echo "Waiting... ($i/60)"
+ sleep 2
+ done
+
+ - name: Check ChromaDB health
+ run: |
+ curl -v http://localhost:8000/api/v1
+ docker logs chroma-${{ matrix.chroma-version }} | tail -20
+
+ - name: Run V2 API tests
+ run: |
+ mvn clean test \
+ -Dtest="tech.amikos.chromadb.v2.**" \
+ -DfailIfNoTests=false \
+ -Dchroma.url=http://localhost:8000
+ env:
+ CHROMA_VERSION: ${{ matrix.chroma-version }}
+ CHROMA_URL: http://localhost:8000
+
+ - name: Generate detailed test report
+ if: always()
+ run: |
+ mvn surefire-report:report-only
+ mvn site -DgenerateReports=false
+
+ - name: Collect container logs
+ if: failure()
+ run: |
+ docker logs chroma-${{ matrix.chroma-version }} > chroma-logs-${{ matrix.chroma-version }}-java-${{ matrix.java-version }}.txt
+
+ - name: Upload test artifacts
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: nightly-v2-chroma-${{ matrix.chroma-version }}-java-${{ matrix.java-version }}
+ path: |
+ target/surefire-reports/
+ target/site/
+ chroma-logs-*.txt
+
+ - name: Stop ChromaDB container
+ if: always()
+ run: docker stop chroma-${{ matrix.chroma-version }} && docker rm chroma-${{ matrix.chroma-version }}
+
+ stress-tests:
+ name: V2 API Stress Tests
+ runs-on: ubuntu-latest
+
+ services:
+ chroma:
+ image: chromadb/chroma:latest
+ ports:
+ - 8000:8000
+ env:
+ ALLOW_RESET: 'TRUE'
+ IS_PERSISTENT: 'TRUE'
+ PERSIST_DIRECTORY: '/chroma/data'
+ options: >-
+ --health-cmd "wget -q --spider http://localhost:8000/api/v1 || exit 1"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+ --mount type=tmpfs,destination=/chroma/data
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Java 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Run stress tests
+ run: |
+ mvn test -Dtest=V2StressTest -DfailIfNoTests=false
+ env:
+ CHROMA_URL: http://localhost:8000
+
+ - name: Upload stress test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: stress-test-results-v2
+ path: |
+ target/surefire-reports/TEST-*V2StressTest.xml
+ target/site/
+
+ report-summary:
+ name: Generate Nightly Report
+ needs: [comprehensive-v2-tests, stress-tests]
+ runs-on: ubuntu-latest
+ if: always()
+
+ steps:
+ - name: Download all artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: test-artifacts
+
+ - name: Generate summary report
+ run: |
+ echo "# V2 API Nightly Test Report" > nightly-report.md
+ echo "Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> nightly-report.md
+ echo "" >> nightly-report.md
+
+ echo "## Test Coverage Matrix" >> nightly-report.md
+ echo "| ChromaDB | Java 8 | Java 11 | Java 17 | Java 21 |" >> nightly-report.md
+ echo "|----------|--------|---------|---------|---------|" >> nightly-report.md
+
+ # Process test results
+ for dir in test-artifacts/nightly-v2-*; do
+ if [ -d "$dir" ]; then
+ basename "$dir" | grep -o "chroma-[^-]*" | cut -d- -f2 >> versions.txt
+ fi
+ done
+
+ sort -u versions.txt > unique-versions.txt || true
+
+ while IFS= read -r version; do
+ if [ -n "$version" ]; then
+ row="| $version |"
+ for java in 8 11 17 21; do
+ if [ -d "test-artifacts/nightly-v2-chroma-${version}-java-${java}" ]; then
+ if ls test-artifacts/nightly-v2-chroma-${version}-java-${java}/TEST-*.xml 2>/dev/null | head -1 | xargs grep -q 'failures="0".*errors="0"' 2>/dev/null; then
+ row="$row ✅ |"
+ else
+ row="$row ❌ |"
+ fi
+ else
+ row="$row - |"
+ fi
+ done
+ echo "$row" >> nightly-report.md
+ fi
+ done < unique-versions.txt || true
+
+ echo "" >> nightly-report.md
+ echo "## Stress Test Results" >> nightly-report.md
+ if [ -f "test-artifacts/stress-test-results-v2/TEST-*V2StressTest.xml" ]; then
+ echo "✅ Stress tests completed successfully" >> nightly-report.md
+ else
+ echo "⚠️ Stress test results not found" >> nightly-report.md
+ fi
+
+ cat nightly-report.md >> $GITHUB_STEP_SUMMARY
+
+ - name: Create issue for failures
+ if: failure()
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const date = new Date().toISOString().split('T')[0];
+ await github.rest.issues.create({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ title: `[V2 API] Nightly test failures - ${date}`,
+ body: `Nightly V2 API tests have failed. Please check the [workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`,
+ labels: ['bug', 'v2-api', 'nightly-test']
+ });
\ No newline at end of file
diff --git a/.github/workflows/v2-api-pr-validation.yml b/.github/workflows/v2-api-pr-validation.yml
new file mode 100644
index 0000000..98248a6
--- /dev/null
+++ b/.github/workflows/v2-api-pr-validation.yml
@@ -0,0 +1,267 @@
+name: V2 API PR Validation
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+ paths:
+ - 'src/main/java/tech/amikos/chromadb/v2/**'
+ - 'src/test/java/tech/amikos/chromadb/v2/**'
+
+jobs:
+ quick-validation:
+ name: Quick V2 API Validation
+ runs-on: ubuntu-latest
+
+ services:
+ chroma:
+ image: chromadb/chroma:1.1.0
+ ports:
+ - 8000:8000
+ env:
+ ALLOW_RESET: 'TRUE'
+ IS_PERSISTENT: 'FALSE'
+ options: >-
+ --health-cmd "wget -q --spider http://localhost:8000/api/v1 || exit 1"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ - name: Checkout PR branch
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up Java 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Check code changes
+ id: changes
+ run: |
+ echo "Changed files in V2 API:"
+ git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E "v2/|V2" || true
+
+ # Check if only test files changed
+ if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E "src/main/java.*v2" > /dev/null; then
+ echo "src_changed=true" >> $GITHUB_OUTPUT
+ else
+ echo "src_changed=false" >> $GITHUB_OUTPUT
+ fi
+
+ if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E "src/test/java.*v2" > /dev/null; then
+ echo "test_changed=true" >> $GITHUB_OUTPUT
+ else
+ echo "test_changed=false" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Compile V2 API code
+ run: |
+ mvn compile -pl . -am
+
+ - name: Run checkstyle on V2 API
+ run: |
+ mvn checkstyle:check -Dcheckstyle.includes="**/v2/**/*.java" || true
+
+ - name: Run V2 API unit tests
+ if: steps.changes.outputs.src_changed == 'true' || steps.changes.outputs.test_changed == 'true'
+ run: |
+ mvn test \
+ -Dtest="tech.amikos.chromadb.v2.**Test" \
+ -DfailIfNoTests=false
+ env:
+ CHROMA_URL: http://localhost:8000
+
+ - name: Check test coverage
+ if: steps.changes.outputs.src_changed == 'true'
+ run: |
+ mvn jacoco:prepare-agent test jacoco:report \
+ -Dtest="tech.amikos.chromadb.v2.**Test" \
+ -DfailIfNoTests=false
+
+ # Extract coverage percentage (simplified)
+ if [ -f target/site/jacoco/index.html ]; then
+ echo "Code coverage report generated"
+ # You can add coverage threshold checks here
+ fi
+
+ - name: Run basic integration test
+ run: |
+ cat > BasicV2IntegrationTest.java << 'EOF'
+ import tech.amikos.chromadb.v2.auth.AuthProvider;
+ import tech.amikos.chromadb.v2.client.Collection;
+ import tech.amikos.chromadb.v2.client.ServerClient;
+
+ public class BasicV2IntegrationTest {
+ public static void main(String[] args) throws Exception {
+ ServerClient client = ServerClient.builder()
+ .baseUrl("http://localhost:8000")
+ .auth(AuthProvider.none())
+ .build();
+
+ try {
+ // Test heartbeat
+ String heartbeat = client.heartbeat();
+ System.out.println("✅ Heartbeat successful: " + heartbeat);
+
+ // Test collection creation
+ Collection collection = client.createCollection("pr_validation_test");
+ System.out.println("✅ Collection created: " + collection.getName());
+
+ // Test add operation
+ collection.add()
+ .ids(java.util.Arrays.asList("test1"))
+ .embeddings(java.util.Arrays.asList(
+ java.util.Arrays.asList(0.1f, 0.2f, 0.3f)
+ ))
+ .execute();
+ System.out.println("✅ Document added successfully");
+
+ // Test count
+ int count = collection.count();
+ if (count == 1) {
+ System.out.println("✅ Count verified: " + count);
+ } else {
+ throw new RuntimeException("Count mismatch: expected 1, got " + count);
+ }
+
+ // Cleanup
+ client.deleteCollection("pr_validation_test");
+ System.out.println("✅ Collection deleted successfully");
+
+ System.out.println("\n✅ All basic V2 API operations passed!");
+ System.exit(0);
+ } catch (Exception e) {
+ System.err.println("❌ Test failed: " + e.getMessage());
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+ }
+ EOF
+
+ javac -cp "target/classes:target/test-classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" BasicV2IntegrationTest.java
+ java -cp ".:target/classes:target/test-classes:$(mvn dependency:build-classpath -Dmdep.outputFile=/dev/stdout -q)" BasicV2IntegrationTest
+
+ - name: Comment PR with results
+ if: always()
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const fs = require('fs');
+
+ let comment = '## V2 API PR Validation Results\n\n';
+
+ // Add emoji based on job status
+ const status = '${{ job.status }}';
+ if (status === 'success') {
+ comment += '✅ **All checks passed!**\n\n';
+ } else if (status === 'failure') {
+ comment += '❌ **Some checks failed**\n\n';
+ } else {
+ comment += '⚠️ **Validation canceled**\n\n';
+ }
+
+ // Add change summary
+ comment += '### Changes Detected\n';
+ comment += '- Source files changed: ${{ steps.changes.outputs.src_changed }}\n';
+ comment += '- Test files changed: ${{ steps.changes.outputs.test_changed }}\n\n';
+
+ // Add test results if available
+ const testResults = `${{ steps.test-results.outputs.summary }}`;
+ if (testResults) {
+ comment += '### Test Results\n';
+ comment += testResults + '\n\n';
+ }
+
+ comment += '---\n';
+ comment += `🔗 [View full workflow run](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})\n`;
+
+ // Find existing comment
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ });
+
+ const botComment = comments.find(comment =>
+ comment.user.type === 'Bot' &&
+ comment.body.includes('V2 API PR Validation Results')
+ );
+
+ if (botComment) {
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: botComment.id,
+ body: comment
+ });
+ } else {
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body: comment
+ });
+ }
+
+ code-quality:
+ name: V2 API Code Quality
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Java 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Run SpotBugs on V2 API
+ continue-on-error: true
+ run: |
+ mvn compile spotbugs:check -Dspotbugs.includeFilterFile=v2-api-include.xml || true
+
+ - name: Run PMD on V2 API
+ continue-on-error: true
+ run: |
+ mvn pmd:check -Dpmd.includes="**/v2/**/*.java" || true
+
+ - name: Check for security issues
+ continue-on-error: true
+ run: |
+ mvn dependency-check:check -DfailBuildOnCVSS=8 || true
+
+ - name: Generate quality report
+ if: always()
+ run: |
+ echo "## Code Quality Report" >> quality-report.md
+ echo "" >> quality-report.md
+
+ if [ -f target/spotbugsXml.xml ]; then
+ echo "### SpotBugs" >> quality-report.md
+ echo "Report generated at target/spotbugsXml.xml" >> quality-report.md
+ fi
+
+ if [ -f target/pmd.xml ]; then
+ echo "### PMD" >> quality-report.md
+ echo "Report generated at target/pmd.xml" >> quality-report.md
+ fi
+
+ cat quality-report.md >> $GITHUB_STEP_SUMMARY
+
+ - name: Upload quality reports
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: quality-reports-v2
+ path: |
+ target/spotbugsXml.xml
+ target/pmd.xml
+ target/dependency-check-report.html
\ No newline at end of file
diff --git a/.github/workflows/v2-api-release.yml b/.github/workflows/v2-api-release.yml
new file mode 100644
index 0000000..029eccb
--- /dev/null
+++ b/.github/workflows/v2-api-release.yml
@@ -0,0 +1,271 @@
+name: V2 API Release Validation
+
+on:
+ push:
+ tags:
+ - 'v2.*'
+ - 'v*.*.0-v2'
+ workflow_dispatch:
+ inputs:
+ release_version:
+ description: 'Release version (e.g., 2.0.0)'
+ required: true
+ dry_run:
+ description: 'Perform dry run without publishing'
+ required: false
+ type: boolean
+ default: true
+
+jobs:
+ validate-release:
+ name: Validate V2 API Release
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up Java 8
+ uses: actions/setup-java@v4
+ with:
+ java-version: '8'
+ distribution: 'adopt'
+ cache: 'maven'
+
+ - name: Determine version
+ id: version
+ run: |
+ if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
+ VERSION="${{ github.event.inputs.release_version }}"
+ else
+ VERSION="${GITHUB_REF#refs/tags/}"
+ fi
+ echo "version=${VERSION}" >> $GITHUB_OUTPUT
+
+ # Extract version components
+ if [[ $VERSION =~ ^v?([0-9]+)\.([0-9]+)\.([0-9]+)(-.*)?$ ]]; then
+ echo "major=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT
+ echo "minor=${BASH_REMATCH[2]}" >> $GITHUB_OUTPUT
+ echo "patch=${BASH_REMATCH[3]}" >> $GITHUB_OUTPUT
+ echo "suffix=${BASH_REMATCH[4]}" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Update version in pom.xml
+ run: |
+ mvn versions:set -DnewVersion=${{ steps.version.outputs.version }}
+ mvn versions:commit
+
+ - name: Run full test suite
+ run: |
+ mvn clean test -Dtest="tech.amikos.chromadb.v2.**"
+
+ - name: Check backward compatibility
+ run: |
+ echo "Checking backward compatibility..."
+
+ # Download previous version for comparison
+ PREV_MAJOR=${{ steps.version.outputs.major }}
+ PREV_MINOR=$((steps.version.outputs.minor - 1))
+ PREV_VERSION="v${PREV_MAJOR}.${PREV_MINOR}.0"
+
+ if git rev-parse "$PREV_VERSION" >/dev/null 2>&1; then
+ git checkout "$PREV_VERSION" -- src/main/java/tech/amikos/chromadb/v2/client/Client.java || true
+ mv src/main/java/tech/amikos/chromadb/v2/client/Client.java /tmp/Client.java.prev || true
+ git checkout HEAD -- src/main/java/tech/amikos/chromadb/v2/client/Client.java
+
+ # Simple diff to check for breaking changes
+ if [ -f /tmp/Client.java.prev ]; then
+ echo "### API Changes from ${PREV_VERSION}:" >> $GITHUB_STEP_SUMMARY
+ diff -u /tmp/Client.java.prev src/main/java/tech/amikos/chromadb/v2/client/Client.java || true >> $GITHUB_STEP_SUMMARY
+ fi
+ fi
+
+ - name: Generate Javadoc
+ run: |
+ mvn javadoc:javadoc -Dadditionalparam=-Xdoclint:none
+
+ - name: Build release artifacts
+ run: |
+ mvn clean package -DskipTests
+ mvn source:jar
+ mvn javadoc:jar
+
+ - name: Create release notes
+ id: release-notes
+ run: |
+ cat > release-notes.md << EOF
+ # V2 API Release ${{ steps.version.outputs.version }}
+
+ ## What's New
+ - ChromaDB V2 API support
+ - Improved performance and reliability
+ - Enhanced testing coverage
+
+ ## Compatibility
+ - Java: 8, 11, 17, 21
+ - ChromaDB: 1.0.0+
+
+ ## Installation
+
+ ### Maven
+ \`\`\`xml
+
+ io.github.amikos-tech
+ chromadb-java-client
+ ${{ steps.version.outputs.version }}
+
+ \`\`\`
+
+ ### Gradle
+ \`\`\`groovy
+ implementation 'io.github.amikos-tech:chromadb-java-client:${{ steps.version.outputs.version }}'
+ \`\`\`
+
+ ## Changes
+ $(git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 HEAD^)..HEAD | grep -E "v2|V2" | head -20)
+
+ ## Documentation
+ - [V2 API Documentation](https://github.com/amikos-tech/chromadb-java-client/blob/main/V2_API_EXAMPLE.md)
+ - [Migration Guide](https://github.com/amikos-tech/chromadb-java-client/blob/main/V2_MIGRATION.md)
+
+ ## Checksums
+ \`\`\`
+ $(sha256sum target/*.jar)
+ \`\`\`
+ EOF
+
+ cat release-notes.md >> $GITHUB_STEP_SUMMARY
+
+ - name: Upload release artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: release-artifacts-v2
+ path: |
+ target/*.jar
+ release-notes.md
+
+ compatibility-matrix:
+ name: V2 Release Compatibility Test
+ needs: validate-release
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ chroma-version: ['1.0.0', '1.0.4', '1.1.0', 'latest']
+ java-version: [8, 11, 17, 21]
+
+ services:
+ chroma:
+ image: chromadb/chroma:${{ matrix.chroma-version }}
+ ports:
+ - 8000:8000
+ env:
+ ALLOW_RESET: 'TRUE'
+ options: >-
+ --health-cmd "wget -q --spider http://localhost:8000/api/v1 || exit 1"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Java ${{ matrix.java-version }}
+ uses: actions/setup-java@v4
+ with:
+ java-version: ${{ matrix.java-version }}
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Run compatibility tests
+ run: |
+ mvn test -Dtest="tech.amikos.chromadb.v2.**Test" -DfailIfNoTests=false
+ env:
+ CHROMA_URL: http://localhost:8000
+
+ - name: Report results
+ if: always()
+ run: |
+ echo "ChromaDB: ${{ matrix.chroma-version }}, Java: ${{ matrix.java-version }}" >> compatibility-results.txt
+ if [ $? -eq 0 ]; then
+ echo "✅ PASSED" >> compatibility-results.txt
+ else
+ echo "❌ FAILED" >> compatibility-results.txt
+ fi
+
+ - name: Upload compatibility results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: compatibility-chroma-${{ matrix.chroma-version }}-java-${{ matrix.java-version }}
+ path: compatibility-results.txt
+
+ publish-release:
+ name: Publish V2 API Release
+ needs: [validate-release, compatibility-matrix]
+ runs-on: ubuntu-latest
+ if: github.event.inputs.dry_run != 'true'
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Java 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ server-id: ossrh
+ server-username: MAVEN_USERNAME
+ server-password: MAVEN_PASSWORD
+ gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
+ gpg-passphrase: MAVEN_GPG_PASSPHRASE
+
+ - name: Download release artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: release-artifacts-v2
+ path: ./release
+
+ - name: Create GitHub Release
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ github.ref }}
+ release_name: V2 API Release ${{ github.ref }}
+ body_path: ./release/release-notes.md
+ draft: false
+ prerelease: ${{ contains(github.ref, '-') }}
+
+ - name: Upload JAR to release
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./release/chromadb-java-client-${{ steps.version.outputs.version }}.jar
+ asset_name: chromadb-java-client-${{ steps.version.outputs.version }}.jar
+ asset_content_type: application/java-archive
+
+ - name: Deploy to Maven Central
+ if: github.event.inputs.dry_run != 'true'
+ env:
+ MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
+ MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
+ MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+ run: |
+ mvn clean deploy -P release -DskipTests
+
+ - name: Update documentation
+ run: |
+ # Update README with new version
+ sed -i "s/.*<\/version>/${{ steps.version.outputs.version }}<\/version>/g" README.md
+ git config user.name "GitHub Actions"
+ git config user.email "actions@github.com"
+ git add README.md
+ git commit -m "docs: update version to ${{ steps.version.outputs.version }}" || true
+ git push origin HEAD:main || true
\ No newline at end of file
diff --git a/.github/workflows/v2-api-tests.yml b/.github/workflows/v2-api-tests.yml
new file mode 100644
index 0000000..753c3ff
--- /dev/null
+++ b/.github/workflows/v2-api-tests.yml
@@ -0,0 +1,298 @@
+name: V2 API Tests
+
+on:
+ push:
+ branches:
+ - main
+ - develop
+ - 'feature/chroma-v2-api-*'
+ paths:
+ - 'src/main/java/tech/amikos/chromadb/v2/**'
+ - 'src/test/java/tech/amikos/chromadb/v2/**'
+ - '.github/workflows/v2-api-tests.yml'
+ - 'pom.xml'
+ pull_request:
+ branches:
+ - main
+ - develop
+ paths:
+ - 'src/main/java/tech/amikos/chromadb/v2/**'
+ - 'src/test/java/tech/amikos/chromadb/v2/**'
+ - '.github/workflows/v2-api-tests.yml'
+ - 'pom.xml'
+ workflow_dispatch:
+ inputs:
+ chroma_versions:
+ description: 'Comma-separated list of ChromaDB versions to test (e.g., 1.1.0)'
+ required: false
+ default: ''
+
+env:
+ MAVEN_OPTS: -Xmx4096m -Xms1024m
+
+jobs:
+ determine-versions:
+ name: Determine ChromaDB Versions
+ runs-on: ubuntu-latest
+ outputs:
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
+ steps:
+ - name: Set ChromaDB versions matrix
+ id: set-matrix
+ run: |
+ if [ -n "${{ github.event.inputs.chroma_versions }}" ]; then
+ # Use custom versions from workflow dispatch
+ IFS=',' read -ra VERSIONS <<< "${{ github.event.inputs.chroma_versions }}"
+ JSON_ARRAY=$(printf '"%s",' "${VERSIONS[@]}" | sed 's/,$//')
+ echo "matrix=[${JSON_ARRAY}]" >> $GITHUB_OUTPUT
+ else
+ # Default versions for v2 API testing
+ echo 'matrix=["1.0.0", "1.1.0", "latest"]' >> $GITHUB_OUTPUT
+ fi
+
+ v2-api-tests:
+ name: V2 API Tests (ChromaDB ${{ matrix.chroma-version }})
+ needs: determine-versions
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ chroma-version: ${{ fromJson(needs.determine-versions.outputs.matrix) }}
+ java-version: [8, 17]
+
+ services:
+ chroma:
+ image: chromadb/chroma:${{ matrix.chroma-version }}
+ ports:
+ - 8000:8000
+ env: # TODO these are not accurate and won't work
+ ALLOW_RESET: 'TRUE'
+ IS_PERSISTENT: 'FALSE'
+ CHROMA_SERVER_AUTH_PROVIDER: 'chromadb.auth.token_authn.TokenAuthenticationServerProvider'
+ CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER: 'chromadb.auth.token_authn.TokenConfigServerCredentialsProvider'
+ CHROMA_SERVER_AUTH_TOKEN_TRANSPORT_HEADER: 'X_CHROMA_TOKEN'
+ CHROMA_SERVER_AUTH_CREDENTIALS: 'test-token'
+ options: >-
+ --health-cmd "wget -q --spider http://localhost:8000/api/v1 || exit 1"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Java ${{ matrix.java-version }}
+ uses: actions/setup-java@v4
+ with:
+ java-version: ${{ matrix.java-version }}
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Cache Maven dependencies
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.m2/repository
+ ~/.m2/wrapper
+ key: ${{ runner.os }}-maven-v2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-v2-
+ ${{ runner.os }}-maven-
+
+ - name: Wait for ChromaDB to be ready
+ run: |
+ echo "Waiting for ChromaDB to be ready..."
+ for i in {1..30}; do
+ if curl -f http://localhost:8000/api/v1 > /dev/null 2>&1; then
+ echo "ChromaDB is ready!"
+ break
+ fi
+ echo "Waiting... ($i/30)"
+ sleep 2
+ done
+
+ # Verify ChromaDB is responding
+ curl -v http://localhost:8000/api/v1 || true
+
+ - name: Get ChromaDB Version Info
+ run: |
+ echo "Testing against ChromaDB version: ${{ matrix.chroma-version }}"
+ curl -s http://localhost:8000/api/v1/version || echo "Version endpoint not available"
+
+ - name: Compile project
+ run: mvn clean compile -DskipTests
+
+ - name: Compile tests
+ run: mvn test-compile
+
+ - name: Run V2 API Unit Tests
+ run: |
+ mvn test \
+ -Dtest="tech.amikos.chromadb.v2.**Test" \
+ -DfailIfNoTests=false \
+ -Dchroma.url=http://localhost:8000 \
+ -Dchroma.token=test-token
+ env:
+ CHROMA_VERSION: ${{ matrix.chroma-version }}
+ CHROMA_URL: http://localhost:8000
+ CHROMA_TOKEN: test-token
+
+ - name: Run V2 API Integration Tests
+ if: success() || failure()
+ run: |
+ mvn test \
+ -Dtest="tech.amikos.chromadb.v2.**IT" \
+ -DfailIfNoTests=false \
+ -Dchroma.url=http://localhost:8000 \
+ -Dchroma.token=test-token
+ env:
+ CHROMA_VERSION: ${{ matrix.chroma-version }}
+ CHROMA_URL: http://localhost:8000
+ CHROMA_TOKEN: test-token
+
+ - name: Generate test report
+ if: always()
+ run: |
+ mvn surefire-report:report-only
+ mvn site -DgenerateReports=false
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: test-results-v2-chroma-${{ matrix.chroma-version }}-java-${{ matrix.java-version }}
+ path: |
+ target/surefire-reports/
+ target/site/surefire-report.html
+
+ - name: Upload coverage reports
+ if: success()
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverage-v2-chroma-${{ matrix.chroma-version }}-java-${{ matrix.java-version }}
+ path: target/site/jacoco/
+
+ - name: Test Report Summary
+ if: always()
+ run: |
+ echo "## Test Results Summary" >> $GITHUB_STEP_SUMMARY
+ echo "- ChromaDB Version: ${{ matrix.chroma-version }}" >> $GITHUB_STEP_SUMMARY
+ echo "- Java Version: ${{ matrix.java-version }}" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ if [ -f target/surefire-reports/TEST-tech.amikos.chromadb.v2.ServerClientTest.xml ]; then
+ echo "### V2 API Test Results" >> $GITHUB_STEP_SUMMARY
+ # Parse XML to get test counts (simplified - you might want to use xmllint or similar)
+ grep -o 'tests="[^"]*"' target/surefire-reports/TEST-*.xml | head -1 >> $GITHUB_STEP_SUMMARY || true
+ grep -o 'failures="[^"]*"' target/surefire-reports/TEST-*.xml | head -1 >> $GITHUB_STEP_SUMMARY || true
+ grep -o 'errors="[^"]*"' target/surefire-reports/TEST-*.xml | head -1 >> $GITHUB_STEP_SUMMARY || true
+ fi
+
+ v2-api-compatibility-matrix:
+ name: V2 API Compatibility Report
+ needs: v2-api-tests
+ runs-on: ubuntu-latest
+ if: always()
+
+ steps:
+ - name: Download all test results
+ uses: actions/download-artifact@v4
+ with:
+ path: test-artifacts
+
+ - name: Generate compatibility matrix
+ run: |
+ echo "# V2 API Compatibility Matrix" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| ChromaDB Version | Java 8 | Java 17 |" >> $GITHUB_STEP_SUMMARY
+ echo "|------------------|--------|---------|" >> $GITHUB_STEP_SUMMARY
+
+ # Check test results for each combination
+ for chroma_version in "1.0.0" "1.1.0" "latest"; do
+ java8_status="❓"
+ java17_status="❓"
+
+ if [ -d "test-artifacts/test-results-v2-chroma-${chroma_version}-java-8" ]; then
+ if grep -q 'failures="0"' test-artifacts/test-results-v2-chroma-${chroma_version}-java-8/TEST-*.xml 2>/dev/null && \
+ grep -q 'errors="0"' test-artifacts/test-results-v2-chroma-${chroma_version}-java-8/TEST-*.xml 2>/dev/null; then
+ java8_status="✅"
+ else
+ java8_status="❌"
+ fi
+ fi
+
+ if [ -d "test-artifacts/test-results-v2-chroma-${chroma_version}-java-17" ]; then
+ if grep -q 'failures="0"' test-artifacts/test-results-v2-chroma-${chroma_version}-java-17/TEST-*.xml 2>/dev/null && \
+ grep -q 'errors="0"' test-artifacts/test-results-v2-chroma-${chroma_version}-java-17/TEST-*.xml 2>/dev/null; then
+ java17_status="✅"
+ else
+ java17_status="❌"
+ fi
+ fi
+
+ echo "| ${chroma_version} | ${java8_status} | ${java17_status} |" >> $GITHUB_STEP_SUMMARY
+ done
+
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "✅ = All tests passed | ❌ = Tests failed | ❓ = No results" >> $GITHUB_STEP_SUMMARY
+
+ - name: Comment on PR
+ if: github.event_name == 'pull_request'
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const fs = require('fs');
+ const summary = fs.readFileSync(process.env.GITHUB_STEP_SUMMARY, 'utf8');
+
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: summary
+ });
+
+ v2-api-performance-tests:
+ name: V2 API Performance Tests
+ runs-on: ubuntu-latest
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+ services:
+ chroma:
+ image: chromadb/chroma:latest
+ ports:
+ - 8000:8000
+ env:
+ ALLOW_RESET: 'TRUE'
+ IS_PERSISTENT: 'FALSE'
+ options: >-
+ --health-cmd "wget -q --spider http://localhost:8000/api/v1 || exit 1"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Java 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ cache: 'maven'
+
+ - name: Run performance tests
+ run: |
+ mvn test \
+ -Dtest="tech.amikos.chromadb.v2.**PerformanceTest" \
+ -DfailIfNoTests=false \
+ -Dchroma.url=http://localhost:8000
+ env:
+ CHROMA_URL: http://localhost:8000
+
+ - name: Upload performance results
+ uses: actions/upload-artifact@v4
+ with:
+ name: performance-results-v2
+ path: target/performance-reports/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index aa70b23..3893731 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,7 +30,10 @@ build/
.vscode/
### Mac OS ###
-.DS_Store*.class
+.DS_Store
+
+### Java ###
+*.class
*.log
*.ctxt
.mtj.tmp/
diff --git a/CLAUDE.md b/CLAUDE.md
index 36f7865..315fd2d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -28,10 +28,21 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
- `HF_API_KEY` - Required for HuggingFace embedding tests
- `CHROMA_VERSION` - Specifies ChromaDB version for integration tests
-## Architecture Overview
+## API Design Principles (V2)
-### Core Client Structure
-The client follows a standard Swagger/OpenAPI generated client pattern with custom enhancements:
+### Radical Simplicity
+The V2 API follows principles of radical simplicity based on successful Java libraries like OkHttp, Retrofit, and Jedis:
+
+1. **Single Configuration Pattern**: Use ONLY fluent builders, NEVER Consumer patterns
+2. **Flat Package Structure**: All public API classes in `tech.amikos.chromadb.v2` package (no sub-packages)
+3. **One Way to Do Things**: Each task has exactly one idiomatic approach
+4. **Minimal Public API Surface**: ~20-25 classes total (following OkHttp's model)
+5. **Concrete Over Abstract**: Prefer concrete classes over interfaces where possible
+
+### Architecture Overview
+
+#### V1 Client (Legacy - Maintained for Compatibility)
+The V1 client (`tech.amikos.chromadb`) follows a standard Swagger/OpenAPI generated client pattern:
1. **Generated API Layer** (`target/generated-sources/swagger/`)
- Auto-generated from OpenAPI specifications
@@ -48,6 +59,31 @@ The client follows a standard Swagger/OpenAPI generated client pattern with cust
- Each implements `EmbeddingFunction` interface
- Default embedding uses ONNX Runtime for local inference
+#### V2 Client (Recommended - Radical Simplicity)
+The V2 client (`tech.amikos.chromadb.v2`) implements radical simplicity:
+
+1. **Single Flat Package** - All classes in `tech.amikos.chromadb.v2`
+ - No sub-packages for auth, model, client, etc.
+ - Everything discoverable in one location
+
+2. **Core Classes** (~20 total)
+ - `ChromaClient` - Single client class with builder
+ - `Collection` - Concrete collection class (not interface)
+ - `Metadata` - Strongly-typed metadata with builder
+ - Query builders: `QueryBuilder`, `AddBuilder`, etc.
+ - Model classes: `Where`, `WhereDocument`, `Include`
+ - Auth: `AuthProvider` interface with implementations
+ - Exceptions: Strongly-typed exception hierarchy
+
+3. **Builder-Only Pattern**
+ ```java
+ // Only way to query - no Consumer alternative
+ collection.query()
+ .where(Where.eq("type", "article"))
+ .nResults(10)
+ .execute();
+ ```
+
### Key Design Patterns
1. **Authentication Handling**
diff --git a/V2_API.md b/V2_API.md
new file mode 100644
index 0000000..8ebd550
--- /dev/null
+++ b/V2_API.md
@@ -0,0 +1,377 @@
+# ChromaDB V2 API Documentation
+
+## Overview
+
+The V2 API is an experimental implementation of the ChromaDB v2 client for Java, designed with principles of radical simplicity based on successful Java libraries like OkHttp, Retrofit, and Jedis.
+
+**⚠️ Important:** The v2 API does not yet exist in ChromaDB. This implementation is based on anticipated v2 API design and is provided for experimental/preview purposes only.
+
+## Design Principles
+
+### Radical Simplicity
+- **Dual API Approach**: Convenience methods for common cases (80%), builders for complex operations (20%)
+- **Chroma-Aligned**: API mirrors official Python/TypeScript SDKs for familiarity
+- **Flat Package Structure**: All public API classes in `tech.amikos.chromadb.v2` package (no sub-packages)
+- **Simple Things Simple**: Common operations in 1-2 lines, no builders required
+- **Minimal Public API Surface**: ~20-25 classes total (following OkHttp's model)
+- **Concrete Over Abstract**: Prefer concrete classes over interfaces where possible
+
+## Architecture
+
+```
+Client (interface)
+ ├── BaseClient (abstract)
+ │ ├── ServerClient (self-hosted)
+ │ └── CloudClient (cloud - future)
+ │
+ └── Collection (smart entity with operations)
+ ├── query()
+ ├── get()
+ ├── add()
+ ├── update()
+ ├── upsert()
+ ├── delete()
+ └── count()
+```
+
+### Core Classes (~20 total)
+- `ServerClient` / `CloudClient` - Client implementations
+- `Collection` - Concrete collection class (not interface)
+- `Metadata` - Strongly-typed metadata with builder
+- Query builders: `QueryBuilder`, `AddBuilder`, etc.
+- Model classes: `Where`, `WhereDocument`, `Include`
+- Auth: `AuthProvider` interface with implementations
+- Exceptions: Strongly-typed exception hierarchy
+
+## Quick Start
+
+### 1. Create a Client
+
+```java
+import tech.amikos.chromadb.v2.ChromaClient;
+import tech.amikos.chromadb.v2.AuthProvider;
+
+ChromaClient client = ChromaClient.builder()
+ .serverUrl("http://localhost:8000")
+ .auth(AuthProvider.none())
+ .tenant("default_tenant")
+ .database("default_database")
+ .build();
+```
+
+### 2. Create a Collection
+
+```java
+// Simple creation
+Collection collection = client.createCollection("my-collection");
+
+// With metadata
+Collection collection = client.createCollection("my-collection",
+ Map.of("description", "My collection"));
+```
+
+## Simple API (Convenience Methods)
+
+For most use cases, use the simple, Chroma-aligned convenience methods:
+
+### 3. Add Records
+
+```java
+// Simple add - mirrors Python/TypeScript Chroma API
+collection.add(
+ List.of("id1", "id2", "id3"),
+ List.of(
+ List.of(0.1f, 0.2f, 0.3f),
+ List.of(0.4f, 0.5f, 0.6f),
+ List.of(0.7f, 0.8f, 0.9f)
+ ),
+ List.of("Document 1", "Document 2", "Document 3"),
+ List.of(
+ Map.of("author", "John"),
+ Map.of("author", "Jane"),
+ Map.of("author", "Bob")
+ )
+);
+```
+
+### 4. Query Collection
+
+```java
+// Simple query by embeddings
+QueryResponse results = collection.query(
+ List.of(List.of(0.1f, 0.2f, 0.3f)),
+ 10 // number of results
+);
+
+// Query with filtering
+results = collection.query(
+ List.of(List.of(0.1f, 0.2f, 0.3f)),
+ 10,
+ Where.eq("author", "John")
+);
+
+// Query by text (auto-embedded)
+results = collection.queryByText(
+ List.of("quantum computing"),
+ 5
+);
+```
+
+### 5. Get Records
+
+```java
+// Simple get by IDs
+GetResponse records = collection.get(List.of("id1", "id2"));
+
+// Get with includes
+records = collection.get(
+ List.of("id1", "id2"),
+ Include.DOCUMENTS, Include.METADATAS
+);
+```
+
+### 6. Update/Upsert Records
+
+```java
+// Simple upsert
+collection.upsert(
+ List.of("id4"),
+ List.of(List.of(0.2f, 0.3f, 0.4f)),
+ List.of("New document")
+);
+```
+
+### 7. Delete Records
+
+```java
+// Delete by IDs
+collection.delete(List.of("id1", "id2"));
+
+// Delete by filter
+collection.delete(Where.eq("status", "archived"));
+```
+
+## Advanced API (Builder Pattern)
+
+For complex operations with multiple options, use the builder pattern:
+
+### Complex Query
+
+```java
+QueryResponse results = collection.query()
+ .queryEmbeddings(List.of(List.of(0.1f, 0.2f, 0.3f)))
+ .nResults(10)
+ .where(Where.and(
+ Where.eq("status", "published"),
+ Where.gte("score", 8.0)
+ ))
+ .whereDocument(WhereDocument.contains("technology"))
+ .include(Include.EMBEDDINGS, Include.METADATAS, Include.DISTANCES)
+ .execute();
+```
+
+### Complex Get with Pagination
+
+```java
+GetResponse records = collection.get()
+ .where(Where.eq("category", "tech"))
+ .limit(100)
+ .offset(0)
+ .include(Include.DOCUMENTS, Include.METADATAS)
+ .execute();
+```
+
+### Complex Add
+
+```java
+collection.add()
+ .ids(List.of("id1", "id2"))
+ .embeddings(embeddings)
+ .documents(documents)
+ .metadatas(metadatas)
+ .uris(uris)
+ .execute();
+```
+
+## Advanced Features
+
+### Authentication
+
+```java
+// Basic authentication
+ServerClient client = ServerClient.builder()
+ .baseUrl("http://localhost:8000")
+ .auth(AuthProvider.basic("username", "password"))
+ .build();
+
+// Bearer token
+client = ServerClient.builder()
+ .baseUrl("http://localhost:8000")
+ .auth(AuthProvider.bearerToken("your-api-token"))
+ .build();
+
+// X-Chroma-Token header
+client = ServerClient.builder()
+ .baseUrl("http://localhost:8000")
+ .auth(AuthProvider.chromaToken("chroma-token"))
+ .build();
+```
+
+### Embedding Functions
+
+```java
+// Default embedding (uses all-MiniLM-L6-v2)
+EmbeddingFunction defaultEF = EmbeddingFunction.getDefault();
+
+// OpenAI embeddings
+EmbeddingFunction openAI = EmbeddingFunction.openAI("your-api-key");
+
+// Custom embedding function
+EmbeddingFunction custom = new EmbeddingFunction() {
+ @Override
+ public List> embed(List texts) {
+ // Your embedding logic
+ }
+};
+
+// Use with collection
+Collection collection = client.createCollection(builder -> builder
+ .name("documents")
+ .embeddingFunction(openAI)
+);
+```
+
+### Metadata Filtering (Where DSL)
+
+```java
+// Complex filter conditions
+Where filter = Where.builder()
+ .and(
+ Where.eq("status", "published"),
+ Where.gte("score", 8.0),
+ Where.or(
+ Where.eq("category", "tech"),
+ Where.eq("category", "science")
+ )
+ )
+ .build();
+
+// Use in queries
+QueryResponse results = collection.query(builder -> builder
+ .queryTexts(Arrays.asList("search text"))
+ .where(filter)
+ .nResults(10)
+);
+```
+
+### Document Filtering
+
+```java
+// Filter by document content
+WhereDocument docFilter = WhereDocument.contains("machine learning");
+
+QueryResponse results = collection.query(builder -> builder
+ .queryTexts(Arrays.asList("AI research"))
+ .whereDocument(docFilter)
+ .nResults(5)
+);
+```
+
+## Implementation Status
+
+### What's Implemented ✅
+- Basic client structure (`ServerClient`, `CloudClient`)
+- Authentication providers (Basic, Token, ChromaToken)
+- Model classes for v2 operations
+- Collection operations interface
+- Query builder pattern
+- Fluent API for all operations
+- Type-safe metadata and filtering
+
+### Known Issues ⚠️
+1. **API Endpoints:** Currently modified to use `/api/v1` endpoints as a temporary workaround
+2. **Tenant/Database Support:** v2 expects multi-tenancy which v1 doesn't fully support
+3. **Response Models:** Field names and structure differ between v1 and v2
+4. **Embedding Functions:** Integration needs refinement for v2 API
+
+### Coming Soon 🚀
+- CloudClient implementation
+- Advanced query capabilities
+- Batch operations optimization
+- Streaming results
+- Async/reactive operations
+
+## API Design: Dual Approach
+
+The V2 API offers **two complementary approaches**:
+
+### 1. Convenience Methods (Simple API)
+- **For**: 80% of use cases
+- **Style**: Direct method calls with parameters
+- **Benefit**: Minimal boilerplate, Chroma-aligned
+- **Example**: `collection.add(ids, embeddings, documents)`
+
+### 2. Builder Pattern (Advanced API)
+- **For**: 20% of complex use cases
+- **Style**: Fluent builders with `.execute()`
+- **Benefit**: Maximum flexibility, all options available
+- **Example**: `collection.query().queryEmbeddings(...).where(...).execute()`
+
+### When to Use Which?
+
+| Use Case | Recommended Approach | Example |
+|----------|---------------------|---------|
+| Simple add with all data | Convenience | `collection.add(ids, embeddings, documents, metadatas)` |
+| Add with URIs or complex options | Builder | `collection.add().ids(...).uris(...).execute()` |
+| Basic query | Convenience | `collection.query(embeddings, 10)` |
+| Query with whereDocument or complex filters | Builder | `collection.query().queryEmbeddings(...).whereDocument(...).execute()` |
+| Get by IDs | Convenience | `collection.get(List.of("id1", "id2"))` |
+| Get with pagination | Builder | `collection.get().limit(100).offset(0).execute()` |
+| Delete by IDs | Convenience | `collection.delete(ids)` |
+| Delete by complex filter | Builder | `collection.delete().where(...).whereDocument(...).execute()` |
+
+### Design Philosophy
+
+> **"Simple things should be simple, complex things should be possible."**
+
+The dual API approach ensures:
+- New users can get started quickly with minimal code
+- Power users have full control when needed
+- API feels familiar to Chroma users from Python/TypeScript
+- Java best practices (type safety, clarity) are maintained
+
+## Migration from V1
+
+The V2 API is designed to coexist with V1. Key differences:
+
+| V1 | V2 |
+|----|-----|
+| `Client` class | `ChromaClient` |
+| Swagger-generated models | Hand-crafted POJOs |
+| Builder-only patterns | Dual approach (convenience + builders) |
+| Multiple ways to configure | Flat, simple API surface |
+| Nested packages | Flat package structure |
+
+## Testing
+
+The V2 API includes comprehensive test coverage:
+
+```bash
+# Run all V2 tests
+mvn test -Dtest="tech.amikos.chromadb.v2.**"
+
+# Run with specific ChromaDB version
+export CHROMA_VERSION=1.1.0 && mvn test
+
+# Run stress tests
+mvn test -Dtest=V2StressTest
+```
+
+## Support
+
+This is an experimental API. For production use, please use the stable V1 API.
+
+For issues or questions:
+- GitHub Issues: [chromadb-java-client/issues](https://github.com/amikos-tech/chromadb-java-client/issues)
+- Documentation: This file
+- Examples: See test files in `src/test/java/tech/amikos/chromadb/v2/`
\ No newline at end of file
diff --git a/src/main/java/tech/amikos/chromadb/v2/AddRecordsRequest.java b/src/main/java/tech/amikos/chromadb/v2/AddRecordsRequest.java
new file mode 100644
index 0000000..f98368e
--- /dev/null
+++ b/src/main/java/tech/amikos/chromadb/v2/AddRecordsRequest.java
@@ -0,0 +1,113 @@
+package tech.amikos.chromadb.v2;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class AddRecordsRequest {
+ @SerializedName("ids")
+ private final List ids;
+
+ @SerializedName("embeddings")
+ private final Object embeddings;
+
+ @SerializedName("documents")
+ private final List documents;
+
+ @SerializedName("metadatas")
+ private final List