<SYSTEM>This document contains comprehensive information about Soumyadip's professional profile, portfolio, and blog content. It includes personal details, work experience, projects, and all published blog posts. This data is formatted for consumption by Large Language Models (LLMs) to provide accurate and up-to-date information about Soumyadip's background, skills, and expertise as a Fullstack Developer.</SYSTEM>

# avater.dev

> A clean and minimal portfolio featuring my work and writing.

## About

- Almost 21 y/o semicolon enjoyer, raised by the web and building across TypeScript, Go, Python, and Rust.
- Currently working at Attack Capital [YC W22], with open-source, hackathons, and technical writing on the side.

### Personal Information

- First Name: Soumyadip
- Last Name: Moni
- Display Name: Soumyadip
- Location: India
- Website: https://avater.dev

### Social Links

- [X](https://x.com/Avater004)
- [GitHub](https://github.com/AvaterClasher)
- [LinkedIn](https://linkedin.com/in/soumyadip-moni)

### Tech Stack

- [TypeScript](https://www.typescriptlang.org/)
- [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
- [Node.js](https://nodejs.org/)
- [Express.js](https://expressjs.com/)
- [Bun](https://bun.sh/)
- [React](https://react.dev/)
- [Next.js](https://nextjs.org/)
- [Better-Auth](https://www.better-auth.com/)
- [TailwindCSS](https://tailwindcss.com/)
- [shadcn/ui](https://ui.shadcn.com/)
- [Motion](https://motion.dev/)
- [Redux](https://redux.js.org/)
- [Git](https://git-scm.com/)
- [MongoDB](https://www.mongodb.com/)
- [PostgreSQL](https://www.postgresql.org/)
- [Prisma](https://www.prisma.io/)
- [Supabase](https://supabase.com/)
- [Figma](https://www.figma.com/)

## Experience

### Software Developer Engineer | Attack Capital

Duration: December 2024 - Present

Skills: Go, TypeScript, Distributed Systems, Voice AI, FHIR, OAuth2

Built a distributed workflow engine for OpenMic.AI voice agents with multi-turn flows, resilient STT/TTS pipelines, and real-time monitoring — handling 2000+ concurrent interactions.
Shipped HIPAA-compliant Voice AI systems processing 900,000+ minutes of usage, with retry logic and queue management for high availability.
Built a custom integration pipeline for CRM, ATS, and API connections (OAuth2 / API keys) with Voice AI agents.
Implemented FHIR integrations with EHRs (Athenahealth, ModMed, Tebra) for bi-directional patient sync, scheduling, and clinical notes ingestion.

## Projects

### Ignis

Project URL: /blog/ignis

Skills: TypeScript, Go, Firecracker, NATS

### Lawson

Project URL: https://github.com/Farbyte/lawson

Skills: React, Next.js, Supabase, LangChain, FastAPI

### Appwrite

Project URL: https://github.com/appwrite/templates/pull/211

Skills: TypeScript, Node.js, Appwrite, Meilisearch

### LangChain

Project URL: https://github.com/langchain-ai/langchainjs/pull/5842

Skills: TypeScript, Node.js, LangChain, JinaAI


## Blog

---
title: "Ignis Code Execution"
description: "A deep dive into building a serverless code execution platform using Firecracker microVMs, exploring how platforms like AWS Lambda actually work under the hood."
last_updated: "September 7, 2025"
source: "https://avater.dev/blog/ignis"
---

# Ignis Code Execution

A deep dive into building a serverless code execution platform using Firecracker microVMs, exploring how platforms like AWS Lambda actually work under the hood.


## Prelude

I was on LinkedIn, half-distracted, when I stumbled onto a post by [Arpit Bhayani](https://www.linkedin.com/posts/arpitbhayani_asliengineering-systemdesign-activity-7258316307891146753-c1uL/) about Firecracker.

At first, it was just another tech post in the feed, but something about it stuck. Firecracker wasn't a shiny new framework or a library with yet another abstraction. It was raw infrastructure, the kind of thing that quietly powers the world but rarely gets talked about outside of deep engineering circles.

And that made me curious.

We all use serverless platforms all the time (AWS Lambda, Vercel, Cloudflare Workers) without stopping to think about what's really happening. You write a function, hit deploy, and magically it's running somewhere in the cloud. But that "somewhere" intrigued me. *What's actually happening in that invisible layer where a request triggers a fresh environment, your code spins up in milliseconds, and then disappears without a trace?*

How do these systems manage to cold-start fast enough to feel instant, stay secure when thousands of strangers' code runs side by side, and still scale up or down as if by sleight of hand?

I didn't want the marketing answer.

So I gave myself a small challenge: take Firecracker, strip away the cloud-scale buzzwords, and try to build something around it with my own hands. No production deadlines, no polish, just an excuse to learn.

That's how **Ignis 🔥** was born.

## About Firecracker

Firecracker is an open-source virtualization solution developed by Amazon Web Services (AWS). It is designed to provide lightweight, secure, and efficient virtual machines tailored for containerized and serverless workloads. It powers AWS Lambda and AWS Fargate. It also powers multi-tenant serverless services such as Koyeb and Fly.io.

## Let's get started

So like any other project I went to [firecracker's github](https://github.com/firecracker-microvm/firecracker) to learn about it.

Well firecracker is written in rust. Now I know rust, but I wouldn't use it for writing backends. Why? Because I don't wanna fight with the borrow-checker when I'm just trying to get something to work.

Lucky for me the firecracker folks have bindings for **Golang** along with a pretty well-maintained official source i.e. the [firectl](https://github.com/firecracker-microvm/firectl).

So some warnings: Firecracker only runs on Linux (no wsl support sorry) for now. Also Firecracker uses the KVM linux module to read/write access to `/dev/kvm`.

So let's get started: followed the QuickStart guide and after a little bit of tinkering we have firecracker up and running.

## Project Structure

The project, named Ignis (inspired by the Latin word for fire, akin to Firecracker), supports multiple programming languages through dedicated runtime environments. Currently, it accommodates Python and Go, with an extensible architecture for adding more languages.

The complete source code is available on [GitHub](https://github.com/AvaterClasher/ignis-frontend).

Here is a schema of the global architecture:

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757253049759/6e920bcf-e0a8-427a-afdc-39063896728f.png"
  width={1200}
  height={700}
  quality={100}
  alt="Ignis project schema diagram"
/>

The primary API, developed in Golang, manages the core business logic. Code submissions are queued via [NATS](https://github.com/nats-io/nats-server) for asynchronous processing, with execution handled by virtual machines.

## Implementation Details

The system is divided into three components:

- Ignis-Agent
- Ignis-VMM
- Ignis-Backend

### Ignis-Agent

The Ignis-Agent runs within the microVM as an HTTP API built with Echo in Golang. It compiles and executes code for supported languages.

A key feature of Ignis is its language-agnostic design, which employs distinct root filesystem (rootfs) images for each supported language.

A central language dispatch mechanism routes requests to the appropriate handler based on the specified language:

```go
// Call language handler
switch toID[req.Language] {
case Python:
    return pythonHandler(c, req)
case Golang:
    return golangHandler(c, req)
default:
    return echo.NewHTTPError(http.StatusBadRequest, "Invalid language")
}
```

This dispatch ensures efficient handling of diverse languages within a unified agent framework.

The execution engine captures detailed metrics, such as duration and memory usage:

```go
func execCmd(c echo.Context, program string, arg ...string) error {
    var execStdOut, execStdErr bytes.Buffer
    cmd := exec.Command(program, arg...)
    cmd.Stdout = &execStdOut
    cmd.Stderr = &execStdErr
    start := time.Now()
    err := cmd.Run()
    elapsed := time.Since(start)
    if err != nil {
        return c.JSON(http.StatusBadRequest, runCRes{
            Message:      "Failed to run",
            Error:        err.Error(),
            Stdout:       execStdOut.String(),
            Stderr:       execStdErr.String(),
            ExecDuration: elapsed.Milliseconds(),
            MemUsage:     cmd.ProcessState.SysUsage().(*syscall.Rusage).Maxrss,
        })
    }
    return c.JSON(http.StatusOK, runCRes{
        Message:      "Success",
        Stdout:       execStdOut.String(),
        Stderr:       execStdErr.String(),
        ExecDuration: elapsed.Milliseconds(),
        MemUsage:     cmd.ProcessState.SysUsage().(*syscall.Rusage).Maxrss,
    })
}
```

While effective, this method relies on shell commands, which may lack elegance and introduce security considerations.

To prepare the VM image, the agent is preinstalled, and an OpenRC service ensures it starts on boot.

The rootfs is constructed using techniques from the Firecracker documentation, involving an ext4 image mounted in a Docker container with Alpine.

### Ignis-VMM

This component bridges the API and microVMs, managing job reception, VM lifecycles for multiple languages, agent communication, and status updates.

Jobs are received asynchronously via [NATS](https://github.com/nats-io/nats-server). To minimize latency (given boot times of 1-2 seconds), a pool of pre-warmed VMs is maintained per language.

#### Dynamic Language Discovery

At startup, the system scans the agent directory to identify available languages automatically:

```go
func discoverAvailableLanguages() ([]string, error) {
    files, err := ioutil.ReadDir("agent")
    if err != nil {
        return nil, fmt.Errorf("failed to read agent directory: %w", err)
    }
    var languages []string
    for _, file := range files {
        if file.IsDir() {
            continue
        }
        // Look for rootfs-<language>.ext4 files
        if strings.HasPrefix(file.Name(), "rootfs-") && strings.HasSuffix(file.Name(), ".ext4") {
            // Extract language from filename: rootfs-python.ext4 -> python
            language := strings.TrimPrefix(file.Name(), "rootfs-")
            language = strings.TrimSuffix(language, ".ext4")
            languages = append(languages, language)
        }
    }
    if len(languages) == 0 {
        return nil, fmt.Errorf("no rootfs images found in agent directory")
    }
    return languages, nil
}
```

#### Language Pool Manager

Ignis utilizes a multi-language pool management system rather than a single VM pool:

```go
type LanguagePoolManager struct {
    pools map[string]chan runningFirecracker
    mutex sync.RWMutex
}

func NewLanguagePoolManager() *LanguagePoolManager {
    return &LanguagePoolManager{
        pools: make(map[string]chan runningFirecracker),
    }
}

func (lpm *LanguagePoolManager) GetPool(language string) (chan runningFirecracker, error) {
    lpm.mutex.RLock()
    pool, exists := lpm.pools[language]
    lpm.mutex.RUnlock()
    if !exists {
        return nil, fmt.Errorf("no pool found for language: %s", language)
    }
    return pool, nil
}
```

This approach provides:

- Dedicated pools of pre-warmed VMs for each language.
- Opportunities for language-specific optimizations.
- Isolation of resources across different runtimes.
- Scalability tailored to demand per language.

**Language-Specific VM Creation**:

```go
// Create a VMM with a specific language rootfs and start the VM
func createAndStartVMForLanguage(ctx context.Context, language string) (*runningFirecracker, error) {
    vmmID := xid.New().String()
    baseRootFS := getRootfsPath(language)
    // Check if the rootfs file exists
    if _, err := os.Stat(baseRootFS); os.IsNotExist(err) {
        return nil, fmt.Errorf("rootfs for language %s not found: %s", language, baseRootFS)
    }
    // Prepare a dedicated writable copy of the root filesystem for this VM instance
    if err := copyFile(baseRootFS, "/tmp/rootfs-"+vmmID+".ext4"); err != nil {
        return nil, fmt.Errorf("failed to prepare rootfs for language %s: %w", language, err)
    }
    fcCfg, err := getFirecrackerConfig(vmmID)
    if err != nil {
        log.Errorf("Error: %s", err)
        return nil, err
    }
    // ... VM creation logic
}

func getRootfsPath(language string) string {
    return filepath.Join("agent", fmt.Sprintf("rootfs-%s.ext4", language))
}
```

**Multi-Language Pool Management**:

Pools are created for each language, with dedicated goroutines for replenishment:

```go
// Create pools for each language and start pool fillers
const poolSize = 1 // Number of VMs per language pool
for _, language := range languages {
    poolManager.AddPool(language, poolSize)
    // Start the pool filler for this language
    pool, _ := poolManager.GetPool(language)
    go fillLanguageVMPool(ctx, language, pool)
}
```

The pool filler ensures each language always has warm VMs available. It operates as an infinite loop in a goroutine, adding VMs to the pool once ready, verified by checking the health endpoint of the Ignis-Agent.

**Job Execution with Language Routing**:

When a job is received, it is routed to the correct language pool:

```go
func (job benchJob) run(ctx context.Context, poolManager *LanguagePoolManager) {
    log.WithField("job", job).Info("Handling job")
    // Get the appropriate pool for this job's language
    pool, err := poolManager.GetPool(job.Language)
    if err != nil {
        log.WithField("language", job.Language).WithError(err).Error("No pool available for language")
        q.setjobFailed(ctx, job, agentExecRes{Error: fmt.Sprintf("No pool available for language %s: %v", job.Language, err)})
        return
    }
    // Get a ready-to-use microVM from the language-specific pool
    vm := <-pool
    // ... execute job on vm
}
```

To initiate a microVM, the worker performs several steps:

- Copies the language-specific "golden image" of the rootfs to a temporary file dedicated to the microVM.
- Configures the `firecracker.Config`.
- Creates a `firecracker.Machine`.
- Starts the machine instance.

The resulting `runningFirecracker` struct is stored in the channel, containing elements such as the VM's IP address for agent communication and the `firecracker.Machine` and context for shutdown.

Networking is facilitated by CNI plugins. On the host, a configuration file is required in `/etc/cni/conf.d/fcnet.conflist`:

```json
{
  "name": "fcnet",
  "cniVersion": "1.0.0",
  "plugins": [
    {
      "type": "ptp",
      "ipMasq": true,
      "ipam": {
        "type": "host-local",
        "subnet": "192.168.127.0/24",
        "resolvConf": "/etc/resolv.conf"
      }
    },
    {
      "type": "tc-redirect-tap"
    }
  ]
}
```

With CNI plugin binaries in `/opt/cni/bin` from:

- containernetworking/plugins: [host-local](https://github.com/containernetworking/plugins), [ptp](https://github.com/containernetworking/plugins)
- awslabs: [tc-redirect-tap](https://github.com/awslabs/tc-redirect-tap)

#### A tc-redirect-tap CNI version bug

The setup initially seemed straightforward: I prepared a language-specific root filesystem, launched the microVM, and configured networking parameters via a CNI configuration file (`fcnet.conflist`). However, an unexpected version conflict disrupted the process.

The first error appeared when using the default CNI version 1.0.0: `incompatible CNI versions; config is "1.0.0", plugin supports ["0.3.0", "0.3.1", "0.4.0", "1.1.0"]`.

This error indicated that the tc-redirect-tap plugin did not support version 1.0.0, despite it being a standard choice in recent CNI tools. Following the error's guidance, I updated `fcnet.conflist` to use version 0.4.0, hoping to resolve the mismatch. Instead, a new error emerged: `plugin type="tc-redirect-tap" failed (add): unsupported CNI result version "1.1.0"`.

This was puzzling: the plugin was returning a result version (1.1.0) that conflicted with the configured version (0.4.0). After digging deeper, I discovered the issue stemmed from the plugin's logic, which always returned the latest implemented CNI version (1.1.0), regardless of the configuration.

This caused a compatibility issue with the firecracker-go-sdk, which relied on an older CNI library version (1.0.1) that didn't recognize 1.1.0.

So I opened an issue for this: [awslabs/tc-redirect-tap/issues/98](https://github.com/awslabs/tc-redirect-tap/issues/98).

The maintainers promptly identified the bug and released fixes in two pull requests (#99 and #106). These updates corrected the plugin's version handling to respect the configured CNI version and ensured compatibility with 1.0.0.

### Ignis-Backend

This is a Gin backend implemented in Go, providing CRUD operations for jobs and updates, along with integration for pushing and receiving from the NATS queue.

That's it.

## Possible Improvements

- **Rootfs Optimization**: Reduce the image sizes even more by custom building linux images.
- **Snapshotting**: Try out snapshotting the initial state of the rootfs image and use that instead of spinning up new ones repeatedly.
- **Fix the balloon up problem**: Firecracker doesn't return the space it has occupied back till the vm is killed.
- Also random crashes and vm not starting up sometimes.

## Conclusion

Ignis is not production-grade, nor was it meant to be. It's a **prototype that sits somewhere between a playground and a proof-of-concept**.

If you're curious, the code's here on [GitHub](https://github.com/AvaterClasher/ignis-frontend).

And if you've ever thought "I wonder how serverless actually works under the hood?", try pointing Firecracker at a rootfs and booting your first micro-VM. You'll learn a ton about virtualization, container runtimes, and the beautiful complexity of modern cloud infrastructure.


Last updated on September 7, 2025

---
title: "From Bug Hunter to Builder: HackerRank Edition"
description: "How discovering bugs in HackerRank's resume builder led me to create my own resume parser solution - NResume"
last_updated: "November 15, 2024"
source: "https://avater.dev/blog/hackerrank"
---

# From Bug Hunter to Builder: HackerRank Edition

How discovering bugs in HackerRank's resume builder led me to create my own resume parser solution - NResume


Recently, I came across a job posting for HackerRank's SDE Intern role, and I was really excited to apply. One of my seniors had previously worked at HackerRank, and from all the articles I had read, it was clear that the company had an amazing work culture. While applying for the role, I came across a blog that caught my attention: [**Summer Internship Experience '21**](https://blog.ishandeveloper.com/hackerrank) written by Ishan Bhaiya. It resonated with me deeply, as Ishan Bhaiya's situation was strikingly similar to mine. Much like Ishan Bhaiya, I too began to dream of seeing my name on that TV screen.

During my application process, I was introduced to HackerRank's resume builder, also coincidentally built by Ishan Bhaiya during his internship. As I used the platform, I encountered a couple of bugs that were quite frustrating. These bugs not only highlighted areas for improvement but also inspired me to build my own tools to enhance the experience. Interestingly, I felt a sense of excitement when I discovered these issues. Why? Because just like Ishan Bhaiya, who was noticed by the HackerRank team after mailing them about a custom HTTP header, I felt like I too could contribute something valuable to the platform for them to notice me.

## The Bugs I Discovered

### 1. The GitHub Import Pagination Bug

The first issue I stumbled upon was related to the GitHub import feature in the resume builder. When navigating through the pagination of repositories, I noticed that despite clicking on the "Next" button, the API request URL remained the same, preventing any new data from loading. For example, the request URL stayed as `https://www.hackerrank.com/resume/api/github/repositories/xxxxxxxx?limit=14&page=1`.

No matter what button I clicked, the same API was called, which resulted in the inability to load further repositories.

**Solution**: Resolving this is quite easy: we just need to ensure the pagination logic includes proper query parameter updates when the "Next" button is clicked. Specifically, the page parameter should increment with each subsequent request to ensure that the correct repositories for the next page are fetched. Additionally, logging and error handling on the client side should also be added to alert users when such issues arise, improving user experience.

### 2. The CORS Issue

I initially attempted to report this bug through HackerRank's support page, but I faced another issue, one of the nightmares of new devs: CORS (Cross-Origin Resource Sharing) errors. I couldn't submit my bug report because my request to the support page was blocked due to CORS policy restrictions. The exact error I encountered was `Access to XMLHttpRequest at 'https://metrics.hackerrank.com/app_metrics' from origin 'https://www.hackerrank.com' has been blocked by CORS policy.`.

At this point, I felt stuck, as I was unable to report the issue effectively.

**Solution**: This one also has a very easy solution: allow CORS requests from authorized domains.

### 3. Resume Matcher Bugs

Further investigation revealed another bug in the resume matcher tool. When I tried to match my resume to the SDE intern job listing on HackerRank's site, I noticed that the system made multiple backend requests, all resulting in 404 errors. After several failed attempts, it displayed a "no data found" message, unlike for other job links where the data was fetched after a few retries. The issue here appeared to be that if there are no Requirements listed on the page that is being parsed, the requests just error out.

**Solution**: The easy solution is to return a more meaningful error message, something like "No skill requirements found on the page". The slightly costlier solution is to maybe use an LLM model to ingest the page's data and compare it against the user's resume to generate the matching result. (One of the things I want to implement in H2R2).

### 4. The Placeholder URL Bug

I encountered an issue with the GitHub project link placeholder in the HackerRank resume builder. The builder suggests entering a GitHub URL like `github.com/Username/project`, but when used, it generates a link like `https://www.hackerrank.com/resume/builder/github.com/AvaterClasher/zexd-backend`.

This happens because the `<a>` tag treats the entered URL as a **relative URL** and appends it to the base URL of the platform (`https://www.hackerrank.com/resume/builder`). This causes the URL to break, leading to a 404 page. Once the resume is downloaded, the URL is recognized correctly as an external link, but the issue occurs while using the builder.

**Solution**: The placeholder should be updated to prompt users to enter the full, absolute URL with the `https://` protocol, like `https://github.com/Username/project`. This will prevent the builder from mistakenly treating it as a relative path and ensure correct redirection in the preview.

### 5. The Overflow Problem (Recently Found)

While exploring how HackerRank handles overflow in its resume preview and splits content across pages, I discovered an interesting behavior regarding line breaks. If a user types a very long word without spaces, it simply overflows the container instead of breaking properly. I understand this is not a bug. However, I thought it was worth pointing out in case the team wants to address it, or even better, let me work on fixing it during my internship!

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731676194539/d5c0e007-915c-4064-9318-9da53b930250.png"
  width={800}
  height={400}
  quality={100}
  alt="Text overflow issue in HackerRank resume builder"
/>

## Reporting the Bugs

Unable to reach the HackerRank support team directly, I decided to explore other channels like email and LinkedIn. Through this, I connected with [Apoorve Bhaiya](https://www.linkedin.com/in/apoorve-goyal/), an SDE2 at HackerRank. He appreciated my efforts in reporting the bugs and mentioned that he would take the issues to the team to get them resolved as soon as possible. However, shortly after our conversation, I received an email informing me that I had not been selected.

This setback only motivated me further. I asked myself: _"Why should HackerRank hire me? How can I improve their product?"_

That's when I identified a significant pain point in their **Resume Builder**: the lack of an import button for recurring information, like a candidate's name, education, and other constant details. Determined to address this, I set out to build a solution.

## Building NResume: A Resume Parser for HackerResume 2.0

Inspired by the bugs I encountered, I created [**nresume**](https://www.npmjs.com/package/nresume), a **resume parser** designed to extract structured information from resume PDFs, such as job titles, companies, dates, and descriptions. This tool aims to fill the gap in HackerRank's Resume Builder, making it more efficient for users.

To test [**nresume**](https://www.npmjs.com/package/nresume), I quickly built a prototype website called **H2R2** at [**h2r2.vercel.app**](https://h2r2.vercel.app) using **Next.js**, all in a single night. While the site has rough edges due to its rapid development, it provided a functional environment to showcase nresume's capabilities.

I wanted a solution that didn't rely on a backend, as that would mean either extracting text from the PDF on the frontend and sending it to the server or uploading the file to S3 and then parsing it on the backend-side. My thought was, why not handle the entire parsing process on the frontend? That's when I found [**pdfjs**](https://github.com/mozilla/pdf.js), a library by Mozilla that allows text extraction directly in the browser.

My second challenge was that I'd never built a JavaScript package before, which opened up a whole new world of learning about bundling and packaging. Then came another big roadblock: deploying it on Vercel. I expected a smooth React package integration, but instead, I encountered multiple issues during deployment. After a lot of reading, searching for fixes, and diving into discussions on [react-pdf issues](https://github.com/wojtekmaj/react-pdf/issues), I finally got it working (p.s. I do write meaningful commit messages, this one's just for fun, no judgments!).

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731344728506/56e3fe4f-d55f-4d38-bfa4-06c0f9ee001a.png"
  width={800}
  height={400}
  quality={100}
  alt="Fun commit message screenshot from the development process"
/>

**NResume** is designed to work within the browser, making it flexible for various environments. It uses a combination of regular expressions and feature scoring to identify the most relevant information from resumes.

However, the parser has some limitations:

- It currently only supports single-column resumes
- It does not yet handle project sections, as they often vary too much in structure to process reliably

## Future Upgrades

### Resume Preview and Download

Working out how to properly display the resume's preview and download the same without breaking the layout. Currently, the layout breaks.

### Named Entity Recognition (NER)

Use AI models to identify and classify key entities such as job titles, skills, certifications, and companies, making the parser more context-aware.

### Customizable LLM Queries

Allow users to define their own prompts, models, and keys to generate personalized resume insights or summaries using LLMs like GPT.

### Semantic Search for Resumes

Implement AI models to enable semantic matching of resumes against job descriptions, identifying the best-fit candidates for specific roles.

### Resume Optimization Recommendations

Add AI-powered suggestions to reword or optimize bullet points, ensuring they align with ATS (Applicant Tracking System) best practices.

## Conclusion

Building **nresume** has been one of the most rewarding projects I've undertaken. The idea was born out of the frustrations I experienced while using HackerRank's resume builder. Encountering multiple bugs was certainly challenging, but those challenges ultimately inspired me to create my own solution to the problem.

Is **nresume** perfect? Not at all. Does it need significant improvements? Absolutely. So, why am I publishing it now? With HackerRank's internships starting in January and my end-semester exams lasting until November 25th, this is my best opportunity to showcase my work before it's too late.

If any HackerRank team member happens to read this, I'd love the chance to prove my skills, be it through an interview or even a take-home assignment. I'm confident that my abilities align with what HackerRank is looking for, and I'm eager to demonstrate my potential!

Thank you for reading!

Also attaching my resume just in case :) → [My Resume](https://drive.google.com/file/d/1uiI7ddnX4xHSmYAzcrCV8wAOWxUINJpH/view?usp=sharing)


Last updated on November 15, 2024

---
title: "Lawson: LegalClerk for Lawyers"
description: "An AI-powered tool designed to revolutionize the way legal professionals interact with court cases by providing concise summaries and interactive analysis."
last_updated: "July 21, 2024"
source: "https://avater.dev/blog/lawson"
---

# Lawson: LegalClerk for Lawyers

An AI-powered tool designed to revolutionize the way legal professionals interact with court cases by providing concise summaries and interactive analysis.


## Introduction

Imagine if lawyers could grasp the essence of complex court cases in mere seconds. This idea hit close to home for our team when we learned about the struggles of one teammate's sister, who is currently studying law. She shared her experience of the daunting challenge of reading through long judgments while preparing for cases. Inspired by her plight, we embarked on a mission to create Lawson. Recognizing this widespread issue, we were inspired to create a solution that could alleviate the burden faced by lawyers and law students alike. Thus, Lawson was born.

Lawson is an AI-powered tool designed to revolutionize the way legal professionals interact with court cases. By leveraging advanced natural language processing and machine learning algorithms, Lawson can analyze court documents and provide concise, relevant summaries in a matter of seconds. Our goal is to streamline the process of legal research, allowing lawyers to focus more on their strategic and client-facing responsibilities rather than getting slowed down by lengthy texts.

The Hashnode hackathon served as our first stop on the voyage, where we had a fruitful brainstorming session about using technology to solve practical issues. Our team set out to design a tool that would improve the accuracy and efficiency of legal research while also saving time. We did this by combining our wide skill set in frontend development, backend development, AI and legal knowledge (of course guided by our friend's sister).

## Links

Please read the [vercel function limitation](https://avater.hashnode.dev/lawson-a-tool-for-lawyers-to-understand-court-cases-in-seconds?showSharer=true#heading-vercel-function-duration-limit) before going to the live website.

Here's a demo legal case pdf for trying out lawson: [Download](https://utfs.io/f/69612007-89d9-44da-a40c-c8edca9c173d-2d0m.pdf)

- **Website**: [https://law-son.vercel.app/](https://law-son.vercel.app/)
- **Documentation**: [https://law-son.vercel.app/docs](https://law-son.vercel.app/docs)
- **FAQ**: [https://law-son.vercel.app/faq](https://law-son.vercel.app/faq)
- **GitHub Repository**: [https://github.com/Farbyte/lawson](https://github.com/Farbyte/lawson)

## Problem Statement: Defining the Pain Point

### Time-Consuming Research

Legal professionals and law students spend countless hours reading through lengthy court judgments. These documents are often complex, dense, and filled with legal jargon, making it difficult to quickly extract the most pertinent information. This exhaustive process eats into valuable time that could be better spent on case strategy, client interaction, and other critical tasks. The time spent on research not only delays legal proceedings but also increases costs for clients.

### Information Overload

Court cases and legal documents are extensive and contain vast amounts of information. Lawyers need to sift through numerous pages to find relevant details, which can be overwhelming and lead to cognitive overload. The sheer volume of information increases the risk of missing crucial details that could impact the outcome of a case. This can lead to mistakes, misinterpretations, and ultimately, unfavorable results for clients.

## Tech Stack

Our technology stack includes:

1. **React** - Frontend user interface
2. **Next.js** - React framework with SSR
3. **TypeScript** - Type-safe JavaScript
4. **Python** - Backend processing
5. **FastAPI** - Fast web framework for APIs
6. **Langchain** - LLM application framework
7. **Pinecone** - Vector database
8. **Prisma** - Database ORM
9. **PostHog** - Product analytics
10. **Vercel** - Deployment platform

## Development Process: The Journey

Our development journey was quite an experience: we had a lot of fun doing the project, and it was great to learn new things. This put us in some undesirable situations, but we are developers, and we found ways to solve those issues in our style. Some of the problems we faced:

### Token Limit of the AI Model for Large Judgments

**Challenge**: One of the significant hurdles we faced was the token limit of our AI model. Legal judgments can be extremely lengthy, often exceeding the token capacity of standard AI models. This limitation made it difficult to process and analyze entire documents effectively.

**Solution**: To address this issue, we developed a solution using k-means clustering. By segmenting the judgment text into smaller, more manageable clusters, we were able to process each segment independently. Different types of prompts were used to ensure that each cluster captured the essential information. This approach allowed us to maintain the integrity of the analysis while staying within the token limits of the AI model.

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721577094029/d7a21784-2cb2-41af-a2ce-c50cc800981e.png"
  width={800}
  height={400}
  quality={100}
  alt="K-means clustering solution diagram"
/>

### Timing Issues in Creating Embeddings

**Challenge**: Creating embeddings for large volumes of text data was another time-consuming process that posed a challenge. Embeddings are crucial for understanding the context and semantics of the text, but generating them efficiently was a bottleneck in our development workflow.

**Solution**: We tackled this problem by implementing multithreading. Lawson starts with an input document, typically a legal judgment, which is divided into smaller chunks with text and vector representations. These chunks are batched based on the number of available API keys. Each batch gets a unique API key, and threads are spawned to parallelize embedding creation. The embedding function generates embeddings for each chunk, and the results are formatted and added to a shared resource vector pool. Finally, all vectors are added to a Pinecone index for efficient retrieval. This approach allows Lawson to process large documents efficiently and within API limits.

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721580340575/5e372203-1500-430b-9502-e81f89df915b.png"
  width={800}
  height={400}
  quality={100}
  alt="Multithreading embedding creation workflow"
/>

### Utilizing Next.js 14 Server Architecture

**Challenge**: We decided to use the new Next.js 14 server architecture for the first time. Understanding and implementing server-side rendering (SSR) effectively was a significant challenge, particularly given the tight timeframe of the hackathon.

**Solution**: By server-side rendering everything except client components, we managed to reduce the amount of JavaScript sent to the client. This optimization not only improved the performance of our application but also provided a smoother user experience. The new Next.js 14 architecture allowed us to leverage modern web development practices, ensuring our solution was both efficient and scalable.

## How Lawson Works

Lawson operates in a simple and user-friendly manner designed to make legal research more efficient for professionals. Here's a detailed look at the process:

1. **Upload Document**: The user starts by uploading a document containing the judgment they need to analyze. This document could be a lengthy legal judgment, often dozens of pages long, which would typically require significant time and effort to read and comprehend.

2. **Document Processing**: Once the document is uploaded, Lawson immediately begins processing it. This involves breaking the document down into smaller, manageable chunks, each containing text and its vector representation. This step ensures that the document fits within the token limits of AI models, making the processing more efficient and manageable.

3. **Generating Summary**: After the document is processed, Lawson generates a concise summary of the judgment. This summary provides the key points and essential information from the document, allowing the user to quickly grasp the main findings and implications of the case without having to read through the entire document.

4. **Interactive Chat for More Details**: If the user needs more detailed information beyond the summary, they can engage in an interactive chat with Lawson. This feature allows users to ask specific questions about the judgment and receive detailed answers, making it easy to delve deeper into particular aspects of the case. The chat functionality is designed to be intuitive and responsive, providing users with the information they need in real time.

This straightforward workflow ensures that legal professionals can quickly and efficiently understand court cases, saving valuable time and effort. By combining document processing, summarization, and interactive chat features, Lawson provides a comprehensive tool for legal research and analysis.

## Features

### User-Friendly Interface

One of the cleanest UIs which is visually pleasing and comfortable.

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721546880398/1f010339-a83a-4c3c-949a-8e95c16f65af.jpeg"
  width={800}
  height={500}
  quality={100}
  alt="Lawson's clean and user-friendly interface"
/>

### Instant Summary

Users will get summaries in three different ways and they can also download the summary in PDF format.

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721547790191/452cf80a-7bc2-4ad0-a5af-56652f37dc28.jpeg"
  width={800}
  height={500}
  quality={100}
  alt="Summary generation feature showing three different summary types"
/>

### Chat Section

Users can ask for details about the judgments in the chat section. They can also copy the generated text and use the speak-aloud function to listen to the text. Users can upload new documents by clicking the plus icon.

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721548418373/34544db1-20ca-46ce-b7af-18003aa0006e.jpeg"
  width={800}
  height={500}
  quality={100}
  alt="Interactive chat interface with copy and speak features"
/>

### History Section

Our history section neatly divides the chat history into today, yesterday, and previous 30 days. Users can easily delete their documents. If the user has already uploaded any document, they can access it by clicking it once.

<Image
  src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721548985748/3ec7050f-5dd5-4493-a23c-b52efdd93f9e.jpeg"
  width={800}
  height={500}
  quality={100}
  alt="History section showing organized document access"
/>

## Future Plans and Limitations

While Lawson is a powerful tool designed to streamline legal research, there are some limitations we are currently addressing:

### Vercel Function Duration Limit

Due to Vercel's function duration limit, users can only upload judgments up to 10 pages. Processing longer documents takes more than the allotted 60 seconds to create vectors, which impacts the usability of Lawson for more extensive cases.

To overcome this limitation, we recommend using Lawson locally, where there are no such restrictions. Running Lawson on your local machine allows you to process longer documents without the time constraints imposed by Vercel.

**Setting up locally**: [https://law-son.vercel.app/setting-up-locally](https://law-son.vercel.app/setting-up-locally)

### Semantic Search

**Future Enhancement**: One of the exciting features we plan to introduce is semantic search. This functionality will allow users to input case details and receive the top 5 judgments related to their case. By leveraging advanced natural language processing and machine learning algorithms, Lawson will provide more relevant and precise search results, making legal research even more efficient and accurate.

## Thank You

We are committed to continuously improving Lawson based on feedback from the legal community. We built Lawson using all free resources and delivered our best, but there may still be some problems. We encourage users to share their experiences and suggestions to help us refine and enhance the tool.

## Team Members

- [Soumyadip Moni](https://github.com/AvaterClasher)
- [Suvarn Vats](https://github.com/FaYMan2)
- [Krushna kanta Sahoo](https://github.com/Krushna-sahoo)


Last updated on July 21, 2024