diff --git a/.gitignore b/.gitignore
index 714dd47f5..4d039ac90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ docs/.validation/
# Java
java/target
java/sdk/target
+java/copilot-native/target
java/smoke-test
java/.classpath
java/.project
diff --git a/java/copilot-native/pom.xml b/java/copilot-native/pom.xml
new file mode 100644
index 000000000..de57c313f
--- /dev/null
+++ b/java/copilot-native/pom.xml
@@ -0,0 +1,214 @@
+
+
+
+ 4.0.0
+
+
+ com.github
+ copilot-sdk-java-parent
+ 1.0.10-preview.0-SNAPSHOT
+ ../pom.xml
+
+
+ com.github
+ copilot-sdk-java-runtime
+ jar
+
+ GitHub Copilot SDK :: Java :: Native Runtime
+ Native runtime binaries for the GitHub Copilot Java SDK, published as per-platform classifier JARs
+
+
+
+ ${project.basedir}/../..
+
+ linux-x64
+ ${project.build.directory}/native-staging
+
+ false
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ fetch-native-linux-x64
+ generate-resources
+
+ exec
+
+
+ node
+
+ ${project.basedir}/scripts/fetch-native.mjs
+ ${copilot.sdk.root}
+ ${copilot.native.staging}
+ ${copilot.native.classifier}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ jar-linux-x64
+ package
+
+ jar
+
+
+ ${copilot.native.classifier}
+ ${copilot.native.staging}/${copilot.native.classifier}
+
+ .version
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ verify-native-jars
+ package
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.sonatype.central
+ central-publishing-maven-plugin
+ true
+
+ central
+ true
+
+
+
+
+
+
+
+
+ skip-native-download
+
+
+ copilot.native.skip.download
+ true
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ jar-linux-x64
+ none
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ verify-native-jars
+ none
+
+
+
+
+
+
+
+
diff --git a/java/copilot-native/scripts/fetch-native.mjs b/java/copilot-native/scripts/fetch-native.mjs
new file mode 100644
index 000000000..18449badf
--- /dev/null
+++ b/java/copilot-native/scripts/fetch-native.mjs
@@ -0,0 +1,99 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ *--------------------------------------------------------------------------------------------*/
+
+/**
+ * Downloads the `runtime.node` native binary for a single platform classifier
+ * and stages it for packaging into a classifier JAR.
+ *
+ * Steps:
+ * 1. Read the pinned version and the SHA-512 `integrity` value for
+ * `@github/copilot-` from `nodejs/package-lock.json`.
+ * 2. `npm pack` that exact version into the staging directory.
+ * 3. Verify the downloaded tarball against the `integrity` value.
+ * 4. Extract `package/prebuilds//runtime.node` to
+ * `//native//runtime.node`.
+ * 5. Write `//native//platform.properties`.
+ *
+ * Usage: node fetch-native.mjs
+ */
+
+import { createHash } from 'node:crypto';
+import { execFileSync } from 'node:child_process';
+import fs from 'node:fs';
+import path from 'node:path';
+
+const [repoRoot, stagingDir, classifier] = process.argv.slice(2);
+
+if (!repoRoot || !stagingDir || !classifier) {
+ console.error('Usage: node fetch-native.mjs ');
+ process.exit(1);
+}
+
+const lockPath = path.join(repoRoot, 'nodejs', 'package-lock.json');
+const packageName = `@github/copilot-${classifier}`;
+const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
+const entry = lock.packages?.[`node_modules/${packageName}`];
+
+if (!entry?.version || !entry?.integrity) {
+ console.error(`Could not find version/integrity for ${packageName} in ${lockPath}`);
+ process.exit(1);
+}
+
+const { version, integrity } = entry;
+if (!integrity.startsWith('sha512-')) {
+ console.error(`Unsupported integrity algorithm for ${packageName}: ${integrity}`);
+ process.exit(1);
+}
+
+const outDir = path.join(stagingDir, classifier);
+const resourceDir = path.join(outDir, 'native', classifier);
+const runtimePath = path.join(resourceDir, 'runtime.node');
+const stampPath = path.join(outDir, '.version');
+
+// Idempotence: skip the download when the staged binary already matches.
+// The stamp stores version + integrity + binary digest to ensure a corrupted
+// binary or lockfile integrity change is detected.
+if (fs.existsSync(runtimePath) && fs.existsSync(stampPath)) {
+ const stampLines = fs.readFileSync(stampPath, 'utf8').trim().split('\n');
+ const stampVersion = stampLines[0] || '';
+ const stampIntegrity = stampLines[1] || '';
+ const stampBinaryDigest = stampLines[2] || '';
+ const currentBinaryDigest = `sha512-${createHash('sha512').update(fs.readFileSync(runtimePath)).digest('base64')}`;
+ if (stampVersion === version && stampIntegrity === integrity && stampBinaryDigest === currentBinaryDigest) {
+ console.log(`${packageName}@${version} already staged at ${runtimePath}`);
+ process.exit(0);
+ }
+}
+
+fs.rmSync(outDir, { recursive: true, force: true });
+fs.mkdirSync(resourceDir, { recursive: true });
+
+console.log(`Downloading ${packageName}@${version} ...`);
+const packOutput = execFileSync('npm', ['pack', `${packageName}@${version}`, '--pack-destination', outDir], {
+ encoding: 'utf8',
+ shell: process.platform === 'win32',
+});
+const tarballName = packOutput.trim().split('\n').pop().trim();
+const tarballPath = path.join(outDir, tarballName);
+
+const actual = `sha512-${createHash('sha512').update(fs.readFileSync(tarballPath)).digest('base64')}`;
+if (actual !== integrity) {
+ console.error(`Integrity verification failed for ${tarballPath}`);
+ console.error(` expected: ${integrity}`);
+ console.error(` actual: ${actual}`);
+ process.exit(1);
+}
+console.log(`Integrity verified (${integrity.slice(0, 20)}...).`);
+
+const memberPath = `package/prebuilds/${classifier}/runtime.node`;
+execFileSync('tar', ['-xzf', tarballPath, '-C', outDir, memberPath], { stdio: 'inherit' });
+fs.renameSync(path.join(outDir, memberPath), runtimePath);
+fs.rmSync(path.join(outDir, 'package'), { recursive: true, force: true });
+fs.rmSync(tarballPath, { force: true });
+
+fs.writeFileSync(path.join(resourceDir, 'platform.properties'), `classifier=${classifier}\nversion=${version}\n`);
+const binaryDigest = `sha512-${createHash('sha512').update(fs.readFileSync(runtimePath)).digest('base64')}`;
+fs.writeFileSync(stampPath, `${version}\n${integrity}\n${binaryDigest}\n`);
+
+console.log(`Staged ${runtimePath}`);
diff --git a/java/copilot-native/src/main/resources/native/lib/copilot-runtime.properties b/java/copilot-native/src/main/resources/native/lib/copilot-runtime.properties
new file mode 100644
index 000000000..0f3230898
--- /dev/null
+++ b/java/copilot-native/src/main/resources/native/lib/copilot-runtime.properties
@@ -0,0 +1,12 @@
+# Placeholder marker for the primary (classifier-less) artifact of
+# com.github:copilot-sdk-java-runtime.
+#
+# The real native binaries ship in per-platform classifier JARs
+# (e.g. copilot-sdk-java-runtime--linux-x64.jar) under
+# native//runtime.node. This primary JAR exists only to satisfy
+# Maven Central's requirement for a main artifact and intentionally contains
+# no native binaries.
+#
+# This file is processed by Maven resource filtering.
+placeholder=true
+version=${project.version}
diff --git a/java/pom.xml b/java/pom.xml
index efffeca92..9b4a92294 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -38,11 +38,11 @@
sdk
+ copilot-native
-