PyGuard
Architecture

One agent layer, one persistence layer, one PDF pipeline

PyGuard is a small FastAPI backend that coordinates a set of focused sub-agents over the OpenAI Agents SDK, persists per-report bundles on disk, and talks to users through Slack. The beta release only adds what was strictly needed to support in-thread Q&A and LaTeX edits.

Agentic architecture

The beta-release agent topology

A birds-eye view of the agents, data flows, and storage that make up PyGuard today. The diagram below evolved from the alpha design and reflects every orchestrator, sub-agent, and external service currently in production.

PyGuard agentic architecture diagram: Slack surface, memory agent, fraud orchestrator, report follow-up agents, tex editor, and external services (OpenAI Agents SDK, Composio, tectonic, SQLite).
Figure 0. Agentic architecture diagram. The request-routing view below zooms into how a single Slack message moves through the same topology.
System topology

How a single Slack message is routed

This diagram reflects the beta-release state. Solid arrows are in-process calls, dashed ones are optional or external services.

flowchart TB
  subgraph clients [Clients]
    Slack["Slack user"]
    Web["Web chat UI (existing)"]
    WA["WhatsApp (via bridge, optional)"]
  end

  subgraph surface [Surface layer]
    SlackSvc["slack.service (Socket Mode)"]
    WebApi["api.routes / chat_handler"]
    Bridge["bridge (Node, Baileys)"]
  end

  subgraph handler [process_chat_message]
    Phase0{"thread_ts maps to fraud_reports row?"}
    Followup["ReportFollowupAgent"]
    Memory["MemoryAgent (intent + complexity)"]
  end

  subgraph fraud [Fraud agent stack]
    FraudOrch["FraudOrchestratorAgent"]
    DataAg["FraudDataAnalystAgent"]
    PatAg["FraudPatternAgent"]
    RepAg["FraudReportAgent"]
    AlertAg["FraudAlertAgent"]
    VerAg["FraudVerificationAgent"]
  end

  subgraph followup [Follow-up stack]
    QAAg["ReportQAAgent"]
    EditAg["ReportEditorAgent"]
    TexEdit["tex_editor (pure Python)"]
  end

  subgraph storage [Local storage]
    Sqlite[("SQLite: pyguard.db
messages, fraud_transactions, fraud_reports")]
    Bundles[("backend/reports/fraud_report_<ts>/
report.tex, PDF, charts, history/")]
  end

  subgraph external [External services]
    OAI["OpenAI Agents SDK + Responses API"]
    Comp["Composio (Gmail, Calendar, Docs)"]
    Tec["tectonic (LaTeX to PDF)"]
  end

  Slack --> SlackSvc --> handler
  Web --> WebApi --> handler
  WA --> Bridge --> WebApi

  handler --> Phase0
  Phase0 -->|yes| Followup
  Phase0 -->|no| Memory

  Followup --> QAAg
  Followup --> EditAg
  EditAg --> TexEdit --> Tec
  TexEdit --> Bundles

  Memory -->|fraud intent| FraudOrch
  FraudOrch --> DataAg
  FraudOrch --> PatAg
  FraudOrch --> RepAg
  FraudOrch --> AlertAg
  FraudOrch --> VerAg

  RepAg --> Bundles
  RepAg --> Tec
  DataAg --> Sqlite
  QAAg --> Sqlite
  QAAg --> Bundles

  FraudOrch --> OAI
  Followup --> OAI
  Memory --> OAI

  SlackSvc --> Bundles

  Memory -.-> Comp

  classDef ext fill:transparent,stroke:#2a3356,stroke-dasharray:4 4;
  class OAI,Comp,Tec ext;
Full beta-release topology. The fraud_reports table and the per-report bundles are what make the in-thread Q&A and LaTeX edit flows possible.
Components

Major components and what they own

ComponentLayerResponsibility
slack.service
Surface
Socket Mode client; captures thread_ts and channel_id, reacts, posts replies, uploads PDFs.
api.routes + chat_handler
Surface
HTTP endpoints (/api/chat, /api/history) and the shared process_chat_message that every surface calls.
MemoryAgent
Orchestration
Classifies intent, complexity, and picks between fraud, rule, user_management, conversational, and action paths.
FraudOrchestratorAgent
Orchestration
Runs the full report generation: FraudDataAnalyst -> FraudPatternAgent -> FraudReportAgent -> FraudVerificationAgent.
ReportFollowupAgent
Orchestration
Phase 0 router. Picks qa, edit, or new_report for messages inside an existing report's thread.
ReportQAAgent
Sub-agent
Read-only expert on the saved report bundle plus the live SQL data tools. Answers questions in thread, no PDF.
ReportEditorAgent
Sub-agent
Applies structured LaTeX edits via the tex_editor module and recompiles with tectonic.
tex_editor
Primitive
Pure Python. Section-anchor edits, minimal validation, history/v{n}/ backup, atomic writes, tectonic wrapper with rollback.
fraud_reports (SQLite)
Storage
One row per Slack thread. Stores pdf_path, tex_path, bundle_dir, sections_json, data_snapshot_json, version.
backend/reports/<bundle>
Storage
Durable on-disk bundle: report.pdf, report.tex, charts/, metadata.json, history/v{n}/ after edits.
Data flows

Four paths through the system

  • Inbound message

    Slack event → slack.service → process_chat_message. For Slack, thread_ts and channel_id are captured on the way in so Phase 0 can match an existing report.

  • Report generation

    MemoryAgent classifies intent → FraudOrchestratorAgent coordinates the four fraud sub-agents → FraudReportAgent renders LaTeX and compiles with tectonic → fraud_reports row inserted keyed by thread_ts.

  • In-thread Q&A

    Phase 0 finds the fraud_reports row → ReportFollowupAgent classifier picks qa → ReportQAAgent reads the bundle and optionally the live SQL → plain text answer lands in the thread.

  • LaTeX edit

    ReportFollowupAgent picks edit → per-report asyncio.Lock acquired → tex_editor backs up current tex, applies structured edits, recompiles → Slack uploads the new PDF into the thread, or rollback restores the previous bundle.

External dependencies

What PyGuard depends on outside the process

  • OpenAI Agents SDK

    LLM orchestration. Models and reasoning levels are defined centrally in backend/config/agent_config.py.

  • Composio

    Used by the general orchestrator for Gmail, Calendar, and Google Docs tool calls. Not used by the fraud path.

  • Tectonic

    LaTeX engine invoked per compile. 120-second timeout; rollback restores the previous PDF on failure.

  • SQLite (pyguard.db)

    Messages, rules, users, fraud_transactions, and the new fraud_reports table all share one database. Unique index on slack_thread_ts enforces one active report per thread.

  • Slack

    Socket Mode app. Requires bot token + app token plus the bot scopes listed in /setup.

Rationale

What changed since alpha, and why

The alpha topology generated a PDF and walked away. The beta release keeps the conversation alive inside the thread. Four targeted changes make that possible.

1

Durable report bundles

Alpha wrote report.tex into a tempfile.mkdtemp and only moved the PDF out. That meant the LaTeX source was effectively thrown away after generation. In beta, every report is its own folder (backend/reports/fraud_report_<ts>/) containing the PDF, the tex source, the chart PNGs, metadata.json, and a history/ directory for backups. Without this, in-place LaTeX edits are impossible.

backend/fraud_system/report_generator.py
2

fraud_reports table and thread keying

Alpha had no way to find a previously generated report from a Slack thread. Beta adds a fraud_reports table with a unique index on slack_thread_ts, plus insert/get/update helpers. This table is what lets Phase 0 know whether an incoming message is a follow-up.

backend/database/local_db.py
3

ReportFollowupAgent and Phase 0 routing

Alpha routed every incoming message through MemoryAgent, so a follow-up question would generate a brand-new report. Beta adds a Phase 0 fast path in chat_handler.py that consults fraud_reports before the Memory Agent, and a small classifier that chooses between qa, edit, and new_report.

backend/fraud_system/report_followup_agent.py
4

tex_editor module with validated rollback

Alpha had no safe way to edit the PDF after the fact. Beta introduces pure-Python helpers for section-anchor edits, minimal LaTeX validation, history/v{n}/ backups, and a composite apply_edits_and_recompile tool that rolls back on tectonic failure. Twenty-one unit tests in backend/tests/test_tex_editor.py cover every primitive.

backend/fraud_system/tex_editor.py

Nothing else in the alpha topology was replaced. The Memory Agent, Orchestrator Agent, general sub-agents (calendar, email, research, report_writer), Composio wiring, SQLite schema, and Slack Socket Mode client all behave exactly as they did in alpha. The beta release is strictly additive.