app

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

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.