Skip to content

Add an offline AI agent skill to migrate vanilla Kafka Streams to Kstreamplify #551

Description

@AnkurSinhaaa

Problem

Migrating an existing vanilla Kafka Streams application to Kstreamplify is mechanical but tedious and easy to get subtly wrong. You have to swap raw streamsBuilder.stream(...) / .to(...) for the TopicWithSerde API, delete hand-rolled serde init and Kafka @configuration classes, extend KafkaStreamsStarter, move Transformer/ValueTransformer to ContextualProcessor, wire the DLQ handlers in application.yml, and rewrite tests to KafkaStreamsStarterTest.

All of these rules already live in the README and AGENTS.md, but there's nothing that lets a developer's AI coding agent apply them automatically. Teams re-do the same conversion by hand on every service, and "almost-right" migrations slip through (wrong imports, leftover Consumed.with(...), obsolete default. handler prefixes, etc.).

Suggestion

Ship a small, self-contained AI agent skill in this repo — migrate-to-kstreamplify — that a developer can download/fork and run entirely offline (no MCP server, no tokens, no network calls). It's just Markdown that lives next to the library, so it always matches the current API.

End-user flow: copy the skill folder into their project → run /migrate-to-kstreamplify (Copilot) or "use the migrate-to-kstreamplify skill" (Claude/Cursor) → point it at the old topology → review the generated Kstreamplify code + migration notes.

Proposed layout (one source of truth, thin per-tool entrypoints, building on the existing AGENTS.md):

AGENTS.md                                              # add a short "Migration skill" pointer
.github/prompts/migrate-to-kstreamplify.prompt.md      # Copilot slash command → defers to SKILL.md
.github/instructions/kstreamplify-conventions.instructions.md   # always-on guardrails
docs/agents/migrate-to-kstreamplify/
    SKILL.md            # canonical, self-contained rules + step-by-step workflow
    examples/           # before→after snippets used as grounding anchors

One SKILL.md; every other file just points to it (no duplicated rules). Portable across tools via AGENTS.md.

Version handling (no hardcoded numbers): the skill always resolves target versions — Kstreamplify, Kafka, Spring Boot, and Java — from this repo's own pom.xml / latest release, never from baked-in constants. Because the skill ships with the library, generated code and POMs automatically track whatever the latest release uses. It also aligns with the library's current conventions (e.g. Lombok is optional, not required, so generated *Topics classes use a plain private constructor), and uses the current handler property names without the default. prefix.

What the migration covers:

  • Consume/produce via TopicWithSerde (stream, produce, table, globalTable) — never raw stream(...), Consumed.with(...), Produced.with(...), or .to(...).
  • Topology shape: @component extends KafkaStreamsStarter with only topology(StreamsBuilder) + dlqTopic(); delete @configuration Kafka/topic classes, initSerdes(), new SpecificAvroSerde<>(), serde fields/getters, buildTopology(), empty onStart(), manual Properties/lifecycle/shutdown hooks.
  • Serdes: Serdes.String() for keys, SerdesUtils.getValueSerdes() / getKeySerdes() for Avro.
  • API modernization: Transformer/ValueTransformer → ContextualProcessor/ContextualFixedKeyProcessor.
  • Error handling: recommend the ProcessingExceptionHandler (configured in application.yml, natural return types) while tolerating — not forbidding — the legacy ProcessingResult / TopologyErrorHandler.catchErrors(), mirroring the README's "Migrating to Processing Exception Handler" section. It offers the migration but won't break code that keeps the legacy API.
  • Older Kstreamplify → latest: .utils.* → .serde.*, getSerdesForValue() → getValueSerdes(), drop default. prefix.
  • Structure & advanced cases: topic prefixes (prefix.self), dynamic config via KafkaStreamsExecutionContext, meaningful repartition names, package restructuring, hand-coded Avro → .avsc + avro-maven-plugin, flatten-vs-preserve legacy base classes, complex reconciliation pipelines with TTL state stores + punctuator eviction.
  • Deduplication: map hand-rolled dedup to the standardized DeduplicationUtils API.
  • POM cleanup: add kstreamplify-spring-boot + kstreamplify-core-test; remove now-transitive deps (kafka-streams, kafka-clients, kafka-streams-avro-serde, kafka-streams-test-utils, spring-boot-starter-web, spring-boot-starter-actuator); align the Spring Boot parent + Java version with the library's latest release.
  • Tests: extends KafkaStreamsStarterTest, getKafkaStreamsStarter(), createInputTestTopic/OutputTestTopic(TopicWithSerde); drop TopologyTestDriver, manual Properties, @AfterEach teardown. Generate tests when the source has none.

Alternatives Considered

  • Keep the skill in a separate repo fetched via an MCP server — works, but requires an MCP server + token + network, so users can't just download and run it offline. Rejected for this goal.
  • Build a Maven plugin / codemod that rewrites code deterministically — powerful but a large parser/AST project to build and maintain, and it loses the flexibility LLM agents bring to messy real-world topologies. Much higher effort.
  • Ship a VS Code extension bundling the skill — locks users into a single tool; a plain Markdown skill referenced from AGENTS.md works across Copilot, Claude Code, Cursor, and Aider with far less effort.
  • Do nothing / keep it in docs only — leaves every team hand-migrating and re-discovering the same pitfalls.

Additional Context

  1. Builds directly on the existing AGENTS.md — extends it rather than competing with it.
  2. Because the skill lives with the library, it resolves all versions from this repo's pom.xml / latest release and grounds guidance on the shipped kstreamplify-core / *-test modules, so it can never drift from the current API version.
  3. Suggested addition: a self-checking example that keeps the skill from going stale. Ship one tiny app in two matching versions:
  • examples/before/ — a small, deliberately vanilla Kafka Streams app (raw streamsBuilder.stream(...), .to(...), Consumed.with(...), a Transformer, etc.).
  • examples/after/ — the exact same app correctly migrated to Kstreamplify — i.e. what the skill should produce when fed before/.

Because after/ is a real, compilable Maven project, CI builds and tests it on every change (mvn clean install). This turns it into a smoke test: if a future Kstreamplify release renames an API or moves a package (e.g. .utils. → .serde.), examples/after/ stops compiling and CI goes red, immediately signalling that the skill's guidance needs updating. Without it, the skill could keep recommending outdated code and no one would notice until a user hit the error. In short: before/ is the input, after/ is the ideal output, and CI continuously proves that ideal output still compiles against the latest release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementThis issue or pull request improves a feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions