Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,40 @@

Coderrr is an AI-powered coding agent that analyzes tasks, creates actionable plans, performs file operations, and executes commands with user permission. Built for developers who want automated assistance without sacrificing control.

---

## 🧩 Skills Marketplace

**Extend Coderrr's capabilities with installable skills!**

Browse and install skills from the [coderrr-skills](https://github.com/Akash-nath29/coderrr-skills) marketplace:

```bash
# Browse available skills
coderrr market

# Install a skill
coderrr install web-scraper

# List installed skills
coderrr skills
```

| Skill | Description |
|-------|-------------|
| **web-scraper** | Fetch and extract content from web pages |
| **pdf** | Create, merge, split, and extract PDFs |
| **code-analyzer** | Lint code, count lines, find TODOs |
| **docx/xlsx/pptx** | Work with Office documents |
| **api-client** | Make HTTP requests |

👉 **[Browse all skills →](https://github.com/Akash-nath29/coderrr-skills)**

---

## Table of Contents

- [🧩 Skills Marketplace](#-skills-marketplace)
- [See Coderrr in Action](#see-coderrr-in-action)
- [Features](#features)
- [Core Capabilities](#core-capabilities)
Expand Down
5 changes: 4 additions & 1 deletion backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class PlanStep(BaseModel):
action: Literal[
"create_file", "update_file", "patch_file", "delete_file",
"read_file", "run_command", "create_dir", "delete_dir",
"list_dir", "rename_dir"
"list_dir", "rename_dir", "invoke_skill"
]
path: Optional[str] = None
content: Optional[str] = None
Expand All @@ -102,6 +102,9 @@ class PlanStep(BaseModel):
old_path: Optional[str] = Field(default=None, alias="oldPath")
new_path: Optional[str] = Field(default=None, alias="newPath")
command: Optional[str] = None
skill: Optional[str] = None # Skill name for invoke_skill
tool: Optional[str] = None # Tool name for invoke_skill
args: Optional[dict] = None # Arguments for invoke_skill
summary: str


Comment on lines 109 to 110
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

Missing validation for required PlanStep fields in invoke_skill action. The backend PlanStep model defines optional fields skill, tool, and args for the invoke_skill action, but there's no validation ensuring these required fields are present when action is "invoke_skill". This could lead to runtime errors if the AI model returns an invoke_skill step without providing the necessary skill/tool information.

Consider adding a validation decorator or custom validator to ensure that when action == "invoke_skill", the fields skill and tool are required (not None). The Pydantic model should enforce this constraint.

Suggested change
@model_validator(mode="after")
def validate_invoke_skill_fields(self):
"""
Ensure that invoke_skill steps include the required fields.
When action == "invoke_skill", both `skill` and `tool` must be provided.
"""
if self.action == "invoke_skill":
if not self.skill:
raise ValueError(
"Invalid plan step: 'skill' is required when action is 'invoke_skill'"
)
if not self.tool:
raise ValueError(
"Invalid plan step: 'tool' is required when action is 'invoke_skill'"
)
return self

Copilot uses AI. Check for mistakes.
Expand Down
4 changes: 4 additions & 0 deletions bin/coderrr.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ program
const { displayRecipeList } = require('../src/recipeUI');
const recipeManager = require('../src/recipeManager');
const { displayInsights } = require('../src/insightsUI');
const { registerSkillCommands } = require('../src/skillsUI');

// Register skill management commands
registerSkillCommands(program);

// Optional: Load .env from user's home directory (for advanced users who want custom backend)
const homeConfigPath = path.join(os.homedir(), '.coderrr', '.env');
Expand Down
38 changes: 38 additions & 0 deletions src/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const GitOperations = require('./gitOps');
const { sanitizeAxiosError, formatUserError, createSafeError, isNetworkError } = require('./errorHandler');
const configManager = require('./configManager');
const { getProvider } = require('./providers');
const skillRegistry = require('./skillRegistry');
const skillRunner = require('./skillRunner');

/**
* Core AI Agent that communicates with backend and executes plans
Expand Down Expand Up @@ -59,6 +61,10 @@ class Agent {
// Track running processes spawned in separate terminals
this.runningProcesses = [];

// Load installed agent skills for tool invocation
this.installedSkills = skillRegistry.loadAllSkills();
this.toolManifest = skillRegistry.generateToolManifest();

// Register cleanup handler for when Coderrr exits
this.registerExitCleanup();
}
Expand Down Expand Up @@ -251,6 +257,16 @@ When editing existing files, use EXACT filenames from the list above. When creat
For command execution on ${osType}, use appropriate command separators (${osType === 'Windows' ? 'semicolon (;)' : 'ampersand (&&)'}).`;
}

// Inject available skill tools into context (if any are installed)
if (this.toolManifest) {
enhancedPrompt = `${enhancedPrompt}

${this.toolManifest}

To invoke a skill tool, use the action: "invoke_skill" with "skill", "tool", and "args" properties.
Example: {"action": "invoke_skill", "skill": "web-scraper", "tool": "fetch_page", "args": {"url": "..."}, "summary": "Fetching page"}`;
}

const spinner = ui.spinner('Thinking...');
spinner.start();

Expand Down Expand Up @@ -451,6 +467,10 @@ For command execution on ${osType}, use appropriate command separators (${osType
// Store the process handle for potential cleanup later
if (!this.runningProcesses) {
this.runningProcesses = [];

// Load installed agent skills for tool invocation
this.installedSkills = skillRegistry.loadAllSkills();
this.toolManifest = skillRegistry.generateToolManifest();
Comment on lines +470 to +473
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

Redundant skill loading during execution. Lines 471-473 reload installed skills and regenerate the tool manifest inside the run_command execution block, but this is already done during agent initialization (lines 64-66). This redundant loading serves no purpose as it's only executed when this.runningProcesses is undefined, which is unlikely after proper initialization.

The comment says "Load installed agent skills for tool invocation" but this is not related to command execution. This appears to be leftover code or a copy-paste error. Consider removing this redundant code block as skills are already loaded at initialization.

Suggested change
// Load installed agent skills for tool invocation
this.installedSkills = skillRegistry.loadAllSkills();
this.toolManifest = skillRegistry.generateToolManifest();

Copilot uses AI. Check for mistakes.
}
this.runningProcesses.push(result);

Expand Down Expand Up @@ -487,6 +507,24 @@ For command execution on ${osType}, use appropriate command separators (${osType
break;
}
}
} 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');
}
Comment on lines +510 to +527
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

Skill tool execution lacks user permission prompts. According to the project's architecture guidelines (CodingGuidelineID: 1000000), "ALL commands require user permission" like GitHub Copilot's model. The run_command action uses requirePermission: true (line 454), but the new invoke_skill action executes Python tools directly without asking for user confirmation. This violates the established safety pattern where users must approve potentially dangerous operations.

Consider adding a permission prompt before executing skill tools, similar to how command execution is handled. This is especially important since skills are third-party code that could perform arbitrary operations.

Copilot generated this review using guidance from repository custom instructions.
} else {
// File operation
const result = await this.fileOps.execute(step);
Expand Down
1 change: 1 addition & 0 deletions src/executor.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const fsSync = require('fs');
const path = require('path');
const os = require('os');
const ui = require('./ui');
const skillRunner = require('./skillRunner');
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

Unused variable skillRunner.

Suggested change
const skillRunner = require('./skillRunner');

Copilot uses AI. Check for mistakes.

class CommandExecutor {
constructor() {
Expand Down
Loading
Loading