diff --git a/.github/scripts/central_release.py b/.github/scripts/central_release.py
index dd2acf0..a191989 100644
--- a/.github/scripts/central_release.py
+++ b/.github/scripts/central_release.py
@@ -111,7 +111,7 @@ def check_ci(info):
def read_bundle(path, version):
- prefix = f'com/qoder/qca-sdk/{version}/qca-sdk-{version}'
+ prefix = f'com/qoder/sdk/qoder-cloud-agents-sdk/{version}/qoder-cloud-agents-sdk-{version}'
primary = {prefix + suffix for suffix in ('.pom', '.jar', '-sources.jar', '-javadoc.jar')}
required = primary | {name + '.asc' for name in primary}
allowed = required | {name + '.' + algo for name in required for algo in ('md5', 'sha1', 'sha256', 'sha512')}
@@ -161,11 +161,11 @@ def seal(source, candidate, output):
contents = read_bundle(bundle, info['version'])
checks = json.loads((candidate / 'package-check.json').read_text())['sha256']
for local, expected in checks.items():
- filename = f"qca-sdk-{info['version']}.pom" if local == 'pom.xml' else Path(local).name
- path = f"com/qoder/qca-sdk/{info['version']}/{filename}"
+ filename = f"qoder-cloud-agents-sdk-{info['version']}.pom" if local == 'pom.xml' else Path(local).name
+ path = f"com/qoder/sdk/qoder-cloud-agents-sdk/{info['version']}/{filename}"
require(hashlib.sha256(contents[path]).hexdigest() == expected,
'Signed bundle differs from reviewed build: ' + filename)
- expected_files = {'pom.xml'} | {f"target/qca-sdk-{info['version']}{suffix}.jar"
+ expected_files = {'pom.xml'} | {f"target/qoder-cloud-agents-sdk-{info['version']}{suffix}.jar"
for suffix in ('', '-sources', '-javadoc')}
require(set(checks) == expected_files, 'Incomplete candidate digests')
info.update(run_id=run_id(os.environ['GITHUB_RUN_ID']), workflow_sha=os.environ['GITHUB_SHA'],
@@ -247,7 +247,7 @@ def portal_request(path, data=b'', content_type=None):
def deployment_name(info):
- return f"qca-sdk-{info['version']}-{info['source_sha']}-{info['batch_id']}-{info['bundle_sha256']}"
+ return f"qoder-cloud-agents-sdk-{info['version']}-{info['source_sha']}-{info['batch_id']}-{info['bundle_sha256']}"
def upload(output):
@@ -277,7 +277,7 @@ def publish(output):
status = json.loads(portal_request('/status?' + urllib.parse.urlencode(dict(id=identifier))))
require(status.get('deploymentId') == identifier
and status.get('deploymentName') == deployment_name(info), 'Central deployment identity differs')
- expected = f"pkg:maven/com.qoder/qca-sdk@{info['version']}"
+ expected = f"pkg:maven/com.qoder.sdk/qoder-cloud-agents-sdk@{info['version']}"
require(not status.get('purls') or status['purls'] == [expected], 'Unexpected Central coordinates')
state = status.get('deploymentState')
require(state in ('PENDING', 'VALIDATING', 'VALIDATED', 'PUBLISHING', 'PUBLISHED', 'FAILED'),
diff --git a/.github/scripts/check_package.py b/.github/scripts/check_package.py
index 1da98b9..f267f0b 100644
--- a/.github/scripts/check_package.py
+++ b/.github/scripts/check_package.py
@@ -19,9 +19,11 @@ def check(root):
pom = root / "pom.xml"
xml = ET.parse(pom).getroot()
ns = {"m": "http://maven.apache.org/POM/4.0.0"}
+ group = xml.findtext("m:groupId", namespaces=ns)
artifact = xml.findtext("m:artifactId", namespaces=ns)
version = xml.findtext("m:version", namespaces=ns)
- require(artifact == "qca-sdk" and version, "Unexpected SDK coordinates")
+ require(group == "com.qoder.sdk" and artifact == "qoder-cloud-agents-sdk" and version,
+ "Unexpected SDK coordinates")
target = root / "target"
jars = [target / (artifact + "-" + version + suffix + ".jar")
for suffix in ("", "-sources", "-javadoc")]
@@ -52,7 +54,7 @@ def check(root):
"Internal implementation leaked into public Javadoc")
files = jars + [pom]
digests = {str(path.relative_to(root)): hashlib.sha256(path.read_bytes()).hexdigest() for path in files}
- report = {"artifact_id": artifact, "version": version, "class_count": len(classes),
+ report = {"group_id": group, "artifact_id": artifact, "version": version, "class_count": len(classes),
"class_major_version": 52, "sha256": digests}
(target / "package-check.json").write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
(target / "SHA256SUMS").write_text("".join(digest + " " + name + "\n" for name, digest in digests.items()), encoding="utf-8")
diff --git a/.github/scripts/check_repository.py b/.github/scripts/check_repository.py
index df772f0..5949d47 100644
--- a/.github/scripts/check_repository.py
+++ b/.github/scripts/check_repository.py
@@ -18,12 +18,12 @@ def check_versions(root):
version = pom.findtext("m:version", namespaces=NS)
if not version or not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+(?:-[A-Za-z0-9.-]+)?", version):
raise ValueError("Use an explicit SDK version in pom.xml")
- if pom.findtext("m:groupId", namespaces=NS) != "com.qoder" or pom.findtext("m:artifactId", namespaces=NS) != "qca-sdk":
+ if pom.findtext("m:groupId", namespaces=NS) != "com.qoder.sdk" or pom.findtext("m:artifactId", namespaces=NS) != "qoder-cloud-agents-sdk":
raise ValueError("Unexpected Maven coordinates")
consumer = ET.parse(root / "examples/pom.xml").getroot()
deps = [d for d in consumer.findall("m:dependencies/m:dependency", NS)
- if d.findtext("m:groupId", namespaces=NS) == "com.qoder"
- and d.findtext("m:artifactId", namespaces=NS) == "qca-sdk"]
+ if d.findtext("m:groupId", namespaces=NS) == "com.qoder.sdk"
+ and d.findtext("m:artifactId", namespaces=NS) == "qoder-cloud-agents-sdk"]
if len(deps) != 1 or deps[0].findtext("m:version", namespaces=NS) != version:
raise ValueError("examples SDK dependency must match the root POM")
if consumer.findtext("m:version", namespaces=NS) != version:
diff --git a/.github/scripts/test_central_release.py b/.github/scripts/test_central_release.py
index 8b2d5f5..489777a 100644
--- a/.github/scripts/test_central_release.py
+++ b/.github/scripts/test_central_release.py
@@ -19,7 +19,7 @@
def write_bundle(path, transform=lambda values: values):
- prefix = 'com/qoder/qca-sdk/1.2.3/qca-sdk-1.2.3'
+ prefix = 'com/qoder/sdk/qoder-cloud-agents-sdk/1.2.3/qoder-cloud-agents-sdk-1.2.3'
values = {}
for suffix in ('.pom', '.jar', '-sources.jar', '-javadoc.jar'):
name = prefix + suffix
@@ -51,7 +51,7 @@ def setUp(self):
def status(self, state, **changes):
return json.dumps(dict(deploymentId=UUID, deploymentName=release.deployment_name(self.info),
- deploymentState=state, purls=['pkg:maven/com.qoder/qca-sdk@1.2.3'],
+ deploymentState=state, purls=['pkg:maven/com.qoder.sdk/qoder-cloud-agents-sdk@1.2.3'],
**changes)).encode()
def test_identity_rejects_forks_events_and_snapshots(self):
@@ -62,7 +62,7 @@ def test_identity_rejects_forks_events_and_snapshots(self):
def test_bundle_requires_signatures_checksums_and_exact_coordinates(self):
self.assertEqual(self.info, release.load(self.output))
- prefix = 'com/qoder/qca-sdk/1.2.3/qca-sdk-1.2.3'
+ prefix = 'com/qoder/sdk/qoder-cloud-agents-sdk/1.2.3/qoder-cloud-agents-sdk-1.2.3'
for name in (prefix + '.pom.asc', prefix + '.jar.md5'):
with self.subTest(name=name):
write_bundle(self.output / 'central-bundle.zip', lambda values: {k: v for k, v in values.items() if k != name})
@@ -73,7 +73,7 @@ def test_bundle_requires_signatures_checksums_and_exact_coordinates(self):
release.read_bundle(self.output / 'central-bundle.zip', '1.2.3')
def test_bundle_rejects_wrong_checksums_and_manifest_tampering(self):
- key = 'com/qoder/qca-sdk/1.2.3/qca-sdk-1.2.3.jar.sha1'
+ key = 'com/qoder/sdk/qoder-cloud-agents-sdk/1.2.3/qoder-cloud-agents-sdk-1.2.3.jar.sha1'
write_bundle(self.output / 'central-bundle.zip', lambda values: dict(values, **{key: b'bad'}))
with self.assertRaisesRegex(ValueError, 'checksum mismatch'):
release.read_bundle(self.output / 'central-bundle.zip', '1.2.3')
@@ -88,13 +88,13 @@ def test_seal_detects_rebuild_differences(self):
release.save(candidate / 'intent.json', release.identity())
checks = {}
for suffix in ('.pom', '.jar', '-sources.jar', '-javadoc.jar'):
- filename = 'qca-sdk-1.2.3' + suffix
+ filename = 'qoder-cloud-agents-sdk-1.2.3' + suffix
key = 'pom.xml' if suffix == '.pom' else 'target/' + filename
- checks[key] = self.info['files']['com/qoder/qca-sdk/1.2.3/' + filename]
+ checks[key] = self.info['files']['com/qoder/sdk/qoder-cloud-agents-sdk/1.2.3/' + filename]
release.save(candidate / 'package-check.json', dict(sha256=checks))
(candidate / 'release-notes.md').write_text('Reviewed notes\n')
release.seal(source, candidate, self.output / 'sealed')
- checks['target/qca-sdk-1.2.3.jar'] = '0' * 64
+ checks['target/qoder-cloud-agents-sdk-1.2.3.jar'] = '0' * 64
release.save(candidate / 'package-check.json', dict(sha256=checks))
with self.assertRaisesRegex(ValueError, 'differs from reviewed build'):
release.seal(source, candidate, self.output / 'sealed')
@@ -127,7 +127,7 @@ def test_tag_rejects_moved_sha_and_changed_bundle(self):
def test_preflight_without_environment_still_requires_current_main_and_ci(self):
source, candidate = self.output / 'source', self.output / 'candidate'
- coordinates = 'com.qoderqca-sdk1.2.3'
+ coordinates = 'com.qoder.sdkqoder-cloud-agents-sdk1.2.3'
project = '{}'
files = {
'pom.xml': project.format(coordinates),
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5403829..080459f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -64,7 +64,7 @@ jobs:
with:
name: candidate-java-${{ matrix.java }}
path: |
- target/qca-sdk-*.jar
+ target/qoder-cloud-agents-sdk-*.jar
target/package-check.json
target/SHA256SUMS
pom.xml
diff --git a/.github/workflows/release-preflight.yml b/.github/workflows/release-preflight.yml
index 31d3189..77475fc 100644
--- a/.github/workflows/release-preflight.yml
+++ b/.github/workflows/release-preflight.yml
@@ -57,7 +57,7 @@ jobs:
with:
name: release-candidate-${{ inputs.version }}
path: |
- target/qca-sdk-*.jar
+ target/qoder-cloud-agents-sdk-*.jar
target/package-check.json
target/SHA256SUMS
pom.xml
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3b1175f..bff38e4 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -126,7 +126,7 @@ jobs:
MAVEN_GPG_KEY: ${{ secrets.MAVEN_GPG_KEY }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
run: |
- test "$CENTRAL_NAMESPACE" = com.qoder || { echo 'Verify com.qoder in Central Portal and set the CENTRAL_NAMESPACE repository Actions variable'; exit 1; }
+ test "$CENTRAL_NAMESPACE" = com.qoder.sdk || { echo 'Verify publishing access to com.qoder.sdk in Central Portal and set the CENTRAL_NAMESPACE repository Actions variable'; exit 1; }
test -n "$CENTRAL_USERNAME" && test -n "$CENTRAL_PASSWORD" || { echo 'Central Portal token secrets are missing'; exit 1; }
if [[ -z "$RESUME_RUN_ID" ]]; then
test -n "$MAVEN_GPG_KEY" && test -n "$MAVEN_GPG_PASSPHRASE" || { echo 'GPG signing secrets are missing'; exit 1; }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10cacc0..e27f5ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
## [Unreleased]
+## [0.1.0-rc.1] - 2026-10-21
+
+First public release candidate for installation and integration testing ahead of `0.1.0`.
+
+### Changed
+
+- Use `com.qoder.sdk:qoder-cloud-agents-sdk` as the Maven coordinates. Java packages remain under `com.qoder.cloudagents`.
+
### Fixed
- Repeated default header settings now replace earlier values case-insensitively, while per-request headers retain precedence.
@@ -68,4 +76,4 @@
- Usage, Token management and Drive round-trip examples with installed-JAR consumer checks, scoped cleanup and storage credential isolation.
- HTTP error request ID fallback from top-level and nested error bodies when response headers omit it.
-The current SNAPSHOT can be built from source; Maven Central publication is not enabled. See the [maintenance guide](docs/maintaining.md) for current checks and delivery boundaries.
+This version can be built from source; Maven Central publication remains pending. See the [maintenance guide](docs/maintaining.md) for current checks and delivery boundaries.
diff --git a/README.md b/README.md
index c805988..1d43a39 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,26 @@
Java 8 compatible client for the **Forward API**. The repository follows the resource and authentication structure of the QCA Go, Python and TypeScript SDKs, using Maven and Java builders.
-**Status: source available; not yet published to Maven Central.** The current development version is `0.1.0-SNAPSHOT`. Build from source to use the SDK until a public Maven release is available.
+**Status: source available; not yet published to Maven Central.** The current version is `0.1.0-rc.1`. Build from source to use the SDK until a public Maven release is available.
The SDK provides synchronous and asynchronous clients for Models, Templates, Identities, Sessions and Threads, Memory Stores, Environments, Files, Skills, Vaults and Credentials, Schedules, Batches, Channels and Pairing, Usage, Service Account Tokens and Drive. Shared support includes PAT/SA authentication, timeouts, retries, pagination, typed errors and request IDs. Session/Thread SSE supports explicit resumption; Realtime supports text, PCM audio and History. The [API coverage](docs/forward-api-coverage.md) records the 123-operation baseline and its exclusions. Managed APIs are outside this project's scope.
See the [examples](examples/README.md) for authentication and resource workflows, and the [maintenance guide](docs/maintaining.md) for contributor checks and version updates.
+## Maven dependency
+
+After installing the SDK locally or publishing it to your configured Maven repository, use:
+
+```xml
+
+ com.qoder.sdk
+ qoder-cloud-agents-sdk
+ 0.1.0-rc.1
+
+```
+
+The Maven coordinates do not change Java imports, which remain under `com.qoder.cloudagents`.
+
## Local build
```sh
diff --git a/docs/maintaining.md b/docs/maintaining.md
index 7c665e6..47c62ee 100644
--- a/docs/maintaining.md
+++ b/docs/maintaining.md
@@ -27,17 +27,17 @@ For a release, move the applicable entries beneath `## [VERSION] - YYYY-MM-DD` a
- Root `pom.xml` project version.
- `examples/pom.xml` project version.
-- The examples' `com.qoder:qca-sdk` dependency version.
+- The examples' `com.qoder.sdk:qoder-cloud-agents-sdk` dependency version.
The SDK's embedded version is filtered from `${project.version}`; do not replace that template with a hard-coded value. `check_repository.py` rejects mismatched versions and requires a matching changelog entry for a non-SNAPSHOT version.
```sh
python3 .github/scripts/release_notes.py check
# After adding the actual release entry:
-python3 .github/scripts/release_notes.py extract --version 0.1.0
+python3 .github/scripts/release_notes.py extract --version 0.1.0-rc.1
```
-The current version remains `0.1.0-SNAPSHOT`. A SNAPSHOT can resolve to different timestamped builds, so acceptance records must include the resolved version, source SHA and JAR digest. A successful test of an older SNAPSHOT is not evidence for a newer one.
+The current version is `0.1.0-rc.1`. Acceptance records must include the resolved version, source SHA and JAR digest. Release versions must not be overwritten; a successful test of an older build is not evidence for a newer one.
## Build candidates and releases
diff --git a/docs/releasing.md b/docs/releasing.md
index dd9f318..5f479b3 100644
--- a/docs/releasing.md
+++ b/docs/releasing.md
@@ -1,6 +1,6 @@
# Java SDK release setup
-The development version is `com.qoder:qca-sdk:0.1.0-SNAPSHOT`. The manual [Release workflow](../.github/workflows/release.yml) implements publication using repository Actions secrets. Dispatching it from `main` authorizes publication after all automated checks pass; there is no separate environment approval. The Central account, namespace, signing key and repository settings below must be configured first. The GitHub repository and internal Maven access do not grant Maven Central publishing access. No public release has been made by adding this workflow.
+The current version is `com.qoder.sdk:qoder-cloud-agents-sdk:0.1.0-rc.1`. The manual [Release workflow](../.github/workflows/release.yml) implements publication using repository Actions secrets. Dispatching it from `main` authorizes publication after all automated checks pass; there is no separate environment approval. The Central account, namespace, signing key and repository settings below must be configured first. The GitHub repository and internal Maven access do not grant Maven Central publishing access. No public release has been made by adding this workflow.
## Optional GitHub protection
@@ -26,7 +26,7 @@ The [Release preflight workflow](../.github/workflows/release-preflight.yml) run
- `commit_sha`: the full 40-character lowercase SHA of the current `main` commit.
- `batch_id`: 1–64 letters, digits, dots, underscores or hyphens, starting with a letter or digit.
-It checks the source and changelog, runs quality checks, builds and tests on JDK 17, and retains the candidate JARs, POM, checksums, release intent and notes. It neither creates a tag nor uploads to Maven Central nor publishes a GitHub Release. Current `0.1.0-SNAPSHOT` cannot be passed as a release version. Five-JDK CI remains a separate required gate.
+It checks the source and changelog, runs quality checks, builds and tests on JDK 17, and retains the candidate JARs, POM, checksums, release intent and notes. It neither creates a tag nor uploads to Maven Central nor publishes a GitHub Release. SNAPSHOT versions cannot be passed as release versions. Five-JDK CI remains a separate required gate.
## Prepare a Maven Central bundle
@@ -45,16 +45,16 @@ The release workflow uses this bundle-only mode, then uploads the retained bundl
## One-time Central registration
1. Register or sign in to [Central Portal](https://central.sonatype.com/). Use the team's intended publisher account, not an unrelated personal namespace.
-2. Open the account menu, **View Namespaces**, and add `com.qoder`. If the namespace is already owned by the team, obtain publisher access from its owner rather than creating another namespace or silently changing the SDK coordinates.
-3. For a new `com.qoder` namespace, ask the `qoder.com` DNS administrator to add the exact verification TXT value shown by Portal at `qoder.com`. Check DNS visibility before clicking **Verify Namespace**; wait for **Verified**. A GitHub repository under QoderAI does not verify this domain-based namespace.
-4. In the publisher's [account page](https://central.sonatype.com/account), generate a **User Token**. The generated username/password pair is used for publication; it is not the normal account login password.
+2. Open the account menu, **View Namespaces**, and confirm publisher access to `com.qoder.sdk`, matching the SDK's group. If the namespace is already owned by the team, obtain publisher access from its owner rather than registering another namespace or changing the SDK coordinates.
+3. Complete any ownership verification requested by Portal before publishing. Existing authorized publishers do not need to repeat namespace registration. A GitHub repository under QoderAI does not itself verify a domain-based namespace.
+4. In the publisher's [User Tokens page](https://central.sonatype.com/usertoken), generate a **User Token**. Save the generated username/password pair before closing the dialog; it cannot be retrieved later. These credentials are used for publication, not the normal account login password.
5. Prepare a team-owned, passphrase-protected GPG signing key. Retain its backup securely and make its public key discoverable as required by [Central's GPG guide](https://central.sonatype.org/publish/requirements/gpg/). The workflow expects an ASCII-armored exported OpenPGP secret key, compatible with Maven GPG Plugin's BC signer. Export only the intended signing key.
In repository **Settings → Secrets and variables → Actions**, configure repository-level values:
| Kind | Name | Value |
| --- | --- | --- |
-| Variable | `CENTRAL_NAMESPACE` | `com.qoder`, after the namespace is verified and the publisher has access |
+| Variable | `CENTRAL_NAMESPACE` | `com.qoder.sdk`, after the namespace is verified and the publisher has access |
| Secret | `CENTRAL_USERNAME` | Central Portal User Token username |
| Secret | `CENTRAL_PASSWORD` | Central Portal User Token password |
| Secret | `MAVEN_GPG_KEY` | ASCII-armored exported private signing key |
@@ -72,7 +72,7 @@ Open **Actions → Release → Run workflow**, select **main**, and verify the f
| Input | First publication |
| --- | --- |
-| `version` | The reviewed version without `v` or `SNAPSHOT`, for example `0.1.0` |
+| `version` | The reviewed version without `v` or `SNAPSHOT`, for example `0.1.0-rc.1` |
| `commit_sha` | Full 40-character lowercase SHA of the current GitHub main |
| `batch_id` | 1–64 letters/digits/dots/underscores/hyphens, starting with a letter or digit |
| `resume_run_id` | Empty |
@@ -104,7 +104,7 @@ Normally leave `deployment_id` empty: recovery downloads the original `central-r
| Tag, notes, source, batch, archive or deployment identity conflict | Stop and investigate the conflict; never move/delete the release tag or overwrite the version |
| Original artifacts expired or missing | Recover the preserved original archive/manifest with maintainer review; this workflow fails rather than rebuilding a replacement |
-Central deployment names use `qca-sdk----` from `manifest.json`. This name binds a manually recovered UUID to the retained bundle. Recovery always points to the original bundle run, not to a later recovery run. If a later recovery supplies the UUID manually, keep supplying it when the original run has no receipt.
+Central deployment names use `qoder-cloud-agents-sdk----` from `manifest.json`. This name binds a manually recovered UUID to the retained bundle. Recovery always points to the original bundle run, not to a later recovery run. If a later recovery supplies the UUID manually, keep supplying it when the original run has no receipt.
## Offline release validation
diff --git a/examples/pom.xml b/examples/pom.xml
index a810966..eb2f8ce 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -2,11 +2,11 @@
4.0.0
- com.qoder.examplesqca-forward-examples0.1.0-SNAPSHOT
+ com.qoder.examplesqca-forward-examples0.1.0-rc.1
8UTF-8
- com.qoderqca-sdk0.1.0-SNAPSHOT
+ com.qoder.sdkqoder-cloud-agents-sdk0.1.0-rc.1
org.junit.jupiterjunit-jupiter5.13.4test
com.squareup.okhttp3mockwebserver5.5.0test
diff --git a/pom.xml b/pom.xml
index 35ec73d..7af3ed2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,9 +2,9 @@
4.0.0
- com.qoder
- qca-sdk
- 0.1.0-SNAPSHOT
+ com.qoder.sdk
+ qoder-cloud-agents-sdk
+ 0.1.0-rc.1
Qoder Cloud Agents Java SDK
Java 8 compatible Qoder Cloud Agents Forward API client.
https://github.com/QoderAI/qoder-cloud-agents-sdk-java