Bevra: an AI-augmented LinkedIn operating system
Multi-tenant SaaS on top of an agentic content-generation engine. The two systems talk over a small webhook contract. This page walks through what's on each side, the seam between them, and the patterns that transfer to an enterprise build. Live product at bevra.app. Telegram bot at @BevraContentAdvisorBot.
The problem
A solo LinkedIn operator runs three jobs off a stack of Notion, ChatGPT, Buffer, and spreadsheets. They track relationships in a funnel. They find high-signal posts and threads to engage with. They produce content on a schedule. Each job lives in a different tool. The switching cost is what kills output.
The same fragmentation exists in enterprise settings where a customer-facing operator has to unify a CRM, a content workflow, and a generation loop. This case study is written for teams scoping that kind of system: agents, tool use, multi-turn workflows, evals.
Approach
Bevra is the operator surface. It holds the relationship funnel, keyword-driven post discovery, saved-post collections, an on-demand post-angle generator, and an ICP-scoring pass that ranks contacts against a prose ICP definition. Every LLM call inside Bevra is single-shot, structured-JSON, and gated by per-tenant token quotas.
Content generation is offloaded to the Next Post Engine, a separate self-hosted agentic backend. The engine owns retrieval, ranking, judgement, and human approval. Bevra fetches the approved suggestion over a webhook and renders it in its AI Studio panel. Each side ships and scales independently.
Architecture
Where the agentic capability lives
Enterprise readers scoping a similar build need to know which parts are agentic and which parts are straight LLM calls. Bevra and the Next Post Engine split cleanly on that boundary.
Inside Bevra: LLM-augmented, single-shot
Every Claude call inside Bevra is a single messages.create with a system prompt and one user turn.
Claude Sonnet 4.6 powers on-demand post-angle generation in AI Studio.
Claude Haiku 4.5 scores contacts 0–100 against a user-defined prose ICP.
Outputs are structured JSON parsed with a tolerant regex extractor.
Per-tenant Anthropic token quotas (100k / 1M / 10M by plan) gate every call at request time.
Inside the Next Post Engine: fully agentic, multi-turn
The agent lives here.
An n8n AI Agent node drives Claude Haiku 4.5 through a structured-output parser.
A producer run flows through synthesis, per-idea retrieval, judge, deterministic eval gate, human approval.
When the operator taps Skip on Telegram, the next run's retrieval steers away from what was rejected.
An hourly dispatcher fans out to the tenants whose local hour matches their digest time.
Each producer run takes 30 to 90 seconds and writes a row into app.runs with counts, scores, tokens, and errors.
Agent tools
Source ingest
Hacker News + RSS + public Telegram channels via a Telethon MTProto ingester. Per-tenant source config.
pgvector retrieval
Gemini embeddings over headline + why_now. Dedup on re-sync. Retrieval steers away from suggestions the operator has skipped.
Synthesis chain
Structured-output LLM pass turning raw items into candidate post ideas (headline, angle, why-now, draft outline, sources, self-score).
Judge chain
Per-idea grounded LLM pass. Scores each candidate 1–10 against the tenant's own accepted / declined / profile evidence retrieved from pgvector, and returns the retrieval IDs it cited.
Eval Gate
Deterministic Code node. Takes the judge's score and applies penalties: -5 for ungrounded sources, -1.5 for hype or trend-inflation phrasing, -5 when the judge cites only rejected past evidence. Drops anything below 7.5/10. Dropped ideas never reach Telegram.
HITL approval
Surviving candidates DM the operator on Telegram with [✅ Approve] / [❌ Skip] inline buttons. The callback handler is idempotent on status='pending'.
Observability & evals
Every producer execution writes a row into app.runs: item counts, judge scores, tokens spent, errors.
Langfuse hosts per-tenant dashboards that correlate judge scores with the operator's approve/skip decision.
A weekly n8n cron refreshes them.
Prompt and system changes are validated offline before they merge.
A LangSmith experiment runs the pipeline against the golden dataset (next-post-golden_v1) with named evaluators: citation grounding (citation_alignment, avg_citation_alignment, n_citations_total), agreement with human labels (matches_human_label, pearson_r), and structured-output validity (wrapper).
Each candidate change becomes an experiment tagged against a baseline; the bar charts show whether the change helped, hurt, or moved nothing.
A parallel Python harness (evals/run_eval.py) runs the same deterministic criteria from evals/criteria.py. That file also defines the runtime Eval Gate's penalties. It exits non-zero on regression so it can gate CI.
next-post-golden_v1) and the experiment history. Each bar is one experiment run against the same 34 examples with a tagged baseline for comparison.Multi-tenant & billing patterns
Every request carries a Supabase JWT (ES256) verified via JWKS in a FastAPI dependency.
Every row in Postgres is keyed on user_id.
A Stripe webhook drives UserSubscription; only active and trialing count as paid.
Per-plan caps run on both apify_actor_runs and anthropic_tokens.
check_anthropic_quota gates every LLM call at request time.
record_anthropic_usage reads the real response.usage object and increments per-tenant counters.
Reliability & failure isolation
The webhook contract is 200-only, with an {available:false} sentinel when nothing is ready.
When the engine is unreachable, Bevra shows an empty AI Studio panel instead of an error.
The ICP-scoring loop isolates failures per contact.
One bad LLM response never poisons the batch.
URL canonicalization plus an Alembic backfill migration healed cross-source duplicates without downtime.
The Telegram approval callback is idempotent on status='pending'.
A re-fired callback never double-approves a suggestion.
What an enterprise team can reuse
Three endpoints (GET /latest, POST /link, POST /plan) let the SaaS front-end and the agentic backend ship on separate cadences without coupling their release cycles.
A deterministic runtime gate keeps bad candidates off the human's plate. An offline LangSmith harness runs the same criteria over a golden set so prompt changes can be scored before they ship. Both read the same criteria.py. Retrofit is more expensive than build.
An inline Telegram callback is the whole approval UI. The same interaction shape ports to Slack, Teams, or an in-app inbox without touching the agent.
Token gates at request time. Real usage read back from the provider's response.usage. Paid-plan enforcement runs inline with the request, not on a nightly reconciliation.
Comparing notes
Get in touch if you're scoping an agentic system with tool use, multi-turn workflows, and evals, and any of the patterns above are worth pressure-testing.