Subsystem · workspaces

Workspaces

Curie inherits Cargo's workspace model. One root Curie.toml lists members; each member is a self-contained project; the root inherits shared config down to every member.

Layout

tree
monorepo/
├── Curie.toml          # workspace root — no [application] / [library]
├── app/
│   ├── Curie.toml      # declares [application]
│   └── src/...
├── core/
│   ├── Curie.toml      # declares [library]
│   └── src/...
└── utils/
    ├── Curie.toml      # declares [library]
    └── src/...

Root configuration

The root Curie.toml declares members and any config that should be inherited:

Curie.toml — workspace root
[workspace]
members = ["app", "core", "utils"]

[java]
sourceCompatibility = "21"

[bom-imports]
"com.fasterxml.jackson:jackson-bom" = "2.17.2"

[test-bom-imports]
"org.junit:junit-bom" = "5.11.0"

Inheritance rules

Members declare dependencies with empty version strings ("") to defer to the inherited BOMs:

app/Curie.toml
[application]
name      = "app"
version   = "0.1.0"
mainClass = "com.example.App"

[dependencies]
# resolved from the workspace's jackson-bom
"com.fasterxml.jackson.core:jackson-databind" = ""

[workspace-dependencies]
core  = { path = "../core" }
utils = { path = "../utils" }

Topo-sorted builds

Run curie build from the workspace root and Curie computes a topological order over [workspace-dependencies], then builds each member in dependency order. Upstream target/classes directories — not just their JARs — are placed on downstream compile classpaths, so downstream tests don't have to wait for upstream JAR packaging to complete.

$ curie build # from workspace root
Workspace . build (3 members)

[1/3] utils
  Compile         3 source file(s)
  Tests           ✔ 8 tests successful
[2/3] core
  Compile         5 source file(s)
  Tests           ✔ 12 tests successful
[3/3] app
  Resolve deps    7 JAR(s)
  Compile         4 source file(s)
  Tests           ✔ 7 tests successful
  Done            target/app-0.1.0.jar

Targeted builds

Run curie build from a member directory and Curie still respects topology — it builds the member plus its transitive workspace dependencies, but skips siblings the target doesn't depend on. This is the everyday loop in a large monorepo: edit one package, build only what's affected.

List members

curie list from the root prints the member roster and their declared roles (application vs library):

$ curie list
Workspace . (3 members)
  app    application  v0.1.0
  core   library      v0.1.0
  utils  library      v0.1.0

Parallel formatting

curie fmt at the workspace root fans out across every member in parallel. palantir-java-format is resolved once, then the JAR list is shared across the worker threads so there's no contention on the local cache.