Communications and marketing teams monitor coverage, track emerging narratives, research briefs and produce content - four different jobs that usually mean four different tools. We built the platform where all of it happens in one conversation: twenty-five independent services, four conversational AI engines, two monitoring pipelines and a governed knowledge layer, wired asynchronously so a long research run never blocks the chat.
Next.js web appthe user types; the user waits seconds, not minutes
API gatewayauthenticates, then decides which AI service owns the request
APS · GAS · SAD · CRAresearch, converse, generate, deep-dive
Asynchronous response hubpersists the result, then pushes it
AppSync subscriptionthe answer appears in the open session
An AI platform company whose product gives communications and marketing teams one place to monitor media, track risk and narratives, research topics and generate content.
Four unrelated workloads - live chat, long-running research, scheduled monitoring and multimedia generation - had to feel like one product, for many companies at once, without any of them blocking the others.
A twenty-five service platform: a routing gateway, four conversational AI engines, two monitoring pipelines, four exploration agents, four knowledge providers and an event hub that returns every result.
Queued, never blocking. Every request crosses a queue, every result lands in PostgreSQL and S3, and the browser is updated over a WebSocket rather than left holding a request open.
The client is an AI platform company building for communications and marketing professionals - the people who have to know what is being said about a company before anyone else does, and then say something back.
Their product promises one surface for the whole job: watch media coverage, track the risks and narratives that are forming, research an industry question properly, and produce the content that answers it - text, audio, images, short video. All of it through a chat interface, because that is how the work actually arrives: as a question someone asks in the middle of a working day.
What makes that promise hard is not any single capability. It is that the four capabilities have almost nothing in common. A quick question wants an answer in seconds. A deep research brief takes many minutes and dozens of sources. Monitoring runs on a schedule whether anyone is logged in or not. Generation calls out to external models. Behind one text box sit four very different machines.
The structural fact that shapes the whole platform.
Between the two sits the question the architecture had to answer: how do you put an unbounded workload behind a live interface? Everything downstream - the queues, the event hub, the WebSocket layer - follows from refusing to make the user wait on a synchronous call.
Each capability, taken alone, is a solvable problem. Putting them behind one chat box - for many companies at once, with none of them able to slow the others down - is where the architecture is decided.
"What is the latest on this launch?", "write me a statement", "make a fifteen-second video", "why is this narrative accelerating?" - four requests, four completely different execution paths, one input field.
A quick factual answer and an evidence-graded communications brief are different products. Forcing both through one agent makes the fast case slow and the deep case shallow.
A deep brief can take many minutes and dozens of source fetches. No HTTP request should be held open that long, and no user should watch an unmoving spinner while it happens.
News, research, social, government and academic content sit in different collections, each with its own shape - and the live web sits outside all of them. Agents cannot be wired to each one individually.
Discovery and analysis pipelines fire on a daily schedule, sweep every tracked subject, and produce reports nobody requested. That work cannot compete with a user waiting for a reply.
Every company subscribes to its own topics and sees only its own knowledge base. Tenant isolation had to be a property of the data path, not a filter each agent remembers to apply.
The product is judged entirely on the chat box. A user does not know or care that twenty-five services are involved - they know whether the answer arrived, whether it cited something real, and whether the alert reached them before their CEO saw the story. Every seam in the architecture has to be invisible from the front, and every service behind it has to fail without taking the conversation down.
Focaloid engaged to design and build the platform's services and agent layer. Three constraints were set as hard requirements rather than preferences, and every later decision is downstream of them.
Every request crosses a queue. The gateway hands off and returns; the result comes back through the event hub and a WebSocket push. No user-facing call ever waits on a model.
Twenty-five services, each with a single responsibility and its own deployment. Routing does not research, research does not persist, persistence does not search. A failure stays where it happened.
A new assistant is a configuration file, not a deployment. Agent behaviour - model, tools, prompt - is declared and loaded at runtime, so the product can add assistants without engineering time.
The decision that shaped everything: the chat surface is the only contract. The frontend talks to exactly two things - the gateway for requests and the WebSocket for updates. It has no knowledge of which AI service handled a message, how many agents ran, or which knowledge store answered. That single constraint is what allowed the service count to grow from a handful to twenty-five without a single frontend rewrite.
Gateway, queues and the event hub first - the transport that every later service plugs into, built and proven before any agent existed.
Four conversational services, each with the shape its workload needs: an agent graph, a single orchestrator, a middleware pipeline, a config-driven runtime.
Four provider services in front of the vector stores and the live web, so agents call a search tool and never a database.
Scheduled discovery, deep analysis and digest delivery - plus the exploration agents that let a user interrogate what the pipelines found.
Agents never query a knowledge store directly - they call a provider service. Monitoring never writes to the chat path - it writes to the database and lets the exploration agents read. And no AI service talks to another AI service: everything meets at a queue. What the services are not allowed to do is as much of the design as what they do.
The gateway classifies and routes; a queue carries the request to the service that owns it; that service does the work with the tools it needs; the event hub stores the result and pushes it to the browser. The same five beats whether the job takes two seconds or twenty minutes.
The console replays a representative research request: the gateway routes it, the research service classifies intent, plans its angles, searches several sources in parallel, writes a cited report, and the event hub pushes the result back into the live session - each step narrated as it happens.
Illustrative run with representative data. In the delivered platform every step, source and citation is produced from the real request against the client's own knowledge base and the live web.
The platform is a layered system: one interface, one gateway, a queue fabric, four conversational AI services, a monitoring engine, four knowledge providers, an event hub that returns results, and a data plane underneath all of it. No service reaches past its layer.
The as-delivered system - redrawn from the engagement's architecture documentation.
Counted as delivered. Each is independently deployed.
APSMedia monitoring and report research, 8 agentsGASGeneral assistant with memory and media generationCRADeep communications research, 17-stage pipelineSADYAML-configured assistant platformIIMSFinds new issues and scores them for riskTMSFinds new topics from Knowledge Graph themesICDGSDeep-dives each issue and writes the reportTCGSDaily deep analysis of each tracked topicIDSScheduled dispatcher, one message per issueTMADiscovery, tracking and digest in one agent serviceMEAIssue analyst, orchestrator plus 7 specialistsIEAIssue analyst that remembers the conversationTEATrend analyst, orchestrator plus 6 specialistsTMEATenant-isolated topic command centreGKPMulti-source semantic search, tenant-awareKBPGeneral knowledge retrieval for chatKBTAcademic, government and think-tank collectionsWDPLive web search behind one interfaceBFFGateway, accounts and dashboard dataARPHResult persistence and live pushNOSSlack, email, webhook and SMS deliveryDCSCatalogue of agent configurationsSASSupporting platform serviceYCAyaml-config-agent - factory, loader, runtime, schema, middleware and storage backendsSplitting a system into services is easy. Splitting it so that the seams never show, the failures stay local, and a new capability is a configuration change lives in a handful of deliberate choices. Each one below is as-built.
The gateway authenticates a message, decides which AI service owns it, publishes it to that service's queue, and returns. It holds nothing open. When the service finishes - two seconds later or twenty minutes later - it publishes to another queue, where the event hub picks the result up, writes it to PostgreSQL, stores large artifacts in S3, and pushes a live update to the browser over the WebSocket layer.
That one pattern is why a deep research brief and a one-line reply can share an interface. It is also why an AI service can be redeployed mid-conversation without a user noticing: the queue holds the work, and the result finds its way back to the session that asked for it.
No AI service calls another AI service. Everything meets at a queue. It costs a hop, and it buys the property the platform depends on: one service failing degrades one capability, not the conversation.
A quick sourced answer and a full communications brief are not the same product, so they are not the same architecture. The platform runs both, and the difference between them is the most instructive decision in the build.
Media monitoring and report research runs as a LangGraph workflow with state persisted in PostgreSQL. Each agent owns one decision, and the graph moves forward.
Plus an instant-chat agent and an output-format classifier - eight in total, over six tools: live web search, full-article extraction, vector search, web-data search, article expansion and user context.
Deep communications research is not a loop, it is a production line. CRA runs as a middleware pipeline: each stage transforms the state and passes it on, so a complex brief decomposes instead of spiralling.
Retry and state-management stages sit alongside the pipeline, so a failed extraction costs one bucket rather than the brief.
The shape follows the workload, not a house style. An agent graph suits a request that needs a decision at every step. A middleware pipeline suits one that needs the same forty tools applied in a dependable order. Forcing either pattern onto the other job would have made the fast case slow and the deep case shallow.
Every new assistant type used to mean new code: a module, a prompt, a tool list, a release. So the assistant platform was built the other way round. A shared library reads an agent definition - model, tools, system prompt, middleware - from a YAML file and returns a running agent. The service itself contains no assistant-specific logic at all.
Five assistant types run on it as delivered: a multimedia researcher that finds video, podcast and image material for a query; a lightweight quick-chat assistant with no memory; a deep-dive analyst; a video script writer that works from an outline; and a newsletter generator for weekly and monthly sends.
The library is six modules - a factory that builds agents from definitions, a loader that reads and validates the files, a runtime that executes the agent loop, a schema that rejects a malformed definition before it runs, middleware for pre- and post-processing, and pluggable storage backends.
Shape only - the delivered definitions are the client's. The point is what is absent: no service code changes when this file is added.
Product decisions stop queueing behind engineering ones. A new assistant is a definition file and a catalogue entry, validated against a schema before it ever runs - which is what makes "we should try an analyst variant" a same-day change rather than a sprint.
No agent in the platform holds a database connection. Every knowledge store is fronted by a provider service that exposes search as a callable tool, so an agent asks for information and a provider decides how to find it - which store, which collection, which tenant, which date window.
| Provider | What it fronts | Used by | Why it exists |
|---|---|---|---|
GKP General knowledge provider | Curated base across news, research, social and government content - vector search | APS, GAS, SAD, TMEA | Semantic search that understands meaning, and enforces tenant scope at the source |
KBP KB provider | General chat knowledge - product launches, executive mentions, company news | APS, GAS, SAD | The earlier retrieval path, still serving the general chat use cases |
KBT KB academic | Academic papers, government publications, think-tank reports, social and company news | ICDGS and the legacy discovery pipeline | Specialist collections that risk analysis depends on and chat rarely needs |
WDP Web data provider | Live web search behind a single integration | APS, GAS | One place to hold an external search contract, rather than one per agent |
Tenancy is a property of the data path. Because search runs inside a tenant-aware provider rather than inside each agent, a company can only ever be served its own knowledge base - and an agent cannot leak across tenants by forgetting a filter, because it never had the option of writing one.
The newer pipeline also pre-loads: before analysis starts, the run fetches the graph articles it will need in one batch and exposes them as an in-memory tool, so an agent that would otherwise make dozens of round trips makes none. And a history tool injects previous runs' metrics into the context, so the agent is reasoning about a trajectory rather than a snapshot.
The interesting part is what moved, not what was added. Clustering moved out of the daily run and into a continuous ingestion process; gathering moved out of five sub-agents and into one; scheduling, analysis and delivery moved into a single agent service. The risk model stayed identical - the same six dimensions scored the same way - so results from both generations remain comparable.
When a user opens an issue or a topic and starts asking questions, no new research runs. The monitoring pipelines have already written their analysis files to object storage - article summaries, key insights, sentiment, entities, cross-source analysis, extended extractions - and the exploration agents answer from those. It keeps a conversation about a tracked narrative fast, cheap and consistent with the report the user is looking at.
An orchestrator over seven specialists: data summaries, sentiment, timeline, claims, authors, business impact and recommended responses.
A lighter single-orchestrator variant that remembers earlier turns, for longer multi-turn conversations about one issue.
An orchestrator over six specialists, including a prediction analyst for trajectory and escalation, and a response generator for talking points.
Searches, creates and updates topics across everything a company tracks - with tools injected per tenant and a tenant-scoped virtual filesystem over S3.
Tenant isolation is injected, not remembered. The command-centre agent receives a company context at construction time and its tools are bound to it, so "search topics" can only ever return that company's topics. The agent has no unscoped tool to reach for.
Two pipelines run on a schedule: one tracks issues - regulatory actions, controversies, legal disputes, product failures - for a single company; the newer one tracks topics and narratives across many companies at once. Both discover, score, analyse and report. Both use the same six-dimension risk model, which is what makes their output comparable.
Government oversight, legal action, regulatory pressure - probes, fines, new rules landing on the category.
Reputational threat and public controversy - customer backlash, executive scandal, a story that will not settle.
Financial and competitive exposure - share price movement, a competitor launch, market share shifting.
How the framing is moving across sources, and whether analyst and public sentiment agree.
How fast the story is spreading - days to go wide, mentions accumulating across outlets.
How much coverage exists - article counts and geographic spread over a window.
A composite score above the configured threshold is what promotes a cluster from noise to a tracked issue or topic.
For each subscribed company: read the latest graph themes, filter for relevance, check whether the theme is already tracked, score it across the six dimensions, classify it against the threshold, enrich it, and write it.
New topics get a seven-day backfill so the first report has history behind it rather than a single day of coverage.
For every tracked topic: pull the latest articles for its cluster, filter off-topic noise, then run the full analysis - sentiment, volume and velocity, timeline, quotes, claims, author profiles, network signals, business impact, risk delta, propagation and narrative characterisation.
Six analysis files per run are written to object storage, and the topic's risk score is updated in place.
Fetch the company's subscribers, aggregate new and updated topics, surface the high-velocity and high-risk ones, gather regional takeaways into a summary narrative, render a branded HTML email and route it for sending.
Delivery is a stage of the pipeline, not a separate reporting job bolted on afterwards.
Scoring tells you how serious a cluster is. Enrichment tells you what it is: a narrative class (regulatory scrutiny, market competition, brand safety, technology trend), a business domain (legal, regulatory, brand and reputation, market and competition, product and innovation), and a tracking threshold - continuous, watch-list or archive. That last field is what stops a monitoring product from becoming a firehose: a topic can be tracked without being escalated.
| Aspect | Risk monitoring - the original pipeline | Narrative monitoring - the newer pipeline |
|---|---|---|
| Unit of tracking | Issues | Topics and narratives |
| Tenancy | Single company | Multi-tenant - any company, any number of topics |
| Service shape | Microservices - discovery, dispatch and analysis as separate services | One agent service handling discovery, tracking and digest |
| Discovery source | Five knowledge collections searched in parallel, then clustered | Knowledge Graph themes, pre-clustered ahead of the run |
| Analysis | Five sub-agents gathering separately | One analysis sub-agent with pre-loaded graph tools |
| Cluster enrichment | None - classification straight after scoring | Narrative class, business domain and tracking threshold |
| Scheduling | A simple daily dispatcher, one message per issue | Scheduler with fan-out and hourly, daily and digest modes |
| Delivery | Standalone reporting | A digest stage inside the pipeline, sent by email |
| User exploration | Two agents - one with eight tools, one with memory | Two agents - a seven-agent trend explorer and a tenant-isolated command centre |
| Risk model | Six dimensions - A, T, M, N, P, S | Six dimensions - identical, so scores stay comparable |
Nothing in the data plane is general-purpose. Relational state, vector search, object storage and the queue fabric each hold what they are good at holding - which is why a twenty-minute research run and a live chat session can share the same platform without contending for the same store.
Accounts, companies, workspaces and preferences; chat sessions and conversation memory; the issue and topic tables with their current risk scores; and per-run agent state for the workflow services.
Why: the platform's core objects are relational and heavily queried by the dashboards. Agent state persisted here is also what lets a long workflow survive a restart.
The vector collections behind every knowledge provider - news, research, social, government, academic and think-tank content, each tenant-scoped.
Why: embedding-based search finds material by meaning rather than keyword, which is the difference between a librarian and a search box when a user does not know the exact headline.
Reports, the six analysis files each monitoring run produces, extracted article summaries and key insights, generated images and video, and the tenant-scoped virtual filesystem the command-centre agent reads and writes.
Why: analysis artifacts are large, written once and read often. Keeping them out of the database keeps the dashboards fast and every intermediate output available for a later question.
Queues carry every request and every result, with FIFO queues where conversation order matters. AppSync holds the WebSocket subscriptions the event hub pushes to.
Why: together they are the reason nothing blocks. The queue absorbs the latency; the subscription delivers the result whenever it is ready.
The platform is not one deployable. Twenty-five services deploy independently - FastAPI for the Python services, Node.js for the event hub, Next.js for the front end, containerised orchestration for the monitoring agent, and Lambda for the dispatchers. The coupling between them is a queue contract, which is what makes that independence real rather than nominal.
We report build facts, not projections. The figures below are as-delivered and verified by the engineering team; the before and after describes how the work changed rather than a claimed metric. Buyers can tell the difference - so can we.
| Before | After - the delivered platform |
|---|---|
| Monitoring, research and content production lived in separate tools and separate habits | One chat surface routes to whichever of four AI services owns the request |
| A long research job meant a held-open request and an unmoving spinner | Every request crosses a queue; results are pushed into the open session when ready |
| Deep briefs and quick answers competed for one research path | Two engines with different shapes - an agent graph for decisions, a pipeline for depth |
| Each new assistant type was code, a release and engineering time | An assistant is a validated configuration file plus a catalogue entry |
| Agents wired to individual knowledge stores, each remembering its own tenant filter | Four provider services own retrieval and enforce tenant scope at the source |
| Discovery re-searched five collections daily and clustered the results at run time | A Knowledge Graph clusters continuously; discovery reads themes it has already grouped |
| Monitoring served a single company | Multi-tenant discovery, tracking and digest across every subscribed company |
| Reporting was a separate job after the analysis finished | Digest is a stage of the pipeline, delivered by email, Slack and webhook |
One capability degrades, not the conversation. Because services meet at queues and never call each other directly, an image-generation outage does not take research down, and a monitoring run cannot slow a live reply.
New assistants ship as configuration. Model, tools, prompt and middleware are declared, schema-validated and loaded at runtime - so trying an idea costs a file, not a sprint.
The risk model did not change. Both monitoring pipelines score the same six dimensions the same way, so the migration to graph-based discovery did not invalidate the history already collected.
The queue contract and the provider boundary were chosen so the platform could keep growing without a rewrite. The next moves are consolidation as much as addition.
An asynchronous spine, a tool boundary in front of every data store, agents shaped to their workload rather than to a house style, and tenant scope enforced by the data path - the pattern transfers to any product where a live interface sits over work that takes longer than a request.
Let's build
We design and ship production agent platforms - asynchronous, grounded in your own data, multi-tenant from the first release, and built so the twenty-sixth service does not need a rewrite.