---
title: The checklist
---

Everything below is pulled from the detailed pages in this section — this page exists so you can
work through it top to bottom while you build, and come back to it when you're not sure what's
left. Each item links to the page that explains the *why*.

## Before you write any code

- [ ] Talk to the Cratis team about generating and publishing a contracts package for your
      language, rather than hand-rolling a `protoc` toolchain yourself. See
      [Two ways to start](/chronicle/building-a-client/starting-points/).

## Contracts (generated layer)

- [ ] Treat the generated contracts package as read-only — never hand-edit it, never hand-maintain
      a fork of it. It's regenerated by Chronicle's own pipeline on every kernel release.
- [ ] Depend on the *published* contracts package as an ordinary dependency in your idiomatic
      client. Don't vendor it, and don't build your idiomatic client in the same package.
      See [Layering an idiomatic client](/chronicle/building-a-client/layering-an-idiomatic-client/).

## The idiomatic client

- [ ] Build it as a separate, hand-maintained package with its own release cadence — not inside
      the generated contracts package, and not by hiding hand-written code inside generated files.
- [ ] Name and export it so nobody consuming it ever needs to import the contracts package
      directly.
- [ ] Make it a complete, general-purpose client on its own: usable from a console tool, a script,
      or a background worker with no hosting framework required. A convenience/hosting package (an
      ASP.NET-Core- or Spring-Boot-style integration) is optional and comes later, once the
      idiomatic client is stable — see
      [Layering an idiomatic client](/chronicle/building-a-client/layering-an-idiomatic-client/#convenience-packages-sit-above-that-and-are-optional).

## Authentication

- [ ] Parse all three authentication modes from the connection string: client credentials, API
      key, and none (`auth=none`).
- [ ] For client credentials, implement the OAuth `client_credentials` exchange against
      `/connect/token` — the username and password in the connection string map to `client_id`
      and `client_secret`, not to HTTP Basic auth.
- [ ] Fall back to the `chronicle-dev-client` / `chronicle-dev-secret` development defaults when
      the connection string carries no credentials at all.
- [ ] Attach `authorization: Bearer {token}` to every outgoing call, across every streaming shape
      your gRPC library exposes.
- [ ] Cache the token, refresh it proactively ahead of expiry, and retry exactly once on an
      `Unauthenticated` response.
- [ ] Never log a raw connection string or a raw token — always log through a redacted rendering.
      See [Authentication and bearer tokens](/chronicle/building-a-client/authentication-and-bearer-tokens/).

## Clustering and the connection lifecycle

- [ ] Support both connection-string forms: an explicit, comma-separated host list and
      `chronicle+srv://` DNS-based discovery.
- [ ] Re-resolve the server list on *every* connect and reconnect, not just once at startup.
- [ ] Ship at least `least-connections` (matching the real probe/reserve protocol against
      `/connections/count` and `/connections/reserve`) and `round-robin` (with a random start
      offset per instance).
- [ ] Embed your contracts package's compiled descriptor set, and run the wire-compatibility check
      before treating a new connection as usable. Fail hard on a real incompatibility — don't
      degrade silently.
- [ ] Run a keep-alive watchdog with capped exponential backoff, and reuse the same connect path
      for reconnects that the initial connect uses.
      See [Clustering and the connection lifecycle](/chronicle/building-a-client/clustering-and-connection-lifecycle/).

## The connection string object model

- [ ] Parse the connection string into a typed value once. Don't re-parse or grep the raw string
      wherever a setting is needed.
- [ ] Compute the authentication mode from the parsed fields rather than storing it separately, so
      the two can't drift apart.
- [ ] Offer a fluent builder that validates as it assembles (reject "credentials and API key both
      present" at construction time, not at first connect).
- [ ] Offer a redacted rendering of the connection string, and use it everywhere the client itself
      logs. See [Connection string elements](/chronicle/building-a-client/connection-string-elements/).

## Publishing

- [ ] Publish the contracts package from Chronicle's own release pipeline, version-locked to the
      kernel release it was generated from.
- [ ] Publish the idiomatic client as its own artifact, on its own release cadence, once it's
      stable enough to ship.
- [ ] **The moment you add a second publishable module — a testing package, a convenience/hosting
      package — add it to your CI's actual publish job in the same change that adds its build
      config.** This is not a hypothetical: `io.cratis:chronicle-testing` and
      `io.cratis:chronicle-spring-boot-starter` both had correct Maven coordinates and a working
      `mavenPublishing` block for weeks before anyone noticed the release workflow only ever ran
      `:Source:publishAndReleaseToMavenCentral`. Valid build config for a module that CI never
      tells to publish is indistinguishable, from the outside, from a module that doesn't exist.

## Documentation

- [ ] Create a `Documentation/` folder with a `toc.yml`, an `index.md`, and a `client-snippets/**`
      tree from day one.
- [ ] Add a snippet validator and a CI workflow that runs it before your first snippet ships.
- [ ] Don't write your own "Events" or "Projections" pages — those concepts live in the shared
      Chronicle docs. Your repo only owns pages that are genuinely different per client:
      installation, connection setup, framework integration, troubleshooting.
- [ ] If your artifact serves two languages the way Kotlin serves Java, plan for two parallel
      snippet trees (`client-snippets/`, `client-snippets-<other-language>/`) from the start.
      See [Documentation and snippets](/chronicle/building-a-client/documentation-and-snippets/).

Next: [Two ways to start](/chronicle/building-a-client/starting-points/) walks through the first decision in more depth.
