# Prototype recipes

> Four narrow product patterns for field monitoring, offline scouting, signal change alerts, and boundary review.

Human-readable version: https://agsemble.com/docs/guides/recipes

## Field monitor

Use one field summary for the initial screen, then refresh granular weather or earth-observation endpoints only when that card needs newer data.

```ts
const fields = await agsemble.fields.list({ limit: 20 });
const summaries = await Promise.all(
  fields.data.map((field) => agsemble.fields.summary(field.id)),
);

for (const summary of summaries) {
  renderWeather(summary.components.weather);
  renderNdvi(summary.components.earth_observation);
}
```

## Offline scouting

Create the observation ID and persist the complete record in SQLite before sending. A lost connection becomes a queued state, not an error that destroys the note.

```ts
const observation = {
  id: `obs_${crypto.randomUUID().replaceAll("-", "")}`,
  field_id: fieldId,
  type: "scouting_note" as const,
  note,
  captured_at: new Date().toISOString(),
};

await localQueue.insert(observation);
await agsemble.observations.create(observation, {
  idempotencyKey: observation.id,
});
```

## Field signal change watch

Store the previous normalized value in your own product, compare it with the latest summary, and show the exact rule that fired. Treat a threshold crossing as a review prompt, not a diagnosis.

```ts
const summary = await agsemble.fields.summary(fieldId);
const currentNdvi = summary.components.earth_observation.data?.indicator.mean;

if (currentNdvi != null && previousNdvi != null) {
  const change = currentNdvi - previousNdvi;
  if (change <= -0.15) {
    queueReview({ fieldId, change, rule: "NDVI change <= -0.15" });
  }
}
```

## Field boundary change review

Start from a user drawing, GeoJSON import, or satellite-derived suggestion. Require human review, save provenance, and compare durable versions without treating the boundary as cadastral truth.

```ts
const updated = await agsemble.fields.update(fieldId, {
  geometry: reviewedGeometry,
  boundary: {
    determination_method: "auto_imagery",
    confidence: modelConfidence,
    source: { provider: "Fields of the World", version: "2025-alpha" },
  },
});

const history = await agsemble.fields.boundaries(updated.id);
```
