Skip to content

Adding Kotlin DataFrame skill - #48

Open
Jolanrensen wants to merge 10 commits into
Kotlin:mainfrom
Jolanrensen:add-kotlin-data-dataframe
Open

Adding Kotlin DataFrame skill#48
Jolanrensen wants to merge 10 commits into
Kotlin:mainfrom
Jolanrensen:add-kotlin-data-dataframe

Conversation

@Jolanrensen

Copy link
Copy Markdown

Fixes #47

Adds a new skill to help working with the DataFrame library and its compiler plugin.

  • I will ask the DataFrame team first to test building some projects with an agent using this skill and report back here
  • DataFrame could fit into "backend", but, as it's just a data structure, I believe that may be too limiting. I created a new category "data", for data exploration, analysis, etc. Feel free to suggest something else if you think that would be better.

Jolanrensen and others added 4 commits May 21, 2026 16:30
Covers idiomatic kotlinx.dataframe usage across the three operating
contexts (Kotlin Notebook, Gradle with compiler plugin, plain Gradle):
schema generation, @DataSchema, common operations, IO, and gotchas
around the kotlin("plugin.dataframe") compiler plugin.

Introduces a new 'data' category in CATEGORIES and README for
kotlinx.* data manipulation libraries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original "schema-flows-in-chains-only rule" / "type is frozen at the
declaration" framing implied a plugin-specific quirk. The reality is plain
Kotlin immutability: every DataFrame operation returns a new instance, the
plugin assigns each expression its own schema, and a `val` simply keeps the
type of the instance it was bound to.

Also merge the now-redundant pandas-immutability gotcha into the rewritten
"operations on a `val` don't update that `val`" entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@devcrocod devcrocod left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, I think a dataframe skill is a handy thing to have

Regarding this specific skill, I have a few comments:

The skill looks quite large and feels like it was written more for humans than for coding agents. Since skills are primarily used by code agents, it would be better to keep it shorter, more concise, and focused: without unnecessary explanations, duplicates, or redundant information. You may want to take a look at Anthropic’s recommendations here: https://code.claude.com/docs/en/best-practices

Also, in my opinion, this skill should be more general-purpose. For example, it currently contains a lot of information about the dataframe plugin. If a user doesn't use this plugin, the agent will still load a lot of irrelevant information, which may confuse it and waste tokens (money) unnecessarily

Comment thread skills/kotlin-data-dataframe/SKILL.md
Comment thread skills/kotlin-data-dataframe/SKILL.md Outdated
Comment thread skills/kotlin-data-dataframe/SKILL.md
Comment thread skills/kotlin-data-dataframe/SKILL.md Outdated
Comment thread skills/kotlin-data-dataframe/SKILL.md Outdated
Comment thread skills/kotlin-data-dataframe/SKILL.md Outdated
Comment thread skills/kotlin-data-dataframe/SKILL.md Outdated

`columnOf(1, 2, null)` infers `Int?`. Type inference looks at the actual runtime values.

## Common operations (with-plugin idiomatic syntax)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems it duplicates references

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe I can merge this with the cookbook?

Comment thread skills/kotlin-data-dataframe/SKILL.md Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file necessary?
Doesn't the AI already know the dataframe API?
If the API changes, this file may quickly become outdated

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's true, but it could save it from searching deep through the sources, costing even more tokens. In my latest test with the skill, I didn't notice it unzipping a sources.jar once. It is true, outdated-ness is a problem

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, mistakes in the cookbook are indeed problematic. They weigh heavily in the context. I noticed in the tests that the agent would very strictly stick to the recipe as written and not deviate from it, even if the library itself has a better solution.

Comment thread skills/kotlin-data-dataframe/SKILL.md Outdated
@Jolanrensen

Copy link
Copy Markdown
Author

@devcrocod Thanks!

The skill looks quite large and feels like it was written more for humans than for coding agents. Since skills are primarily used by code agents, it would be better to keep it shorter, more concise, and focused: without unnecessary explanations, duplicates, or redundant information. You may want to take a look at Anthropic’s recommendations here: https://code.claude.com/docs/en/best-practices

Which is funny because I used the generate-skill skill to create it :) I'll see what I can do to shorten it.

Also, in my opinion, this skill should be more general-purpose. For example, it currently contains a lot of information about the dataframe plugin. If a user doesn't use this plugin, the agent will still load a lot of irrelevant information, which may confuse it and waste tokens (money) unnecessarily

This was done on purpose because it's the most difficult thing to understand for an agent. DataFrame is the only library that "breaks" Kotlin in this way, and while it can figure out the API from the sources, it cannot figure out what the compiler plugin can do that way.

@Jolanrensen

Jolanrensen commented May 22, 2026

Copy link
Copy Markdown
Author

First test: Following our simple 2025 KotlinConf DataFrame workshop.
(it's private, but I can share it to whomever would like in the team)

The task: https://github.com/Jolanrensen/KotlinConf2025Workshop/tree/2026-ai-profile solve part1a and part1b using mcp actions to run the notebook.

Our solutions:

These were removed before running the agents:
part 1a: the notebook: https://github.com/Jolanrensen/KotlinConf2025Workshop/blob/unzipped/Part%201/notebooks/part%201%20-%20csv/solutions/Part%201a%20Solutions.ipynb

part 1b: the kt file: https://github.com/Jolanrensen/KotlinConf2025Workshop/blob/unzipped/Part%201/src/main/kotlin/com/kotlinconf/dataWorkshop/part1csv/solutions/Part%201b%20Solutions.kt

Without skill:

https://github.com/Jolanrensen/KotlinConf2025Workshop/tree/2026-ai-profile-no-skills-solution

Took quite a long time (30min +), spent a lot of time hitting OK on it trying to unzip source jars. The results were quite good, though.

  • notebook solutions
    • look good! It correctly figured out how to get the right csv reading parse options.
    • It used less preferable but still correct notations sometimes, like
df0
    .rename { arter and ø and næblængde_mm and næbdybde_mm and luffelængde_mm and kropsmasse_g and køn and måledato }
    .into(
        "species",
        "island",
        "bill_length_mm",
        "bill_depth_mm",
        "flipper_length_mm",
        "body_mass_g",
        "sex",
        "measurement_date",
    )
  • understood quite well what happened to DFs in between cell calls,

  • kt file solutions

    • Similar to the notebook.
    • It did take two tries to build a @DataSchema interface because it didn't know it needed to be at least internal.

With skill:

https://github.com/Jolanrensen/KotlinConf2025Workshop/blob/2026-ai-profile-with-skill-solution

A lot faster, about 10 minutes. Did not see it decompile jars anymore.

  • notebook solution
    • did not figure out convert {}.toLocalDate(danishDate) could be used, instead converting the dates to String first and then manually parsing it.
    • Used the more explicit and safer:
df0
    .rename { arter }.into("species")
    .rename { ø }.into("island")
    .rename { næblængde_mm }.into("bill_length_mm")
    .rename { næbdybde_mm }.into("bill_depth_mm")
    .rename { luffelængde_mm }.into("flipper_length_mm")
    .rename { kropsmasse_g }.into("body_mass_g")
    .rename { køn }.into("sex")
    .rename { måledato }.into("measurement_date")

Results

Using the skill was faster; it spent less time having to sift through source jars. However, it did seem to rely more on the functions written inside the skill. Since convert {}.toLocalDateTime(format) was not mentioned, it used a different solution, while the agent without the skill was able to discover it.

@Jolanrensen
Jolanrensen marked this pull request as ready for review May 22, 2026 16:27
@Jolanrensen

Copy link
Copy Markdown
Author

I'll check whether having the cookbook or not makes any difference using https://github.com/JetBrains/skills-ab-eval next week (when I have new tokens, oops XD)

@devcrocod

Copy link
Copy Markdown

@Jolanrensen

This was done on purpose because it's the most difficult thing to understand for an agent. DataFrame is the only library that "breaks" Kotlin in this way, and while it can figure out the API from the sources, it cannot figure out what the compiler plugin can do that way.

Yes, I understand that. However, my comment about the case where the user does not use the plugin still stands.
In that scenario, we could either move this into the reference section, make it a separate skill, or state more explicitly at the beginning which dataframe configurations are supported.

In my view, a skill should either be very general, essentially an equivalent of best practices for working with dataframes. Or be focused on one specific task.

I think it would be fine to add the skill as it is now, with a few parts polished, and then decide how to improve it based on actual usage

@Jolanrensen

Copy link
Copy Markdown
Author

I created and ran some tests with and without the skill in its current state using skills-ab-level and Air :)

TL;DR, the skill helps a tiny bit in its current state, but not for each test. Sometimes it makes it worse, which is definitely not desirable.

I'll try to optimize it slightly and rerun the tests, probably omitting the cookbook to see if there's any difference.

kotlin-dataframe-skill-tasks.zip

Results with the skill as is (summarized by Air):

Eval Results — kotlin-data-dataframe skill

Rewards & efficiency

Task Side Reward Steps Tool calls Cost
Salary without-skill 1.0 ✅ 13 18 $0.10
Salary with-skill 1.0 ✅ 17 22 $0.15
Titanic without-skill 1.0 ✅ 17 21 $0.16
Titanic with-skill 1.0 ✅ 14 19 $0.14
Netflix without-skill 1.0 ✅ 14 19 $0.12
Netflix with-skill 1.0 ✅ 11 16 $0.09

Skill impact (with − without)

Task Δ reward Δ steps Δ cost skill_helped
Salary 0.0 +4 +$0.05
Titanic 0.0 −3 −$0.02
Netflix 0.0 −3 −$0.03

skill_helped = False in all cases because reward is identical (both sides maxed out at 1.0). The efficiency gains on Titanic and Netflix are real but not captured by the binary reward signal.

Qualitative observations

Aspect without-skill with-skill
First action Inspects project files Reads SKILL.md first
CSV reading readCSV (deprecated alias) readCsv (correct modern API)
Titanic delimiter Discovered via runtime failure Knew to use delimiter = ';' upfront
Titanic locale Did not handle European decimal commas Used ParserOptions(locale = Locale("fr"))
Salary build failures 0 1 (missing io.* import — fixed in one retry)
Titanic build failures 2 1

@Jolanrensen

Copy link
Copy Markdown
Author

@devcrocod Made some small changes to the skill file (like adding imports, because I noticed agents struggling there), but I'm burning through my tokens really fast A/B testing... I'm not sure what's the best way forward. Merge as is and gather more data that way or do some more testing first. wdyt?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a Skill for working with Kotlin DataFrame

3 participants