AGENTS.md (12969B)
1 # AGENTS.md — HarvestCircle 2 3 These instructions apply to the complete standalone HarvestCircle repository. 4 A more specific `AGENTS.md` may refine them for its subtree. 5 6 ## Repository role and source boundary 7 8 This repository owns the public HarvestCircle desktop product: the 9 Kotlin/Compose presentation shell, desktop lifecycle, client-side state, 10 generated UniFFI integration, host packaging, product-specific Rust core, and 11 their tests. The Rust workspace under `core/**` owns HarvestCircle application, 12 domain, runtime, persistence, Nostr-adapter, preference, native FFI, and UniFFI 13 binding-generator implementation. 14 15 HarvestCircle remains a client of canonical public Radroots library packages. 16 It does not own shared Radroots identity, transport, signing, wire-contract, or 17 other reusable library policy. Product-specific Rust code must live in this 18 repository and may depend on the exact public Radroots library revision selected 19 by the capsule; it must not depend on an implicit sibling checkout. 20 21 Product-owned names use the HarvestCircle identity consistently: 22 23 - Human-facing product name: `HarvestCircle`. 24 - Rust crate directories, Cargo packages, and dependency keys: 25 `harvestcircle_*`. 26 - Kotlin source namespace: `org.harvestcircle`. 27 - Product-owned Kotlin and UniFFI types: `HarvestCircle*`. 28 - Product-owned environment variables: `HARVESTCIRCLE_*`. 29 30 These product-specific names are intentionally distinct from canonical shared 31 `radroots_*` library packages, Radroots service terminology, and Radroots 32 corporate or vendor identity, which retain their existing names. 33 34 The repository must remain independently cloneable, buildable, testable, and 35 packageable through its checked-in command surfaces with or without extbuild. 36 It must not depend on private parent code, parent-only contracts, unpublished 37 local artifacts, absolute host paths, or an enclosing monorepo layout. 38 39 ## Machine authority and generated inputs 40 41 - `core/Cargo.toml`, `core/Cargo.lock`, `core/rust-toolchain.toml`, 42 `radroots.lib.source-lock.v1.toml`, and the product crates under 43 `core/crates/**` own the Rust workspace inputs. 44 - Gradle settings, build scripts, the version catalog, wrapper properties, 45 policy configuration, and `config/product/harvestcircle-v1.properties` own 46 the desktop build, dependency, product-coordinate, and package inputs. 47 Kotlin and Rust source and tests are implementation evidence. 48 - `gradlew`, `gradlew.bat`, and `gradle/wrapper/gradle-wrapper.jar` are 49 checked-in command implementation and supply-chain inputs, not policy 50 authority. Review them with `gradle-wrapper.properties`; keep the launcher, 51 distribution URL/version, and distribution checksum aligned, and never 52 replace the wrapper binary without explicit provenance review. 53 - Keep every shared Radroots dependency on the canonical public Git source, 54 one exact immutable revision, and the declared exact version. The manifests, 55 lockfile, compatibility baseline, and generated native package metadata must 56 agree. 57 - Never use a path dependency, floating branch or tag, private mirror, 58 implicit sibling override, dirty source cache, or unrecorded native binary. 59 Local product crates are workspace path dependencies; shared Radroots 60 packages remain immutable public Git dependencies. 61 - The repository retains only concise standalone governance and operational 62 guidance in `README.md`, `NOTICE`, `CONTRIBUTING.md`, `SECURITY.md`, 63 `LICENSE`, and `LICENSES/**`. Authoritative product specifications, 64 decisions, reviews, handoffs, and qualification evidence are owned by the 65 consuming Radroots monorepo under `docs/oss/harvestcircle/**` and must not be 66 required to build or test this standalone source tree. All `docs/**`, 67 `spec/**`, `.github/**`, and `.act/**` paths are forbidden here. Local 68 workflow orchestration belongs to the consuming monorepo's governed 69 `.act/**` surface and must call this capsule's standalone Make targets. 70 71 Generated UniFFI Kotlin and native libraries are derived build output. Change 72 the local canonical Rust producer contract/generator first, regenerate into 73 the active Gradle and Cargo build locations, and inspect the result. Never 74 hand-edit or check in generated bindings or native binaries as a source 75 substitute. 76 77 ## Application and security boundaries 78 79 - Product state is bound only through `radroots_runtime_paths::RuntimeContext` 80 for service `harvestcircle` and instance `desktop`; the canonical database 81 and lock names are `state.sqlite` and `state.lock`. Fresh state initializes 82 at schema v1 and is migrated through the pinned current schema v3 before host 83 exposure; `radroots_service_sqlite` owns the governed SQLite mechanics. 84 - Public listing-version evidence retains exact verified original wire and first 85 named provenance independently of installed accounts or local signing custody. 86 The global public payload meter admits at most 4,096 versions and 120 MiB of 87 ordinary growth within its 128 MiB total; 8 MiB remains reserved for recovery. 88 Charges are logical payload bytes. Duplicate IDs preserve first evidence 89 without growth; no automatic eviction or recovery bypass is exposed. 90 - The durable-operation journal records terminal completion time, retains 91 terminal receipts for exactly seven days, admits at most 1,024 unfinished 92 operations and 4,096 total rows, and deletes no more than 256 expired terminal 93 rows in one transaction. Admission reserves terminal capacity in the same row 94 and must never evict an in-window receipt. 95 - `harvestcircle.sqlite3` is legacy evidence only. Never delete, rename, 96 import, dual-read, dual-write, or otherwise treat it as current state. 97 - SQLx is the only high-level SQLite library. HarvestCircle may use its sealed 98 application-schema callback inside `radroots_service_sqlite` initialization, 99 but must not create another pool, expose a raw connection, or reintroduce 100 Rusqlite, Refinery, arbitrary repair, or a second migration authority. 101 - Storage bootstrap requires the injected runtime context's canonical state 102 root to exist. `RuntimeContext::state_directory_plan` is the only production 103 authority allowed to create the exact `services/harvestcircle/desktop` 104 suffix. `ServiceSqliteHost::open_or_initialize` alone selects create versus 105 existing state under one retained writer authority and returns the actual 106 verified database metadata. Do not probe paths, recursively create roots, 107 repair permissions, or open a raw SQLx connection during bootstrap. 108 - Native production qualification is limited to macOS aarch64 and Linux 109 x86_64. Do not add or claim another target without an explicit contract 110 change and its complete platform evidence. 111 - Keep Compose screens and stores as client presentation and orchestration. 112 Do not make them a source of truth for accounts, identities, approvals, 113 domain objects, synchronization, reconciliation, or publication state. 114 - Private keys and signing operations remain behind the generated native 115 boundary. Kotlin must handle opaque identifiers and bounded public DTOs; it 116 must not persist, log, fixture, or expose raw secret material. 117 - Recovery and backup operations must be explicit, user-initiated, bounded, 118 fail closed, and keep sensitive material out of logs, crash text, analytics, 119 filenames, and long-lived UI state. 120 - Backup and restore must use the sealed HarvestCircle wrappers over Lib's 121 capture, verify, stage, finalize, and marker-recovery protocol. Verification 122 requires a trusted manifest digest, current database identity, and positive 123 caller-supplied member limit; never accept an arbitrary replacement path. 124 - Clipboard writes of sensitive output require explicit user action, bounded 125 lifetime, ownership-aware clearing, and tests for cancellation and 126 replacement. Never clear unrelated clipboard content. 127 - Native library loading must verify the generated artifact, platform/ABI, 128 compatibility baseline, and exact source provenance before application use. 129 Do not search ambient library paths or silently fall back to another binary. 130 - Keep lifecycle and coroutine work structured, cancelable, and scoped. Avoid 131 hidden workers, process-global mutable state, unbounded retries, blocking UI 132 work, and external mutation inferred from environment state. 133 - Relay parsing, destination policy, DNS admission, and connection ownership 134 come from the pinned `radroots_transport_nostr` boundary. Product code may 135 select a governed profile and verify product events, but must not recreate 136 relay URL policy or open a second production `nostr-sdk` client. 137 - The native host owns its Tokio runtime for exactly one application-core 138 lifetime. Runtime close is explicit, idempotent, and cancellation-resumable; 139 observer work and the bounded keyring worker must finish before terminal 140 close is reported. `SecretStore` is an object-safe asynchronous application 141 port. Every caller awaits it, Tokio workers await one-shot results, and only 142 the dedicated credential thread may drive the blocking platform adapter. 143 Authoritative locks fail closed on poison. The worker queue remains fixed at 144 eight, mutations carry the canonical UUIDv7 durable request identity, queued 145 cancellation has no effect, started caller loss is recovery-required, and 146 shutdown succeeds only after join within the fixed 30-second bound. Native 147 creation is create-only (`SecKeychainAddGenericPassword` on macOS and Secret 148 Service `replace=false` on Linux); exact same-operation replay verifies the 149 complete zeroizing credential envelope before it is accepted as idempotent. 150 - Services-hardening changes use the approved target-state contracts. Do not 151 add compatibility aliases, dual reads, dual writes, or fallback behavior for 152 prototype surfaces removed by the clean-slate refactor. 153 154 ## Change and command rules 155 156 Inspect status, all relevant manifests and locks, compatibility inputs, Gradle 157 tasks, native generation logic, source, tests, and package 158 configuration before editing. Make one coherent, reviewable change at a time; 159 keep implementation, tests, generated outputs, dependency evidence, and public 160 behavior aligned while preserving unrelated work. 161 162 The root `Makefile` is the standalone command surface and its durable behavior 163 belongs in Gradle or public producer tools. Standalone targets never invoke or 164 probe extbuild, even when it is installed. Explicit `governed-*` targets run a 165 green extbuild doctor and route the same underlying commands through extbuild. 166 Gradle otherwise uses its standard ignored `build/` directories and Cargo uses 167 the ignored target trees. Run `make doctor` before the first standalone 168 mutating lane and `make governed-doctor` before a governed lane. Use `make 169 format`, `make lint`, and `make test` while iterating, and run `make check` or 170 `make governed-check` for a complete source checkpoint. The active development 171 milestone is qualified with `make governed-development-check` on macOS aarch64 172 and `make governed-linux-x86_64-development-check` for the faithful Linux 173 x86_64 lane. These development targets must retain source, runtime, generated, 174 API, source-lock, SQLx-topology, and offline license/source verification without 175 activating advisory retrieval, package assembly, release evidence, signing, 176 notarization, Nix, or OCI work. Signing, notarization, and release targets are 177 governed-only and require a separately declared release candidate and fresh 178 authority. Unknown build modes fail before build mutation. 179 180 Shared public Git dependencies and deferred package or advisory lanes may 181 require external services. Do not weaken immutable inputs or silently switch 182 sources when offline. During the active development milestone, do not run or 183 claim the deferred release integrations merely because they remain available 184 as explicit targets. Never claim a lane passed unless it ran successfully; 185 report network, toolchain, platform, or external-artifact blockers exactly. 186 187 Verify exact manifests/lock agreement, generated binding and native artifact 188 freshness when affected, compatibility and architecture guards, 189 license/source policy, zero forbidden roots, `git diff --check`, and final 190 status and diff. Parent local-`act` proof is integration evidence only: it must 191 execute, and never replace, the standalone repository validation commands. 192 193 ## Git and external gates 194 195 Use focused commits in the established `<scope>: <imperative summary>` style. 196 Do not reset, discard, rewrite, push, tag, sign, publish, deploy, package for 197 distribution, change signing/notarization identities, or rotate credentials 198 without the corresponding explicit authority. 199 200 The change is complete only when it is implemented at the correct desktop or 201 public producer boundary, the relevant standalone lanes are green, locks and 202 generated evidence are fresh, forbidden roots remain absent, and final review 203 finds no secret exposure, private dependency, stale native artifact, hidden 204 domain authority, or unreported skipped lane.