Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ba3d3d9
Skill Quick Install
Fedoseew May 15, 2026
784354a
Add Studio meta-data
Fedoseew May 15, 2026
e9f3cb4
Add support for Jmix version flag
Fedoseew May 15, 2026
70610c2
Add version detect fallback mechanism
Fedoseew May 15, 2026
7907dc5
Rewrite enhance scripts and studio-meta-data.json
Fedoseew May 18, 2026
43bf7be
Update studio-meta-data.json steps
Fedoseew May 18, 2026
2ab58d9
Update studio-meta-data.json steps
Fedoseew May 18, 2026
0ce5101
Update studio-meta-data.json steps
Fedoseew May 18, 2026
2d1190f
Create backup files only in case of flag --backup-existing-files
Fedoseew May 18, 2026
6c982b5
Fixes
Fedoseew May 19, 2026
6dd26b1
Fixes
Fedoseew May 19, 2026
ac59eec
Fixes
Fedoseew May 19, 2026
217f42b
Skills installation scope
Fedoseew May 20, 2026
b7a76f4
Skills installation scope
Fedoseew May 20, 2026
83184cc
Fixes
Fedoseew May 20, 2026
8ba7879
skills-manifest.json
Fedoseew May 20, 2026
74812ae
Add <br> to messages
Fedoseew May 20, 2026
7b8dc8f
Improve messages
Fedoseew May 20, 2026
18c24df
Improve messages
Fedoseew May 20, 2026
be5e94e
Improve messages
Fedoseew May 21, 2026
cb86d78
Fix agent skill symlink creation
Fedoseew May 21, 2026
cb5d653
Update README and schema descriptions
Fedoseew May 21, 2026
a1dbba2
Add emojis to messages
Fedoseew May 21, 2026
77f8d10
Add emojis to labels
Fedoseew May 21, 2026
93bbca7
Fixes
Fedoseew May 21, 2026
c1bc3b4
Fixes
Fedoseew May 21, 2026
481b19a
Fixes
Fedoseew May 21, 2026
9be1e23
Fix symlinks configuration for agent skills
Fedoseew May 21, 2026
76e5ba0
Rewrite playwright installation flow to use npx instead of npm (root …
Fedoseew May 22, 2026
1347588
Rewrite playwright installation flow to use npx instead of npm (root …
Fedoseew May 22, 2026
c2f2966
Fixes
Fedoseew May 22, 2026
851a972
Add checks for infinite loop
Fedoseew May 22, 2026
1d915d1
Fix silent exit in playwright install when ~/.claude/skills is empty
knstvk May 22, 2026
ab117c6
Rewrite playwright scripts installation
Fedoseew May 22, 2026
917a8b1
Fixes
Fedoseew May 23, 2026
07b0c3d
Merge branch 'main' into skill-quick-install
Fedoseew May 25, 2026
7bf5683
Fixes
Fedoseew May 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/skills-manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Update skills manifest

on:
push:
branches: [ main ]
paths:
- 'v*/skills/**'
- '.studio/gen_skills_manifest.py'
workflow_dispatch:

permissions:
contents: write

jobs:
update-manifest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.x'
- name: Generate manifest
run: python3 .studio/gen_skills_manifest.py
- name: Commit if changed
run: |
if git diff --quiet -- .studio/skills-manifest.json; then
echo "manifest unchanged"
else
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .studio/skills-manifest.json
git commit -m "chore: update skills-manifest.json [skip ci]"
git push
fi
72 changes: 72 additions & 0 deletions .studio/gen_skills_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""Generate .studio/skills-manifest.json (version -> {skills[], sha256}).

The aggregate hash is byte-identical to jmix-studio logic:
for each listed skill folder, walk files; entry = relpath(UTF-8) + 0x00 + bytes,
relpath is POSIX-separated and relative to the version's skills/ dir; sort
entries by relpath bytes; SHA-256 over the concatenation; lowercase hex.
"""
import hashlib
import json
import os

REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Canonical per-scope skill store (relative to the scope root: the user home for
# "global", the project base for "local"). The global store appends /v<major>.
# Studio reads this from the manifest; install.sh / install.ps1 mirror it.
STORE = {
"global": ".agents/.jmix/skills",
"local": ".skills",
}

def list_skill_names(skills_dir):
return sorted(
name for name in os.listdir(skills_dir)
if os.path.isdir(os.path.join(skills_dir, name))
)

def aggregate_hash(skills_dir, skill_names):
entries = []
for name in sorted(skill_names):
base = os.path.join(skills_dir, name)
if not os.path.isdir(base):
continue
for current, _dirs, files in os.walk(base):
for filename in files:
full = os.path.join(current, filename)
rel = os.path.relpath(full, skills_dir).replace(os.sep, "/")
with open(full, "rb") as f:
entries.append((rel, f.read()))
entries.sort(key=lambda e: e[0].encode("utf-8"))
digest = hashlib.sha256()
for rel, data in entries:
digest.update(rel.encode("utf-8"))
digest.update(b"\x00")
digest.update(data)
return digest.hexdigest()

def build_manifest():
versions = {}
for entry in sorted(os.listdir(REPO_ROOT)):
if not entry.startswith("v"):
continue
skills_dir = os.path.join(REPO_ROOT, entry, "skills")
if not os.path.isdir(skills_dir):
continue
names = list_skill_names(skills_dir)
versions[entry] = {"skills": names, "sha256": aggregate_hash(skills_dir, names)}
return {"schemaVersion": 1, "store": STORE, "versions": versions}

def main():
manifest = build_manifest()
out_dir = os.path.join(REPO_ROOT, ".studio")
os.makedirs(out_dir, exist_ok=True)
out_path = os.path.join(out_dir, "skills-manifest.json")
text = json.dumps(manifest, indent=2, ensure_ascii=False, sort_keys=True) + "\n"
with open(out_path, "w", encoding="utf-8") as f:
f.write(text)
print("wrote " + out_path)

if __name__ == "__main__":
main()
25 changes: 25 additions & 0 deletions .studio/skills-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"schemaVersion": 1,
"store": {
"global": ".agents/.jmix/skills",
"local": ".skills"
},
"versions": {
"v2": {
"sha256": "d2d53b6cc53b623c51d05611fc48908342d4cdda2afeefe5289d69eac3c4c2a7",
"skills": [
"jmix-dto",
"jmix-entities",
"jmix-enums",
"jmix-fetch-plans",
"jmix-fragments",
"jmix-i18n",
"jmix-liquibase",
"jmix-security-roles",
"jmix-services",
"jmix-testing",
"jmix-views"
]
}
}
}
231 changes: 231 additions & 0 deletions .studio/studio-meta-data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
{
"$schema": "./studio-meta-data.schema.json",
"install-flow": {
"steps": [
{
"id": "skills",
"title": "Skills",
"message": "🛠️ Install Jmix <code>skills</code> for the selected agents in the preferred scope (local/global). <br>⏭️ Click <i>Skip</i> to opt out.",
"inputs": [
{
"id": "skillsScope",
"label": "Installation scope",
"type": "options",
"choices": [
{
"value": "local",
"label": "Local (project)",
"default": true
},
{
"value": "global",
"label": "Global (user home)"
}
]
},
{
"id": "skillsAgents",
"label": "🤖 Agents",
"type": "options",
"multi": true,
"choices": [
{
"value": "claude",
"label": "Claude Code",
"default": true
},
{
"value": "codex",
"label": "Codex",
"default": true
},
{
"value": "opencode",
"label": "OpenCode",
"default": true
},
{
"value": "junie",
"label": "Junie",
"default": true
}
]
}
],
"command": {
"windows": "& ([scriptblock]::Create((iwr -useb https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.ps1).Content)) skills -Agents \"${skillsAgents}\" -Scope \"${skillsScope}\" -Version \"${JMIX_VERSION}\"",
"macos": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- skills --agents \"${skillsAgents}\" --scope \"${skillsScope}\" --version \"${JMIX_VERSION}\"",
"linux": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- skills --agents \"${skillsAgents}\" --scope \"${skillsScope}\" --version \"${JMIX_VERSION}\""
}
},
{
"id": "guidelines",
"title": "Guidelines",
"message": "📘 Add Jmix coding guidelines (<code>CLAUDE.md</code> / <code>AGENTS.md</code> / <code>guidelines.md</code>) to the project root for the selected agents. <br>⏭️ Click <i>Skip</i> to leave the project as is.",
"inputs": [
{
"id": "guidelinesAgents",
"label": "\uD83E\uDD16 Agents",
"type": "options",
"multi": true,
"choices": [
{
"value": "claude",
"label": "Claude Code",
"default": true
},
{
"value": "codex",
"label": "Codex",
"default": true
},
{
"value": "opencode",
"label": "OpenCode",
"default": true
},
{
"value": "junie",
"label": "Junie",
"default": true
}
]
}
],
"command": {
"windows": "& ([scriptblock]::Create((iwr -useb https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.ps1).Content)) agents-md -Agents \"${guidelinesAgents}\" -Version \"${JMIX_VERSION}\"",
"macos": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- agents-md --agents \"${guidelinesAgents}\" --version \"${JMIX_VERSION}\"",
"linux": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- agents-md --agents \"${guidelinesAgents}\" --version \"${JMIX_VERSION}\""
}
},
{
"id": "jetbrainsMcp",
"title": "JetBrains MCP",
"message": "🔌 Register the <code>JetBrains MCP</code> server with the selected agents. <br>⏭️ Click <i>Skip</i> to opt out.",
"inputs": [
{
"id": "jetbrainsMcpAgents",
"label": "\uD83E\uDD16 Agents",
"type": "options",
"multi": true,
"choices": [
{
"value": "claude",
"label": "Claude Code",
"default": true
},
{
"value": "codex",
"label": "Codex",
"default": true
},
{
"value": "opencode",
"label": "OpenCode",
"default": true
},
{
"value": "junie",
"label": "Junie",
"default": true
}
]
}
],
"command": {
"windows": "& ([scriptblock]::Create((iwr -useb https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.ps1).Content)) mcp-jetbrains -Agents \"${jetbrainsMcpAgents}\"",
"macos": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- mcp-jetbrains --agents \"${jetbrainsMcpAgents}\"",
"linux": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- mcp-jetbrains --agents \"${jetbrainsMcpAgents}\""
}
},
{
"id": "context7",
"title": "Context7 MCP",
"message": "\uD83D\uDD0C Register the <code>Context7 MCP</code> server with the selected agents. <br>\uD83C\uDF10 You can get key on <a href=\"https://context7.com\" target=\"_blank\">context7.com</a>. Your key is sent to the MCP CLI and never stored by Studio. <br>⏭\uFE0F Click <i>Skip</i> to opt out.",
"inputs": [
{
"id": "context7Agents",
"label": "\uD83E\uDD16 Agents",
"type": "options",
"multi": true,
"choices": [
{
"value": "claude",
"label": "Claude Code",
"default": true
},
{
"value": "codex",
"label": "Codex",
"default": true
},
{
"value": "opencode",
"label": "OpenCode",
"default": true
},
{
"value": "junie",
"label": "Junie",
"default": true
}
]
},
{
"id": "context7Key",
"label": "\uD83D\uDD11 API key",
"type": "userInput",
"regex": "^.{8,}$",
"errorMessage": "Context7 API key must be at least 8 characters.",
"placeholder": "ctx7_..."
}
],
"command": {
"windows": "& ([scriptblock]::Create((iwr -useb https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.ps1).Content)) mcp-context7 -Agents \"${context7Agents}\" -Context7Key \"${context7Key}\"",
"macos": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- mcp-context7 --agents \"${context7Agents}\" --context7-key \"${context7Key}\"",
"linux": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- mcp-context7 --agents \"${context7Agents}\" --context7-key \"${context7Key}\""
}
},
{
"id": "playwright",
"title": "Playwright",
"message": "\uD83D\uDD0C Install <code>Playwright</code> testing skills for the selected agents. <br>📦 Requires <b>npm</b> to be installed on PATH. <br>⏭️ Click <i>Skip</i> to opt out.",
"inputs": [
{
"id": "playwrightAgents",
"label": "\uD83E\uDD16 Agents",
"type": "options",
"multi": true,
"choices": [
{
"value": "claude",
"label": "Claude Code",
"default": true
},
{
"value": "codex",
"label": "Codex",
"default": true
},
{
"value": "opencode",
"label": "OpenCode",
"default": true
},
{
"value": "junie",
"label": "Junie",
"default": true
}
]
}
],
"command": {
"windows": "& ([scriptblock]::Create((iwr -useb https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.ps1).Content)) playwright -Agents \"${playwrightAgents}\"",
"macos": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- playwright --agents \"${playwrightAgents}\"",
"linux": "curl -fsSL https://raw.githubusercontent.com/jmix-framework/jmix-agent-guidelines/main/install.sh | bash -s -- playwright --agents \"${playwrightAgents}\""
}
}
]
}
}
Loading