Inspiration
Twice now, I've stood in a store aisle looking at food that was about to expire — still perfectly good, just too close to its date to stay on the shelf much longer — and thought about how absurd it is that this happens constantly, everywhere, while people go hungry. It's not that anyone is being careless. Store managers are running a business; they don't have the time or the tooling to figure out, item by item, what should be donated, what should be discounted, and who to call. The food that could feed someone just becomes shrink, because redirecting it is a repetitive coordination task nobody has bandwidth for.
That's the gap EdiFlow tries to close: take that exact repetitive task; check what's expiring, decide where it should go, get it there, and hand it to an agent that runs it in the background, so "too busy to sort this out" stops being the reason good food gets thrown away.
What it does
EdiFlow watches a store's short-dated inventory and acts on it automatically. Items with 0–5 days left get matched to a nearby food pantry, checked against real capacity and refrigeration constraints, and dispatched to a volunteer for pickup. Items with 6–10 days left get published as a discounted flash-sale listing that neighbors can browse and reserve immediately. The store owner's entire job is to let it run.
How I built it
This is the first agent I've built, so a lot of the early work was less about the food-rescue domain and more about learning what an agent framework actually gives you. I used the Strands Agents SDK to wrap an Amazon Bedrock model with a set of tools — fetching inventory, matching pantry capacity, dispatching volunteers, publishing flash sales, and reading unpackaged goods (like a bakery tray or a produce crate) out of a photo using Bedrock's vision capabilities.
One decision I made early and kept coming back to: the classification that decides where food goes — 0–5 days, 6–10 days, or excluded, is a plain, deterministic Python function, not something I ask the model to figure out. The agent gets handed an already-computed route plan and executes it through tools; it doesn't decide the expiry math itself. Everything downstream of that: the FastAPI backend, the Supabase (Postgres) persistence layer, the Next.js frontend with separate store and resident workspaces, the HMAC-signed webhook trigger with rate limiting and idempotency, and the deployment path to Amazon Bedrock AgentCore Runtime — was built to support that one boundary: the agent should have real autonomy over how to execute a rescue, but not over the safety-relevant judgment of whether something is still routable.
Challenges I ran into
- Learning what "agentic" actually means. My first instinct was to just prompt a model well and call it an agent. It took building this to understand that wrapping a model in a framework like Strands is what actually makes it agentic — giving it tools it can choose to call, in a loop, rather than a single prompt-response pair. That distinction shaped almost every other decision in the project.
- Deciding what not to hand to the model. Once I understood tool-calling, the harder problem was figuring out where to draw the line — food routing has a real-world consequence if it's wrong, so I had to actively resist giving the agent more judgment than it should have, even though it would have been easier to just let it "figure out" the routing from the prompt.
- Concurrency and idempotency. This was my first time building request signing, replay-window verification, rate limiting, and idempotency keys for real — and my first time reasoning carefully about race conditions, like two residents trying to reserve the last unit of a flash-sale listing at the same time. I ended up pushing that guarantee down into a Postgres function so the database itself enforces it, rather than trusting application code to get there first.
- Scope, as a solo build. Balancing a genuinely working two-sided product (store side and resident side) against the time available meant a lot of the surrounding integrations — real POS/IMS connectors, real SMS dispatch to volunteers — are still demo adapters behind interfaces built to be swapped out later, rather than fully real yet.
Accomplishments that I'm proud of
- Getting a working agent end to end for the first time, with tool use I actually understand rather than copied from an example.
- Keeping the one decision that matters most for safety, routing by expiry, out of the model's hands entirely.
- Making the reservation flow race-condition safe instead of just hoping it wouldn't come up in a demo.
What I learned
Building this taught me the difference between a model and an agent: a framework like Strands doesn't just format prompts, it gives the model a decision loop and a toolbox, and that changes what you have to design around — not just "what should I ask it," but "what should I let it decide versus what should I compute for it ahead of time." I also learned a lot I hadn't touched before outside of an agent context: signing and verifying webhook requests, designing for idempotent retries, and pushing correctness guarantees into the database instead of the application layer.
What's next
- Real POS/IMS adapters (Shopify, Square, Odoo) behind the existing swappable interface.
- Actual SMS/WhatsApp delivery to volunteers for dispatch offers, rather than just a persisted dispatch record.
- Real distance-based matching for pantries and residents, instead of the current nearest-active-pantry heuristic.
Built With
- amazon
- amazon-bedrock
- amazon-bedrock-agentcore
- docker
- fastapi
- next.js
- python
- react
- strands-agents-sdk
- supabase-(postgres)
- typescript
Log in or sign up for Devpost to join the conversation.