Skip to content

feat(agents): add JetBrains AI Assistant and Junie support#23

Open
wai-calvin wants to merge 2 commits into
mainfrom
feature/add-jetbrains-support
Open

feat(agents): add JetBrains AI Assistant and Junie support#23
wai-calvin wants to merge 2 commits into
mainfrom
feature/add-jetbrains-support

Conversation

@wai-calvin
Copy link
Copy Markdown

Add two new agents for JetBrains IDEs:

  • JetBrains AI Assistant: generates project rules in .aiassistant/rules/ as plain markdown with tracking comments (reuses KIRO format)
  • Junie: generates Agent Skills in .junie/skills//SKILL.md with YAML frontmatter (name + description) per the Agent Skills spec

Introduces subdirectory layout support in AgentConfig for Junie's skill-per-directory structure, with corresponding writer changes for path construction, file discovery, and cleanup.

Why?

What Changed?

Testing

Additional Notes

Checklist

  • Linked related issues (e.g., Closes #123)
  • Ran tests and all pass
  • Ran linters/hooks: pre-commit run --all-files
  • Updated documentation if behavior changed
  • Followed conventional commit message format

wai-calvin and others added 2 commits April 2, 2026 10:00
Add two new agents for JetBrains IDEs:
- JetBrains AI Assistant: generates project rules in .aiassistant/rules/
  as plain markdown with tracking comments (reuses KIRO format)
- Junie: generates Agent Skills in .junie/skills/<name>/SKILL.md with
  YAML frontmatter (name + description) per the Agent Skills spec

Introduces subdirectory layout support in AgentConfig for Junie's
skill-per-directory structure, with corresponding writer changes for
path construction, file discovery, and cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for two additional “agents”/output formats so the tool can generate prompt artifacts for JetBrains IDEs (AI Assistant rules) and Junie (Agent Skills), including handling Junie’s skill-per-directory layout.

Changes:

  • Add jetbrains-ai-assistant agent targeting .aiassistant/rules using the existing Kiro (plain markdown + tracking comment) generator.
  • Add junie agent and a new JunieCommandGenerator that emits SKILL.md with YAML frontmatter and tracking metadata.
  • Extend the writer to support subdirectory layouts for agents like Junie (path building, discovery, backup discovery, and cleanup of empty skill dirs).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
slash_commands/config.py Adds JUNIE format and registers jetbrains-ai-assistant + junie agent configs (Junie uses subdirectory layout + fixed filename).
slash_commands/generators.py Introduces JunieCommandGenerator and wires it into the generator factory.
slash_commands/writer.py Adds _build_output_path() and updates generation/discovery/cleanup to support subdirectory-based outputs.
tests/test_config.py Updates config invariants/tests for the new format and layout fields.
tests/test_generators.py Adds tests for JetBrains (via Kiro) and Junie generator behavior.
tests/test_writer.py Adds writer integration tests for JetBrains rules and Junie skill directory output, discovery, and cleanup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +432 to +442
# Sanitize name per Agent Skills spec: lowercase a-z, numbers, hyphens only,
# 1-64 chars, no leading/trailing hyphens, no consecutive hyphens.
skill_name = _strip_ordering_prefix(prompt.name).lower()
skill_name = re.sub(r"[^a-z0-9-]", "-", skill_name)
skill_name = re.sub(r"-{2,}", "-", skill_name).strip("-")[:64]

# Build Junie YAML frontmatter
frontmatter: dict[str, Any] = {
"name": skill_name,
"description": (description or prompt.name)[:1024],
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

Junie skill names can become an empty string after sanitization (e.g., prompt.name with only punctuation). The Agent Skills spec requires a 1–64 char name, but skill_name is not validated/fallbacked after strip('-')[:64], so this can emit invalid frontmatter (name: ''). Add a post-sanitization fallback (and ideally raise/skip with a clear error) when skill_name ends up empty.

Copilot uses AI. Check for mistakes.
Comment thread slash_commands/writer.py
Comment on lines +311 to +315
if agent.use_subdirectory_layout and agent.fixed_filename:
dir_name = self._sanitize_filename(prompt_name, "")
return self.base_path / agent.get_command_dir() / dir_name / agent.fixed_filename
filename = self._sanitize_filename(prompt_name, agent.command_file_extension)
return self.base_path / agent.get_command_dir() / filename
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

For subdirectory-layout agents, _build_output_path() derives the directory name via _sanitize_filename(prompt_name, ''), which allows uppercase/underscores/dots and does not strip ordering prefixes. Junie’s generator independently sanitizes the skill name (lowercase, hyphens only, strips ordering prefixes). This can produce mismatches like .junie/skills/SDD-1-My_Complex.Prompt/SKILL.md while frontmatter name is my-complex-prompt, conflicting with the PR’s intended .junie/skills/<name>/SKILL.md layout. Consider deriving the directory name from the same sanitized skill-name logic used by the Junie generator (or centralize this into a shared helper/AgentConfig).

Copilot uses AI. Check for mistakes.
Comment thread tests/test_generators.py
# No consecutive hyphens
assert "--" not in name


Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

Current Junie generator tests validate character constraints but don’t cover the edge case where sanitization yields an empty name (e.g., prompt names consisting only of punctuation). Adding a test for that case would lock in the required 1–64 char constraint and prevent emitting invalid frontmatter.

Suggested change
def test_junie_generator_sanitized_name_is_never_empty():
"""Test that sanitization never produces an empty Junie frontmatter name."""
from pathlib import Path
from mcp_server.prompt_utils import MarkdownPrompt
prompt = MarkdownPrompt(
name="!!!...___---",
description="Test",
tags=[],
arguments=[],
enabled=True,
body="# Test",
path=Path("test.md"),
meta={},
)
agent = get_agent_config("junie")
generator = JunieCommandGenerator()
generated = generator.generate(prompt, agent)
frontmatter, _ = _extract_frontmatter_and_body(generated)
name = frontmatter["name"]
assert 1 <= len(name) <= 64
assert name == name.lower()
assert all(c in "abcdefghijklmnopqrstuvwxyz0123456789-" for c in name)
assert not name.startswith("-")
assert not name.endswith("-")
assert "--" not in name

Copilot uses AI. Check for mistakes.
Comment thread tests/test_writer.py
Comment on lines +1007 to +1025
def test_writer_generates_junie_skill_in_subdirectory(mock_prompt_load: Path, tmp_path):
"""Test that writer generates Junie skills in subdirectory layout."""
prompts_dir = mock_prompt_load

writer = SlashCommandWriter(
prompts_dir=prompts_dir,
agents=["junie"],
dry_run=False,
base_path=tmp_path,
)

writer.generate()

skills_output_dir = tmp_path / ".junie" / "skills"
assert skills_output_dir.exists()

# Should create a subdirectory with SKILL.md inside
skill_file = skills_output_dir / "test-prompt" / "SKILL.md"
assert skill_file.exists()
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The writer’s Junie subdirectory-layout test only exercises a simple prompt name (test-prompt). Consider adding a case with an ordering prefix / punctuation (e.g., SDD-1-My_Complex.Prompt!Name) and asserting the output directory matches the sanitized skill name. This would catch mismatches between directory naming and Junie frontmatter name generation.

Copilot uses AI. Check for mistakes.
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.

2 participants