app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 53617c8f0e4827a93ac2c85420c03e7dfbfcf298
parent 66b603cf145bbb4ade64da622e440daedb4776c8
Author: triesap <tyson@radroots.org>
Date:   Sun,  9 Aug 2026 18:24:35 +0000

build: support standalone contributor outputs

- keep extbuild output routing when the tool is available
- fall back to ignored Gradle build and Cargo target directories
- make the checked-in Makefile usable without the extbuild subcommand
- document generated-source and standalone-build ownership

Diffstat:
MAGENTS.md | 42++++++++++++++++++++++--------------------
MMakefile | 4++--
Mapp/desktop/build.gradle.kts | 19+++++++++----------
Mbuild.gradle.kts | 7+++----
4 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md @@ -19,10 +19,9 @@ repository and may depend on the exact public Radroots library revision selected by the capsule; it must not depend on an implicit sibling checkout. The repository must remain independently cloneable, buildable, testable, and -packageable through its checked-in command surfaces. It may materialize the -exact public source revision into an extbuild-owned cache; it must not depend -on private parent code, parent-only contracts, unpublished local artifacts, -absolute host paths, or an enclosing monorepo layout. +packageable through its checked-in command surfaces with or without extbuild. +It must not depend on private parent code, parent-only contracts, unpublished +local artifacts, absolute host paths, or an enclosing monorepo layout. ## Machine authority and generated inputs @@ -52,8 +51,9 @@ absolute host paths, or an enclosing monorepo layout. Generated UniFFI Kotlin and native libraries are derived build output. Change the local canonical Rust producer contract/generator first, regenerate into -extbuild-owned build locations, and inspect the result. Never hand-edit or -check in generated bindings or native binaries as a source substitute. +the active Gradle and Cargo build locations, and inspect the result. Never +hand-edit or check in generated bindings or native binaries as a source +substitute. ## Application and security boundaries @@ -88,20 +88,22 @@ keep implementation, tests, generated outputs, dependency evidence, and public behavior aligned while preserving unrelated work. The root `Makefile` is the standalone command surface and its durable behavior -belongs in Gradle or public producer tools. Gradle intentionally requires -`EXT_BUILD_GRADLE_BUILD_DIR`, and native Cargo work requires -`CARGO_TARGET_DIR`; do not bypass extbuild or add repo-local build-output -fallbacks. Run `make doctor` before the first mutating lane, use `make format`, -`make lint`, and `make test` while iterating, and run `make check` for the -complete source checkpoint. Use `make build`, `make bindings`, `make audit`, -`make licenses`, `make package`, and `make release-check` when their affected -artifact or release scope requires them. - -Source-lock synchronization may fetch the exact public revision and package or -advisory lanes may require external services. Do not weaken immutable inputs or -silently switch sources when offline. Never claim a lane passed unless it ran -successfully; report network, toolchain, platform, advisory-service, package, -or external-artifact blockers exactly. +belongs in Gradle or public producer tools. When extbuild is installed, the +Makefile routes commands through it. Without extbuild, Gradle uses its standard +ignored `build/` directories and Cargo uses the ignored `core/target/` tree; +the same checked-in tasks must remain functional. Set `EXTBUILD=` explicitly +to exercise the standalone lane on a machine that also has extbuild. Run +`make doctor` before the first mutating lane, use `make format`, `make lint`, +and `make test` while iterating, and run `make check` for the complete source +checkpoint. Use `make build`, `make bindings`, `make audit`, `make licenses`, +`make package`, and `make release-check` when their affected artifact or +release scope requires them. + +Shared public Git dependencies and package or advisory lanes may require +external services. Do not weaken immutable inputs or silently switch sources +when offline. Never claim a lane passed unless it ran successfully; report +network, toolchain, platform, advisory-service, package, or external-artifact +blockers exactly. Verify exact manifests/lock agreement, generated binding and native artifact freshness when affected, compatibility and architecture guards, diff --git a/Makefile b/Makefile @@ -3,7 +3,7 @@ GRADLE ?= ./gradlew CARGO ?= cargo CARGO_MANIFEST := core/Cargo.toml -EXTBUILD := cargo extbuild run -- +EXTBUILD ?= $(if $(shell cargo extbuild --version 2>/dev/null),cargo extbuild run --) .PHONY: help doctor format format-fix lint test check build bindings dev run audit licenses package release-check clean @@ -11,7 +11,7 @@ help: @printf '%s\n' doctor format format-fix lint test check build bindings dev run audit licenses package release-check clean doctor: - cargo extbuild doctor + $(if $(strip $(EXTBUILD)),cargo extbuild doctor,@:) $(EXTBUILD) java -version $(EXTBUILD) $(CARGO) --version $(EXTBUILD) $(GRADLE) --version diff --git a/app/desktop/build.gradle.kts b/app/desktop/build.gradle.kts @@ -66,13 +66,16 @@ configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> { } } -val extBuildGradleRoot = - providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull - ?: throw GradleException("EXT_BUILD_GRADLE_BUILD_DIR is required; run Gradle through cargo extbuild") +val rustCoreSource = + rootProject.layout.projectDirectory + .dir("core") + .asFile +providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull?.let { extBuildGradleRoot -> + layout.buildDirectory.set(file(extBuildGradleRoot).resolve("app-desktop")) +} val cargoTargetRoot = - providers.environmentVariable("CARGO_TARGET_DIR").orNull - ?: throw GradleException("CARGO_TARGET_DIR is required; run Gradle through cargo extbuild") -layout.buildDirectory.set(file(extBuildGradleRoot).resolve("app-desktop")) + providers.environmentVariable("CARGO_TARGET_DIR").orNull?.let(::file) + ?: rustCoreSource.resolve("target") val radrootsOffline = providers @@ -86,10 +89,6 @@ val immutableCargoArguments = listOf("--locked") } -val rustCoreSource = - rootProject.layout.projectDirectory - .dir("core") - .asFile val rustManifest = rustCoreSource.resolve("Cargo.toml") fun workspacePackageValue(key: String): String { diff --git a/build.gradle.kts b/build.gradle.kts @@ -4,7 +4,6 @@ plugins { alias(libs.plugins.compose.compiler) apply false } -val extBuildGradleRoot = - providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull - ?: error("EXT_BUILD_GRADLE_BUILD_DIR is required; run Gradle through cargo extbuild") -layout.buildDirectory.set(file(extBuildGradleRoot).resolve("root")) +providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull?.let { extBuildGradleRoot -> + layout.buildDirectory.set(file(extBuildGradleRoot).resolve("root")) +}