Law-student portfolio project · Product + engineering

Argus

A working M&A drafting and review prototype I built to explore lawyer control: source-grounded analysis, inspectable redlines, and work product that can leave the interface.

Role
Product, workflow design, engineering
Status
Live portfolio demonstration
Mutual NDA · seller draft Illustrative review

Confidentiality obligations

The Receiving Party shall hold all Confidential Information in strict confidence and shall use it solely for the evaluation of a possible transaction Permitted Purpose.

These obligations will survive for three years from the date of disclosure.

§1 · Trade-secret carve-out
Work product Redline · clean · memo · register
Illustrative composition based on the current Drafting & Review Hub; use the live demo for actual behavior.
Project status Working portfolio prototype
My role Product · workflow · engineering
Core workflow Generate · revise · review
Source Public repository

The problem

Contract review is document-heavy and demands careful comparison against drafting guidance. Argus asks whether a retrieval pipeline can support a first pass — flagging potential issues, proposing missing provisions, and citing its sources — while leaving legal judgment with the reviewer.

What I built

Argus has two surfaces. The Drafting & Review Hub is the main product: a two-pane editor where you can generate a contract from a prompt, revise an uploaded draft, or review an existing agreement — with per-clause accept/reject/edit controls, anchored chat, and four downloadable artifacts (redline.docx, clean.docx, memo.docx, register.json). The M&A Research Desk is a source-grounded research surface backed by 11,266 corpus chunks indexed in Neon pgvector: 22 playbook chunks across 12 categories plus ~7,067 spans from CUAD (the Contract Understanding Atticus Dataset, Hendrycks et al., NeurIPS 2021) and ~4,177 spans from MAUD (the Merger Agreement Understanding Dataset, Wang et al., NLLP @ EMNLP 2023).

Data handling depends on the selected path. Research and document-backed Revise or Review requests attempt entity anonymization with Flash-Lite before retrieval and generation. When that step succeeds, stable placeholders such as PARTY_A and ORG_001 are maintained in a per-session, in-process map and restored for display. The current prototype can continue with the original text if the anonymization provider is unavailable, so this is a risk-reduction measure rather than a confidentiality guarantee. Generate without a document is a separate fast path: its prompt goes directly to Gemini and skips anonymization and retrieval. Do not submit confidential or identifying information through any path. A regex PII firewall re-screens content before each Supermemory write on paths that persist memory.

Pipeline

Argus data paths: Research and document-backed Revise or Review attempt anonymization before retrieval and generation; Generate without a document sends its prompt directly to Gemini
Boxes with a double burgundy border are persistent data layers; single-border boxes are compute steps. The dashed bypass is Generate without a document, which skips anonymization and retrieval. The anonymization step can fail open in the current prototype, so no path should receive confidential or identifying information.

Stack

Generation

  • Vertex Gemini 2.5 Flash
  • Gemini 2.5 Flash-Lite (anonymizer)

Retrieval

  • Cohere Embed v4 (1024-dim)
  • Cohere Rerank 3.5
  • Neon pgvector (HNSW)

Memory

  • Supermemory
  • kind=chat_exchange / context / review_summary
  • Session-scoped records screened by a regex PII firewall

Backend

  • Flask + gunicorn
  • Cloud Run (min-instances=1)
  • Neon Postgres

Export

  • python-docx
  • docx-revisions (native <w:ins>/<w:del>)

Infra

  • Google Cloud Platform
  • Cloudflare DNS + Pages
  • Secret Manager

What I learned

The hardest part was making the path-specific data flow explicit. When anonymization succeeds, Research and document-backed Revise or Review use a two-way pseudonym map that stays in process memory and is discarded when the worker recycles. The current fail-open fallback and the no-document Generate bypass are important limitations. A production version should fail closed before third-party calls or memory writes whenever anonymization is required.

The Hub reranks vector-search candidates with Cohere Rerank 3.5 before generation. I spent the most iteration time on that retrieval stage because its output directly shaped whether the spotter surfaced a specific drafting issue or a generic observation.

Validation matters more than I expected. v1.1.1 caught four silent failures in the Supermemory write path that all happened to mask one another: the standalone chat surface was missing the write code entirely; the PII heuristic substring-matched "ein" inside common English words; the Supermemory SDK changed its API surface (client.memories.addclient.add); and the test prompt I used didn't reference enough entity names to exercise rehydration. Each one looked like a deploy problem until logs proved otherwise.