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
Section titled “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
protoctoolchain yourself. See Two ways to start.
Contracts (generated layer)
Section titled “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.
The idiomatic client
Section titled “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.
Authentication
Section titled “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_credentialsexchange against/connect/token— the username and password in the connection string map toclient_idandclient_secret, not to HTTP Basic auth. - Fall back to the
chronicle-dev-client/chronicle-dev-secretdevelopment 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
Unauthenticatedresponse. - Never log a raw connection string or a raw token — always log through a redacted rendering. See Authentication and bearer tokens.
Clustering and the connection lifecycle
Section titled “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/countand/connections/reserve) andround-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.
The connection string object model
Section titled “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.
Publishing
Section titled “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-testingandio.cratis:chronicle-spring-boot-starterboth had correct Maven coordinates and a workingmavenPublishingblock 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
Section titled “Documentation”- Create a
Documentation/folder with atoc.yml, anindex.md, and aclient-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.
Next: Two ways to start walks through the first decision in more depth.