CONTRIBUTING.md
Rama main · réplica de lectura del repositorio original.
# Contributing to Agronaut
Thanks for being here. Agronaut combines cited aquatic design with farm records and
experimental field irrigation tools. It gets better mainly through two things outsiders can give it:
**real-world data** and **domain knowledge**. You do not need to be an ML engineer. Some of
the most valuable contributions are a CSV, a photograph, or a paragraph with a citation.
**New here? Start with [issues labelled `good first issue`](https://github.com/Rekin226/Agronaut/labels/good%20first%20issue).**
---
## The one thing to understand before you write code
Agronaut has a **trust zone** and everything else.
```
YOU ──▶ agent layer (LLM: collect facts, route, explain)
│ proposes values
▼
validation gate ── rejects bad/uncertain input ──┐
│ typed, validated │
▼ │
aqua_model (TRUST ZONE — pure, tested, cited) │
coefficients ▸ mass balance ▸ sizing ▸ triage ◀────┘
```
`aqua_model/` is the trust zone. Three rules hold there, and CI enforces the first one:
1. **No LLM, no network, no I/O, and no imports from `agent/` or `srcs/`.** A CI job installs
only `pytest pandas Pillow` and asserts `import aqua_model` pulls in no LLM or UI library.
If your change needs one, it belongs in `agent/` instead.
2. **Every number carries a source.** Magic numbers live in `aqua_model/coefficients.py` as a
`Coefficient` with a value, a plausible range, a unit, and a `source`. Functions read the
registry; they never hard-code a number.
3. **Every output says what it does *not* model.** This is the project's credibility, not a
formality. A result that omits its caveats is incomplete.
The agent layer may import from `aqua_model`. **Never the reverse.**
The same boundary applies to the field calculation package, `agro_model/`: keep its
calculations independent of the language model, network, storage, and UI. Cite assumptions
and report missing inputs and unsupported cases. Persistence and orchestration belong in
`agronaut_agent/`; the web views belong in `agent/`.
Field capabilities currently remain experimental. Reference arithmetic and synthetic
workflow tests are useful engineering evidence, but cannot establish field validity.
See [field calculations](docs/FIELD_CALCULATIONS.md) for supported methods and limits and
[the field-cycle rehearsal](docs/FIELD_CYCLE_REHEARSAL.md) for a reproducible workflow.
### The other rule: nothing bypasses the gate
Values proposed by a model — from chat, from a photo, from memory — reach `aqua_model` only
through `validate_design_input` (or a sibling validator). A rejected value is never stored.
If you find a path that gets a model-proposed number into a calculation without passing a
gate, that is a bug worth an issue on its own.
---
## Getting set up
```bash
git clone https://github.com/Rekin226/Agronaut.git
cd Agronaut
python3 -m venv .venv && source .venv/bin/activate
pip install -e . # deps + the `agronaut` command on your PATH
```
Run things:
```bash
pytest # the full suite
pytest aqua_model/tests -q # just the deterministic core (fast, no LLM needed)
pytest agro_model/tests -q # field calculations (no LLM needed)
python -m scripts.safety_eval # the advice-safety golden set; exits non-zero on a CRITICAL failure
streamlit run app.py # the web UI (Calculator + Optimizer need no LLM at all)
agronaut --help # the one command over all of the above
python -m skills.aquaponics_engineer.cli size-aquaponics --help # the portable skill CLI
```
**You do not need an API key to contribute.** The Design Calculator, the Optimizer, the whole
of `aqua_model`, the visual triage table, and the golden set are all fully deterministic. Only
the chat agent needs a model provider.
**On Ubuntu 23.10+, headless-browser QA fails until you allow it.** Chromium dies at startup
with `No usable sandbox!` because the distro restricts unprivileged user namespaces, which
Chromium needs to build its own sandbox. `contrib/apparmor/` has the profile and the reasoning
— including why it is the right fix and `--no-sandbox` is not. Nothing else in this repo needs
it; the suite and the app run fine without.
---
## Ways to contribute, easiest first
### 1. Add a crop or a fish species (no ML, high value)
`aqua_model/crops.py` and `aqua_model/species.py` are cited seed databases. Adding an entry
means finding published values and citing them. Every field needs a source — a paper, an FAO
document, an extension-service guide.
See [#23](https://github.com/Rekin226/Agronaut/issues/23). Bring the citation and we will help
with the plumbing.
### 2. Add a visual-triage rule
`aqua_model/triage.py` maps what you can *see* to a ranked differential. It currently has ~22
rules. Real agronomy has hundreds.
A rule needs: the feature pattern that triggers it, why that pattern implies that cause, the
**checks that discriminate it from its neighbours**, fish-safe first actions, and a `source`
pointing at a file in `knowledge/`. A test asserts every cited document exists.
Two hard constraints, both tested:
- **Never a lone verdict.** If a photo cannot distinguish your cause from another, both are
candidates. That is the whole design.
- **Never a dose.** No dosing coefficient is cited anywhere in the model, so no amount is
ever stated.
### 3. Improve or add a knowledge document
`knowledge/*.md` is the curated, cited knowledge base behind the RAG layer and every triage
citation. Corrections from practitioners are especially welcome — if something in there is
wrong or dangerous, an issue saying so is a real contribution.
### 4. Share real system data
The coefficients are literature seeds meant to be **calibrated** against reality. If you run a
system, your FCR, harvest weights, and yields make the model true rather than plausible.
See [#22](https://github.com/Rekin226/Agronaut/issues/22).
### 5. Donate photographs
The vision path is verified against handwritten test strings, not real photographs, because
`data/vision_corpus/` is empty. Field photos of deficient leaves, sick fish, algae, and
root disease would turn an untested claim into a measured one. Run
`python -m scripts.check_vision_corpus` to see exactly which shots are wanted.
### 6. Code
Pick up a `good first issue`, or open an issue describing what you want to change before
writing a lot of it — especially anything touching the trust zone.
---
## How we work
**Tests come first.** This codebase is test-driven: write the failing test, watch it fail,
make it pass. A PR that changes behaviour without a test that would have caught the old
behaviour will get that asked for in review.
**Small PRs, one concern each.** They get reviewed faster and merged sooner.
**Commit messages explain *why*.** The diff shows what changed; the message should say what
was wrong before. Compare "fix regex" with "the guard's lexicon missed bare imperatives, so
'Add chelated iron' reached the user as if they had written it."
**Say what you did not do.** If you left a case unhandled, note it in the PR. Known and stated
is fine; discovered later is expensive.
**An assigned issue is yours until you say otherwise.** If a maintainer ends up doing an
assigned task anyway — it turned out to be urgent, or larger than the assignment implied —
they say so on the issue, say why, and credit the work already done. Silently landing
something out from under a contributor is the fastest way to lose one.
### AI-assisted contributions
Welcome, and used here too — a good deal of this repository was written with a coding agent.
The bar does not move either way, and it is the bar an agent is most likely to walk past:
- **Open a PR, not a comment.** A patch pasted into an issue thread cannot be run, reviewed,
or merged. If there is no branch, there is no contribution.
- **The files have to exist.** Agents confidently patch plausible paths that this repository
does not have. Check the diff against a real checkout before you post it.
- **Run the tests you claim to have run.** `pytest` and `python -m scripts.safety_eval`, on
your branch, merged with `main`. Do not describe a verification you did not perform.
- **Cite the number or leave it out.** Coefficients need a `source=` string pointing at
published work, and a `low`/`high` envelope. An illustrative or plausible-looking constant
is worse than a missing one: the missing one is visibly missing, and the invented one gets
copied forward for years.
- **You are the author.** Review what your agent wrote before it becomes your PR, and be able
to answer questions about it. "The model produced it" is not an answer in review.
Contributions that fail these are closed and hidden as off-topic, regardless of how they are
formatted. A confident report is not evidence of work.
### Before you open a PR
```bash
pytest # green
python -m scripts.safety_eval # exits 0
```
If you added a rule, a coefficient, or a guard behaviour, add a probe to
`docs/dpg/safety_eval/golden_set.json` so it is scored on every future change. That file is
how this project keeps promises it made months ago.
### Adding an image classifier
`agent/classifier.py` is a finished seam with **no backend** — deliberately. To add one:
1. Register a default model in `DEFAULT_MODELS` and build it in `_build_classifier_backend`,
importing your library **inside the function** so it never becomes a hard dependency.
2. Return `[Prediction(label, confidence)]` or `[(label, confidence)]`.
3. Map any new label vocabulary in `_LABEL_FEATURES` — to **visible evidence**, not to a
diagnosis. `late blight` becomes "brown spots on leaves", never "late blight".
The classifier is a *feature source*. It can add evidence; it can never introduce an uncited
candidate. A test enforces that.
---
## Adding a channel
`agronaut_agent/channels/` holds the adapters. A new one (SMS, USSD, Signal, Matrix, a web
widget) implements `ChannelAdapter` and routes to three seams:
`handle_message`, `handle_image`, `handle_voice`. Everything else — memory, tools, the
observation guard, cited knowledge, follow-ups — comes for free. The Telegram and WhatsApp
adapters are the worked examples.
---
## Reporting bugs and security issues
Bugs: open an issue with what you did, what happened, and what you expected.
**Security or safety:** see [SECURITY.md](SECURITY.md). Advice that could hurt someone's fish
or crop counts as a safety issue, not just a bug — please report it that way.
---
## Licence and conduct
Contributions are under the [MIT Licence](LICENSE). By participating you agree to the
[Code of Conduct](CODE_OF_CONDUCT.md).