DEV Community

w4ffl35
w4ffl35

Posted on

What I split into public Capsize packages

I didn't set out to make a pile of tiny repos. I kept finding code that already had one clear job and could be useful outside the app where it started. This week I gave those pieces their own public homes.

The companion and social pieces are the largest group:

  • capsize-auth provides password, token and OAuth2 primitives.
  • capsize-bluesky is the AT Protocol client used by the social tools.
  • capsize-social handles Bluesky and Discord account connections.
  • capsize-voice measures a writing style and uses that profile during generation.
  • capsize-persona combines persona, voice and long-term conversation facts in a reply service.
  • capsize-memory provides SQLAlchemy models and functions for rooms, participants and conversation turns.

That was the test: does this piece have one job, and can another app use it on its own? A bot can use the Bluesky client without loading the persona service. A local chat app can keep conversation memory without knowing anything about Discord. An app can also hand capsize-memory its own database session. The package doesn't need to own the connection.

The supporting repositories cover a different layer:

  • capsize-commons contains selectively installable Python, TypeScript and C++ building blocks.
  • capsize-ci contains versioned reusable GitHub Actions workflows.
  • capsize-fastmail reads Fastmail through JMAP, including mailbox listing, pagination and delta sync.
  • capsize-github-traffic saves repository traffic history before GitHub's 14-day window drops it.

AIRunner had the same problem. I split out airunner-common, airunner-eval, airunner-native and airunner-tts-vendor. Shared code, agent tests, the native launcher and the MeloTTS/OpenVoice layer no longer need to move as one block.

A practical way to use the split

Start small. If an app only needs Bluesky, use capsize-bluesky. If it needs account storage and posting across services, add capsize-social. Bring in memory, voice or a persona only when the app needs it.

The same rule applies to AIRunner. Its launcher shouldn't own the eval harness, and the eval harness shouldn't drag in the desktop app. The split makes that obvious. It also lets each piece ship when it's ready.

I want these repos to stay small enough to read. If one starts collecting unrelated work, that is a sign that the boundary has gone bad. The point is not the repo count. The point is being able to use one part without hauling the rest of the system behind it.

The full list, including commit and release counts, is in the four-week Capsize report.

Top comments (0)