Build Cal AI

KINDAreplaces $9.99/mosaves $119.88/yrback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A private photo food log whose hard problems are presenting an estimate honestly when the published error is tens of percent, making the correction step the centre of the interface rather than a dialogue nobody opens, and learning a personal calibration from corrections without pretending it is precision.

estimated effort weekendthe files for this build are in the project pack

RuntimeA small web application installed to the phone home screen, served on your own networkStorageSQLite beside the app, with photographs on disk, nothing in anyone else's cloudEstimationOne call per photograph to a multimodal model, with structured output and validationPresentationRanges everywhere, never a single number, with the model and date attachedCorrectionAn edit step that cannot be skipped, storing what you changed

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the application on the machine that serves your phone.

    Get it nodejs.org, or your version manager. open ↗

    Verify node --version prints v22 or higher

  2. API keypay per image; a few meals a day is small change, and the ceiling in this build is what stops it becoming otherwise

    Why The estimate is one call per photograph, and this is the only part of the build that leaves your machine or costs money.

    Get it Create a key with the provider you prefer and set a spend limit in their console.

    Verify One photograph returns valid structured output

  3. have readyfree

    Why The whole design stands or falls on the capture being two taps, and that is only testable on the device you will actually use at dinner.

    Get it Open the app on the phone and add it to the home screen.

    Verify Two taps from the icon produce a stored photograph

  4. have readyfree

    Why The camera will not open on an insecure origin from another device, which is the single most common reason this kind of build stalls on day one.

    Get it A local certificate authority for your network, or a hostname with a real certificate pointed at the local address.

    Verify The phone opens the app without a certificate warning and the camera works

  5. decidefree

    Why The literature is clear that the error is large and directional, and deciding presentation rules afterwards means deciding them from whatever looked nicest.

    Get it Write down that ranges are mandatory, that the middle value is never shown alone, and what the minimum correction count for calibration is.

    Verify All three rules appear in the README and are asserted in tests

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- meals(id, at, photo_path, note, model_id, prompt_version, raw_response_json, api_cost_minor, state)
- items(id, meal_id, name, grams_low, grams_mid, grams_high, kcal_low, kcal_mid, kcal_high, protein_g, carbs_g, fat_g, confidence, source) · source is model, edited or manual
- corrections(id, item_id, field, model_value, user_value, at) · the record of every time the estimate was wrong, which is the only calibration data that exists
- calibration(period_start, period_end, n_items, median_ratio, iqr_low, iqr_high) · computed from corrections, shown with its sample size or not shown
- targets(id, kind, value, set_at, hidden) · optional, and hideable, because a target is not a requirement
- settings(photo_retention_days, monthly_cost_ceiling_minor, numbers_hidden, model_id)
- Every displayed figure carries a low and a high. There is no column anywhere in this schema holding a single authoritative calorie value.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
MODEL_API_KEYsecretrequiredsk-...redactedThe multimodal model. Give it a provider-side spend limit as well as the ceiling in this app.
MODEL_IDrequireda multimodal model identifierStored with every meal, because a different model gives different numbers.
DATABASE_PATHrequired./data/food.dbMeals, items, corrections and calibration. Back this up; the photographs matter less.
PHOTO_DIRrequired./data/photosMeal photographs. Deleted after the retention period, rows retained.
PHOTO_RETENTION_DAYSrequired30How long pictures of your meals are kept. Shorter is a reasonable default.
MONTHLY_COST_CEILINGrequired5.00Estimation stops at this figure for the month and manual entry continues.
CALIBRATION_MIN_CORRECTIONSrequired40Below this, no calibration figure is shown at all.

The build, in order

  1. A camera that opens, and a meal that stays yours

    Photographing a meal takes one tap and nothing leaves the machine except the model call.

    1. This number decides whether the app survives the first week.

      Files src/app/page.tsxsrc/components/Capture.tsx

    2. A phone photograph is several megabytes of detail the model does not use.

      Files src/components/Capture.tsx

    3. The camera will not open otherwise, and this trips everyone once.

      Files docs/lan-setup.md

    done when · tick each as it passes
    watch out
    • A capture flow that takes three taps and two seconds is abandoned by the fourth day, which is the actual reason paid trackers win, so any friction you add here costs more than any accuracy you gain elsewhere. Measure the taps from opening the app to a stored photograph and keep it at two.
  2. An estimate that arrives as a range

    The model returns items with low, middle and high values, validated, and never invented on failure.

    1. The range is the honest output of this measurement.

      Files src/lib/estimate.tssrc/lib/schema.ts

    2. Never fabricate a number when the response did not parse.

      Files src/lib/estimate.tstests/estimate.test.ts

    3. So a strange estimate can be explained rather than argued about.

      Files src/lib/meals.ts

    done when · tick each as it passes
    watch out
    • Asking for one number per food and displaying it produces an interface that looks like a scale reading, and people then plan around a figure whose published error on mixed meals runs into the tens of percent. Ask for a range, store all three values, and let the interface have no way of showing the middle one on its own.
  3. The correction step is the product

    Confirming a meal means editing what the model got wrong, and the edit is recorded.

    1. An edit step people can skip is an edit step people skip.

      Files src/app/confirm/page.tsx

    2. That is where the energy a photograph cannot see is hiding.

      Files src/app/confirm/page.tsx

    3. It is the only data you will ever have about your own errors.

      Files src/lib/corrections.tstests/corrections.test.ts

    done when · tick each as it passes
    watch out
    • Saving the estimate straight to the log with an edit button somewhere afterwards means nobody ever edits, and the log fills with numbers that the published evidence says are biased downwards and get worse as the plate gets bigger. Put the edit between the photograph and the log, and ask about oil and sauce by name because that is where the missing energy is.
  4. Calibration from your own corrections

    The app learns how wrong it usually is for you, and says so with the sample size.

    1. Old corrections describe an older diet and an older model.

      Files src/lib/calibration.tstests/calibration.test.ts

    2. A ratio from eight corrections is a rumour.

      Files src/lib/calibration.ts

    3. Stored numbers are what the model said and what you said.

      Files src/lib/meals.ts

    done when · tick each as it passes
    watch out
    • Quietly multiplying future estimates by a factor learned from a dozen corrections produces numbers that look better and are not, because the factor was fitted on the meals you happened to correct and those are the ones that looked wrong. Display the calibration with its sample size, let the user decide whether to apply it, and never fold it into a stored value.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more wellness.