Three ways your
team shows up.
Every interaction with your AI workforce falls into one of three patterns. Pick a tab to see each one.
Your team starts work before you do.
Each morning, your three proactive agents β Maya, Kai, and Ava β are already on it. Without a prompt, a click, or a calendar invite.
Maya begins her inventory scan π Maya
She walks through every product in your store, compares stock to your reorder thresholds, and makes a note of anything running low or about to oversell. If you've turned on "Let Maya decide", she first checks with Kai how fast each product is selling and flags it by days of cover against your supplier's lead time instead.
Ava starts her morning brief π Ava
She pulls yesterday's activity from each specialist on your team, picks out what matters, and writes you a three-line summary β plus one suggested action.
Your brief lands on your phone
One Telegram message. Coffee in hand. You know what happened overnight before you open a single tab.
It just happens. No servers to manage, no settings to keep up to date β your team shows up every morning, on time.
Technical detail β how the daily rhythm runs, for agent architects
maya_shop_settings.dailyScanTime, Kai's snapshot at kai_shop_settings.snapshotTimeLocal (default 07:00, 5-min poll), and the specialist snapshot workers ~30 min before the owner's brief time. The first brief is held until the day after Telegram is connected β the connection-day brief and its snapshot are suppressed (compared in the shop's timezone) so Ava's welcome message is the owner's first contact, not a brief on an empty relationship. The brief time and on/off are changeable from the dashboard or straight from chat β just tell Ava "send my brief at 7:30" or "turn off the morning brief" and confirm; she checks the new time still leaves room for Maya's scan and Kai's snapshot beforehand.agent_memory; maya-scan-worker records a DailyMemo; kai-snapshot-worker upserts kai_snapshots.SpecialistReport (runJimDailySummary / runSarahDailySummary / runMayaDailySummary / runKaiAnalyticsSummary) and makes exactly one Claude Sonnet call per shop β no tools, worker concurrency 4. Ava writes it in the owner's preferred_language (falling back to the store-wide shops.language when none is set) and briefing_structure.When you message your team.
Type in chat or Telegram. The right agent picks up β and asks you before changing anything. Replies are concise by default (the answer first, no padding); you can switch the whole team to a more balanced or detailed style anytime in Settings β Response style.
They remember what you tell them
Every teammate keeps a short memory of your standing preferences β just tell them in chat, or add, edit, and remove items yourself on each agent's page in the dashboard. They apply what they remember when answering you and when doing their own work. (Sarah's preferences shape the tone and sign-off of customer replies and any offer you've authorized β never the facts, which always come from your real order data.)
Language works the same way. You pick the language your team speaks when you sign up (and can change it anytime in Settings) β every agent replies in it. Want just one teammate in a different language? Tell that agent on Telegram; it'll ask whether the change is just for them or for everyone, then remember it. A per-agent choice always wins, so you can run the whole team in English but have Kai answer you in French.
You can also set how your team frames things. There's a store-wide messaging style in Settings: keep it standard, or switch it to sales-led, where every teammate leads with the revenue angle and ends with the next move that grows sales β restock a best-seller before it sells out, prioritise a high-value order, nudge a popular pairing, win back a lapsing customer. It changes the emphasis of what your team says, never what they can actually do, and the numbers always come from your real store data.
They also build up a picture of your store over time. Beyond the standing preferences above, your team keeps a short, growing set of notes about how your store actually behaves β recurring issues and how they were solved, what worked (a discount, a supplier swap), busy seasons, supplier quirks, common customer questions. Each night a quiet background routine reviews the day and updates these notes; the next day your team starts already knowing the context, instead of asking again. They look a note up only when it's relevant to your question, and they treat it as background β never acting on an old note without checking the live data first. You can switch this off anytime in Settings (next to the thinking-level control); it's on by default.
Who picks up the phone?
Technical detail β routing & the approval gate, for agent architects
ManagerRouter), which picks Ava or a hired specialist β biased toward conversational continuity, with an explicit domain rule per specialist: Jim for order-fulfilment writes, Kai for analytics (including hypothetical "what would you recommend if X?" framings), and Maya for inventory, product/catalog (including creating brand-new products β "add this product to the store"), supplier, and reorder asks β including supplier purchase-order emails like "send an order request to Tom", which used to slip through to Ava because she has no email tools (as did add-product asks, until the catalog rule was added). A brief interim handoff line is shown in the customer's language.guardrailLevel ladder enforced at runtime:ALWAYS_ALLOWED reads & lookups Β· CONFIRM_USER small actions Β· OWNER_APPROVAL store-mutating / refunds / customer email Β· BLOCKED never.
approval-interceptor.ts) catches the tool_use, persists a pending_approvals row with a paraphrased summary, and asks the owner β only a yes executes the real tool. CONFIRM_USER and OWNER_APPROVAL are intercepted identically. If an approved action can't be completed (e.g. the store rejects it), the agent doesn't just say "failed" β it reads the real error, explains in plain language why it didn't work, and tells you what it needs or offers an alternative.approve / cancel / unclear. Anything that isn't a clean yes or cancel (e.g. "yes but use UPS") supersedes the pending approval with a fresh proposal.pg_advisory_xact_lock, keyed on conversation id) serialises turns; every executed write lands one or more action_log rows that power Recent Activity. Web β API calls carry a short-lived Bearer JWT.When something happens, your team tells you first.
You don't have to ask. Ava, Maya, Kai, Jim, and Sarah all start conversations on their own β they watch your store (Jim watches your deliveries, Sarah watches your support inbox) and ping you with the news, plus a draft or action you can approve in one tap.
Maya catches it before you do
Before the order goes out
Jim spots a stuck parcel
Ava introduces your team
π Kai β analytics Β· π Maya β inventory Β· π¦ Jim β shipping.
Tap a teammate to say hi:
π Meet Kai π Meet Maya π¦ Meet Jim Ask me anything
Ava tells you when free credit lands
Each teammate introduces itself when you tap "Meet"
Want to meet the rest of the team, or ask me something?
π Meet Kai π Meet Maya Ask me about your orders
They point you to the obvious next move
Tip: connect Google Analytics and I can break down traffic sources, conversion, and per-channel performance β not just Shopify's own sales. Connect it here β
Ava sums up the morning
Kai spots a trend before it hurts
Sarah works the inbox
Technical detail β the proactive triggers, for agent architects
orders/create (oversell check) and inventory_levels/update (threshold check). Each webhook route verifies β enqueues β returns 200 fast; a separate worker drains the queue and sends one message per event (a discrete, actionable thing happened), deduped via Redis SET β¦ NX EX 86400 keyed on (shop, type, variant, tz, day) so the same SKU doesn't ping twice. The daily scan works differently: it does not send its own message. It records the day's findings (so they land in your morning brief) and quietly queues each reorder draft for approval behind the scenes β then stops, leaving the news to Ava's brief a few minutes later. That mirrors Kai's daily run and stops a separate "good morning, you're low onβ¦" Maya message from arriving right before a brief that already covers it. (For the webhooks to fire, Maya's subscriptions have to exist on your store β they're set up when you hire her and now re-checked on every Shopify reconnect and on startup, so a hiccup can't quietly switch the real-time alerts off.)kai_snapshots β kai-analyst-worker (Claude Sonnet, scores insights 1β5) β kai_insights β kai-proactive-worker. Runs once daily (full analysis) plus an intra-day tripwire every tripwireIntervalHours (default 4): the tripwire computes the cheap snapshot and a deterministic gate (evaluateTripwire) only fires the Sonnet analyst when revenue / orders / conversion / sessions move past tripwireThresholdPct (default 15%) vs the prior 24h β quiet ticks cost zero LLM and write nothing. The daily full run does not ping Telegram β its insights are delivered by the daily brief that runs minutes later β so only the intra-day tripwire (and owner-initiated manual runs) send proactive pings, and then only for severity β₯ proactiveSeverityThreshold (default 3); everything else waits for the brief, and analyst-side dedupe means a persistent dip pings once, not every check. The message itself is plain-language (friendly severity tag + headline + suggested actions) β the insight's internal evidence fields are never dumped into it. The daily run also includes a deterministic bought-together pass (no Claude, no tokens): it mines persisted order line items for products frequently purchased together and raises a low-severity bought_together insight for a strong pair β a bundling/cross-sell prompt that flows through the same feed + brief, and pairs with Maya's bundles.fulfillments/create and fulfillments/update (carrier-driven status transitions: failure / attempted-delivery / delivered). Each route verifies β enqueues onto jim-event-queue β returns 200 fast. Because the absence of progress never arrives as a webhook, a daily safety-net scan (jim-scan-queue, fanned out per shop alongside the pre-brief snapshots) re-reads recently-shipped orders and catches the quiet failures: shipped with no tracking past a grace window, a label stuck pre-transit, or a parcel stalled in transit. Both detectors run the same pure rule set (evaluateDelivery over Shopify's shipment_status), dedupe per (fulfillment, flag) in agent_memory so the same parcel pings once, and deliver one message per problem through jim-proactive-queue (Claude prose, deterministic fallback). It works from Shopify's own shipment status β which only some carriers populate β so an opt-in carrier-API fallback (per-shop carrierTrackingEnabled, default off) fills the gap: for exactly the parcels Shopify can't track, Jim looks them up with a carrier API for a live status, ETA, and exception reason (which can also clear a false alarm), then a webhook follows up if the parcel later fails. The fallback is multi-provider β Jim routes each carrier to the provider that covers it and is cheapest (EasyPost for the common US carriers, TrackingMore for the long tail of ~1,600 carriers incl. integrators like MBE) β so a seller on a regional integrator still gets tracked. Each tracker registered costs BroomAI tokens (the same balance as the AI agents) and is skipped when the shop is out of balance, so it's reserved for the gone-quiet cases. Owner-tunable thresholds + the on/off switches live in jim_shop_settings; subscriptions are set up on hire and re-checked on every Shopify reconnect and on startup.purpose='support') registers a Gmail users.watch. New mail flows users.watch β Google Cloud Pub/Sub β /api/webhooks/gmail/push (verifies a shared token β enqueues β 200 fast) β sarah-inbox-worker. The worker records a support_ticket per thread, runs a Haiku triage (category + confidence) wrapped in deterministic guards, enforces the identity check (sender email == order email) and the always-escalate rule for critical actions (refund / cancel / dispute / order edit), then runs the reply brain as a bounded Sonnet tool-loop (β€3 steps) that may call three customer-safe, field-whitelisted consult lookups β lookup_product (coarse stock only, no exact counts/cost/vendor), get_shipping_options (Shopify shipping zones or policy text, no carrier contract rates), and identity-gated get_order_tracking β then drafts a grounded reply or escalates. Answerable emails below the confidence threshold are now attempted (drafted, held for approval) rather than escalated; confidence still gates auto-send. Replies are grounded only in order facts + the admin knowledge base + those looked-up facts; a failed lookup returns "unavailable" β escalate, never guess. Each capability is owner-toggleable (default on).shop.briefingChatId via the shop's Telegram client; on failure deliveredToTelegram stays false so the next run re-enqueues. Reply intents ack / snooze 24h / tell me more update the insight's status.