A walkthrough of the create-canking-gui-extension and develop-canking-gui-extension agent skills — from an empty folder to a live thermometer gauge running against simulated CAN traffic, driven entirely by plain-language prompts.
Developer Blog
From Prompt to Plugin: Building a CanKing GUI Extension with Agent Skill
Introduction
Building a custom GUI panel for Kvaser CanKing has always been a multi-step process: generate the initial project structure and starter files, wade through SDK docs, wire up CAN signal hooks, get the MUI layout right, run the build, load it into CanKing, and eventually package it for distribution. None of those steps are particularly hard on their own, but together they create enough friction that a quick experiment can easily turn into a half-day setup task.
Agent skills help automate repetitive development tasks by giving the AI agent a reusable set of instructions for a specific workflow. Instead of manually creating a project, you can describe what you want in plain language and let the AI agent handle much of the setup and implementation. This post walks you through installing the CanKing skills, building a thermometer extension from scratch, enhancing it through follow-up prompts, running it against live data, and packaging it for installation.
What You Will Build
By the end of this post you will have a CanKing WorkspaceView extension that renders a live thermometer gauge tied to a CAN signal value. Along the way you will see how to:
- Install the agent skills for use in VS Code
- Describe an extension in natural language and let a skill scaffold and implement it
- Iterate on the result with targeted enhancement prompts
- Run the extension inside CanKing against simulated bus traffic — no hardware required
- Package it as a distributable
.ckextbundle
Prerequisites
The examples in this post use GitHub Copilot in VS Code. The CanKing skills are essentially reusable guides that help an AI assistant understand how to create and modify CanKing extensions. Each is stored in a SKILL.md file and can be used with any AI coding tool that supports skills, not just GitHub Copilot. While Part 2 covers installation for other tools, the prompts, project setup steps, and extension-building workflow shown here are the same regardless of which AI assistant you use.
- VS Code with the GitHub Copilot extension (v1.250 or later for agent skill support)
- Node.js 22 LTS or later and npm
- A Kvaser interface and CanKing if you want to run the extension at runtime — although Part 5 shows how to get data flowing without hardware, and build validation works without CanKing installed at all
- Optionally, the CanKing MCP server, which lets the agent drive CanKing itself. Part 5 covers setting it up; nothing before that needs it.
Part 1: Understanding Agent Skills
An agent skill is a reusable guide that helps GitHub Copilot carry out a specific task. Technically, a skill is a Markdown file with a YAML frontmatter header, but you can think of it as a packaged set of expert instructions. It provides Copilot with the context, recommendations, and quality checks needed for a particular workflow, enabling you to describe your goal in plain language while the skill handles much of the process behind the scenes.
CanKing extension development ships as two skills, split at a single question: does the project exist yet?
| create-canking-gui-extension | develop-canking-gui-extension | |
|---|---|---|
|
Precondition |
An empty folder | A folder with a package.json depending on @kvaser/canking-api |
|
Covers |
Scaffold, install, read docs, first working view | Features, dialogs, build breaks, SDK upgrades, running in CanKing, packaging |
|
Ends at |
The first green build, then hands off | Wherever you stop |
The split matters in practice, because it is what the agent uses to pick the right skill.createwill refuse to scaffold over an existing extension and point you at develop instead; develop will refuse to work on a folder that has no extension in it yet. In a normal project you invoke create exactly once and develop from then on.
Both skills share one thing that is worth calling out early: they read the SDK documentation from node_modules/@kvaser/canking-api/doc_md/ — the copy installed in your project, at your pinned version. The docs and the code therefore cannot disagree, which is a large part of why the generated code compiles against the API you actually have rather than an API the model half-remembers.
Part 2: Installing the Skills
Skills live in a directory that contains a SKILL.md file. VS Code scans a set of well-known locations automatically, at either a project scope (committed to a repository, available only when that project is open) or a global scope (stored under your user profile, available in every workspace).
Both skills can be found on GitHub at canking-agent-skills
Using the Skills CLI (recommended)
The Skills CLI npx skills installs Agent Skills into whichever coding agent(s) you have set up, including Claude Code, GitHub Copilot, Codex, etc..
npx skills add Kvaser/canking-agent-skills
Without any flags, the CLI auto-detects the agents installed on your machine. To target specific agents, pass one or more -a flags:
npx skills add Kvaser/canking-agent-skills -a claude-code -a codex -a github-copilot
By default, skills are installed at the project level (e.g. .agents/skills/), committed alongside your project. That works well for develop-canking-gui-extension, which always runs inside an extension repository and can usefully ship to everyone who clones it. But create-canking-gui-extension scaffolds a brand-new project from an empty folder, so there is no repository to commit it to yet. A global install covers both cases, and is the simplest place to start. Pass -g/--global to install to your user directory instead (e.g. ~/.copilot/skills/):
npx skills add Kvaser/canking-agent-skills -g
Manual installation
Alternatively, copy the two skill folders from canking-agent-skills directly into the skills directory your agent reads from:
| Agent | Project-level | Global |
|---|---|---|
|
Claude Code |
.claude/skills/ |
~/.claude/skills/ |
|
GitHub Copilot |
.agents/skills/ |
~/.copilot/skills/ |
|
Codex |
.agents/skills/ |
~/.codex/skills/ |
Copy the whole folder, not just the SKILL.md. Each skill carries a references/implementation-conventions.md that it reads at runtime — the SDK documentation map, the project layout, and the coding conventions. A SKILL.md on its own is missing half the instructions.
For example, to install globally for GitHub Copilot on Windows:
Copy-Item -Recurse skills\create-canking-gui-extension, skills\develop-canking-gui-extension "$env:USERPROFILE\.copilot\skills\"
Or on macOS / Linux:
cp -r skills/create-canking-gui-extension skills/develop-canking-gui-extension ~/.copilot/skills/
Reload or restart the agent afterwards so it picks up the new skills.
Tip: Every skill includes a small YAML frontmatter header. The name field in that header determines the /slash-command you use in Copilot Chat. Keeping the folder nameand the skill’s name field identical helps ensure your agent registers the skill correctly.
Verifying the install
Open VS Code, launch Copilot Chat (Ctrl+Alt+I / Cmd+Alt+I), and type /. You should see both create-canking-gui-extension and develop-canking-gui-extension appear in the autocomplete list. If they do not appear, reload the VS Code window (Ctrl+Shift+P → Developer: Reload Window) and try again.
Part 3: Creating the Thermometer Extension
Start by creating the project folder and opening it in VS Code. Open a terminal, navigate to wherever you keep your projects, and run:
mkdir signal-thermometer
cd signal-thermometer
code .
VS Code opens with signal-thermometer as the workspace root. Open Copilot Chat (Ctrl+Alt+I / Cmd+Alt+I) and you are ready to prompt.
The first prompt
Because you already created and opened the project folder, you can omit project-name from the scaffold answers. The skill resolves the project name to . and scaffolds in place.
Paste the following into Copilot Chat:
/create-canking-gui-extension Create a CanKing GUI Extension that displays
one CAN signal's value using a thermometer.
Use a dialog to select the signal from the DBC files present in the CanKing setup.
Show the signal name above the thermometer and the current value as a number
below the thermometer. Also show the signal's unit below the thermometer.
Get the signal's min and max limits from its DBC definition and use them to
configure the thermometer.
Save the selected signal's properties to the CanKing project.
scaffold-answers:
package-name: signal-thermometer
display-name: Signal Thermometer
package-description: "Displays a CAN signal value as a thermometer gauge"
package-author: Your Name
Replace Your Name with your own name or organization.
The scaffold-answers block is a convenience, not a requirement. The skill accepts the same values written as prose (Display name: Signal Thermometer) or as a bulleted list, and it accepts label variants such as folder name, extension name, or npm package name. Anything you leave out is filled in from documented defaults — the package name falls back to the current folder name, the display name to a short title derived from your feature description — and if something is genuinely ambiguous, the skill asks you once rather than guessing.
What the skill does with this prompt
The skill processes your input in a predictable sequence, and it is worth understanding each step so you know what to expect:
Step 1 — Confirm there is nothing to scaffold over. The skill checks the target folder for an existing package.json depending on @kvaser/canking-api. If it finds one, it stops and tells you to use develop-canking-gui-extension instead. On a genuinely empty folder it proceeds; on a folder that has unrelated files in it, it warns you before scaffolding in place.
Step 2 — Resolve every scaffold value up front. The skill maps your scaffold-answers block to the create script’s options, validates the package name against npm’s rules, and confirms the display name is not empty. This all happens before a single command runs.
Resolving values first matters more than it sounds. The create script takes the project name as a positional argument and the rest as command line options:
npm create @kvaser/canking-extension@latest . -- \
--package-name signal-thermometer \
--display-name "Signal Thermometer" \
--description "Displays a CAN signal value as a thermometer gauge" \
--author "Your Name"
Anything not passed as an option becomes an interactive prompt — and an interactive prompt blocks an agent’s non-interactive shell indefinitely. So the skill’s rule is to always pass all four. (If you are on an older create script that predates the options, the skill detects the usage error, falls back to answering the prompts interactively, and notes the fallback in its summary.)
Step 3 — Install. It runs npm install inside the new project so the local SDK docs and TypeScript definitions are available for the next steps.
Step 4 — SDK docs. Before writing a single line of implementation code, the skill reads node_modules/@kvaser/canking-api/doc_md/README.md and then only the specific pages for the hooks, controls, IPC functions, and models the requested behavior needs — the signal subscription hook, the signal selection dialog, the project data slice hook. It deliberately does not bulk-read the docs folder; there are several hundred pages in it.
It then reads the generated src/WorkspaceView/index.tsx — a working sample view wired up with useProjectDataSlice, useSessionDataSlice, useOnlineStatusSync, CanChannelSelectControl, and sendCanMessage — to see how the pieces fit together before changing anything.
Step 5 — Implementation. It replaces the scaffold sample with a vertical thermometer that reads from the selected CAN signal. The fill level is computed from the signal’s current value relative to its configured min/max range; text below the gauge shows the raw value and unit. Colors come from the active MUI theme rather than hard-coded hex values, so the thermometer looks correct in both light and dark mode. The selected signal is persisted with useProjectDataSlice, so it survives saving and reopening the project.
Step 6 — Validate. It runs npm run build (which runs tsc -b plus the Vite build, so it catches type errors) and then npx eslint ., repairing and rerunning before expanding scope. If either fails, it diagnoses and repairs before reporting success.
Step 7 — Hand off. The summary reports the exact create command used, which values were assumed rather than given, which SDK docs were consulted, and — importantly — what has *not* been verified. A green build proves the extension compiles, not that it works. The skill then points you at develop-canking-gui-extension for everything that comes next.
Reviewing the result
The project is already open in VS Code. The key file is src/WorkspaceView/index.tsx. You should see a React component that:
- Subscribes to the selected CAN signal through a CanKing hook
- Computes a fill percentage from the signal’s live value and its DBC min/max
- Renders the thermometer with MUI components and theme palette colors
- Displays the numeric value and signal unit below the gauge
- Persists the signal selection as project data
One structural detail worth noticing, because it is easy to break later: the component renders inside a SizedBox that receives the height and width props passed by its host. Without that, the view does not resize with the CanKing workspace pane. Both skills treat it as a standing convention.
Part 4: Enhancing the Extension
From here on, the project exists — so the skill changes. develop-canking-gui-extension picks up where create left off: it confirms the folder really is a CanKing GUI extension, runs a baseline build before touching anything (so that pre-existing breakage is never mistaken for breakage it caused), notes the installed SDK version, reads the existing code and only the relevant doc pages, then makes the change and validates it.
That baseline step is a small thing that saves a lot of confusion. If a project was already failing to build when you asked for a feature, you get told that, rather than watching the agent silently repair unrelated code.
Enhancement 1: Color-coded temperature zones
/develop-canking-gui-extension Add color zones to the thermometer.
Color the fill green when the value is in the lower third of the range,
yellow in the middle third, and red in the upper third.
Use MUI theme colors rather than hard-coded hex values.
The skill reads the existing index.tsx, identifies the fill bar, and adds threshold logic mapping the current percentage to the appropriate MUI semantic color token (success, warning, error). Because these are theme tokens, the colors stay correct whether the user has the light or dark theme active in CanKing.
Enhancement 2: Min and max value markers
/develop-canking-gui-extension Add a min and max value tracker to the
thermometer. Show a small horizontal marker line at the highest value
seen since the view was opened, and another at the lowest. Display both
values as labels next to the thermometer.
The skill adds state to track the running minimum and maximum, updates them on each signal tick, and renders the marker lines inside the thermometer container. The labels use MUI’s Typography so font size and color follow the theme.
Enhancement 3: A settings dialog
/develop-canking-gui-extension Add a settings dialog that lets the user
override the min and max range used for the thermometer fill calculation.
Default to the signal's own min/max metadata, but let the user type custom
values. Persist the overrides with the CanKing project so they survive a reload.
This is the most substantial enhancement, and it is where the skill’s accumulated knowledge earns its keep. A dialog rendered inside the workspace view would be clipped to the pane, so a real dialog has to be registered in src/Dialogs/index.tsx and opened with openExtensionDialog, passing the view’s id so both windows share project data.
Two gotchas the skill handles that are easy to get wrong by hand:
- Project data, not session data. Session data slices are loaded once when a view mounts and are *not* synced between windows. Anything the pane and the dialog both need to see change must be project data.
- Check
completedbefore readingresult. A CanKing older than the dialog API resolves withcompleted: falseandreason: 'unsupported-host', so the extension needs a fallback path. Closing the dialog window any other way also resolves without a result — that is how a cancel is reported.
Other things develop handles
The same skill covers the unglamorous work too:
/develop-canking-gui-extension The build broke after I bumped
@kvaser/canking-api to 7.6.0. Fix it.
Here the skill reads node_modules/@kvaser/canking-api/CHANGELOG.md from the old version up to the new one *before* touching code. The SDK version tracks the CanKing application version, so a bump can carry behavior changes that never show up as type errors — the changelog is usually a faster route to the fix than working backwards from compiler output.
Part 5: Running It Against Live Data
A green build is not proof that anything works. Getting the extension in front of real data used to be the manual step at the end; develop-canking-gui-extension now covers it.
The dev loop launches CanKing itself, pointed at a Vite dev server:
| Command | What it does |
|---|---|
|
|
Vite dev server plus CanKing with --ck-debug-pkg ./package.json --ck-debug-port 4000. Hot reload. |
|
|
The same, but serving a production build — use this to confirm a change survives bundling. |
|
VS Code Debug configuration (F5) |
The same loop with the debugger attached. |
Two honest caveats, both of which the skill is explicit about:
These commands never exit. They start a GUI application that runs until you close it. An agent that runs one in a blocking foreground call simply hangs. The skills are written to either run them in the background or — more usually — hand them to you to run.
The agent cannot see your screen. Nothing in this loop reports back what the extension actually rendered. So the skill tells you precisely what to look at and what should happen, and treats your answer as the verdict. This is a genuine limit, and it is better to know about it than to be told a feature “works” on the strength of a compile.
Connecting the agent to CanKing itself
So far the agent has only been reading and writing files. CanKing also ships an MCP (Model Context Protocol) server that exposes the CanKing CLI as tools your agent can call — listing connected devices, building a measurement setup, starting and stopping measurements, sending CAN and LIN messages, managing extensions, and analyzing logged data. Connecting it is what turns the agent from something that writes your extension into something that can also exercise it.
CanKingMcpServer is installed next to ck in the CanKing installation folder:
- Windows:
C:\Program Files\Kvaser CanKing\service\CanKingMcpServer.exe - Linux:
/opt/canking/service/CanKingMcpServer
It uses the stdio transport, so your agent starts it as a subprocess and talks to it over standard input and output. A running CanKing Service is required; its port is discovered automatically.
GitHub Copilot — create .vscode/mcp.json in your workspace, then open the Chat view, switch to Agent mode, and the CanKing tools appear in the tools picker:
{
"servers": {
"canking": {
"type": "stdio",
"command": "C:\\Program Files\\Kvaser CanKing\\service\\CanKingMcpServer.exe",
"args": []
}
}
}
Claude Code — register it once from a terminal, then run /mcp inside Claude Code to confirm it connected:
claude mcp add canking --scope user -- "C:\Program Files\Kvaser CanKing\service\CanKingMcpServer.exe"
Codex — add it to %USERPROFILE%\.codex\config.toml (~/.codex/config.toml on Linux):
[mcp_servers.canking]
command = 'C:\Program Files\Kvaser CanKing\service\CanKingMcpServer.exe'
args = []
The full details are in the CanKing User’s Guide installed with CanKing, under CLI → Overview → AI Agent Tools — on Windows, C:\Program Files\Kvaser CanKing\docs\user-guide\html\ck\overview.html.
None of this is required for the skills themselves — scaffolding, implementing, and building all work without it. It is required for everything in the rest of this section, and it makes packaging in Part 6 easier.
Making the needle move without hardware
The thermometer is not very convincing against a silent bus. With the MCP server connected, the agent can drive a running CanKing directly — add a virtual CAN channel, attach a DBC database or send individual frames, and start the measurement:
/develop-canking-gui-extension I have CanKing running with one virtual CAN channel and a database node.
The thermometer is displaying the EngineTemp signal. Help me test it by controlling CanKing to do this:
- Start a measurement and send out CAN messages that ramps the EngineTemp from min to max in 10 steps
- Stop the measurement.
- Wait 3 seconds.
- Restart the measurement and ramp the signal from max to min in 10 steps.
- Stop the measurement.
That turns “I need a Kvaser interface and a live bus on my desk to try this” into something you can do on a laptop on a train. For a gauge extension in particular, it is the difference between a demo you can iterate on in minutes and one you can only test in the lab.
Part 6: Packaging and Installing
Once the extension does what you want, it needs to become something installable.
npm pack # -> signal-thermometer-1.0.0.tgz
npm pack produces a .tgz that CanKing can install directly, and that is enough to hand to a colleague. What it does not carry is documentation. The distributable format is .ckext, which bundles the README, changelog, license, and user guide alongside the package:
ck pack extension signal-thermometer-1.0.0.tgz \
--readme README.md --changelog CHANGELOG.md \
--license LICENSE.txt --userguide userguide.md
ck is the CanKing CLI, installed with CanKing — on Windows, typically C:/Program Files/Kvaser CanKing/service/ck.exe. Two things to check before assuming this just runs: ck is not necessarily on your PATH, and older extension projects have no npm run package script at all. The skill checks both rather than guessing.
Installing:
ck install extension signal-thermometer.ckext --replace
--replace updates an already-installed extension of the same name — which is what you want on every iteration after the first. You can also install from the CanKing UI with More → Extensions → Install, and install accepts a bare .tgz as readily as a .ckext (it gets bundled on the way in).
If you set up the CanKing MCP server in Part 5, the skill prefers its pack_extension and install_extension tools, which invoke exactly these commands and save having to locate ck.exe.
/develop-canking-gui-extension Package this extension as a .ckext with the
README and license included, and install it into CanKing.Part 7: Prompt patterns that work well
After working through the thermometer example, a few patterns emerge for writing effective skill prompts.
Let the skill boundary do its job
You rarely need to think hard about which skill to invoke. If the folder is empty, it is create; if the extension exists, it is develop. Many agents will pick the right one from the skill descriptions without a slash command at all — typing /develop-canking-gui-extension just makes the choice explicit. And if you get it wrong, the skill tells you which one you wanted rather than doing something destructive.
Be specific about the visual behavior, not the implementation
The skills already know MUI and the CanKing SDK. Your job is to describe what the user sees and experiences, not which React component to use:
// Good: describes behavior
"The mercury level should rise and fall with the signal value."
// Less useful: prescribes implementation
"Use a LinearProgress component in vertical mode."
The skill will pick a component that fits. If it picks one you do not like, describe the behavior you expected in a follow-up and let it self-correct.
Group scaffold answers separately from feature description
This applies to create only. Mixing scaffold metadata into the feature narrative makes both harder to parse. Keep the feature description as a plain paragraph or two, then supply the scaffold values separately — as YAML, as a bulleted list, or as labeled lines:
/create-canking-gui-extension Displays battery voltage as a large arc gauge.
The needle sweeps from 9 V on the left to 15 V on the right. Show 12 V as
the center reference mark.
- project name: battery-gauge
- display name: Battery Voltage
- author: Your Name
Reference previous state when enhancing
When asking for enhancements, mention what currently exists to help the skill locate the right spot in the code:
/develop-canking-gui-extension The thermometer currently shows a solid fill bar.
Add an animated transition so the fill level moves smoothly when the signal
value changes. Keep the transition duration short (under 300 ms) so it feels
responsive rather than sluggish.
The skill reads the code either way, but the reference gets it to the relevant lines directly.
Say when you want runtime proof
Because the skills distinguish “it builds” from “it works”, it is worth being explicit about which you are asking for:
/develop-canking-gui-extension Add a warning icon that appears when the
signal value exceeds 90% of the max range, then start CanKing with the
extension loaded and tell me how to trigger it.Part 8: What is still on you
The two skills between them cover scaffold through packaging. A few things remain genuinely outside their scope:
You are the verdict on anything visual. The agent can launch CanKing and generate traffic, but it cannot see what rendered. Expect to be told what to look at, and expect your answer to be what the skill acts on.
Service extensions are a different system. CanKing also supports service extensions — WASM data processors and data targets, packed from a .wasm with a different SDK. These skills cover GUI extensions only. They share the ck pack extension / ck install extension path, which is why the distinction is easy to miss.
Judgment about what the extension should do. A skill can turn “show the signal as a thermometer” into working code remarkably quickly. Deciding that a thermometer is the right way to show that signal is still your job.
Summary
Agent skills make the repetitive parts of CanKing extension development fast enough that experimentation becomes practical again. The two skills encode the full lifecycle — scaffold, install, read docs, implement, build, run, package — into instruction files you install once and invoke from VS Code Copilot Chat whenever you need them.
The thermometer example in this post went from an empty folder to a theme-aware live gauge with color zones, min/max markers, and a persisted settings dialog, then into CanKing against simulated traffic and out again as an installable .ckext — all driven by plain-language prompts, with no manual SDK lookup required.
Install the skills, create an empty folder, and start describing your next extension.
About the author
Krister Johansson is a Software Developer at Kvaser who likes to explore new ideas and turn them into practical tools. His work with CanKing includes looking at how technologies such as AI agents can remove some of the repetitive work from software development and leave more room for experimentation. This DevBlog grew from that practical, try-it-and-see approach.