Yesterday's feed for House 1 was never recorded. Log it before it becomes a guess.
Log something
🌾
Feeding
4 batches due
🥚
Eggs
House 1 · daily
✖
Mortality
Any batch
⚖
Weights
Sampling day
Today so far
Entries logged3
Feed used7 bags
Feed cost₦105,000
◐
Worker view — you record what happened. Prices, costs and totals are not shown.
Batches in play
BR-2026-07 · broilersday 24
LY-2025-11 · layerswk 61
FSH-2026-02 · catfishwk 14
6:14▮▮ ᯤ ▮
‹
Log feeding
One entry · House 2
Batch
BR-2026-07 · 500 broilers day 24
Feed item
Broiler finisher 50 kg bag
Quantity used
3 bags ▾
= 150 kg · item-scoped conversion, a bag of feed ≠ a bag of maize
Date it happened
Wed 12 Aug 2026 today
Two dates, always
occurredAt12 Aug 06:00
recordedAtserver-set
The farmer owns the first. The database owns the second. Never one field.
6:15▮▮ ᯤ ▮
‹
How sure are you?
3 bags · broiler finisher
⚖ I weighed it
👁 I estimated
Measured
Counted bags or read a scale. Goes into FCR and cost-per-bird at full confidence.
Estimated
A good guess. Still recorded, still costed — but reports will say so, and a stock take will correct the drift.
This batch so far
Measured62%
Estimated38%
!
Above 40% estimated, FCR stops being a number you can act on. Consider a stock take.
POST /farms/:farmId/livestock-logs basis: measured
6:15▮▮ ᯤ ▮
Recorded
BR-2026-07 · feeding
✓
3 bags logged
Broiler finisher · 150 kg · measured
What followed, on its own
Derived
Feed store− 3 bags
Batch cost pool+ ₦45,000
Cost per bird so far₦1,284
You recorded a feeding. The stock movement and the ledger entry wrote themselves.
Derived
Feed store− 3 bags
The rest of what this changed is on the owner's account.
livestock-log→stock-movement+ledger-entry
Both are derived: GET-only endpoints. No client ever POSTs them.
17:40▮▮ ᯤ ▮
‹
Today's eggs
LY-2025-11 · House 1 · 1,143 birds
Collected
31 crates ▾
= 930 eggs · 30 per crate
Cracked / rejected
14 eggs
⚖ Counted
👁 Estimated
Lay rate today
81.4%
Flock is week 61 · expected band 78–84% · on curve
This is not a harvest
Eggs are continuous output from a producing asset. The batch does not close, nothing transfers to COGS, and the flock keeps amortizing.
POST /farms/:farmId/yield-logs
6:30▮▮ ᯤ ▮
‹
Record mortality
Choose the batch first — it changes the meaning
🐔
BR-2026-07 · broilers
Terminal · loss reduces batch stock
a1
🥚
LY-2025-11 · layers
Producing asset · partial asset disposal
a2
🐟
FSH-2026-02 · catfish
Terminal · loss reduces batch stock
a1
Same word, two accounting events
A dead broiler is a WIP loss. A dead layer is a disposal of a capitalized asset — its unamortized value is written off. The farmer types the same number; the archetype decides the posting.
19:02▮▮ ᯤ ▮
‹
Catch up on feeding
FSH-2026-02 · Pond 3
◷
No feed logged for this pond since 29 Jul. That's 14 days.
From
Wed 29 Jul 2026
To
Tue 11 Aug 2026 14 days
Per day
3 bags ▾
⚖ Counted
👁 Estimated
!
Bulk entry is nearly always estimated. Pre-selecting estimated is honest; making the farmer pick it is friction they will resolve by lying.
19:03▮▮ ᯤ ▮
‹
This will create 14 entries
One per day — not one row of 42 bags
29 Jul3 bags
30 Jul3 bags
31 Jul3 bags
… 10 more3 bags
11 Aug3 bags
Total42 bags · 2,100 kg
Grouped
entryGroupIdeg_7fa31c…
All 14 share one group. Correct the group and all 14 reverse together — never one day in place.
Why daily, not one lump
FCR, growth curves and lay % are all rate-per-day. Storing 42 bags on one date puts a spike in every chart and makes the day-14 sampling weight meaningless.
POST /farms/:farmId/livestock-logs/bulk
08:22▮▮ ᯤ ▮
‹
When did this happen?
You're recording on Thursday
Today
Tuesday
Pick date
Recorded 2 days late
occurredAtTue 11 Aug
recordedAtThu 13 Aug 08:22
The feeding counts on Tuesday — that's the day FCR, stock and the ledger use. Thursday is only the audit fact of when it was typed.
And it is flagged
Entries recorded more than 24h after the fact are marked in analytics. Memory-based data drifts in one direction: down.
late entrybasis: estimated
✓
August is still open — this posts normally.
07:48▮▮ ⊘ ▮
‹
No signal
Poultry house · keep working
⊘
Offline. 6 entries waiting. Nothing is lost — they send themselves when signal returns.
Waiting to send
🌾
Feeding · BR-2026-07
3 bags · occurred 06:12
queued
✖
Mortality · BR-2026-07
4 birds · occurred 06:20
queued
🥚
Eggs · LY-2025-11
29 crates · occurred 07:05
queued
💧
Water quality · Pond 3
pH 6.8 · occurred 07:30
queued
Why this works at all
occurredAt is captured on the phone, recordedAt on the server. A queued entry that sends 6 hours later still lands on the right day.
Each carries a key
Every queued entry has an Idempotency-Key minted at capture. Resending is free; the server replays the original response instead of writing twice.
09:31▮▮ ᯤ ▮
Sent
Signal returned at 09:30
↑
5 of 6 entries sent
Each landed on the day it happened, not today.
Feeding · 12 Aug 06:12✓ sent
Mortality · 12 Aug 06:20✓ sent
Eggs · 12 Aug 07:05✓ sent
Water · 12 Aug 07:30✓ sent
Weights · 12 Aug 07:52✓ sent
Feeding · 31 Julneeds you
!
One entry could not be sent. It is still on this phone — nothing was discarded.
09:32▮▮ ᯤ ▮
‹
Two people, one day
Feeding · House 2 · Tue 11 Aug
⚠
Musa recorded feeding for this batch and this day while you were offline.
Yours
3 bags
Captured 06:12 measured
Musa's
2 bags
Captured 06:40 estimated
Not a conflict — a question
Two feedings in one day is normal. Only the farm knows whether these are the same event typed twice or the morning and afternoon rounds.
What happened?
Both are real — keep 5 bags total
Same feeding — keep mine, drop Musa's
Same feeding — keep Musa's, drop mine
◐
Last-write-wins would have silently deleted a real feeding. Never auto-merge farm observations.
09:33▮▮ ᯤ ▮
Already recorded
Harvest · FSH-2026-02
↺
Sent twice, recorded once
The first attempt reached the server before the connection dropped. We replayed its answer instead of creating a second harvest.
What the server did
Idempotency-Keyik_c41a…9b
First response201 · 09:31:04
This responsereplayed
Lots created1 — not 2
Why this is not an edge case
Field data is captured on cheap phones over rural networks. A retried harvest that doubles 640 kg of catfish corrupts stock, COGS and margin at once. The retry will happen; the only question is whether it is safe.
640 kg · catfish · Lot FSH-3-0812
09:34▮▮ ᯤ ▮
July is closed
Feeding · 31 Jul · 3 bags
🔒
This day is locked
July's books were closed on 4 Aug. Nothing can be added to a month that has already been reported.
What that protects
July's profit figure has been seen. If a cost could still slip into it, last month's number would change every time someone caught up on paperwork — and no report could be trusted twice.
PeriodJul 2026
Closed4 Aug · Mrs. Adeyemi
Response409 PERIOD_CLOSED
◐
Your entry is still here. It has not been deleted, and nothing else in the queue was blocked by it.
09:35▮▮ ᯤ ▮
‹
Two ways forward
3 bags · feed · 31 Jul
Recommended · post it to August
The feed was really used in July, but the cost lands in August. Small and honest — the batch total is still right, only the month split moves.
no reopenworker can do thismonth split shifts
Ask the owner to reopen July
Correct to the day, but July's profit changes after it was reported — and every report already run against it is now stale.
owner onlyaudit entryrestates July
The rule underneath
Same rule as a correction: the past is never edited in place. Reopening writes a reversal and a replacement; posting to August writes a fresh entry. Both leave a trail.
◐
As a worker you can only take the first option. Reopening a closed month is the owner's decision.
10:02▮▮ ᯤ ▮
farm-os
Record what happens on your farm. The books write themselves.
Set up my farm
About 3 minutes. You'll record your first entry before you're done.
Look around a sample farm first
A full year of a mixed farm — poultry, fish, maize, a dairy cow. Nothing you type is kept.
I was invited by someone
Enter the code from your WhatsApp message
The sample farm is free
The demo seed already covers all eight enterprise types. Letting someone evaluate before typing a single number costs nothing to build.
seeds/baseline-demo-farm
10:03▮▮ ᯤ ▮
What do you farm?
Pick one to start. Add the rest later.
🐔
Poultry
Birds
🐟
Fish
Ponds or tanks
🌽
Crops
Fields or plots
🐐
Goats, pigs, cattle
Pens or paddocks
✓
You can run all of them. Setting up eight enterprises before recording anything is how people abandon on day one.
What this choice really sets
Location type, log types, metrics, report set — and costingArchetype, the most consequential field in the schema. The farmer will never see that word.
10:03▮▮ ᯤ ▮
‹
What are the birds for?
This changes how we count your money
🍗
Sell them for meat
Broilers, cockerels, turkey
🥚
Keep them for eggs
Layers, breeders
🐣
Both — I raise chicks and sort them
We'll ask again when you sex them
The whole archetype decision, in one question
"Meat" is terminal costing; "eggs" is a producing asset that capitalises and amortises. Ask it as consequence, never as category — a farmer knows what the birds are for and does not know what an archetype is.
◐
Get this wrong and you land on the recovery screen (E11). That path must exist precisely because this choice is invisible.
10:04▮▮ ᯤ ▮
‹
Where do you keep them?
Call it whatever you call it
Name
House 2
House 1Back penÌta Ẹyẹ
Their word, not ours
The system stores a location of type house. The farmer sees whatever they already shout across the yard. Forcing "Poultry House 01" makes every later screen read like someone else's farm.
One place is enough
No map, no hectares, no GPS. Those are commercial-tier fields and asking for them here loses the farm.
✓
Two questions in and nothing irreversible has been asked yet.
10:05▮▮ ᯤ ▮
‹
Tell us about the birds
House 2
How many are in there now
476 birds
When did they arrive
Tue 21 Jul 2026 22 days ago
Today
Some weeks ago
I forget
Nobody starts on day zero
Almost every farm signs up with birds already three weeks old, fish half grown, a field already planted. An onboarding that only accepts "starting today" is wrong for nearly every real user.
Which forces a question
These birds have already eaten 22 days of feed. If we pretend they haven't, the first cost-per-bird you see will be a lie.
10:06▮▮ ᯤ ▮
‹
Spent on them so far?
Chicks, feed, drugs — a rough figure
Roughly
₦ —
I don't know
Fine. We'll mark this flock's costs as incomplete and you can fill it in — or a stock take will settle it.
The wall that kills adoption
Demanding opening balances up front is where farm software loses people. Skipping them entirely makes the first profit figure wrong. "I don't know" is the third option — recorded as basis: estimated, flagged on every derived figure until answered.
Asked again when it matters
Not in a wizard. The first time this farmer opens cost-per-bird, the question comes back — because that is the first moment the answer changes anything.
10:07▮▮ ᯤ ▮
Record something now
House 2 · 476 broilers
✓
Your farm is set up. One entry and you'll have seen the whole loop.
Fed them today?
3 bags ▾
⚖ I weighed it
👁 I estimated
Why the first entry is part of setup
Setup that ends on an empty dashboard has delivered nothing. Setup that ends with a recorded feeding, a reduced feed store and a cost that moved has shown the entire product in one tap.
Target: under three minutes
Farm name → one enterprise → one place → one batch → one entry. Chart of accounts, contacts, workers and cash balances are all deferred, and none of them blocks anything.
10:07▮▮ ᯤ ▮
One thing to know
Shown once, then never again
Measured or estimated
You said you weighed those 3 bags. When you guess instead, say so — nothing is rejected, but your reports will tell you how much of a number is guesswork.
"FCR 1.4 — 62% of feed data estimated" is a useful sentence. "FCR 1.4" alone is not.
Teach at first occurrence, not in a tour
Only two concepts genuinely need explaining: basis, and that fixing a number reverses and reposts rather than overwriting. Each gets one inline moment the first time it happens.
Tours don't survive a poultry house
A five-screen carousel at signup is read by nobody and remembered by no one. The moment of use is the only moment the explanation is cheap.
✓
Feed store down 3 bags. Cost per bird updated. You did that by saying what happened.
10:08▮▮ ᯤ ▮
You're set up
3 minutes, 1 entry recorded
✓
House 2 is live
476 broilers · day 22 · recording daily
When you're ready — not now
🐟
Add your ponds
Or fields, or goats
☺
Invite whoever helps you
They record, they never see money
₦
What you already own and owe
Feed in store, debts, equipment
Deferred, not skipped
Each of these becomes a question in Today at the moment it first matters — not a checklist nagging from day one. Onboarding ends; setup keeps going quietly.
10:10▮▮ ᯤ ▮
‹
Invite Tunde
He records; he sees no money
Phone number
0803 ••• ••••
He can
Record feeding, eggs, mortality✓
Fix his own entries✓
See prices, costs, profit✕
Sell, or close a month✕
His language
English
Yorùbá
Hausa
Chosen by the person inviting
The owner knows. Making the worker find a language setting before they can read the language setting is a loop worth avoiding.
✓
Sends a WhatsApp link. No app store, no password, no account form.
6:02▮▮ ᯤ ▮
T
Morning, Tunde
Ogbomoso Mixed Farm
✓
You're in. Record what you do; that's all.
✓
Feed House 2
Broilers · usually 3 bags
6am
✓
Check for deaths · House 2
Every morning
6am
✓
Collect eggs · House 1
Layers
5pm
Thirty seconds, no setup
He tapped a WhatsApp link and landed on three tasks. No account creation, no tour, no configuration. He never learns the app has a setup surface.
A different product
Same binary, and almost nothing in common with what the owner opened. Worker onboarding is not a shortened owner onboarding — it is its own thing, and treating it as a subset is how it ends up with a farm-creation form in it.
+
◉Today
▦Places
☺Me
19:20▮▮ ᯤ ▮
‹
Cost per bird
BR-2026-07 · day 31
So far
₦742
⚠ Missing the first 22 days
What had you spent before you started here?
Chicks and 22 days of feed for these 476 birds. A rough figure makes this number real.
Enter it
Still don't know
This is the whole design
The question was deferred at signup and returns at the exact moment the answer changes something the farmer is looking at. Now they have a reason to go and find the receipt.
And it is honest until answered
The figure isn't hidden and isn't faked — it is shown with a flag saying what it's missing. Every derived number carries the same flag until the opening balance lands.
◐
Same mechanism as basis: estimated on a log row. Incompleteness is a property you carry, not an error you block on.
6:05▮▮ ⊘ ▮
⊘ Offline · 2 waitingkeep going
T
Today
Wed 12 Aug · 4 to record
✓
Feed House 2
Broilers · day 24 · usually 3 bags
6am
✓
Feed Pond 3
Catfish · usually 3 bags
7am
✓
Collect eggs · House 1
Layers · yesterday 31 crates
5pm
✓
Water quality · Pond 3
Every 3 days · last Sun
due
✓
Mortality check · House 2
4 birds · recorded 6:20
A queue, not a dashboard
Derived from the active batches: what each one expects today. A farmer arrives with one job. Charts are for people who browse.
+
◉Today
▦Places
☺Me
7:30▮▮ ᯤ ▮
A
Today
Ogbomoso Mixed Farm switch
Have they started laying?
PU-2026-03 · 402 pullets · week 18
Yes
Not yet
July is ready to close
All entries in. Closing locks the month.
Review
Later
Being recorded
✓
Feed House 2 · Tunde
3 bags · 6:12
✓
Eggs · House 1
Not yet · usually 5pm
5pm
This month · in₦4,120,000
out₦2,780,000
owed to you₦1,046,500
+
◉Today
▦Places
₦Money
7:31▮▮ ᯤ ▮
‹
Questions for you
2 open · nothing expires
Have they started laying?
Asked every 3 days since week 17. Until you answer, this flock's costs keep piling into one pool.
Yes
Not yet
Pond 3 hasn't been counted since March
5 months of estimated feed. A count would tell you whether FCR 1.3 is real.
Count now
Remind me
Why an inbox and not a notification
A notification that gets swiped is gone. Point of lay would then never be answered, and the whole archetype-2 chain silently never fires. Questions the books depend on need somewhere durable to sit.
Push, never poll
No farmer goes looking for a "capitalize asset" button. The system raises what it needs, on the right week, in the farmer's words — and keeps asking.
◐
This surface has no home in the current 40 modules. It is a real gap, not a UI flourish.
◉Today
▦Places
₦Money
7:34▮▮ ᯤ ▮
Places
7 in use · 2 empty
⌕
Poultry
🥚
House 1
1,143 layers · week 61
laying
🐔
House 2
476 broilers · day 24
growing
🐤
House 4
384 cockerels · week 3
growing
Ponds
🐟
Pond 3
890 catfish · large grade
count due
🐟
Pond 5
1,140 catfish · medium
—
Pond 9
Empty since 4 Aug
Place is the label, batch is the payload
The farmer says "Pond 3". The system means FSH-2026-02. For a smallholder they are 1:1 nearly always, so navigate by place and resolve to the batch.
+
◉Today
▦Places
₦Money
7:36▮▮ ᯤ ▮
‹
House 2
BR-2026-07 · 476 broilers · day 24
FCR
1.61
Died
4.8%
Per bird
₦2,496
Recent
🌾
Feeding · 3 bags
Today 6:12 · Tunde
✖
Mortality · 4
Today 6:20 · Tunde
⚖
Weight · 1.42 kg
9 Aug · sampling
Everything else lives here
stock usedsortingcost poolhistoryclose
Forty modules, three tabs. Allocations, lots, movements and the ledger are reached from a place — never from a nav root. If a farmer must learn that "allocations" exists, the IA failed.
+
◉Today
▦Places
₦Money
7:37▮▮ ᯤ ▮
Log · House 2
Broilers · day 24
Feeding · 3 bags
What you log here most days
1 tap
✖
Mortality
⚖
Weight
💉
Vaccination
✎
Note
One button, not a menu of twelve
The FAB knows where you are and what this batch usually gets. The full log-type list is the fallback, not the front door.
Wet hands, cheap phone, one thumb
The default action is a single tap with a pre-filled quantity. Everything else is a correction away, and corrections are cheap here.
Voice note on any entry
Cheapest accessibility win available. A worker who reads slowly can still say "two birds limping in the corner".
7:40▮▮ ᯤ ▮
Money
August · open
Profit this month
₦1,340,000
In₦4,120,000
Out₦2,780,000
But not in your hand
Owed to you₦1,046,500
You owe₦412,000
In stock, unsold₦2,190,000
◫
Cash book
Day by day, in and out
◷
Who owes me
4 buyers · 1 overdue
▤
For a lender
Formal statements, on demand
◐
This tab does not exist for a worker. Their third tab is Me — their own entries, their language, their pending sync.
◉Today
▦Places
₦Money
18:02▮▮ ᯤ ▮
T
Tunde
Worker · Ogbomoso Mixed Farm
This week
Entries recorded47
Days complete5 of 6
Measured, not guessed81%
⊘
Waiting to send
2 entries · sends on signal
⚙
Language
English · Yorùbá · Hausa
↺
My entries
Fix something I typed wrong
No money, anywhere
Not a hidden section — it is not in this build of the screen at all. A worker's app is a different app that happens to share a binary.
Their own numbers, though
Entry count and measured-share are the worker's performance in terms they control, and the only feedback loop that improves data quality.
◉Today
▦Places
☺Me
7:44▮▮ ᯤ ▮
‹
Search
basira
☺
Iya Basira
Customer · owes ₦133,000
₦
Sale · 180 kg catfish
12 Aug · ₦333,000
₦
Sale · 12 baskets tomato
28 Jul · ₦114,000
↺
Correction · weight dispute
13 Aug · 180 → 171 kg
The escape hatch
One field resolving contacts, batches, places and entries. Everything a three-tab structure necessarily hides is reachable in one field — which is what makes three tabs defensible.
Not a nav root
Search lives in the header, not the tab bar. Tabs are for where you go daily; search is for the once-a-week question.
7:46▮▮ ᯤ ▮
Switch farm
You manage 2
Ogbomoso Mixed Farm
7 places · 7 batches · you are owner
Ilorin Fish Farm
4 ponds · 3 batches · you are owner
What follows you across both
contactsstock itemsaccountsgrading standards
Iya Basira buys fish from one and maize from the other. She is entered once for the business, not per farm.
What does not
Everything operational — places, batches, logs, sales, the ledger. Switching farms changes the whole app below the header.
tenantId from JWT · never in a path
!
Most smallholders have one farm and must never see this control. It appears only when a second exists.
11:04▮▮ ᯤ ▮
‹
Fix an entry
BR-2026-07 · last 7 days
Search entries…
🌾
Feeding · 3 bags
12 Aug · measured · Tunde
₦45,000
🌾
Feeding · 50 bags
10 Aug · measured · Tunde
₦750,000
✖
Mortality · 4 birds
10 Aug · counted · Musa
—
⚖
Weight sample · 1.42 kg
9 Aug · measured · Tunde
—
!
50 bags in one day for 500 birds is 5 kg per bird. Flagged automatically — an outlier check at capture time would have caught this on the 10th.
11:05▮▮ ᯤ ▮
‹
Feeding · 10 Aug
Change it to what really happened
Quantity used
15 bags ▾
was 50 bags · 750 kg
Date it happened
Mon 10 Aug 2026
Why
Typed 50, meant 15
This reads like an edit
It should. The farmer's mental model is "change the number". What the system does underneath is not their problem — but it must never be a lie about what the books now say.
◐
A reason is required on corrections and optional on entries. It is the only field in the app that exists purely for the audit trail.
11:06▮▮ ᯤ ▮
‹
What this changes
50 → 15 bags · 10 Aug
Feed store
On hand now18 bags
After correction53 bags
Batch BR-2026-07
Cost pool₦1,284,000₦759,000
Cost per bird₦2,588₦1,530
FCR to date3.1 1.8
And in the books
Original entry stays
10 Aug · 50 bags · never deleted
A reversal is written
10 Aug · −50 bags
A replacement is written
10 Aug · 15 bags
◐
Three rows, one visible change. Reports run against last week still reproduce exactly what they said last week.
11:06▮▮ ᯤ ▮
Corrected
Feeding · 10 Aug
✓
Now reads 15 bags
Stock, cost per bird and FCR were all recomputed.
Feed on hand53 bags
Cost per bird₦1,530
FCR to date1.8
On the record
Corrected by Mrs. Adeyemi · 13 Aug 11:06 Reason: "Typed 50, meant 15"
3 ledger rowsimmutable
✓
August is open, so this lands on 10 Aug where it belongs. Had July been the month, you would be on the locked screen instead.
11:20▮▮ ᯤ ▮
‹
This is part of a group
Feeding · 3 Aug · FSH-2026-02
⚯
This entry was created by a 14-day bulk entry on 11 Aug. It has 13 siblings.
The group
29 Jul – 11 Aug14 entries
Per day3 bags · estimated
Total42 bags · 2,100 kg
Cost₦630,000
What do you want to change?
The whole group — the rate was wrong for all 14 days
Reverses 14, reposts 14
Just this day — 3 Aug was different
Still reverses all 14 and reposts 14, one of them changed
◐
Both paths reverse the entire group. The difference is what gets reposted — not whether the group survives.
11:21▮▮ ᯤ ▮
‹
All 14 days will change
3 bags/day → 2 bags/day
Was
42 bags
₦630,000
Becomes
28 bags
₦420,000
Mechanically
Reversals written14
Replacements written14
Rows now in the log42
Rows that count14
A group is corrected as a unit because it was asserted as a unit. Editing one day of a fortnight's guess pretends to a precision that was never there.
Pond 3 · what moves
Feed store+ 14 bags
FCR1.9 1.3
Cost per kg₦985₦712
!
An FCR of 1.3 for catfish is suspiciously good. A correction this large should prompt a stock take, not just a recompute.
11:32▮▮ ᯤ ▮
That entry is in July
Purchase · NPK · 22 Jul
🔒
July closed on 4 Aug. A correction dated 22 Jul cannot be written.
The entry
20 bags NPK₦320,000
Should be₦280,000
Difference₦40,000
Two honest options
Recommended · adjust in August
Post a ₦40,000 credit dated today. July stays as reported; the ₦40,000 is corrected in the month it was discovered — which is what a supplier credit note does anyway.
July unchangedno reopen
Reopen July and restate
Only worth it if July's number has consequences — a loan application, a co-op payout, a partner's share.
owner onlyrestates a reported month
11:34▮▮ ᯤ ▮
‹
Entry history
Feeding · BR-2026-07 · 10 Aug
Recorded · 50 bags
10 Aug 06:40 by Tunde · measured
log_9c2f · active until 13 Aug
Reversed · −50 bags
13 Aug 11:06 by Mrs. Adeyemi
reverses log_9c2f
Replaced · 15 bags
13 Aug 11:06 · "Typed 50, meant 15"
log_a13d · current
Why keep the wrong number
Because someone acted on it. Feed was ordered against a 3.1 FCR. The trail is how you find out that a bad decision came from a typo rather than a bad bird.
Also visible here
Every correction to this batch · who · when · why. This screen is what a lender or a co-op auditor is actually asking for when they ask "are these books real".
07:10▮▮ ᯤ ▮
‹
New sale
Market day · Wed 12 Aug
Buyer
Iya Basira trader
What are you selling
Catfish · Lot FSH-3-0812 640 kg on hand
Quantity
180 kg
Price per kg
₦1,850
Total₦333,000
Cost of this stock₦212,400
Margin₦120,600 · 36%
◐
Margin is shown before the sale is saved. A farmer selling below cost should find out at the point of decision, not in a monthly report.
◐
Workers can record that stock left the farm, but not at what price. This screen is owner/manager only.
07:12▮▮ ᯤ ▮
‹
Sold in baskets
Stocked in kg
Quantity
12 baskets ▾
Price per basket
₦9,500
Converted for stock
12 baskets= 288 kg
Basket of tomatoes24 kg
Conversions are per item. A basket of tomatoes is 24 kg; a basket of pepper is 18 kg; a bag of maize is not a bag of NPK. One global unit table would be wrong within a week.
Where this bites
Farmers buy in bags, feed in kg, sell in baskets, and quote prices in all three. If the app forces one unit, the numbers get converted in someone's head — and that is where the losses hide.
Total₦114,000
Leaves stock288 kg · Grade A
stock-items/uomConversions · item-scoped
07:15▮▮ ᯤ ▮
‹
Who bought it?
Roadside sale · 8 crates of eggs
Recommended · walk-in
Records the sale with no buyer. Cash in hand, nothing owed, nobody to chase.
Pick an existing contact Iya Basira · Kola Foods · Mr. Danjuma
Add a new contact Name and phone — nothing else required
!
Forcing a contact on every sale is how farm apps get abandoned. Most sales are cash to a face you'll never name.
But the moment it's credit
A buyer becomes mandatory the instant payment is anything other than paid-in-full. You cannot chase a debt owed by nobody.
Contacts are tenant-level
Iya Basira buys from your fish pond and your maize field. She is entered once for the whole business, not per farm.
/api/v1/contacts · roles[]: customer | supplier
07:18▮▮ ᯤ ▮
You don't have that
Catfish · you entered 900 kg
⊘
640 kg on hand
Selling 900 kg would put your fish stock at −260 kg.
Stock cannot go negative
Not a warning — a hard stop. A negative balance makes cost-per-kg meaningless and quietly poisons every margin figure downstream.
409 INSUFFICIENT_STOCK
Which of these is true?
Sell what I have — 640 kg ₦1,184,000
I harvested more than I recorded Log the harvest first, then sell
This is a forward sale Take payment now, deliver after the next harvest
◐
The third is common and must not be blocked — it is a customer deposit, not a sale. Money in, no stock out, nothing recognised as revenue yet.
07:20▮▮ ᯤ ▮
‹
How were you paid?
180 kg catfish · ₦333,000
Cash
most used
Paid in full, in hand
Bank transfer
Opay · Moniepoint · bank app
Part now, part later
She pays some today, owes the rest
All on credit
Goods leave now, money comes later
Credit is the default in this market
Traders take stock in the morning and pay after they sell. An app that treats credit as an exception will be used for half the sales and abandoned for the other half.
One thing does not vary
The sale is recorded either way. Revenue and stock movement happen on delivery; the payment is a separate record that may arrive weeks later — or in three pieces.
sale→payment→payment→settled
07:22▮▮ ᯤ ▮
‹
How much today?
Iya Basira · ₦333,000 total
Paid now
₦200,000
Cash
Transfer
Split
Balance
₦133,000
owed by Iya Basira
Expected by
Sat 15 Aug 2026 3 days
Her record
Previous balance₦0
Last 6 salesall settled
Average days to pay4
✓
Payment history is shown at the moment of extending credit, not buried in a contact screen. This is the only time it changes a decision.
07:23▮▮ ᯤ ▮
Sale recorded
Iya Basira · 180 kg catfish
✓
₦200,000 received
₦133,000 due Sat 15 Aug
What wrote itself
Fish stock− 180 kg
Money in+ ₦200,000
Owed to you+ ₦133,000
Cost of what left₦212,400
Profit on this sale₦120,600
Behind it, unseen
Four balanced journal lines and one stock movement. The farmer sees money in, stock out, profit. Dr/Cr never reaches this screen — but a lender can be handed a trial balance from the same rows.
sale+payment→stock-movement+ledger-entries ×4
16:40▮▮ ᯤ ▮
She paid less
Expected ₦133,000 · received ₦120,000
Expected₦133,000
Received₦120,000
Short by₦13,000
What is this?
Part payment — she still owes ₦13,000
Debt stays open, aging continues
Agreed discount — settle it at ₦120,000
₦13,000 comes off revenue, debt closes
Weight was short — the sale itself was wrong
Corrects the sale, not the payment → reverse and repost
!
These three look identical in the bank app and are three different things in the books. Guessing on the farmer's behalf is how receivables become fiction.
16:45▮▮ ᯤ ▮
She paid more
Expected ₦133,000 · received ₦150,000
✓
Debt cleared
₦17,000 extra is held on her account.
Settled first, asked second
The debt closes immediately. Never hold a settled account hostage over an excess — the farmer's question is "are we square?" and the answer is yes.
The extra ₦17,000
Hold as credit — goes against her next purchase
Return it — cash or transfer back
She rounded up — keep it as extra revenue
Not the same as revenue
Held credit is money you owe her, not a sale. Booking it as income inflates this month's profit and understates next month's.
08:02▮▮ ᯤ ▮
‹
Who owes me
Total out: ₦1,046,500
0–7 days8–3030+
!
Mr. Danjuma
Maize · 62 days overdue
₦264,000
30+
◷
Kola Foods Ltd
Eggs · 3 deliveries · 19 days
₦325,500
8–30
◔
Iya Basira
Catfish · due Sat
₦133,000
0–7
◔
Alhaji Sule
Broilers · due Mon
₦324,000
0–7
The number that actually matters
Your profit this month is ₦1,340,000. ₦1,046,500 of it is in other people's pockets. Cash-book and profit answer different questions, and a farmer who only sees profit will run out of money while "doing well".
15:12▮▮ ᯤ ▮
‹
Money received
Kola Foods Ltd · ₦200,000
◐
They owe ₦325,500 across 3 deliveries. Which does this cover?
Recommended · oldest first
14 Jul · 40 crates₦108,000 ✓
28 Jul · 34 crates₦91,800 ✓
06 Aug · 47 crates₦200 of ₦125,700
Let me choose — they named an invoice
Just reduce the total — don't match deliveries
Why allocation is not cosmetic
Aging drives whether you keep supplying. Dumping ₦200,000 against "the balance" makes a 62-day debt look 3 days old and hides exactly the customer you should stop extending credit to.
18:20▮▮ ᯤ ▮
Buyer disputes the weight
Iya Basira · 180 kg catfish · 12 Aug
Her claim
"Market scale said 171 kg, not 180."
What you recorded
Quantity180 kg
Basisestimated
Recorded byTunde · 07:20
!
Your own record says estimated. That is the single most useful field in this screen — it tells you whether to argue.
Resolve
Accept 171 kg Correct the sale: reverse and repost at 171 kg. 9 kg returns to stock, revenue drops ₦16,650.
Split the difference Discount, not a quantity change. Stock stays at 180 kg out.
Hold the line Record the dispute against her contact; debt stands.
Two different corrections
A quantity dispute changes stock and revenue. A price dispute changes revenue only. Collapsing them into "adjust the amount" silently loses 9 kg of fish.
06:50▮▮ ᯤ ▮
‹
Moving animals
FSH-2026-02 · Pond 3 · 2,640 fish
Split
permanent
One group becomes several — size grading, sexing, separating for sale
Move
reversible
Same group, new place — hospital pen, better house, they come back
Merge
permanent
Several small groups become one
This is processing, for living things
Same shape as grading a harvest: inputs, a criterion, several outputs, losses, and a cost that has to follow. The difference is that fish can be moved back, and that handling them kills some.
input=Σ outputs+losses
Why a plain "split" endpoint fails
It cannot express a temporary move, cannot carry handling mortality, cannot merge, and cannot change what a batch is — which sexing does.
06:55▮▮ ᯤ ▮
‹
Size grading
Pond 3 → three ponds
◐
Grading now stops the big ones eating the small ones. Left ungraded, this pond loses 8–12% to cannibalism.
Criterion
Size class weight ▾
Outputs
Pond 3 · large890
> 800 g · stays put · harvest in 3 wks
Pond 5 · medium1,140
400–800 g
Pond 7 · small572
< 400 g · 6 wks behind
In2,640
Out2,602
Unaccounted38
!
38 fish are missing from the arithmetic. The next screen is not optional.
06:58▮▮ ᯤ ▮
‹
What happened to 38 fish?
Grading always costs some
Died during handling
38 fish
In2,640
Out2,602
Losses38
Balanced✓
What the sorting cost
Labour
₦18,000
Nets / ice
₦4,500
Losses and cost belong on the operation
Exactly as waste and packaging sit on a processing run. Handling mortality is caused by the sort — attributing it to the pond's background death rate hides that grading day was rough.
1.4% handling loss
Tracked per sorting operation and per worker. Under 1% is careful; over 3% means the net, the timing or the hands need attention.
07:01▮▮ ᯤ ▮
‹
Splitting the cost
₦1,880,000 accumulated in Pond 3
The parent's cost pool
Fingerlings₦360,000
Feed to date₦1,412,000
Labour, treatment₦108,000
Total₦1,880,000
Split by
Head count
Biomass
Pond 3 · 890₦670,972
Pond 5 · 1,140₦859,289
Pond 7 · 572₦431,161
Sums to₦1,880,000 ✓
The last naira has to land somewhere
₦1,880,000 ÷ 2,602 does not divide evenly. Money.allocate() distributes the remainder deterministically so the children always sum to the parent — no rounding dust, no silent loss.
!
By head count, a 300 g fish carries the same cost as a 900 g fish. By biomass is truer for grading — and it changes cost-per-kg by up to 40%. This choice is a policy, not a default.
07:04▮▮ ᯤ ▮
The numbers don't meet
Pond 3 grading
≠
61 fish unaccounted
2,640 in · 2,579 out · 0 losses entered
Mass balance is a hard rule
Input must equal outputs plus losses. Not a warning to dismiss — an operation that doesn't balance would create or destroy stock, and every cost-per-kg after it would be wrong.
422 MASS_BALANCE_VIOLATION
Which is it?
61 died during handling Recorded as a sorting loss — 2.3%
I miscounted an output Go back and fix the numbers
The pond had fewer than we thought Prior mortality was under-reported → post a stock take
◐
The third is the most common and the most valuable. Sorting day is the one day you actually count a pond, which makes it the natural moment to reconcile months of estimates.
09:30▮▮ ᯤ ▮
‹
Sexing day-olds
CH-2026-09 · 800 chicks
Criterion
Sex vent sexing ▾
Pullets → House 1410
Female · will lay from ~18 weeks
Cockerels → House 4384
Male · sold for meat at ~10 weeks
Handling losses6
800 in794 out + 6 lost ✓
!
These two groups are not two versions of the same thing. They are accounted for differently for the rest of their lives.
09:33▮▮ ᯤ ▮
One batch, two destinies
Confirm before splitting
Parent · CH-2026-09
Costingterminal a1
410 pullets → continuous
Cost keeps building until point of lay, then the flock becomes a producing asset and amortizes over its laying life. Eggs are revenue against it.
a2 · continuousbiological asset
384 cockerels → terminal
Cost builds until slaughter, transfers to inventory, becomes cost of sales when sold. No asset, no amortization.
a1 · terminalinventory
Why this screen exists
A split that could not reassign costingArchetype would force both halves down one path. Book the pullets as inventory and 17 months of egg sales read as pure profit, with a catastrophe at cull.
Not a setting — a moment
This is the only place a farmer is ever asked about costing, and they are not asked in those words. They are asked "which of these will lay?"
14:10▮▮ ᯤ ▮
‹
Move to hospital pen
BR-2026-07 · 22 birds
From → to
House 2 → Hospital pen
Reason
Coccidiosis · under treatment
↩ Temporary
Permanent split
Still the same batch
No new batch, no cost split, no new cost pool. The 22 birds are located elsewhere and are expected back.
Batch count476 · unchanged
In House 2454
In hospital pen22
Why a permanent split would be wrong
It creates a second batch with its own cost pool, its own FCR and its own close — and then you have to merge it back, which loses the stocking date. A sick bird is not a new enterprise.
Treatment cost
Medication and extra labour post to the parent batch, not to the pen. The pen is a place, not a cost object.
08:15▮▮ ᯤ ▮
‹
Bring them back
Hospital pen · 6 days · BR-2026-07
Moved out22 birds · 12 Aug
Died in the pen3
Returning19
Reversal, with an amendment
The move reverses — the 19 survivors rejoin House 2 and the batch's location record closes. The 3 deaths are ordinary batch mortality, not a sorting loss: nothing about the move killed them.
Treatment recorded against the batch
Medication₦12,400
Extra labour · 6 days₦9,000
Cost per bird+ ₦45
◐
Reversibility is the whole reason move is a distinct operation. Modelled as split-then-merge, this batch would come back with the wrong stocking date and a cycle-day off by six.
11:40▮▮ ᯤ ▮
‹
Merge three ponds
Tail-end stock into Pond 5
Pond 7 · 140 fish₦96,400
stocked 14 Mar · day 151
Pond 9 · 208 fish₦171,900
stocked 02 Apr · day 132
Pond 11 · 96 fish₦61,300
stocked 21 Apr · day 113
Result · Pond 5
Fish444
Cost pool₦329,600
Cost sums cleanly. Money is fungible; ₦96,400 plus ₦171,900 plus ₦61,300 is simply the new pool.
!
Dates do not sum. Three stocking dates, three cycle-days — and the merged batch can only have one.
11:42▮▮ ᯤ ▮
Which age is the batch?
14 Mar · 02 Apr · 21 Apr
Recommended · oldest
Stocked 14 Mar · day 151. Harvest planning stays conservative and nothing is ever younger than it looks.
safe for harvest timingflatters FCR
Weighted by count
Effective stocking 29 Mar · day 136. Truest for FCR and growth-rate maths; harder to explain to the person feeding the pond.
Start a new cycle
Day 0, today. Honest that the merged group is a new thing, but throws away five months of growth history.
Make it explicit or it becomes a bug
Whatever the default, the merged batch must record which rule was applied. Six weeks later, "why is FCR 1.1?" has no answer without it.
batch.mergeRule · oldest | weighted | reset
!
The most common real answer is "these are all roughly the same size now" — which is why merging is usually preceded by grading, not by arithmetic.
08:00▮▮ ᯤ ▮
Batches
Ogbomoso Mixed Farm · 7 active
🐔
BR-2026-07 · broilers
House 2 · 476 birds · day 24
a1
🐤
PU-2026-03 · pullets
House 1 · 402 birds · week 17
a2
🥚
LY-2025-11 · layers
House 3 · 1,143 birds · week 61
a2
🐟
FSH-2026-02 · catfish
Ponds 3/5/7 · 2,602 · week 14
a1
🌽
MZ-2026-01 · maize
Field A · 2.4 ha · day 78
a1
🌿
CS-2025-04 · cassava
Plot C · 1.1 ha · month 11
a1 · spans
🐄
Amina · NG-041
Barn · lactation 3 · day 120
a3
Three ways to cost a living thing
a1 terminal→ inventory
a2 continuous→ asset, amortized
a3 breeding→ asset, produces assets
The farmer never sees this word. They chose "broilers" or "layers" at setup and the archetype came with it.
08:04▮▮ ᯤ ▮
‹
BR-2026-07
500 broilers · House 2 · day 24 of ~42
Alive
476
Mortality
4.8%
FCR
1.61
Cost pool · not yet an expense
Chicks₦350,000
Feed₦742,000
Vaccination, labour₦96,000
Cost per bird₦2,496
Why this is not "spending"
₦1,188,000 has left the bank but it has not hit profit. It is sitting in the birds. It becomes a cost only when they are sold — which is why a farm can look unprofitable all month and fine on harvest day.
FCR is 62% estimated
Two weeks of feed came from bulk entry. The number is directionally right and not worth arguing over to two decimals.
06:30▮▮ ᯤ ▮
‹
Harvest BR-2026-07
Day 43 · 471 birds
Birds
471
Total weight
1,036 kg
Creates a lot
LotBR-7-0912
IntoLive bird inventory
Average weight2.20 kg
The transfer that ends the batch
Cost pool₦1,712,400
Moves toinventory
Cost per kg₦1,653
WIP→inventory→COGS on sale
This is archetype 1, entire
One harvest, and the batch is over. Every cost it ever absorbed is now carried by 1,036 kg of meat, waiting to be sold.
◐
Nothing is recognised as profit yet. Unsold birds are stock, not income — the most common place farm software lies to a farmer.
18:00▮▮ ᯤ ▮
Batch closed
BR-2026-07 · 43 days
Final
Revenue · 1,036 kg₦2,382,800
Cost of sales₦1,712,400
Profit₦670,400
Per bird
₦1,423
FCR
1.68
Died
5.8%
Against your last flock
FCR1.81 1.68 ✓
Mortality7.2% 5.8% ✓
Profit per bird₦1,180₦1,423
Close is a guard, not a button
A batch will not close with stock still assigned, an unbalanced cost pool, or logs dated after the close. Closing is the assertion "nothing more will be said about this flock".
08:20▮▮ ᯤ ▮
‹
PU-2026-03
402 pullets · House 1 · week 17
◐
These are the pullets from the sexing split. They have been eating for 17 weeks and have produced nothing.
Week 17 of ~18 to point of lay
Rearing cost so far
Share of parent batch₦318,000
Feed · 17 weeks₦1,864,000
Vaccination, labour₦158,000
Per bird₦5,821
If nothing happens at week 18
This cost keeps piling into a pool that only empties at cull, 17 months from now. Every month of egg sales would show as pure profit, and the final month as a ₦2.3m disaster.
So something must happen
Not automatically — nobody can compute point of lay from a calendar. It has to be observed and told.
06:40▮▮ ᯤ ▮
Have they started laying?
PU-2026-03 · week 18 · House 1
🥚
Pullets usually come into lay between week 17 and 20. We'll keep asking until you say yes.
Yes — first eggs collected
Even a handful counts. Point of lay is a threshold, not a rate.
Not yet Ask me again in 3 days
They started earlier Pick the date it actually began
The most important screen in the app
This one prompt is the difference between correct books and nonsense for the next 17 months. If it does not exist, capitalizationService never fires and the layer flock stays mis-costed forever.
Push, never poll
A farmer will not go looking for a "capitalize asset" button. The system must raise it, on the right week, in the farmer's language — "have they started laying?"
06:42▮▮ ᯤ ▮
They're a laying flock now
PU-2026-03 → LY-2026-03
🥚
402 birds · in lay
18 weeks of rearing cost just became an asset.
What moved
Rearing pool₦2,340,000
Becomesbiological asset
Cull value at end₦482,400
To spread over lay₦1,857,600
Spread over
Productive life14 months
Per month₦132,686
An estimate, and revisable. If the flock lays for 16 months the schedule is re-spread — not back-dated.
Not inventory
The birds are not the product any more. The eggs are. The flock is a machine that makes them, and it wears out.
rearing WIP→asset→amortize→residual
09:00▮▮ ᯤ ▮
‹
LY-2026-03 · September
Month 3 of lay · 397 birds
Lay rate
88%
Crates
349
The month, honestly
Egg sales₦1,396,000
Feed₦742,400
Labour, medication₦86,000
Flock wearing out₦132,686
Profit₦434,914
Without the fourth line
Profit would read ₦567,600 — 30% too high, every month, for fourteen months. Then a single month would swallow ₦1.86m at cull.
"Flock wearing out"
Amortization, in words a farmer already uses. The birds are 3 months closer to being spent, and that has a price whether or not anyone writes it down.
3 of 14 months of productive life used
07:30▮▮ ᯤ ▮
‹
Cull the flock
LY-2026-03 · month 14 · 361 birds
◷
Lay rate fell to 61% and feed cost per crate is above the market price of a crate. Time.
Where the asset stands
Capitalized₦2,340,000
Amortized · 14 mo₦1,857,600
Carrying value₦482,400
Sold as spent hens
361 birds × ₦1,450₦523,450
Carrying value₦482,400
Gain on disposal₦41,050
A small number, and that is the point
Cull month is ordinary. All the cost was recognised while the eggs were being sold. If cull month is dramatic, the flock was mis-costed for a year.
39 birds short
400 at point of lay, 361 at cull. Each death along the way wrote off its share of carrying value — a partial asset disposal, not a WIP loss.
05:40▮▮ ᯤ ▮
‹
Amina · NG-041
Lactation 3 · day 120 · Barn
This morning
8.4 L
Daily avg
14.2 L
One animal, not a group
Amina is her own record: her calvings, her lactations, her yield curve, her sire. Averaging her with the herd hides the only question that matters — is she worth keeping?
batch.trackingMode = individual
Her economics
Feed · this lactation₦486,000
Milk sold · 1,704 L₦1,022,400
Her share of wear₦74,000
Margin per litre₦271
And archetype 3 on top
Amina also produces assets. Her heifer calf is either capitalized into the herd or moved to inventory for sale — a decision, taken at birth, that the herd reconciliation depends on.