I engineer the systems around LLMs. Not the prompts inside them.

Lead Backend Engineer (RA), Boston University, Questrom Computational Lab. Full-time from January 2027.

NVIDIA-Certified Professional: Agentic AI · Claude Certified Developer – Foundations

He found a silent error-swallowing bug in LangChain’s Python SDK. A maintainer merged the fix in 57 hours.

Ready. Ask about his work

, now (RA) at 's Questrom Computational Lab, where he built the that holds agents to the same gates as human engineers, shipped as a plugin with and . A maintainer merged the fix for the bug he reported in 57 hours, certifies him as a , and as a .

Sections

The bug that looked like success

Merged by a LangChain maintainer 57 hours after his report.

langchain-ai/deepagentsCompositeBackend.ls()

results = []for route in self.routes:    results.extend(route_result.entries or []) default_result = self.default.ls(path)results.extend(default_result.entries or [])return ListResult(entries=results)

The default backend failed. The caller was told the filesystem was healthy and nearly empty.

default_result = self.default.ls(path)if default_result.error:    return ListResult(error=default_result.error)results.extend(default_result.entries or [])

Written and merged by a LangChain maintainer 57 hours after the report. PR #4925

He found and root-caused a silent error-swallowing bug in LangChain’s deepagents SDK, and a maintainer merged the fix 57 hours after he reported it, crediting his reproduction in the pull request body.

CompositeBackend.ls("/") and als("/") aggregated results at the root and discarded errors from the default backend, returning a successful-looking listing containing only virtual route directories. A caller whose backend had failed would see a healthy but nearly empty filesystem.

Read more about the LangChain deepagents fixShow less

What made the report land was not spotting a crash, because there was no crash. It was showing that the behaviour contradicted the codebase’s own documented invariant, quoted from _merge_glob_results: a backend error must not be swallowed as a partial success. The routed branch already checked for errors. The grep root merge already returned default backend errors first. Only this path did not. He also traced the precedent, the same bug class as issue #3105, fixed for sandbox backends in #3359.

Filed 19 July 2026 at 15:20 UTC. Mason Daugherty, a LangChain maintainer, wrote and merged the fix on 22 July at 00:45 UTC, 57 hours later, in 29 added lines across 2 files with nothing deleted. The pull request body reads: Credit to @Kushal9889 for reporting the issue and providing the reproduction.

Four more are open and under review. In vLLM he opened pull request #56846, which makes the pythonic tool-call parsers agree across streaming modes. On the Model Context Protocol Python SDK he filed issue #3490: a rejected connect_to_server in ClientSessionGroup leaves its transport running, because the session is established before its components are validated. In FastMCP he opened two pull requests on 21 October 2026: #5980 forwards URL-mode elicitation through the proxy, and #5978 forwards sampling tools through the proxy’s sampling relay.

Fifty-seven hours from a stranger’s bug report to a merged fix in a LangChain SDK. He offered in the issue to write the patch himself. The maintainer wrote it instead, which is the ordinary outcome when the report is good enough that fixing it takes twenty minutes.

  1. Issue he filedlangchain-ai/deepagents#4846closed
  2. 57 hours from his report to a merged fix
  3. Fix a maintainer wrotelangchain-ai/deepagents#4925merged
The issue, the pull request and questions to askShow less
57 hours
from his report to a merged fixsource
3
places the file already contradicted itselfsource
credited
in the merged pull request bodysource

Work

Kushal Gaddamwar builds AI agents, then makes them answer to the same rules as the engineers around them.

  1. Lead Backend Engineer (RA)Boston University, Questrom Computational Lab · August 2026 to present
  2. AI Engineer (RA)Boston University, Questrom Computational Lab · May 2026 to August 2026
  3. Software Engineering InternIMG Systems · August 2024 to April 2025
  4. Associate Software Engineer InternGrowaza · January 2024 to July 2024

Lead Backend Engineer (RA)Boston University, Questrom Computational Lab

August 2026 to present · Boston, MA
Lead
the whole backend for the EST field-service platformsource
Recurring visits
scheduled across sites and clients; a missed job becomes a dispatch alertsource
Build once
one Docker image promoted across Azure environmentssource
Constant memory
a re-runnable migration streams Blob records into PostgreSQLsource

He leads the entire backend for EST’s field-service platform, and the part he architected that matters most is scheduling: technicians make recurring visits to many sites for many clients, so the system has to decide who goes where and when, every time. His idempotent recurrence engine generates those visits, and turns the legacy system’s silent missed jobs into dispatch alerts.

What he builtShow less
  • Claude Code
  • Model Context Protocol
  • Django REST Framework
  • PostgreSQL
  • Docker
  • Azure
  • React

He also architected the agentic SDLC harness that holds Claude Code agents to the same gates as human engineers in a regulated client codebase: least-privilege permissions, context-routing hooks, and CodeRabbit review linked to Linear through the Model Context Protocol, shipped as a plugin.

The backend is Django REST Framework and PostgreSQL: data-layer role-based access control, revocable JWT, and audit logs.

Read more about the Lead Backend Engineer (RA) roleShow less

He hardened delivery: CI fails on API-contract drift from the React frontend, a build-once Docker image promotes across Azure environments, and a re-runnable migration streams Blob records into PostgreSQL at constant memory.

AI Engineer (RA)Boston University, Questrom Computational Lab

May 2026 to August 2026 · Boston, MA
14
tools on one LangGraph agentsource
BM25 + vector
hybrid retrieval, Cohere rerankedsource
LLM-as-a-Judge
hallucination and retrieval scoringsource
Found in prod
a deduplication race and a Docker fault, both fixedsource

He built a document intelligence assistant on Azure for Sikich, an enterprise consulting firm, owned from ingestion through deployment: a LangGraph agent exposing 14 tools for document question answering, cross-document comparison and template-driven generation, grounded by hybrid BM25 and vector retrieval with Cohere re-ranking, guarded by PII and entity redaction, and scored for hallucination rate by LLM-as-a-Judge evaluations.

What he builtShow less
  • Azure OpenAI GPT-4o
  • Azure AI Search
  • LangGraph
  • FastAPI
  • React
  • Cosmos DB Gremlin
  • Cohere

He ran the customer-facing side too: requirements, demos, and weekly knowledge transfer to the client. In production he fixed a deduplication race and a Docker fault.

The constraint: consultants needed answers grounded in a large private document corpus, where a wrong answer delivered confidently is worse than no answer.

Read more about the AI Engineer (RA) roleShow less

What he built. A LangGraph agent exposing 14 tools covering document question answering, cross-document comparison, and template-driven generation. Hybrid retrieval fusing BM25 keyword search with vector search, plus LLM-based query rewriting and Cohere re-ranking. LLM-as-a-Judge evaluations measuring hallucination rate and retrieval quality. PII and entity redaction guardrails applied across ingested documents. Header-aware chunking, Markdown-header splitting plus recursive splitting, with SHA-256 deduplication and Azure Blob Storage metadata. Streaming FastAPI endpoints over Server-Sent Events with a React single-page app. A Cosmos DB Gremlin knowledge graph linking clients, projects, and technologies.

The trade-off worth asking about: hybrid retrieval costs more per query than dense-only. Dense embeddings compress meaning and lose surface form, so they miss exact terms, and in a consulting corpus the exact terms are client names, project codes, and document titles. The cost was worth it.

Software Engineering InternIMG Systems

August 2024 to April 2025 · Remote
+20%
extraction accuracysource
95%
schema accuracy, up from 75-78%source
5,000+
profiles parsed per monthsource
-25%
REST API latencysource
What he builtShow less

He extended a Python document-parsing pipeline built on Apache Tika, raising extraction accuracy 20 percent across more than 5,000 candidate profiles a month and cutting recruiter screening time 15 percent.

  • Python
  • Apache Tika
  • Pydantic
  • JSON Schema
  • PostgreSQL
  • Redis
  • Docker
  • GitHub Actions
  • Node.js

He enforced structured-output validation with Pydantic against a JSON Schema, reaching 95 percent schema accuracy and reducing manual review across a six-person team. Before the validation layer, schema conformance sat around 75 to 78 percent.

He containerized Python microservices backed by PostgreSQL and Redis with Docker, trimming REST API latency 25 percent and lifting throughput 30 percent, and automated CI/CD through GitHub Actions for zero-downtime releases.

Read more about the Software Engineering Intern roleShow less

He also tuned the collaborative filtering that ranks candidates against a role, raising match accuracy 20 percent while cutting false positives 18 percent. Automating the recruiter workflow in Python and Node.js saved the team more than 12 hours a week, across 8 Agile sprints delivered at 95 percent on-time.

Honest scope: this was an internship extending existing systems, not a greenfield build. He owned the pipeline extension, the schema layer, and the CI/CD setup independently.

The mistake he made here, and it is a good interview answer: his first Pydantic schemas were too strict. Documents that were merely unusual got rejected alongside documents that were genuinely malformed. He fixed it with fallback field validators and logging on the rejection path, which turned silent data loss into a visible signal.

Associate Software Engineer InternGrowaza

January 2024 to July 2024 · Remote
-30%
API response timesource
+22%
engagement, 1,000+ daily userssource
2,000+
SKUs tracked livesource
What he builtShow less

He cut API response time 30 percent using Redis caching and asynchronous request handling, lifting engagement 22 percent for more than 1,000 daily active users on an e-commerce platform.

  • React
  • Redux
  • MySQL
  • Redis
  • Node.js
  • JWT
  • RBAC
  • AWS EC2 and S3

He launched a MySQL inventory dashboard tracking more than 2,000 SKUs, and secured REST endpoints with JWT and role-based access control across admin, manager, and staff levels. Deployed on AWS EC2 and S3.

He was an intern on that team and did not manage anyone, which is worth stating plainly because the resume line said “led”.

The agent on this page

The agent on this page answers from his personal Obsidian knowledge base, the notes he keeps about his own work.

Research

He published research on finding bugs automatically, then found one by hand in a production SDK.

IEEE ICAICCIT 2024 · first author

published
91.4%
combined transformer and GNN accuracysource
88.2%
transformer alonesource
13.5 s
detect and fix, against 25.4 s for static analysissource
Bug detection accuracy

Dot chart, 80% to 95%.

  • Graph network alone85.7%
  • Transformer alone88.2%
  • Combined91.4%

Dots, not bars: the scale starts at 80%.

The paper, its timing chart and both papersShow less

He published research on finding bugs automatically, then found one by hand in a production SDK. The IEEE paper is about contextual bug detection: a transformer reads the code, a graph neural network reads the structure around it, and the combination reaches 91.4% accuracy where the transformer alone reaches 88.2% and the graph network alone 85.7%. Detection and fix together run in 13.5 seconds against 25.4 for static analysis.

The LangChain defect in the open source section is the same problem outside the lab. It was a silent failure with no exception and no stack trace, which is precisely the class static analysis does not catch and the class the paper argues context is needed for. First author, pages 624 to 629. doi:10.1109/ICAICCIT64383.2024.10912101 and the code, which carries a CITATION.cff so GitHub renders a citation button.

Read more about publicationsShow less

IGI Global 2024, co-author. Cyber-Physical Systems: Security and Optimization Strategies. Read the chapter and code

Certificates you can check

NVIDIA certifies him in agentic AI; Anthropic certifies him as a Claude developer.

NVIDIA-Certified Professional: Agentic AI certificateVerify on CredlyVerify on Credly
Claude Certified Developer – Foundations certificateVerify on CredlyVerify on Credly

How he works

Finding the place a system is wrong before it fails loudly.

Decisions behind this page

Conversation state: The graph runs without a checkpointer.

The graph runs without a checkpointer. LangGraph persists state after every node by default, which is right for a long-running stateful agent and wrong here. A Postgres saver costs 20 to 50 milliseconds per write, and this graph runs three nodes to answer one question in a conversation that lives in a browser tab. Conversation history rides with each request from the browser tab that is having the conversation, which trades durability he does not need for latency the reader can feel. That half was missing for a while: the graph shipped with the decision written down and the history never implemented, so every follow-up question was answered as though it were the first. It is in content/notes/defects.md with the rest.

Provider failure: When every model provider fails, the answer degrades rather than erroring.

When every model provider fails, the answer degrades rather than erroring. With no provider reachable, the agent returns the retrieved source paragraph instead of a failure: the reader still gets the grounded material, unsummarised, and the rest of the page keeps working. Silence is the failure mode worth avoiding, not imperfection.

Evaluation strategy: The evaluation suite has no LLM judge, deliberately.

The evaluation suite has no LLM judge, deliberately. He built LLM-as-a-Judge evaluation at the Questrom lab, where a large private corpus made grading by model the only tractable option. Here the suite is 26 cases with known correct behaviour, so assertions are substring and route checks. A judge would add cost, latency, and a second thing to trust, to grade questions whose right answer is already written down. The technique is not better than the check; it is what you reach for when a check is not available.

His working habit is reading a system until it contradicts itself. That is how a silent bug in LangChain’s deepagents SDK got fixed in 57 hours. It is also why this page links a number to its source wherever the source is public.

The work he does is context engineering: deciding what a model sees on every inference call. Retrieval, memory, tool surface, evaluation. Most of the difficulty in agentic systems is not the prompt. It is everything around the prompt.

Read more about who he isShow less

He is not a researcher and not an ML training engineer. He has not trained models in production or research. His training work is coursework: the assignments in Advanced Machine Learning and Neural Networks at Boston University. He builds systems that stay correct under load.

Finding the place a system is wrong before it fails loudly.

Two examples. At Questrom he traced answer quality problems to retrieval rather than generation, which is where they usually are and rarely where people look first. In LangChain’s deepagents SDK he found a code path that reported success while discarding an error, and wrote it up precisely enough that a maintainer shipped the fix in 57 hours.

Read more about what he is good atShow less

Pure backend work with no AI layer. As Lead Backend Engineer at Questrom he owns a Django REST and PostgreSQL backend where no model is in the loop: data-layer access control, revocable JWT, audit logs, and an idempotent recurrence engine. He did the same kind of work at IMG Systems and Growaza.

Experience scope

Model training in production or research. He has no PyTorch or TensorFlow project there. His training work is the coursework assignments in Advanced Machine Learning and Neural Networks at Boston University, and he does not present himself as an ML engineer.

Data science and statistical modeling.

Try the redaction demoShow less

Redact it yourself

6 found · nothing sent

What the model is allowed to see. Emails, phone numbers, card numbers, IP addresses, SSNs and keys are replaced before it would leave; names are not.

What the model receives

Ticket from Ana Ruiz ([EMAIL_1], [PHONE_1]): the export failed from [IP_1]. She pasted her card [CARD_1] and a key [KEY_1] to show us. Reply to [EMAIL_1].

email 1phone 1ip 1card 1key 1

How this is measured

26 of 26 eval cases pass on every run.

78/78runs pass
1.00retrieval recall@k
1.7 smedian answer
6.6 s95th percentile
How each figure is measured, and what the 26 cases cannot catchShow less
runs pass
26 cases, 3 runs each. Run once, this suite reported 16 of 16 and moved between 14 and 16 on consecutive runs with no code change, because the model is not deterministic and a sample of one cannot tell certainty from a good afternoon.
retrieval recall@k
Scored apart from the answers, because retrieval and generation fail for different reasons and were being reported as one number. The right section is retrieved every time; precision@1 is 0.70 and MRR 0.85. Every failure left in this suite is the model summarising a figure away, never the retriever missing it.
median answer
End to end, retrieval through generation, against a free tier with no warm instance held open.
95th percentile
The slow tail is the honest number. It is what a visitor gets when the provider is busy and the request is not cached.
Cases by group, and how long an answer takesShow less
  • 12/12grounding · cases cleananswers reproduce a figure that exists in the corpus
  • 6/6policy · cases cleancompensation, personal life and prompt overrides never reach the model
  • 3/3authorisation · cases cleanasked, it answers exactly; unasked, it never raises the subject
  • 2/2out-of-corpus · cases cleana question the corpus cannot answer produces no invention
  • 3/3tools · cases cleanan instruction is executed rather than answered, and a refusal says what would work
Answer latency, October 10, 2026 run

Bar chart, 0 seconds to 8 seconds.

  • Median answer1.7 s
  • 95th percentile6.6 s
What the 26 cases cannot catchShow less
  • Assertions are substring and route checks. Nothing here grades whether an answer reads well, only whether it is grounded and routed correctly.
  • There is no LLM judge, deliberately. At 26 cases with known correct behaviour, a judge adds cost, latency, and a second thing to trust.
  • One provider is measured per run. This one was served by nvidia on nvidia/nemotron-3-nano-omni-30b-a3b-reasoning, after the primary returned a daily rate limit.
  • Both retrievers ran on 45 of 45 retrievals. A short-circuit used to skip the embedding call when one keyword hit led the rest by 2.2×; measured across the suite it never fired on the rare-term queries it was written for, and fired only on the weakest-scoring ones, where it answered a question about his work with a paragraph about this website. It was removed rather than retuned.

Measured by npm run test:evals, which writes the file this section reads. Nothing here is entered by hand, so the figures cannot drift from the run that produced them.

eval suite26/26 · October 10, 2026

26 current cases shown, 3 recorded runs each. Aggregate results above are from the full suite measured October 10, 2026. Every policy and authorisation run passes because none of them reaches a model. The grounding cases are where a language model has to summarise without dropping the figure, and that is where the suite is honest about being probabilistic.

grounding36/36

the answer reproduces a figure that exists in the corpus

policy18/18

compensation, personal life and prompt overrides never reach a model

authorisation9/9

asked, it answers exactly; unasked, it never raises the subject

out of corpus6/6

a question the corpus cannot answer produces no invention

Every cell is one case, filled to the share of runs it passed. Open one to read the assertion the runner wrote for it.

which model answers5 tested · 56 runs each

Answers in about 0.8 seconds, and gets every test question right.

Five models were asked the same 14 questions, 4 times each, through the same pipeline that answers you above. 4 of them were too close to call. Their scores sit inside each other’s margin of error, so ranking them would be reporting luck. Nothing here justified a change, so the model already in use stayed.

  1. nemotron-3-nano-30b-a3banswering now100% rightcould be 94-100%1.6sslowest 1 in 20
  2. nemotron-3.5-lightning-30b-a3b100% rightcould be 94-100%8.0sslowest 1 in 20
  3. gpt-oss-20b95% rightcould be 85-98%9.2sslowest 1 in 20
  4. llama-3.1-8b-instruct93% rightcould be 83-97%3.2sslowest 1 in 20
  5. nemotron-mini-4b-instruct64% rightcould be 51-76%0.9sslowest 1 in 20

The bar is the slow case, not the average: one request in twenty takes at least that long, and that is the one a visitor notices. The fastest model here is also the least accurate, getting 64% right, which is what happens when a model is quick because it says less. Measured August 25, 2026. Re-run with npm run bench:models.

This page, measured now

0 of 3 reported
Largest paint
measuring
Layout shift
measuring
Slowest interaction
after you click

Core Web Vitals from your browser, graded against web.dev’s thresholds. Nothing is sent anywhere.

18 defects this page shipped, and what now stops each oneShow less
A reasoning model leaked its chain-of-thought and the system prompt into answers
cleanAnswer strips think blocks and leading meta-paragraphs, asserted in the unit tests
Streaming shipped with token usage hardcoded to null, so the cost panel was always empty
streamUsage enabled on the client, asserted in the integration tests
The work-authorisation matcher caught “work authorization” and missed “authorized to work”
both word orders matched, both asserted in the eval suite
ScrollTrigger measured the page before webfonts laid it out, so below-fold elements spent their entrance off-screen
the motion kit awaits document.fonts.ready before it resolves
The build crashed when no embedding key was present, instead of degrading to lexical retrieval
the projection step exits cleanly with a null stress, guarded by two regression tests
Question grammar was being scored as content, so a 64-token section matching the shape of the question outranked the section that answered it
stopwords are dropped at tokenisation, including the pronouns that carry no signal in a corpus about one person, with six ranking assertions in the integration tests
The corpus claimed the agent degrades to the retrieved source when every provider fails, and only the non-streaming path did it; the path every visitor uses returned an error
the streaming path serves the top chunk unsummarised and labels the answer degraded
The streaming path applied its reasoning filter per chunk, but a token already sent cannot be retracted, so a visitor was shown the model deliberating before the answer arrived
the opening is held until a paragraph break proves it is not working, and only then released
A corpus section grew past the embedding model’s 512-token limit, so the request returned 400 and the whole site silently dropped to keyword-only retrieval
long passages are split into windows and mean-pooled, and a rejected request now names the chunk and fails loudly instead of reporting a fallback
The graph documented that conversation history was passed per request, and nothing accepted history, so every follow-up was answered as though it were the first question asked
history rides with each request from the browser tab and is folded into both the prompt and the retrieval query
Select-to-ask sent the highlighted phrase with no section and no history, so the one interaction that proves the agent is reading this page answered like a search box
the nearest section heading travels with the selection
The colour system claimed three text tones and had two: the two quiet ones measured 1.06:1 apart, where 1.00 is the same colour
the ramp is set explicitly rather than mixed off a single axis, and every step is measured in-browser
Emphasis in prose was a 6% size change at the same colour as its surroundings, invisible to the scan that hunts for bolded phrases
a second semantic accent, chosen by simulating three kinds of colour blindness rather than by eye
Entrance motion ran correctly and could not be seen: 14px over 500 ms is below the perceptual threshold for motion
30px over 620 ms, which clears the threshold without reading as a template
The site URL in the corpus pointed at an address that was not this site, feeding the canonical tag, the entity graph and the share card
corrected at the source, where every surface reads it from
Two entrance systems owned one element’s opacity: a panel faded itself in with @starting-style and was also swept into the scroll batch, so GSAP wrote an inline zero while the CSS transition was mid-flight and whichever finished second decided what the reader saw
the element that animates itself says so, and the batch skips it
The net that catches an element stranded at zero skipped anything inside [data-state], and panels set that attribute unconditionally, so every panel on the page was exempt from the sweep written to rescue it
only a running instrument is skipped, because an idle panel at zero opacity is reporting nothing
That same net ran once, a second after mount, while the stranding it guards against happens whenever a reader crosses several batch boundaries quickly, which is at any point in the session
it runs again whenever scrolling stops

None of these threw an exception. That is the point: a leaked monologue renders as text, a null token count renders as blank, and a missed pattern returns a confident answer to the wrong question.

Education

Boston University, M.S. Computer Science, GPA 3.5 of 4.0.

Degrees

M.S. in progress
3.5
GPA out of 4.0, M.S. in Computer Science at Boston Universitysource
~40
graduate students in MET CS 664, where he is Teaching Assistantsource
99.1
percentile in JEE Mains 2020, All India top 1 percent of candidatessource
64
CodeChef global rank, February 2022 Long Challengesource
Coursework, timeline and earlier achievementsShow less

Boston University, M.S. Computer Science, GPA 3.5 of 4.0. September 2025 to December 2026 expected. Boston, MA. Graduate Teaching Assistant for MET CS 664 Artificial Intelligence, about 40 graduate students, September 2026 to present. Coursework: Generative AI, Web Mining and Graph Analytics, Software Engineering, AI Systems, Advanced Machine Learning and Neural Networks.

IIIT Design and Manufacturing Jabalpur, B.Tech Computer Science and Engineering. October 2020 to June 2024. India.

3 spans on a timeline from 2020 to 2027.

  1. B.Tech, Computer ScienceIIIT JabalpurOctober 2020 to June 2024
  2. M.S., Computer ScienceBoston UniversitySeptember 2025 to December 2026
  3. Teaching AssistantMET CS 664September 2026 to present
  • Generative AI
  • Web Mining and Graph Analytics
  • Software Engineering
  • AI Systems
  • Advanced Machine Learning and Neural Networks
70+
members in the coding community he co-foundedsource
200
Google Kickstart top 200, where his mentees landedsource
$12K
raised for Tarang Fest 2023, which he ledsource

JEE Mains 2020: 99.1 percentile, All India top 1% of 860K+ candidates.

CodeChef global rank 64, February 2022 Long Challenge. Third place, Code Rumble 2023.

Read more about achievementsShow less

Co-founded BITBYTE, a 70-plus member coding community at IIIT-DM Jabalpur. Mentees reached Google Kickstart top 200 and three internships.

Advisory Committee Head, Tarang Fest 2023. Coordinated programming across 13 colleges and 250-plus students, raised $12,000 from more than 25 sponsors.

Get in touch

Target roles: Agentic AI Engineer, Applied AI Engineer, LLM Engineer, AI Platform Engineer, Context Engineer.

He found a silent error-swallowing bug in LangChain’s Python SDK. A maintainer merged the fix in 57 hours. See the merged fix

Every record behind this page
  • 5certifying issuers
  • 5shipped
  • 2published
  • 3ranked
More ways to reach him

kushal7887pd@gmail.com, +1 (857) 328-4611

Introduce Kushal

Available full-time from January 2027, earlier for the right team. Remote, hybrid or on-site anywhere in the United States. Based in Boston.