For AI agents: the complete documentation index is available at https://docs.tessl.io/llms.txt, the full documentation bundle is available at https://docs.tessl.io/llms-full.txt, and this page is available as Markdown at https://docs.tessl.io/creating-skills-and-plugins/import-a-claude-code-plugin.md.

Import a Claude Code plugin

Info

Takeaway Run tessl plugin import in a Claude Code plugin folder. It writes .tessl-plugin/plugin.json from .claude-plugin/plugin.json, links the folder to a Tessl project, and prints the review, scenario, and eval commands to run next.

You have a Claude Code plugin with several skills, and you want to review them, generate scenarios, and run an eval. Tessl reads only .tessl-plugin/plugin.json, so a Claude Code plugin needs a Tessl manifest and a linked project first. tessl plugin import does both in one step and leaves .claude-plugin/ untouched, so the plugin keeps working in Claude Code.

Import the plugin

From the plugin's root folder, the one that holds .claude-plugin/:

tessl plugin import . --workspace engteam

engteam is a stand-in workspace. Run tessl workspace list and use one of yours in its place.

The command:

  1. Writes .tessl-plugin/plugin.json from the Claude manifest. The Claude name is flat, so the workspace becomes its prefix: my-plugin becomes engteam/my-plugin.
  2. Checks the result with the same validator tessl plugin lint uses, and prints anything it finds.
  3. Links the folder to a Tessl project. It reports a project that is already linked, links the project that matches the repository, or creates one. When no tessl.json encloses the folder, it creates one at the plugin root.
  4. Prints the next commands with real paths: tessl review run for each skill, then tessl scenario generate and tessl eval run for the plugin.

Run it again and nothing changes; it reports that the plugin is already imported.

What it imports

plugin import accepts four kinds of folder:

  • A Claude Code plugin, with .claude-plugin/plugin.json. Its fields map to the Tessl manifest as described below.
  • A folder of skills with no manifest, with skills/<name>/SKILL.md. The plugin is named after the folder. Pass --description, since there is no manifest to copy it from.
  • A single SKILL.md at the folder root. This writes the same manifest as tessl skill import. You can pass the folder or the SKILL.md file itself.
  • A Claude Code marketplace, with only .claude-plugin/marketplace.json. It writes nothing. For each plugin the marketplace keeps in a local folder, it lists the tessl plugin import command to run. A plugin whose source is a git repository or URL is listed by name only; clone it and import it from its own folder.

A folder that already has .tessl-plugin/plugin.json keeps it. The command goes straight to the project step. Pass --force to rebuild the manifest from .claude-plugin/plugin.json.

How the Claude manifest maps

  • name becomes <workspace>/<name>. Pass --name to change the name part. Plugin names use lowercase letters, numbers, dots, underscores, and hyphens, up to 90 characters. A Claude name outside that set is converted, with a warning: My Plugin becomes my-plugin. The same applies to a folder name or a SKILL.md name.
  • version is copied, or set to 0.1.0.
  • description is copied. Tessl requires one, so without it pass --description, or answer the prompt in a terminal.
  • author is copied. A string becomes { "name": "..." }.
  • homepage and license are copied.
  • repository is kept when it is an http(s) URL. git@github.com:owner/repo.git becomes https://github.com/owner/repo. Anything else is dropped with a warning.
  • skills and commands are left out when they point at the default ./skills and ./commands folders, which Tessl finds by convention. Other paths are written out as the list of skill folders and command files they reach, together with the ones in ./skills and ./commands, since Claude Code reads both and Tessl reads only the list.
  • mcpServers pointing at .mcp.json is kept. An inline server map is written to .mcp.json when that file is absent. An existing .mcp.json with different content is kept, with a warning.
  • agents, keywords, and hooks are not imported, and each one produces a warning that names what was dropped. Claude Code also loads hooks/hooks.json and agents/ when plugin.json names neither, so those folders produce the same warning. Add hooks by hand under hooks or nativeHooks; see Configuration files.

The plugin is private unless you pass --public.

Choose the workspace and organization

The plugin name needs a workspace. It comes from the first of these that is set:

  1. --workspace
  2. The workspace of the project the folder is already linked to
  3. TESSL_WORKSPACE
  4. A prompt, in a terminal

In CI or a piped shell with none of these set, the command stops and names --workspace. A workspace name has 4 to 40 lowercase letters, numbers, and hyphens; any other value is refused before anything is written.

The project step uses the same organization rules as tessl project create: --org, then TESSL_ORG, then your only organization, then a prompt.

Flags

FlagPurpose
--workspaceWorkspace for the plugin name, and for a project the command creates.
--orgOrganization for the project step.
--namePlugin name without the workspace.
--descriptionDescription when the source has none.
--publicMake the plugin public. Private by default.
--no-projectWrite the manifest only. Skip linking or creating a project.
--forceRebuild an existing .tessl-plugin/plugin.json from .claude-plugin/plugin.json.
--dry-runPrint the manifest it would write, and write nothing.
--jsonPrint one JSON document: the source type, manifest path, manifest, warnings, project action (existing, linked, created, or skipped), and next commands. A failed import prints { "status": "error", "message": "..." } and exits with code 1.

Writing the manifest needs no login. Linking a project does: without one, the command writes the manifest, then stops and tells you to run tessl login and the import command to finish, with the same --workspace.

Next