feat: Add installable Coderrr-skills marketplace with remote registry#130
feat: Add installable Coderrr-skills marketplace with remote registry#130Akash-nath29 merged 4 commits intomainfrom
Conversation
feat: Add installable Coderrr-skills marketplace with remote registry
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
🚀 Thanks for opening a Pull Request! A maintainer will review this soon. Meanwhile: Your contribution helps make this project better! |
There was a problem hiding this comment.
Pull request overview
This PR adds a skills marketplace and plugin-style skills system to Coderrr, enabling discovery, installation, and invocation of Python-based tools from both a remote registry and local paths. It also integrates installed skills into the agent’s planning flow via a new invoke_skill action and documents how users can browse and install skills from the CLI.
Changes:
- Introduces skills management modules (
skillRegistry,skillRunner,skillMarketplace,skillsUI) to discover, install, validate, and execute Python-based skills from~/.coderrr/skillsand a remote GitHub-backed registry. - Extends the agent and backend schema to surface available tools to the LLM and support a new
"invoke_skill"plan action that runs skill tools viaskillRunner. - Updates the CLI entrypoint and README to expose new commands (
coderrr skills,coderrr install,coderrr market, etc.) and to document the Skills Marketplace for end users.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
src/skillsUI.js |
Adds CLI UI for listing, installing (local/remote), uninstalling, searching, and inspecting skills, and registers new coderrr subcommands. |
src/skillRunner.js |
Implements execution of Python tools from installed skills and automatic installation of per-skill Python dependencies via pip. |
src/skillRegistry.js |
Manages the ~/.coderrr/skills directory, validates skill structure, parses metadata from Skills.md/tool docstrings, and generates a manifest for LLM context. |
src/skillMarketplace.js |
Implements a GitHub-hosted remote registry client with caching, search, listing, and skill download/install logic. |
src/executor.js |
Imports skillRunner in preparation for skill-related command execution integration (no behavioral change yet in this diff). |
src/agent.js |
Loads installed skills, injects a skills/tools manifest into the backend prompt, and adds an invoke_skill execution branch in executePlan. |
bin/coderrr.js |
Wires the new skills CLI commands into the main coderrr commander program. |
backend/main.py |
Extends the PlanStep Pydantic model to allow an invoke_skill action and associated skill, tool, and args fields. |
README.md |
Documents the Skills Marketplace, showcasing example skills and linking to the external coderrr-skills registry, and updates the table of contents. |
| const pythonCommand = process.platform === 'win32' ? 'python' : 'python3'; | ||
|
|
||
| const proc = spawn(pythonCommand, ['-m', 'pip', 'install', '-r', requirementsPath], { | ||
| shell: true, |
There was a problem hiding this comment.
installSkillDependencies spawns Python with shell: true while passing requirementsPath as an array argument; because requirementsPath will often contain spaces on Windows home directories (e.g. C:\Users\First Last\...), the shell will split the path and cause pip install to fail. To make this robust across platforms, avoid shell: true when using an args array (let spawn handle quoting), or build a single command string with proper quoting/escaping for the requirements path.
| shell: true, |
| CODERRR_TOOL: toolName, | ||
| CODERRR_CWD: cwd | ||
| }, | ||
| shell: true, |
There was a problem hiding this comment.
Here executeTool also uses spawn with shell: true and an args array; any tool argument value (or even the toolPath itself) containing spaces or shell metacharacters will be split/misinterpreted by the shell, so tools won’t receive the intended arguments on Windows and some Unix setups. Consider removing shell: true when passing an args array, or otherwise constructing a single shell command string with correctly quoted arguments before spawning.
| shell: true, |
| const python = await checkPythonAvailable(); | ||
| if (!python.available) { | ||
| console.log(chalk.red('✗ Python not available. Skills require Python 3.8+.\n')); | ||
| return false; | ||
| } | ||
| console.log(chalk.green(` ■ Python ${python.version} found`)); | ||
|
|
There was a problem hiding this comment.
installSkill treats any available Python executable as acceptable but the message says “Skills require Python 3.8+”, so users with older Python versions (e.g. 3.7 or 2.7) will see a success message even though skills may not run correctly. Either enforce a minimum version check in checkPythonAvailable (e.g., parse and compare the major/minor version) and fail when it’s below 3.8, or relax the message to match the actual compatibility guarantees.
| async function downloadSkill(skillName) { | ||
| const skillInfo = await getSkillInfo(skillName); | ||
|
|
||
| if (!skillInfo) { | ||
| return { success: false, error: `Skill not found: ${skillName}` }; | ||
| } | ||
|
|
||
| // Check if already installed | ||
| if (skillRegistry.isSkillInstalled(skillName)) { | ||
| return { success: false, error: `Skill "${skillName}" is already installed.` }; | ||
| } | ||
|
|
||
| const skillDir = path.join(skillRegistry.SKILLS_DIR, skillName); | ||
| const toolsDir = path.join(skillDir, 'tools'); | ||
| const baseUrl = skillInfo.download_url; | ||
|
|
||
| try { | ||
| // Create directories | ||
| skillRegistry.ensureSkillsDir(); | ||
| fs.mkdirSync(toolsDir, { recursive: true }); | ||
|
|
||
| // Download Skills.md | ||
| console.log(` Downloading Skills.md...`); | ||
| const skillsMd = await downloadFile(`${baseUrl}/Skills.md`); | ||
| fs.writeFileSync(path.join(skillDir, 'Skills.md'), skillsMd, 'utf8'); | ||
|
|
||
| // Try to download requirements.txt (optional) | ||
| try { | ||
| const requirements = await downloadFile(`${baseUrl}/requirements.txt`); | ||
| fs.writeFileSync(path.join(skillDir, 'requirements.txt'), requirements, 'utf8'); | ||
| console.log(` Found requirements.txt`); | ||
| } catch (e) { | ||
| // requirements.txt is optional, ignore | ||
| } | ||
|
|
||
| // Download each tool | ||
| for (const tool of skillInfo.tools) { | ||
| console.log(` Downloading ${tool}.py...`); | ||
| try { | ||
| const toolContent = await downloadFile(`${baseUrl}/tools/${tool}.py`); | ||
| fs.writeFileSync(path.join(toolsDir, `${tool}.py`), toolContent, 'utf8'); | ||
| } catch (e) { | ||
| console.warn(` Warning: Could not download ${tool}.py`); | ||
| } | ||
| } | ||
|
|
||
| // Install Python dependencies if requirements.txt exists | ||
| const depsResult = await installSkillDependencies(skillName); | ||
| if (!depsResult.success && depsResult.error) { | ||
| console.log(` Note: ${depsResult.error}`); | ||
| } | ||
|
|
||
| return { | ||
| success: true, | ||
| skill: skillInfo, | ||
| message: `Skill "${skillName}" installed successfully` | ||
| }; |
There was a problem hiding this comment.
downloadSkill returns success as long as the downloads and dependency installation calls complete, but it never validates the resulting skill directory structure (e.g., presence of Skills.md and at least one .py tool) before reporting success. This means a misconfigured registry entry or a failed tool download could leave an incomplete skill directory that skillRegistry.validateSkillStructure would treat as invalid while the user has already been told the skill is installed; consider validating with validateSkillStructure and failing/cleaning up if the structure is invalid.
| // Install Python dependencies if requirements.txt exists | ||
| const depsResult = await installSkillDependencies(skillName); | ||
| if (!depsResult.success && depsResult.error) { | ||
| console.log(` Note: ${depsResult.error}`); | ||
| } |
There was a problem hiding this comment.
Installing Python dependencies via pip here happens automatically and non-interactively, which can install arbitrary packages into the user’s environment without any confirmation, unlike the rest of the CLI which uses explicit permission prompts for command execution. To align with the project’s safety model, consider adding a clear warning/confirmation step before running pip install (or delegating the command through the existing CommandExecutor with requirePermission semantics) so users explicitly approve environment-changing operations.
| } else if (step.action === 'invoke_skill') { | ||
| // Execute a skill tool | ||
| ui.info(`Invoking skill tool: ${step.skill}/${step.tool}`); | ||
|
|
||
| const result = await skillRunner.executeTool( | ||
| step.skill, | ||
| step.tool, | ||
| step.args || {}, | ||
| { cwd: this.workingDir } | ||
| ); | ||
|
|
||
| if (result.success) { | ||
| stepResult = `Skill ${step.skill}/${step.tool} executed successfully`; | ||
| stepSuccess = true; | ||
| ui.success(`Tool output:\n${result.output}`); | ||
| } else { | ||
| throw new Error(result.error || 'Skill tool execution failed'); | ||
| } |
There was a problem hiding this comment.
The new invoke_skill branch in executePlan introduces a distinct execution path, but there are currently no tests exercising this behavior, while other Agent behavior and prompt logic are covered in test/ and tests/unit/skills.test.js. It would be valuable to add unit tests that simulate a plan containing an invoke_skill step (mocking skillRunner.executeTool) to verify success and failure handling, integration with the TODO manager, and interaction with the retry/self-healing loop.
| const path = require('path'); | ||
| const os = require('os'); | ||
| const ui = require('./ui'); | ||
| const skillRunner = require('./skillRunner'); |
There was a problem hiding this comment.
Unused variable skillRunner.
| const skillRunner = require('./skillRunner'); |
This pull request introduces a comprehensive "Skills Marketplace" system to Coderrr, enabling users to extend the agent's capabilities with installable skills. It adds backend and frontend support for discovering, installing, managing, and invoking skills/tools, and updates documentation to guide users through these new features. The changes include new modules for marketplace and skill registry management, backend schema updates, and integration with the agent's execution flow.
Skills Marketplace & Skill Management:
src/skillMarketplace.jsmodule to handle fetching skill registry data from a remote marketplace, searching/listing skills, downloading/installing skills, and managing a local cache.src/skillRegistry.jsto manage installed skills, validate skill structure, parse metadata, list/load installed skills, and generate a manifest for LLM context injection.Agent Integration & Tool Invocation:
src/agent.jsto load installed skills and inject a manifest of available skills/tools into the LLM prompt, allowing the agent to invoke tools via a new"invoke_skill"action. The agent now executes skill tools usingskillRunnerand provides feedback on tool execution. [1] [2] [3] [4] [5]src/executor.jsto importskillRunnerfor executing skill tools.Backend Schema Extension:
PlanStepmodel inbackend/main.pyto support the"invoke_skill"action and includeskill,tool, andargsfields for skill invocation steps. [1] [2]Documentation:
README.mdto introduce the Skills Marketplace, provide usage instructions for browsing/installing skills, and list example skills available in the marketplace.These changes collectively enable Coderrr to support a plugin-like ecosystem, making it extensible and more powerful for users.