How to Build a underwriting Agent Using CrewAI in TypeScript for investment banking

By Cyprian AaronsUpdated 2026-04-21
underwritingcrewaitypescriptinvestment-banking

An underwriting agent in investment banking reviews issuer data, financial statements, covenant terms, market context, and internal policy to produce a first-pass credit or deal assessment. It matters because bankers spend a lot of time on repetitive document review and memo drafting; an agent can compress that work while keeping the final decision with humans.

Architecture

  • Input ingestion layer

    • Pulls PDFs, Excel files, deal memos, CIMs, and borrower questionnaires.
    • Normalizes them into text plus structured fields.
  • Policy and compliance layer

    • Checks the request against internal underwriting policy.
    • Flags restricted industries, jurisdiction issues, KYC/AML gaps, and approval thresholds.
  • Analysis agents

    • One agent for financial analysis.
    • One agent for risk/compliance analysis.
    • One agent for memo drafting.
  • Orchestration layer

    • Uses Crew, Agent, Task, and Process from CrewAI.
    • Sequences the work and passes outputs between tasks.
  • Audit logging layer

    • Stores prompts, retrieved documents, tool calls, and final outputs.
    • Required for model risk management and post-trade review.
  • Human approval gate

    • Routes the draft underwriting memo to a banker or credit officer.
    • No final recommendation should bypass this step.

Implementation

1) Set up a TypeScript project and install dependencies

Use CrewAI from a Node/TypeScript service that can call your LLM provider and internal tools. Keep secrets out of code and make sure document storage stays inside your approved region.

npm init -y
npm install @crewai/core zod dotenv
npm install -D typescript tsx @types/node

Create a minimal tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "outDir": "dist"
  }
}

2) Define the underwriting agents

The pattern here is simple: one analyst agent gathers facts, one risk agent challenges assumptions, and one memo writer turns the result into banker-readable output. In investment banking, you want narrow roles so you can audit each step separately.

import 'dotenv/config';
import { Agent } from '@crewai/core';

export const financialAnalyst = new Agent({
  role: 'Financial Analyst',
  goal: 'Analyze issuer financials, leverage, liquidity, and coverage metrics.',
  backstory:
    'You are a senior investment banking analyst focused on underwriting quality and downside risk.',
});

export const riskAnalyst = new Agent({
  role: 'Risk Analyst',
  goal: 'Identify compliance issues, concentration risks, covenant weaknesses, and policy breaches.',
  backstory:
    'You review deals for credit policy alignment, regulatory exposure, and documentation gaps.',
});

export const memoWriter = new Agent({
  role: 'Underwriting Memo Writer',
  goal: 'Draft an investment banking underwriting summary with clear recommendation language.',
  backstory:
    'You write concise memos for managing directors and credit committees.',
});

3) Create tasks that produce audit-friendly outputs

Each task should return structured text that can be logged or converted to JSON later. Avoid free-form “analyze everything” prompts; bankers need traceability from source to conclusion.

import { Task } from '@crewai/core';
import { financialAnalyst, riskAnalyst, memoWriter } from './agents';

const dealContext = `
Issuer: Northwind Capital Holdings
Transaction: $250M senior secured term loan
Purpose: Acquisition financing
Jurisdiction: United States
Requested tenor: 5 years
`;

export const analyzeFinancials = new Task({
  description: `
Review the issuer's financial profile using the provided deal context.
Calculate key underwriting metrics:
- Net leverage
- EBITDA margin trend
- Interest coverage
- Liquidity headroom

Return bullets with assumptions clearly labeled.
Context:
${dealContext}
`,
  expectedOutput:
    'A concise financial analysis with key metrics, assumptions, and red flags.',
  agent: financialAnalyst,
});

export const assessRisk = new Task({
  description: `
Assess compliance and credit risk for this transaction.
Check for:
- Restricted industry exposure
- Covenant weakness
- Documentation gaps
- Data residency concerns if source documents are outside approved regions

Return explicit pass/fail flags where possible.
`,
  expectedOutput:
    'A risk assessment with compliance flags and mitigation actions.',
  agent: riskAnalyst,
});

export const draftMemo = new Task({
  description: `
Write an underwriting memo for an investment banking credit committee.
Include:
- Transaction summary
- Key strengths
- Key risks
- Recommendation
- Human approval required before distribution

Use conservative language. Do not overstate certainty.
`,
  expectedOutput:
    'A banker-ready underwriting memo with recommendation language.',
  agent: memoWriter,
});

4) Run the crew with sequential execution

For underwriting workflows, sequential execution is usually the right default. You want the financial analysis completed before the risk writer drafts the final memo.

import { Crew, Process } from '@crewai/core';
import { analyzeFinancials, assessRisk, draftMemo } from './tasks';

async function main() {
  const crew = new Crew({
    agents: [analyzeFinancials.agent!, assessRisk.agent!, draftMemo.agent!],
    tasks: [analyzeFinancials, assessRisk],
    process: Process.sequential,
    verbose: true,
    memory: false,
  });

  const analysisResult = await crew.kickoff();

  
  
  

  
  

  
  

  
  

  
  

  
  

  
  

  
  

  
  

  
  
}

main().catch(console.error);

In practice, I would split this into two crews or add a post-processing step that feeds task outputs into a final memo task. The important part is that every output is persisted with timestamps so your audit team can reconstruct the decision path.

Production Considerations

  • Compliance controls

    • Enforce approval gates before any output reaches bankers or clients.
    • Add policy checks for KYC/AML status, restricted lists, sanctions screening, and lending authority thresholds.
  • Auditability

    • Log prompts, retrieved source documents, model version, temperature, tool calls, and final outputs.
    • Keep immutable records for model risk management reviews.
  • Data residency

    • Store issuer data in-region if your bank has jurisdictional constraints.
    • Do not send confidential deal materials to unmanaged endpoints or consumer SaaS tools.
  • Monitoring

    • Track hallucination rate on extracted metrics like EBITDA or debt balances.
    • Alert on missing citations, empty confidence fields, or outputs that skip required sections.

Common Pitfalls

  1. Using one generic agent for everything

    • This makes audits painful and increases bad outputs.
    • Split analysis into finance, risk/compliance, and drafting roles.
  2. Letting the model invent numbers

    • Underwriting fails when metrics are guessed instead of derived from source docs.
    • Force every metric to reference a document section or extracted table row.
  3. Skipping human review

    • An underwriting agent should assist bankers, not replace committee judgment.
    • Require explicit sign-off before any memo leaves the desk or enters workflow systems.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides