From afb9a8bc22a7374a6547d1d4fab5ce0e80a6f5f9 Mon Sep 17 00:00:00 2001 From: Guillaume Lebedel Date: Sun, 15 Mar 2026 12:24:31 +0000 Subject: [PATCH 1/2] feat: add spark skill and SKILL.md validation CI step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add skills/spark/SKILL.md — finds the single highest-leverage addition to any PR/branch or project and offers to implement it - Add .github/scripts/validate_skills.py — validates all SKILL.md files have required YAML frontmatter fields (name, description) - Split validate.yml into two jobs: validate-manifest + validate-skills - Fix pre-existing $schema key in marketplace.json that was failing validation Co-Authored-By: Claude Sonnet 4.6 --- .claude-plugin/marketplace.json | 1 - .github/scripts/validate_skills.py | 58 ++++++++++++++++ .github/workflows/validate.yml | 11 ++- README.md | 3 +- skills/spark/SKILL.md | 103 +++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 .github/scripts/validate_skills.py create mode 100644 skills/spark/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 54cce27..b807c4b 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,5 +1,4 @@ { - "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "stackone-marketplace", "owner": { "name": "StackOne", diff --git a/.github/scripts/validate_skills.py b/.github/scripts/validate_skills.py new file mode 100644 index 0000000..d80d87f --- /dev/null +++ b/.github/scripts/validate_skills.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"""Validate all SKILL.md files in the skills/ directory. + +Each SKILL.md must have YAML frontmatter (delimited by ---) containing +at least the 'name' and 'description' fields. +""" +import re +import sys +from pathlib import Path + +REQUIRED_FIELDS = ["name", "description"] + + +def validate_skill(path: Path) -> list[str]: + errors = [] + content = path.read_text(encoding="utf-8") + + if not content.startswith("---"): + return [f"{path}: missing YAML frontmatter (file must start with ---)"] + + parts = content.split("---", 2) + if len(parts) < 3: + return [f"{path}: malformed frontmatter (missing closing ---)"] + + frontmatter = parts[1] + for field in REQUIRED_FIELDS: + if not re.search(rf"^{field}\s*:", frontmatter, re.MULTILINE): + errors.append(f"{path}: missing required frontmatter field '{field}'") + + return errors + + +def main() -> None: + skills_dir = Path("skills") + if not skills_dir.exists(): + print("No skills/ directory found — skipping.") + return + + skill_files = sorted(skills_dir.rglob("SKILL.md")) + if not skill_files: + print("No SKILL.md files found — skipping.") + return + + all_errors: list[str] = [] + for path in skill_files: + all_errors.extend(validate_skill(path)) + + if all_errors: + print("SKILL.md validation failed:\n") + for error in all_errors: + print(f" ✗ {error}") + sys.exit(1) + + print(f"All {len(skill_files)} SKILL.md file(s) passed validation.") + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 078b17e..763232b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,7 +9,7 @@ on: - main jobs: - validate: + validate-manifest: name: Validate marketplace.json runs-on: ubuntu-latest steps: @@ -17,3 +17,12 @@ jobs: - name: Validate plugin manifests run: npx --yes @anthropic-ai/claude-code plugin validate . + + validate-skills: + name: Validate SKILL.md files + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Check SKILL.md frontmatter + run: python3 .github/scripts/validate_skills.py diff --git a/README.md b/README.md index 506392a..6a3566d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Agent skills for [StackOne](https://stackone.com) — integration infrastructure # Add the marketplace /plugin marketplace add stackonehq/agent-plugins-marketplace -# Install the StackOne plugin (all 6 skills) +# Install the StackOne plugin (all 7 skills) /plugin install stackone@stackone-marketplace ``` @@ -34,6 +34,7 @@ npx skills add stackonehq/agent-plugins-marketplace@stackone-agents | [`stackone-cli`](skills/stackone-cli/) | Custom connector development and deployment | "Build a custom connector", "deploy my connector" | | [`stackone-connectors`](skills/stackone-connectors/) | Discover connectors, actions, and integration capabilities | "Which providers does StackOne support?" | | [`stackone-unified-connectors`](skills/stackone-unified-connectors/) | Build unified connectors that transform provider data into standardized schemas | "start unified build for [provider]", "map fields to schema" | +| [`spark`](skills/spark/) | Find the single smartest, most innovative addition to your current PR/branch or project, then implement it | "/spark", "what's the most impactful thing you could add to this PR?", "what single feature would make this better?" | Each skill includes step-by-step workflows, concrete examples, and troubleshooting for common errors. diff --git a/skills/spark/SKILL.md b/skills/spark/SKILL.md new file mode 100644 index 0000000..88a8b6b --- /dev/null +++ b/skills/spark/SKILL.md @@ -0,0 +1,103 @@ +--- +name: spark +description: This skill should be used when the user invokes "/spark" or asks "what's the best thing you could add to this PR/project?", "what single feature would make this better?", "what's the most impactful next move?", or "what would you add to this branch/codebase?". Generates the single smartest, most innovative and high-value addition to the current PR/branch or project, then offers to implement it. +invoke: spark +license: MIT +metadata: + author: stackone + version: "1.0" +--- + +# Spark — Find the Single Best Next Move + +Identify the most innovative, high-value addition to the current context — a PR/branch in progress, or the entire project — then offer to build it. + +## Step 1: Detect Context + +Run these together to understand current state: + +```bash +git branch --show-current # Are we on a named branch? +git status --short # Any uncommitted changes? +git log --oneline -10 # Recent commit history +``` + +Then decide which mode applies: + +### Branch/PR Mode +Triggers when: on a non-default branch (`main`/`master`/`develop`/`trunk`) OR when there are staged/uncommitted changes that form a coherent unit of work. + +Gather PR context: +```bash +git diff main...HEAD --stat # What files changed? +git diff main...HEAD # Full diff (skim for intent) +git log main...HEAD --oneline # Commits in this branch +gh pr view 2>/dev/null # PR title, description, comments +``` + +### Project Mode +Triggers when: on the default branch with no active feature work. + +Gather project context: +```bash +ls -la # Root structure +cat README.md 2>/dev/null | head -60 +cat package.json 2>/dev/null # or Cargo.toml, pyproject.toml, etc. +git log --oneline -20 # Recent trajectory +``` + +Also read key architectural files (routes, main entry points, core modules) to understand what exists. + +## Step 2: Synthesize and Ideate + +With context gathered, think hard. The goal: find the **single highest-leverage addition** that is: + +- **Non-obvious** — not the next logical TODO item or a feature already implied by the PR +- **Accretive** — genuinely multiplies the value of what's already there +- **Feasible** — implementable in this codebase without a full rewrite +- **Specific** — a concrete feature/change, not a vague theme like "better error handling" + +### For Branch/PR Mode +Focus on: what would make this PR go from good to exceptional? What's the one thing that would make reviewers say "wow, I didn't think of that"? Consider: edge cases that become features, DX improvements, observability, composability, performance wins, security hardening that's elegant rather than bolt-on. + +### For Project Mode +Focus on: what single addition would unlock the most value for users/developers? Consider: killer features that are missing, architectural capabilities that enable a class of new use cases, developer experience that removes the biggest friction point, integrations that make the whole more valuable than the sum of parts. + +**Avoid**: generic suggestions (add tests, add docs, add logging). The idea should be surprising and specific. + +## Step 3: Present the Idea + +Present ONE idea with conviction. Format: + +``` +## Spark: [Catchy Name for the Idea] + +**What**: [One crisp sentence] + +**Why it's the right move**: [2-3 sentences on why this is the highest-leverage addition +right now, referencing specifics from the codebase/PR] + +**How it would work**: [Concrete sketch — key files touched, rough approach, any +interesting technical choices. Not a full spec, just enough to make it tangible] + +**Impact**: [What does this unlock? Who benefits? Why does it matter?] +``` + +Then use `AskUserQuestion` to ask: + +- **"Want to build it?"** with options: Yes, build it now / Refine the idea first / Show me alternatives + +## Step 4: Act on Response + +**"Yes, build it now"** → Call `EnterPlanMode` to design the full implementation. Use the existing codebase patterns, read relevant files, and produce a concrete step-by-step plan before writing any code. + +**"Refine the idea first"** → Ask clarifying questions: scope, constraints, preferences. Then re-present the refined version and loop back to Step 3. + +**"Show me alternatives"** → Generate 2-3 more options (weaker than the primary but still strong), let user pick, then proceed with their choice. + +## Principles + +- **One idea, not a list.** Presenting multiple ideas dilutes the thinking. Commit to the best one. +- **Specificity over generality.** "Add a `--watch` flag that re-runs the build on file change, streaming output to a WebSocket" beats "improve developer experience". +- **Reference what's actually there.** The idea should feel inevitable given the existing code, not imported from another project. +- **Be direct.** Don't hedge with "you might consider" or "one option could be". State the idea with confidence. From 218c8aee1b538e56abae5bd0fad48cf444c24e3c Mon Sep 17 00:00:00 2001 From: Guillaume Lebedel Date: Sun, 15 Mar 2026 19:58:33 +0000 Subject: [PATCH 2/2] fix: address PR review comments - spark: detect actual default branch via origin/HEAD instead of hard-coding main - validate_skills.py: resolve skills/ relative to repo root, not cwd Co-Authored-By: Claude Sonnet 4.6 --- .github/scripts/validate_skills.py | 3 ++- skills/spark/SKILL.md | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/scripts/validate_skills.py b/.github/scripts/validate_skills.py index d80d87f..09d1f89 100644 --- a/.github/scripts/validate_skills.py +++ b/.github/scripts/validate_skills.py @@ -31,7 +31,8 @@ def validate_skill(path: Path) -> list[str]: def main() -> None: - skills_dir = Path("skills") + repo_root = Path(__file__).resolve().parent.parent.parent + skills_dir = repo_root / "skills" if not skills_dir.exists(): print("No skills/ directory found — skipping.") return diff --git a/skills/spark/SKILL.md b/skills/spark/SKILL.md index 88a8b6b..af3e501 100644 --- a/skills/spark/SKILL.md +++ b/skills/spark/SKILL.md @@ -29,9 +29,10 @@ Triggers when: on a non-default branch (`main`/`master`/`develop`/`trunk`) OR wh Gather PR context: ```bash -git diff main...HEAD --stat # What files changed? -git diff main...HEAD # Full diff (skim for intent) -git log main...HEAD --oneline # Commits in this branch +BASE=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null | sed 's|origin/||' || echo main) +git diff $BASE...HEAD --stat # What files changed? +git diff $BASE...HEAD # Full diff (skim for intent) +git log $BASE...HEAD --oneline # Commits in this branch gh pr view 2>/dev/null # PR title, description, comments ```