Inspiration

I met Dr. Josie Seydel, a medical herbalist, while traveling. She started telling me everything she found broken about the modern medical system — and honestly, I pushed back. I'm scientific by default, and "herbal medicine" set off every skeptic alarm I have.

Then she convinced me with the research, and one idea reframed everything for me: a huge share of modern drugs are built from a single isolated compound originally found in a plant. Isolate that one molecule, strip it from everything it grew alongside, and you often get a sharper effect — but also sharper side effects. The whole plant, with its full spectrum of compounds working together, tends to act more gently. Aspirin from willow bark, metformin's lineage to French lilac, morphine from the poppy — we took the molecule and threw away the context.

That cracked the problem open. The knowledge of which plants help with what is real, often centuries deep, and increasingly backed by research — but it's scattered across traditions, buried in unsourced folklore online, and impossible to act on. Existing tools don't help: plant-ID apps tell you what a plant is from a photo; herb encyclopedias assume you already know what you're looking for. Nothing goes from your condition and your location to a trustworthy, sourced answer.

So we built the opposite of the folklore swamp — a tool where the citation is the product. When I told Josie what I wanted to build, her reply was the green light: "I've never heard of anything like this — I would use it." She named the exact three things she'd need — plant images, contraindications, and ethical-gathering guidance — and that became our spec.

What it does

Pick a condition (sleep, anxiety, inflammation, digestion, skin) and optionally share your location. WildCraft:

  1. Matches medicinal plants from a curated, sourced corpus, ranked by evidence tier.
  2. Filters to what grows near you using real GBIF occurrence data (e.g. ~6,870 valerian occurrences near London).
  3. Renders a cited, safety-first guide per plant: the contraindication block comes first and overrides tradition, then efficacy grouped by tradition (Western, Ayurveda, TCM, Unani, Indigenous) — each with a source link and an evidence-tier badge — plus an at-risk "harvest ethically" flag and real ID images.

The one principle we refused to break:

Safety overrides tradition, always. No claim renders without a (source, citation, tradition, evidence_tier) tuple. We say "traditionally used to…" — never "treats" or "cures." Not medical advice.

That rule isn't a disclaimer — it's enforced in code. A single gate, isRenderable(), drops any claim missing both a source and a citation before it can reach the UI.

How we built it

The matching agent is a small, legible loop: take a condition (plus optional $\text{lat}/\text{lng}$), select sourced plants, and compose a summary where every sentence is backed by a claim. Ranking blends evidence quality with geographic availability:

$$ \text{score}(p) = w_e \cdot \underbrace{\tau(p)}{\text{evidence tier}} \;+\; w_g \cdot \underbrace{\mathbb{1}[\,d(p,\,\text{user}) < r\,]}{\text{grows near you}} \;-\; w_s \cdot \underbrace{\sigma(p)}_{\text{safety penalty}} $$

where $\tau(p)$ is the highest evidence tier among a plant's claims, the geographic term fires when GBIF occurrences fall within radius $r$ of the user, and $\sigma(p)$ demotes plants carrying serious interaction or toxicity flags so they never lead a result.

The stack:

  • Reference build — Next.js 14 (App Router) + TypeScript + Tailwind, deployed on Render. Every sponsor adapter is fail-soft: the app runs with zero keys, printing a hint instead of crashing.
  • Production consumer site — a TanStack Start app (Vite + React + Tailwind v4 + shadcn/ui), built with Nitro to Cloudflare Workers.
  • LLMPioneer (Anthropic-compatible) composes the safety-first summaries. To save credits during the build, we routed bulk code-gen through a zero-dependency agentic coding harness we wrote ourselves.
  • Data1,050 plants in ClickHouse, ~252 medically annotated with structured claims and safety, queried at build time and baked into the bundle.
  • ObservabilityLangfuse traces every forage run: forage-request → per-plant span → generation with token usage, with non-leaky inputs ({condition, located} — never raw coordinates).
  • Senso / cited.md publishes the public discovery index so other agents can find us.

Challenges we ran into

  • The double-/v1 ghost bug. @anthropic-ai/sdk appends /v1/messages itself, so its base URL must be https://api.pioneer.ai (no /v1) — while @ai-sdk/anthropic only appends /messages, so its base URL must include /v1. Get it backwards and you get /v1/v1/messages → 404 → a silent fallback to template summaries that looks like it works. Same provider, opposite config, in two files. We only caught it by tracing a forage in Langfuse and noticing the model was never actually called.
  • A stale data-generation mapping defaulted family, blurb, lookalikes, alternatives, and illness_tags to empty — even though ClickHouse had them populated (family on 1,048/1,050 rows). The DB was fine; our mapping was throwing the richness away.
  • Broken filter chips. Catalog filters used spaces ("insect bites") while the data used hyphen slugs ("insect-bites") — so every chip matched zero plants. We rebuilt the chip vocabulary to derive from the real tag set and canonicalized near-dupes (digestion → digestive, wound-healing → wounds).
  • Honesty bugs. Early UI showed a fabricated "N 47°36 · 142 species nearby" before any location was shared. For a product whose entire pitch is trust, that had to die — location claims now appear only after you actually share your location.
  • "Live data" can lie. A mid-build DB check confidently reported 9,185 rows / 1,279 named. Ground truth was 1,050 rows, 116 named. Trust the query, not the summary of the query.

Accomplishments that we're proud of

  • Provenance enforced at the type level — the "no source, no render" gate means the safety principle can't rot as features pile on. Every later feature inherited it for free.
  • Six sponsor tools live end-to-end, not stubbed: Pioneer, ClickHouse, Langfuse, Render, and Senso/cited.md.
  • A real, validated wedge — a practicing UK herbalist saw it and said she'd use it, and we shipped the exact three features she asked for.
  • Name backfilling at scale — only 116 of 1,050 plants had common names. We backfilled via GBIF vernacular lookup with frequency ranking, fixed 12 junk Wikidata-Q-id "names," and reached 963 named, with graceful fallback to the Latin binomial.
  • We resisted over-engineering — nearly stood up a runtime ClickHouse path before realizing the existing build-time bake was faster, simpler, and already correct. We deleted the idea.

What we learned

  • Provenance is an architecture decision, not a content decision. Putting the gate at the type level is why the safety rule survived a frantic hackathon.
  • Anthropic-compatible ≠ identical. Two SDKs, same provider, opposite base-URL rules — the kind of thing that costs an hour and teaches a lifetime.
  • Structured-output mode isn't universal. Pioneer doesn't support generateObject, so we fell back to generateText + manual JSON parse + Zod validation. Less magic, more reliable.
  • Silent fallbacks are the enemy of trust. A failure that looks like success is worse than a crash.

What's next for WildCraft

  • A daily "WildCraft Steward" agent that re-verifies every claim against its source and watches GBIF for availability drift.
  • A fastino GLiNER2 ingest microservice to extract entities from herbal monographs at scale.
  • A seasonal "in-season near you" digest.
  • Leaning into the app's quiet second life as a data-collection instrument — the community-anecdote feature compounding into a real research corpus over time.

Built With

Share this project:

Updates