Capstead is not another AI framework. It's the governance layer that sits around whatever you use to call the model — Spring AI, LangChain4j, a raw SDK — and turns your Spring Boot methods into governed, versioned, observable business capabilities with a catalog, per-capability cost, budgets, and durable execution history.
Runs in production Dogfooded at engineerprep.io, governing ~12 capabilities across Claude & Amazon Nova.
Spring AI and LangChain4j make calling a model easy. But once AI features spread across services and teams, one question shows up in every architecture review — and nothing answers it:
What capabilities do we have, who owns them, which version is live, and what do they cost?
Spring AI tells you about a single model invocation. Capstead tells you about the business capability: how often it ran, which model it used, how many tokens it consumed, how much it cost, whether it succeeded, and which version executed.
Every capability with its domain, owner, version, and tags — discoverable at /actuator/capabilities.
Attributes Spring AI's token/model data to the business capability. Real cost per capability, per model.
@DailyBudget("$25") blocks further calls once the day's spend is hit. A kill-switch with teeth.
Structured executions with per-model invocations and parent-child trees, persisted to your DB — surviving restarts, aggregating across instances.
Know exactly which version of a capability executed — the metadata frameworks deliberately leave out.
Export capabilities as Model Context Protocol tools that stay versioned, owned, and budget-enforced.
Annotate any bean method. Auto-configuration wires the rest — no code in your method measures anything.
@Service
class LessonService {
@Capability(name = "Generate Lesson", domain = "Learning",
owner = "Content Team", version = "2")
@DailyBudget("$25")
public Lesson generateLesson(String topic) {
// your normal logic — Spring AI, LangChain4j, a raw HTTP call, anything
return chatClient.prompt().user(topic).call().entity(Lesson.class);
}
}
Prefer not to annotate? Declare capabilities in YAML, or write no body at all
with a declarative @CapabilityClient interface. All three styles coexist —
see the examples.
<dependency>
<groupId>io.capstead</groupId>
<artifactId>capstead-starter</artifactId>
<version>0.5.3</version>
</dependency>
Then open the dashboard at /capstead and hit /actuator/capabilityscorecard.
Full walkthrough in the research write-up.