Support multiple IDEs and implement marketplace features#2
Support multiple IDEs and implement marketplace features#2ganeshdipdumbare wants to merge 2 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR expands Upsun’s “skill” distribution to multiple AI coding agents (Claude Code, Cursor, Codex, OpenCode) by adding agent-specific installation docs, an OpenCode plugin for automatic context injection, and marketplace metadata for publishing/install flows.
Changes:
- Add OpenCode plugin + install/docs to auto-inject
using-upsuncontext and expose skills via symlinked discovery. - Add Codex install/docs leveraging native skill discovery via
~/.agents/skillssymlink/junction. - Add marketplace metadata files for Claude and Cursor, and update the main README to reference these new install paths.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/README.opencode.md | New OpenCode usage & install guide (symlinks + plugin behavior). |
| docs/README.codex.md | New Codex usage & install guide (native skill discovery via symlink/junction). |
| README.md | Updates installation section to cover multiple agents and links to new docs. |
| .opencode/plugins/upsun.js | Adds OpenCode plugin to inject Upsun skill content into system prompt. |
| .opencode/INSTALL.md | Standalone OpenCode install instructions referenced by README. |
| .cursor-plugin/plugin.json | Cursor plugin metadata for packaging/publishing. |
| .cursor-plugin/marketplace.json | Cursor marketplace metadata describing available plugin(s). |
| .codex/INSTALL.md | Standalone Codex install instructions referenced by README/docs. |
| .claude-plugin/plugin.json | Updates Claude plugin metadata to point at the new repo URL. |
| .claude-plugin/marketplace.json | Adds Claude marketplace metadata for distributing the plugin. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| const getBootstrapContent = () => { | ||
| // Try to load using-upsun skill | ||
| const skillPath = path.join(upsunSkillsDir, 'using-upsun', 'SKILL.md'); | ||
| if (!fs.existsSync(skillPath)) return null; | ||
|
|
||
| const fullContent = fs.readFileSync(skillPath, 'utf8'); | ||
| const { content } = extractAndStripFrontmatter(fullContent); |
There was a problem hiding this comment.
The system prompt transform runs on every request, but getBootstrapContent() does synchronous disk I/O (existsSync/readFileSync) each time. This blocks the event loop and can become a latency bottleneck. Consider computing/caching the bootstrap once during plugin initialization (or using async reads and caching) and only reloading when the underlying file changes.
| "repository": "https://github.com/upsun/ai", | ||
| "license": "MIT", | ||
| "keywords": ["upsun", "paas", "deployment", "platform"], | ||
| "skills": "./skills/" |
There was a problem hiding this comment.
plugin.json declares "skills": "./skills/", but there is no .cursor-plugin/skills/ directory in the repo. As-is, the packaged Cursor plugin won’t be able to find or include the Upsun skills. Either add the skills directory under .cursor-plugin/ (and keep it in sync) or point skills at the correct location that will be packaged/published.
| # Clone to personal skills directory | ||
| mkdir -p ~/.claude/skills | ||
| cd ~/.claude/skills | ||
| git clone https://github.com/upsun/skills.git upsun | ||
| git clone https://github.com/upsun/ai.git upsun | ||
|
|
There was a problem hiding this comment.
The manual install "git clone" step clones the entire repository into ~/.claude/skills/upsun, but Claude skills are expected to have a SKILL.md at the skill directory root. In this repo, SKILL.md lives under skills/using-upsun/, so a straight clone into the skills directory won’t be discovered as a skill. Update the instructions to either copy/symlink skills/using-upsun into ~/.claude/skills/upsun (as you already do for the zip path) or use a sparse checkout so the resulting ~/.claude/skills/upsun/SKILL.md exists.
| ``` | ||
| Clone https://github.com/upsun/ai to ~/.config/opencode/upsun, then create directory ~/.config/opencode/plugins, then symlink ~/.config/opencode/upsun/.opencode/plugins/upsun.js to ~/.config/opencode/plugins/upsun.js, then symlink ~/.config/opencode/upsun/skills to ~/.config/opencode/skills/upsun, then restart opencode. | ||
| ``` |
There was a problem hiding this comment.
Quick Install instructs creating ~/.config/opencode/plugins but then symlinks into ~/.config/opencode/skills/upsun without ensuring ~/.config/opencode/skills exists. Add creation of the skills directory (or use mkdir -p ~/.config/opencode/{plugins,skills}) so the one-liner works on a clean install.
| ### Loading a Skill | ||
|
|
||
| Use OpenCode's native `skill` tool to load the Upsun skill: | ||
|
|
||
| ``` | ||
| use skill tool to load upsun/using-upsun | ||
| ``` |
There was a problem hiding this comment.
This section tells users to load upsun/using-upsun via the skill tool, but the OpenCode plugin you ship injects the using-upsun skill content into the system prompt on every request. That makes manual loading redundant and conflicts with the plugin’s own warning message. Clarify that loading is only needed if the plugin isn’t installed/active, or remove this step to avoid confusion.
| ### Loading a Skill | ||
|
|
||
| Use OpenCode's native `skill` tool to load the Upsun skill: | ||
|
|
||
| ``` | ||
| use skill tool to load upsun/using-upsun | ||
| ``` |
There was a problem hiding this comment.
This section instructs users to load upsun/using-upsun, but the plugin described later auto-injects the using-upsun content into the system prompt. That makes this step redundant and inconsistent with the plugin’s own warning not to load it again. Please clarify when/why users should manually load the skill (e.g., only if the plugin isn’t installed).
| const extractAndStripFrontmatter = (content) => { | ||
| const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); | ||
| if (!match) return { frontmatter: {}, content }; |
There was a problem hiding this comment.
extractAndStripFrontmatter only matches \n line endings. On Windows checkouts with CRLF (\r\n), the regex won’t match and the injected content will include the YAML frontmatter block. Make the frontmatter stripping tolerant of CRLF (and ideally optional trailing newlines) so behavior is consistent across platforms.
| "name": "upsun-marketplace", | ||
| "description": "Upsun skills marketplace - comprehensive Upsun CLI management", | ||
| "owner": { | ||
| "name": "Upsun Team", | ||
| "email": "support@upsun.com" | ||
| }, |
There was a problem hiding this comment.
I know this was pre-existing but
- I think this should be more generic
- The top-level
descriptionisn't a field in the schema here - Email isn't required (and generally I believe we prefer not to publish a support email here)
| "name": "upsun-marketplace", | |
| "description": "Upsun skills marketplace - comprehensive Upsun CLI management", | |
| "owner": { | |
| "name": "Upsun Team", | |
| "email": "support@upsun.com" | |
| }, | |
| "name": "upsun", | |
| "owner": { | |
| "name": "Upsun" | |
| }, |
| { | ||
| "name": "upsun", | ||
| "description": "Comprehensive Claude Code skill for managing Upsun projects via the Upsun CLI. Covers 130+ commands including deployments, environments, backups, databases, resources, and security.", | ||
| "version": "1.0.0", |
There was a problem hiding this comment.
As this is optional, perhaps it's not meaningful yet?
| "version": "1.0.0", |
| "plugins": [ | ||
| { | ||
| "name": "upsun", | ||
| "description": "Comprehensive Claude Code skill for managing Upsun projects via the Upsun CLI. Covers 130+ commands including deployments, environments, backups, databases, resources, and security.", |
There was a problem hiding this comment.
Again these problems predate this PR but
- Nothing's ever comprehensive
- The skill should not be about the CLI
- I think we're describing the plugin, not the skill here?
| "description": "Comprehensive Claude Code skill for managing Upsun projects via the Upsun CLI. Covers 130+ commands including deployments, environments, backups, databases, resources, and security.", | |
| "description": "Official Claude plugin for Upsun", | |
| "homepage": "https://upsun.com/", |
| "author": { | ||
| "name": "Upsun Team", | ||
| "email": "support@upsun.com" | ||
| } |
There was a problem hiding this comment.
| "author": { | |
| "name": "Upsun Team", | |
| "email": "support@upsun.com" | |
| } |
| "author": { | ||
| "name": "Upsun Team", | ||
| "email": "support@upsun.com" | ||
| }, |
There was a problem hiding this comment.
| "author": { | |
| "name": "Upsun Team", | |
| "email": "support@upsun.com" | |
| }, | |
| "author": { | |
| "name": "Upsun" | |
| }, |
| { | ||
| "name": "upsun", | ||
| "displayName": "Upsun", | ||
| "description": "Comprehensive skill for managing Upsun projects via the Upsun CLI. Covers 130+ commands including deployments, environments, backups, databases, resources, and security.", |
There was a problem hiding this comment.
I don't like this description (it predates this MR) but also description is not in the example file at this level
https://github.com/cursor/plugin-template/blob/main/.cursor-plugin/marketplace.json
| "name": "upsun", | ||
| "displayName": "Upsun", | ||
| "description": "Comprehensive skill for managing Upsun projects via the Upsun CLI. Covers 130+ commands including deployments, environments, backups, databases, resources, and security.", | ||
| "version": "1.0.0", |
There was a problem hiding this comment.
Same version decision as the Claude one will need to apply here
| @@ -0,0 +1,67 @@ | |||
| # Installing Upsun for Codex | |||
There was a problem hiding this comment.
Codex and OpenCode both discover skills from ~/.agents/skills so they probably can use generic docs rather than tool-specific ones?
No description provided.