limpbiz-kit

The Story of Our Most Critical Internal Package


limpbiz-kit began, as all great platform engineering efforts do, with a Slack message from a director who had just returned from a conference. “We need a unified developer experience layer,” the message read, followed by a link to a blog post from a company ten times our size. By the end of the week, a Jira epic had been created. By the end of the month, a team had been assembled. By the end of the quarter, the team had a name: Developer Empowerment and Enablement Platform Services, or DEEPS.

The original purpose of limpbiz-kit was to wrap three npm packages that every team was already using independently and successfully. The pitch deck described this as “reducing cognitive overhead through abstraction consolidation.” In practice, it meant importing one package instead of three, at the cost of inheriting all three’s dependency trees simultaneously and gaining a fourth configuration file format to maintain.

Version 0.1.0 shipped in March 2023 with a README that opened confidently: “limpbiz-kit is an opinionated toolkit for building resilient, observable, cloud-native microservices.” It contained a logger wrapper (over Winston, which itself wraps Console), a config loader (over dotenv, with the added feature of throwing cryptic YAML parse errors), and an HTTP client factory (over Axios, with retry logic that defaulted to retrying forever).

The name was chosen during a team-building exercise at a brewery. One engineer suggested “platform-kit” but this was rejected for being “too generic.” Another proposed “foundation-js,” which was voted down because the Angular Foundation library already used the word “foundation” and someone might get confused. A third engineer, who had been quiet for most of the evening, said “limpbiz-kit” into the silence, and the room erupted. It was irreverent. It was memorable. It would be a nightmare to explain on a compliance form. It was perfect.

Adoption

Adoption of limpbiz-kit was swift, owing to the fact that it was made mandatory. The DEEPS team published an ADR (Architectural Decision Record) titled “ADR-047: Standardized Service Foundation Layer” which required all TypeScript services to import limpbiz-kit as their base dependency. The ADR was approved by the architecture review board, which consisted of the same people who had proposed the package, plus one staff engineer who was on vacation at the time and whose approval was interpreted from silence.

Teams that had previously been responsible for their own logging, configuration, and HTTP concerns now found themselves responsible for those same concerns, plus keeping up with limpbiz-kit’s release cycle. The package shipped weekly releases, each of which contained at least one breaking change disguised as a patch version bump. The DEEPS team referred to this as “iterating quickly.” Consumer teams referred to it as “Thursday.”

The Plugin Architecture

In version 0.8.0, the team introduced a plugin system. The justification was that different teams had different needs, and the core package should remain lean while allowing extensibility. In practice, the plugin system added 40,000 lines of code to the core package and required every plugin to implement fourteen lifecycle hooks, most of which were called onBeforeInit, onInit, onAfterInit, onBeforeReady, onReady, and so forth, in an order that was documented in a Confluence page that linked to a second Confluence page that had been archived.

The first official plugin was limpbiz-kit-metrics, which wrapped Prometheus client. The second was limpbiz-kit-auth, which wrapped a JWT library and added the innovative feature of reading the signing key from an environment variable named LIMPBIZ_AUTH_SIGNING_KEY_SECRET_V2_NEW_FINAL. The _V2_NEW_FINAL suffix was the result of three successive migrations, each of which was announced as the last.

The Monorepo Migration

By version 1.2.0, limpbiz-kit had accumulated enough plugins and utility packages that the team decided to move to a monorepo. A two-day planning meeting produced a migration timeline of six weeks. The actual migration took four months and required temporarily pinning every consuming service to a specific commit hash because the published versions no longer resolved correctly.

During the migration, the team also adopted Conventional Commits, which meant that every commit message now began with feat:, fix:, or chore:, and the generated changelogs were three hundred lines of entries like chore: update lockfile and fix: fix previous fix and feat: add TODO comment for future feature.

The Configuration Problem

A recurring theme in limpbiz-kit’s history was configuration. The package supported configuration via environment variables, YAML files, JSON files, TOML files (briefly, by accident, when someone merged a PR intended for a different repository), command-line flags, and a proprietary .limpbizrc file format that was “just JSON but with comments.” The loading order was documented in an internal wiki article titled “Configuration Precedence (DO NOT EDIT - SEE ALSO CONFIGURATION PRECEDENCE V2).”

Teams occasionally discovered that their services were reading configuration from files they did not know existed, because limpbiz-kit’s config loader searched upward through the filesystem tree until it found a matching file or hit the root. One production incident was traced to a .limpbizrc file in /home/deploy/ on an EC2 instance that had been placed there during a debugging session nine months earlier by an engineer who had since left the company.

The Rewrite

In Q3 2024, a new engineering director arrived and declared the existing limpbiz-kit architecture “not cloud-native enough.” A rewrite was proposed. The new version, limpbiz-kit-next (later renamed limpbiz-kit-v2, then @limpbiz/core, then back to limpbiz-kit-next after the scoped package name conflicted with an unrelated public npm package called @limpbiz/core that had been published by a hobbyist in Brazil and had four downloads), would be built from the ground up with “developer experience as a first-class citizen.”

The rewrite team spent the first two sprints choosing a build tool, the third sprint arguing about whether to use classes or functions, and the fourth sprint writing a design document that recommended using both classes and functions, each for different “cognitive modes.” By sprint five, the original director had moved to a different business unit, and the rewrite was quietly downscoped to “incremental improvements to the existing package.”

The TypeScript Situation

limpbiz-kit was written in TypeScript, which was appropriate, since TypeScript was the company’s mandated language for all backend services after ADR-012, which noted that “TypeScript provides type safety and improved developer productivity” and was approved unanimously except for one principal engineer who wrote a three-page dissent about runtime characteristics that was attached to the ADR as an appendix that nobody read.

The package’s type definitions were complex enough to visibly slow the TypeScript compiler in larger services. The DEEPS team’s response was to publish a companion document titled “Optimizing TypeScript Performance When Using limpbiz-kit,” which recommended restructuring your service’s import graph to accommodate the package’s type resolution. Several teams instead added // @ts-ignore above the import line and moved on with their lives.

Observability

The package emitted metrics. Many metrics. Every function call, every configuration load, every plugin lifecycle hook produced a metric. The default Grafana dashboard for a limpbiz-kit service had forty-seven panels, of which approximately three were useful. The remaining forty-four existed because the DEEPS team had been given an OKR to “improve observability across the platform” and panel count was the chosen KPI.

One team discovered that twenty percent of their Datadog bill was attributable to custom metrics generated by limpbiz-kit’s internal telemetry. When they raised this with the DEEPS team, they received a link to a configuration option that allowed disabling individual metric emitters, provided you knew their internal identifiers, which were auto-generated UUIDs.

Cultural Impact

Despite everything, limpbiz-kit became a genuine cultural artifact. New engineers were onboarded with the phrase “you’ll need to set up your limpbiz.” The name appeared in Slack emoji (:limpbiz:, a crudely drawn biscuit wearing a backwards baseball cap). Someone printed stickers. The annual engineering survey consistently rated “working with limpbiz-kit” as both the most frustrating and most unifying aspect of the engineering experience.

When one senior engineer attempted to propose an alternative called “bedrock-ts,” the proposal was rejected not on technical grounds but because, as the CTO put it in the review meeting, “nobody is going to make stickers for bedrock-ts.”

Current Status

limpbiz-kit is currently on version 4.7.2. It has 847 open issues on the internal GitHub Enterprise, of which approximately 200 are labeled wontfix, 300 are labeled needs-discussion, and the remainder are unlabeled and presumed orphaned. The DEEPS team has been reorganized twice and is now called Platform Runtime Experience, or PRE, which the engineers pronounce as a word rather than an acronym for reasons they find privately amusing.

The package continues to ship weekly. It remains mandatory. The stickers are still popular.