Org-level parent POM and BOM for the casehubio ecosystem, plus tooling for full-stack local builds and CI/CD.
| Repository | Status |
|---|---|
| casehub-parent | |
| casehub-ledger | |
| casehub-work | |
| casehub-qhorus | |
| casehub-engine | |
| claudony | |
| quarkus-langchain4j |
Full detail: Build Status Dashboard | PR Dashboard | ▶ Run Full Stack Build
- The BOM
- Ecosystem projects
- Local full-stack build
- CI/CD pipeline
- The quarkus-langchain4j fork
- Adding a new project
- Local developer setup
casehub-parent is the Maven Bill of Materials for all casehubio projects. Every project in the ecosystem imports it so that cross-project dependency versions are managed in one place.
| Artifact | GroupId | What it is |
|---|---|---|
casehub-ledger |
io.casehub |
Immutable audit ledger base |
casehub-ledger-deployment |
io.casehub |
Extension deployment module |
casehub-work-api |
io.casehub |
Work item SPI |
casehub-work-core |
io.casehub |
Work item core |
casehub-work |
io.casehub |
Work item runtime |
casehub-work-deployment |
io.casehub |
Work item deployment |
casehub-work-ledger |
io.casehub |
Optional ledger integration for work items |
casehub-qhorus |
io.casehub |
AI agent communication mesh |
casehub-qhorus-deployment |
io.casehub |
Qhorus deployment module |
casehub-qhorus-testing |
io.casehub |
Test utilities for Qhorus consumers |
casehub-ledger |
io.casehub |
CaseHub audit ledger integration |
All are managed at the same version (${casehub.version}, currently 0.2-SNAPSHOT).
The BOM also imports io.quarkus.platform:quarkus-bom to manage Quarkus extension versions.
Add to your project's <dependencyManagement> section:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.casehub</groupId>
<artifactId>casehub-parent</artifactId>
<version>0.2-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>Then declare casehubio dependencies without versions:
<dependency>
<groupId>io.casehub</groupId>
<artifactId>casehub-ledger</artifactId>
</dependency>
<dependency>
<groupId>io.casehub</groupId>
<artifactId>casehub-qhorus</artifactId>
</dependency>Each project in the ecosystem has its own Maven parent (casehub projects use internal root POMs; some use upstream parents for tooling). Maven only allows one parent per project, so a shared parent would break existing inheritance chains. Importing the BOM via <scope>import</scope> achieves centralised version management without requiring a shared parent.
| Repo | GroupId | Remote |
|---|---|---|
casehub-ledger |
io.casehub |
casehubio/ledger |
casehub-work |
io.casehub |
casehubio/work |
casehub-qhorus |
io.casehub |
casehubio/qhorus |
casehub-engine |
io.casehub |
casehubio/engine |
claudony |
dev.claudony |
casehubio/claudony |
quarkus-langchain4j |
(upstream fork) | casehubio/quarkus-langchain4j |
Dependency order (each project may depend on those above it):
casehub-ledger
↑
casehub-work
↑
casehub-qhorus casehub-engine
↑ ↑
claudony
For day-to-day development, use build-all.sh. It clones or updates all ecosystem repos, records the SHA of each, pins each to that SHA, and runs an incremental Maven build.
git clone https://github.com/casehubio/parent.git
cd casehub-parent
./build-all.shAll repos are cloned into subdirectories of casehub-parent/. These directories are gitignored — they are not tracked by this repository.
./build-all.sh # incremental build (default)
./build-all.sh --no-cache # ignore cache, rebuild everything
./build-all.sh --skip-tests # skip test-only phase for TEST-state modules
./build-all.sh -DskipTests # pass-through to Maven: skip all tests
./build-all.sh -T 1C # parallel Maven buildAll unrecognised flags are passed through to Maven.
Each module is classified into one of three states before building. The state is determined by comparing the current HEAD SHA of each repo against the SHA recorded in the most recent successful build log (the cache manifest).
| State | Condition | Action |
|---|---|---|
| BUILD | Own SHA changed since last build | Full compile + test + mvn install |
| TEST | Own SHA unchanged, but a transitive casehub dependency is in BUILD state | mvn test only — tests run against the newly installed dep artifacts, no recompile |
| SKIP | Own SHA and all transitive casehub dep SHAs unchanged | Nothing — artifact already in local .m2 is current |
The rationale for the TEST state: if casehub-ledger changes but casehub-work's own code does not, casehub-work doesn't need recompiling — its bytecode is the same. But its tests should run against the new casehub-ledger to catch integration regressions.
The dependency graph used for propagation:
casehub-ledger → (no casehub deps)
casehub-work → casehub-ledger
casehub-qhorus → casehub-ledger, casehub-work
casehub-engine → casehub-ledger, casehub-work
claudony → casehub-ledger, casehub-work, casehub-qhorus
Example output:
==> Incremental analysis...
casehub-ledger BUILD (own SHA changed)
casehub-work TEST (dep changed, rerun tests against new artifacts)
casehub-qhorus TEST (dep changed, rerun tests against new artifacts)
casehub-engine TEST (dep changed, rerun tests against new artifacts)
claudony SKIP (SHA and all deps unchanged)
==> Installing: casehub-ledger
==> Retesting against updated deps: casehub-work,casehub-qhorus,casehub-engine
Every build-all.sh run writes a timestamped SHA log to build-logs/:
build-logs/
20260424T143022.shas ← each run writes one file
20260424T091511.shas
20260423T220034.shas
Each log records the exact HEAD SHA of every repo at build time:
# casehubio full-stack build
# timestamp: 20260424T143022
# branch: main
casehub-ledger=a2636e132b43bc0faad66cf587ab5b30996ff3df
casehub-work=e085d64c1f2a93b7d0f4e89a3c12d45e678f901a
casehub-qhorus=ef89aaa3b7c1d20f4e5a67b89c0d12e3f456789a
casehub-engine=fccb647d8e2f31a05b6c78d90e1f23a4b5678901
claudony=3fbeac7e9f0a12b34c56d78e90f1a2b3c4567890
The most recent log is used as the cache manifest for the next build. Build logs are committed to this repository as a permanent record of what built together successfully.
To reproduce an exact prior build:
./replay.sh build-logs/20260424T143022.shas
./replay.sh build-logs/20260424T143022.shas -DskipTestsreplay.sh clones or updates each repo, checks out the exact SHA from the log, and runs the full Maven build via aggregator.xml. The result is byte-for-byte identical to the original build.
aggregator.xml lists all ecosystem repos as Maven reactor modules. Maven reads each project's own pom.xml and resolves the build order from actual <dependency> declarations — the order in the aggregator file is advisory only.
# Run directly if repos are already cloned and pinned
mvn install -f aggregator.xml
mvn install -f aggregator.xml -pl casehub-ledger,casehub-work # partial buildThe aggregator is not published to Maven. It is a local build tool only.
Each project in the ecosystem has its own GitHub Actions workflow (.github/workflows/publish.yml) that builds and publishes to GitHub Packages on every push to main. Projects are built and published independently — there is no cross-repo trigger chain.
Every ecosystem repo contains:
- name: Set up Java 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
server-id: github
server-username: GITHUB_ACTOR
server-password: GITHUB_TOKEN
- name: Build and publish
run: mvn --batch-mode deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}mvn deploy publishes artifacts to https://maven.pkg.github.com/casehubio/<repo>. Consumers resolve them via the github-casehubio repository entry in their root pom:
<repositories>
<repository>
<id>github-casehubio</id>
<url>https://maven.pkg.github.com/casehubio/*</url>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>casehub-parent publishes its BOM on every push to main. This must be published before any other project can resolve io.casehub:casehub-parent:0.2-SNAPSHOT in CI.
Because each project publishes independently, upstream artifacts must be available in GitHub Packages before downstream CI can run. The natural order is:
casehub-parent→ publishes BOMcasehub-ledger→ depends on BOMcasehub-work→ depends on BOM +casehub-ledgercasehub-qhorus→ depends on BOM +casehub-ledger+casehub-workcasehub-engine→ depends on BOM +casehub-ledger+casehub-workclaudony→ depends on BOM +casehub-qhorus
If casehub-ledger CI hasn't published yet when casehub-work CI runs, casehub-work will fail with Could not resolve io.casehub:casehub-ledger:0.2-SNAPSHOT. Re-running the failing job after the upstream publish completes resolves this.
casehubio/quarkus-langchain4j is a fork of the upstream Quarkus LangChain4j project maintained here until upstream fixes are merged and published. It is not configured with casehubio CI/CD and does not use the casehub-parent BOM. It is included in the ecosystem only as a build dependency; consuming projects reference it at whatever version casehub-engine declares.
The casehubio ecosystem depends on quarkus-langchain4j for AI agent capabilities. However, fixes required by the ecosystem are not yet merged into an upstream release. Until those PRs land and a new release is published, the ecosystem uses a casehubio-maintained fork.
casehub-engine depends on specific quarkus-langchain4j behaviour that contains fixes not present in the latest public release. Depending directly on the public release would produce runtime failures in casehub-engine.
The fork lives at casehubio/quarkus-langchain4j. It contains:
- All upstream code from
quarkiverse/quarkus-langchain4jat a chosen base commit - The specific fix commits cherry-picked on top
The fork publishes its artifacts to casehubio GitHub Packages as version 999-SNAPSHOT (the fork's own working version) via .github/workflows/casehub-publish.yml. This workflow is casehubio-specific and must not be included in upstream PRs.
Consumers declare 999-SNAPSHOT for langchain4j artifacts rather than the public release version:
<!-- In casehub-engine pom.xml -->
<version.io.quarkiverse.langchain4j>999-SNAPSHOT</version.io.quarkiverse.langchain4j>The github-casehubio repository is already configured in all casehubio project poms, so 999-SNAPSHOT resolves from GitHub Packages without any additional setup.
The fork's pom.xml in git already declares 999-SNAPSHOT — no version changes are committed to the fork. The casehub-publish.yml workflow simply runs mvn deploy against the existing pom. This means any fix commits cherry-picked back to the upstream repo contain no casehubio-specific changes — only the functional fix.
When a fix is ready to contribute upstream:
- Create a branch from the base commit (before the casehub cherry-picks)
- Cherry-pick only the functional fix commits — not
casehub-publish.yml - Open a PR against
quarkiverse/quarkus-langchain4j
The .github/workflows/casehub-publish.yml file is the only casehubio-specific file in the fork. It is not part of any fix commit.
When the required fixes are merged upstream and a new release is published:
- Update
version.io.quarkiverse.langchain4jincasehub-engineto the new upstream release version - Remove the fork from
build-all.shREPOS list - Remove the wildcard GitHub Packages URL still resolves other artifacts — no other config changes needed
- Archive
casehubio/quarkus-langchain4j
- Create the repo under
casehubio/ - Add the casehub-parent BOM import to its
<dependencyManagement>section - Add the
github-casehubiorepository entry to its root pom - Add
<distributionManagement>pointing tohttps://maven.pkg.github.com/casehubio/<repo> - Create
.github/workflows/publish.yml(copy from any existing ecosystem repo) - Add the repo and its casehub dependencies to the
DEPSmap inbuild-all.sh - Add the repo to the
REPOSarray inbuild-all.shin dependency order - Add the repo as a
<module>inaggregator.xml - Add the repo's publishable artifacts to
pom.xml(the BOM) in this repo - Add the cloned directory name to
.gitignore
Consuming projects pull artifacts from GitHub Packages, which requires authentication even for public repos.
Add to ~/.m2/settings.xml:
<settings>
<servers>
<server>
<id>github-casehubio</id>
<username>YOUR_GITHUB_USERNAME</username>
<password>YOUR_GITHUB_PAT</password>
</server>
<server>
<id>github</id>
<username>YOUR_GITHUB_USERNAME</username>
<password>YOUR_GITHUB_PAT</password>
</server>
</servers>
</settings>The PAT needs read:packages scope for consuming artifacts and write:packages scope for publishing.
In CI, GITHUB_TOKEN is used automatically — no PAT setup required.
For local development where you are actively changing multiple projects simultaneously, use build-all.sh rather than relying on GitHub Packages — it builds everything from source and installs to your local .m2.