PyGuard
Workflows

Three flows in, three flows out

Original diagrams of the primary user journeys. Each step shows what the user does, what the system does in response, and every decision point. Nothing on this page is a screenshot.

Primary report generation

From a flagged transaction table to a PDF in Slack.

In-thread Q&A

Ask the report a question without generating a new one.

LaTeX edit and rollback

Change report.tex safely, with automatic rollback on failure.

Flow 1

Primary report generation

The user starts the conversation in Slack. PyGuard captures the thread identifier, decides whether it is a brand-new request or a follow-up, and (for new requests) orchestrates the fraud sub-agents to generate a PDF that lands back in the thread.

flowchart TD
  A["User posts in Slack: Generate a fraud report"] --> B["slack service: capture thread_ts and channel_id"]
  B --> C["process_chat_message stores the message, loads history"]
  C --> D{"thread_ts already maps to a fraud_reports row?"}
  D -->|yes| E["Phase 0: ReportFollowupAgent (Q&A or edit)"]
  D -->|no| F["Phase 1: MemoryAgent classifies intent"]
  F --> G{"Intent is fraud_analysis?"}
  G -->|no| H["Other orchestrator path"]
  G -->|yes| I["Phase 2-F: FraudOrchestratorAgent"]
  I --> J["FraudDataAnalyst pulls SQL summaries"]
  J --> K["FraudPatternAgent interprets the patterns"]
  K --> L["FraudReportAgent renders LaTeX and compiles PDF"]
  L --> M["Bundle written to backend/reports/fraud_report_<ts>/"]
  M --> N["fraud_reports row inserted keyed by thread_ts"]
  N --> O["Slack service uploads the PDF into the thread"]
Figure 1. The primary CSV-to-PDF path. The thread_ts captured up front is what makes every later follow-up possible.
  1. Step 1
    User
    Posts a short message in Slack asking for a report.
    System
    The Slack service captures thread_ts and channel_id, stores the message, and forwards the request to the backend.
    Decision / outcome
    Does this thread already own a fraud_reports row? If yes, jump to the follow-up path; if no, continue to the Memory Agent.
  2. Step 2
    User
    Waits while the orchestration runs (typically 30-60 seconds).
    System
    FraudDataAnalyst pulls deterministic SQL summaries, FraudPatternAgent interprets them, FraudReportAgent builds the LaTeX document and compiles it with tectonic.
    Decision / outcome
    Bundle is written to backend/reports/fraud_report_<ts>/ and a fraud_reports row is inserted for the thread.
  3. Step 3
    User
    Opens the PDF in Slack and reviews it.
    System
    Slack service posts a short summary into the channel and uploads the PDF into the thread under that summary.
    Decision / outcome
    All subsequent replies in that thread will match the stored thread_ts.
Flow 2

Slack thread Q&A

Follow-up questions never generate a new report. A tiny classifier decides between question, edit, or a brand-new report, and binds the existing report as context for the Q&A agent.

flowchart TD
  A["User replies in the PDF thread with a question"] --> B["slack service captures the same thread_ts"]
  B --> C["process_chat_message receives thread_ts"]
  C --> D{"fraud_reports row exists for this thread_ts?"}
  D -->|no| E["Fall through to MemoryAgent (new report path)"]
  D -->|yes| F["ReportFollowupAgent classifier picks qa / edit / new_report"]
  F -->|qa| G["ReportQAAgent binds the report context"]
  G --> H["Agent reads report tex, sections, data snapshot, live data tools"]
  H --> I["Slack service posts narrative answer in the thread"]
  F -->|new_report| E
  F -->|edit| J["ReportEditorAgent path (see next diagram)"]
Figure 2. The in-thread Q&A path. The only way to reach it is by replying inside the thread where the PDF was uploaded.
  1. Step 1
    User
    Clicks 'Reply in thread' on the PDF message and asks a question.
    System
    process_chat_message receives the same thread_ts and finds the matching fraud_reports row. Phase 0 takes over before the Memory Agent runs.
    Decision / outcome
    ReportFollowupAgent's classifier picks qa, edit, or new_report from the user's wording.
  2. Step 2
    User
    Reads the answer and can keep asking follow-ups.
    System
    ReportQAAgent binds the report context, reads report.tex, sections, and the captured data snapshot, and optionally queries the live data tools.
    Decision / outcome
    No PDF is uploaded. The answer is plain text rendered in the Slack thread.
Flow 3

LaTeX edit with compile and rollback

Edits are the most sensitive path. PyGuard takes a per-report asyncio lock, copies the current tex and PDF into history, applies structured edits, and recompiles. If tectonic fails, the previous version is restored before the user sees anything.

flowchart TD
  A["User replies in thread with an edit request"] --> B["ReportFollowupAgent classifier picks edit"]
  B --> C["Per-report asyncio lock acquired for this fraud_reports.id"]
  C --> D["ReportEditorAgent builds structured edits (JSON)"]
  D --> E["apply_edits_and_recompile: back up to history/v{n}/"]
  E --> F["Apply edits in memory, validate LaTeX structure"]
  F --> G["Write report.tex atomically, run tectonic"]
  G --> H{"tectonic compile succeeds?"}
  H -->|yes| I["metadata.json bumped to new version"]
  I --> J["fraud_reports row updated with new pdf_path and version"]
  J --> K["Slack service uploads new PDF into the same thread"]
  H -->|no| L["Restore previous report.tex and PDF from history/v{n}/"]
  L --> M["Agent replies in thread with tectonic stderr tail"]
  M --> N["Human decides whether to retry with a smaller edit"]
Figure 3. The edit path. Every edit creates a history/v{n}/ folder so rollback is a plain copy.
  1. Step 1
    User
    Asks in the thread for a targeted change (rewrite, add, remove, tweak).
    System
    ReportFollowupAgent classifier picks edit. A per-report asyncio.Lock is acquired so concurrent edits on the same thread are serialised.
    Decision / outcome
    ReportEditorAgent builds a JSON array of structured edits: replace_section_body, insert_section_after, delete_section, or replace_text with a uniqueness guard.
  2. Step 2
    User
    Waits for confirmation.
    System
    apply_edits_and_recompile backs up the current tex and PDF into history/v{n}/, validates LaTeX structure, writes the new tex atomically, and compiles with tectonic (120-second timeout).
    Decision / outcome
    Compile success -> metadata.json version bumps, the fraud_reports row updates, Slack uploads the new PDF into the same thread. Compile failure -> rollback restores history/v{n}/ and the user sees the tectonic stderr tail.
  3. Step 3
    User
    Receives the updated report or a short failure note.
    System
    On success: 'Here is your updated Fraud Intelligence Report (v2):'. On failure: the prior PDF is still the active version and the user can retry.
    Decision / outcome
    Humans decide whether to retry, refine the request, or accept the current draft.