Ship a New Version
palette works, but every color is a fixed value. Let's add lighten and darken, release it as 0.2.0, and see how semantic versioning carries the change to anyone who depends on you.
What the version number means
A version is MAJOR.MINOR.PATCH, and the part you bump signals what changed for your users:
- PATCH (
0.1.0 → 0.1.1) — backward-compatible bug fixes. Existing code keeps working. - MINOR (
0.1.0 → 0.2.0) — backward-compatible new features. Existing code keeps working; there's just more it can do. - MAJOR (
0.2.0 → 1.0.0) — breaking changes. Existing code might stop compiling.
Adding new methods is purely additive, so it's a minor bump.
Step 1 — Add the feature
Add two methods to Color. They use the standard library's saturating arithmetic so a channel clamps at 0/255 instead of wrapping:
/// @name Lighten
/// Returns a lighter copy of the color.
///
/// Adds `amount` to every channel, clamping at 255 so a channel never wraps
/// around.
///
/// # Examples
///
/// ```
/// Color(red: 200, green: 100, blue: 0).lighten(by: 100).toHex(); // "#ffc864"
/// ```
public func lighten(by amount: UInt8) -> Color {
Color(
red: self.red.addSaturating(amount),
green: self.green.addSaturating(amount),
blue: self.blue.addSaturating(amount)
)
}
/// @name Darken
/// Returns a darker copy of the color.
///
/// Subtracts `amount` from every channel, clamping at 0.
///
/// # Examples
///
/// ```
/// Color(red: 200, green: 100, blue: 0).darken(by: 100).toHex(); // "#640000"
/// ```
public func darken(by amount: UInt8) -> Color {
Color(
red: self.red.subtractSaturating(amount),
green: self.green.subtractSaturating(amount),
blue: self.blue.subtractSaturating(amount)
)
}
This only adds to the API — every existing use of Color still compiles exactly as before. That's what makes it a minor change.
Step 2 — Bump the version
In flock.toml:
[package]
name = "palette"
version = "0.2.0"
org = "your-name"
Step 3 — Publish it
flock publish
Publishing your-name/palette@0.2.0 to https://registry.kestrel-lang.com...
{"ok":true,"checksum":"sha256:…"}
0.1.0 is untouched and still available — you've published 0.2.0 alongside it. (Remember, you can't re-publish 0.1.0; versions are immutable.)
Step 4 — Dependents pick it up
Over in swatch, bump the constraint to the new version and re-resolve:
[dependencies]
your-name/palette = { version = "0.2.0" }
flock update
flock update re-resolves the graph and rewrites flock.lock. Now swatch can use the new methods:
let brand = Color(red: 58, green: 123, blue: 213);
brand.lighten(by: 40).toHex(); // "#62a3fd"
brand.darken(by: 40).toHex(); // "#1253ad"
Because 0.2.0 only added to the API, swatch's existing code didn't change — it just gained access to lighten and darken.
What would be a breaking change
Some edits force a major bump because they break existing callers:
- Renaming or removing a public item —
toHex()→hexString(). - Changing a signature — making
Color(hex:)return aResultinstead of anOptional, or adding a required parameter. - Changing documented behavior callers rely on.
When you have to do one of those, bump the major version (1.0.0) so dependents opt in deliberately. Until then: patch for fixes, minor for additions.
That's the core publishing loop — build, publish, depend, version. The remaining pages are optional: Organizations & Teams for publishing with others, Publishing from CI to automate releases, and the Reference.