Claude Cursor Skill

skill-author

Author and structure practical Robium skills without unnecessary context or ceremony.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download robium-ai-robium-skills_skill-author-498ea4e.zip · 6 KB
Part of robium-ai/robium — 44 skills

Install

skills CLI npx skills add https://github.com/robium-ai/robium/tree/main/skills/skill-author
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install robium-ai-robium@llmmart
Git git clone https://github.com/robium-ai/robium.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole robium-ai/robium collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Skill author

Treat every loaded line as a cost. A skill earns that cost by changing an ordinary coding agent's decision.

Start with the trigger

  • Give the skill one clear job and a short name that matches its directory.
  • Write a brief description that says what the skill helps accomplish and distinguishes it from its closest neighbors.
  • Do not turn the description into a keyword inventory. Test realistic user requests when the boundary is uncertain.
  • If an existing skill already owns the decision, deepen it instead of adding another trigger surface.

Write the entrypoint

  • Frontmatter contains only name and description.
  • Organize SKILL.md around one useful mental model, not a universal template.
  • Prefer short, natural bullets that a human can scan without decoding process language.
  • Assume the agent can already code, search a repository, and read ordinary documentation. Keep only constraints, choices, and failure patterns that materially improve its work.
  • Avoid fixed sequences unless order protects correctness, safety, money, or external state.
  • Mention another skill only where evidence crosses that skill's boundary.

Put depth behind links

  • Keep the common path in SKILL.md. Put conditional commands, failure diagnosis, tuning, platform compatibility, schemas, and substantial examples in focused supporting files.
  • Link each supporting file at the point where it becomes useful and say when to read it. Do not load every reference by default.
  • Reuse a focused existing file before creating another layer of navigation.
  • Preserve exact Robium-observed values with their measured conditions. They are evidence, not universal defaults.
  • Use current official documentation for volatile APIs, flags, packages, and configuration. Do not copy a manual into the skill.
  • Keep executable helpers only when deterministic reuse justifies maintaining code; keep examples only when they show something prose cannot.

Test usefulness

  • Read QUALITY.md for the review bar and mechanical checks.
  • Run uv run skills/skill-author/scripts/validate_skills.py once after a coherent batch of skill changes, not after every edit. It checks the lightweight contract, not writing quality.
  • For description, routing, or behavioral changes, review one common request, one likely failure, and one neighboring request that should route elsewhere. A typo or source-link refresh needs only the relevant mechanical check.
  • Start with manual scenario review. Run bounded live-agent evals only for unresolved behavioral uncertainty, meaningful regression evidence, or an explicit request; do not rerun every model or prompt after each prose edit.
  • Prefer observable behavior checks over tests that assert headings or exact prose. Keep evals.yaml only when a real routing or task regression is worth preserving.

Done

  • The entrypoint is small enough to load routinely.
  • Optional detail is discoverable without being injected into every task.
  • Every strong claim is either stable, sourced upstream, or tied to observed conditions.
  • There is no version field, changelog, README, or format-only section.
Files (robium)
  • scripts
    • validate_skills.py 8.1 KB
      # /// script
      # requires-python = ">=3.10"
      # dependencies = ["pyyaml"]
      # ///
      """Validate Robium's lightweight live-skill contract.
      
      The validator protects discovery and obvious packaging mistakes. It does not
      prescribe headings, prose, or a universal workflow; usefulness remains a human
      review question.
      """
      
      import re
      import sys
      from pathlib import Path
      from urllib.parse import unquote
      
      import yaml
      
      ENGINE_DIR = Path(__file__).resolve().parents[3] / "scripts" / "engine"
      sys.path.insert(0, str(ENGINE_DIR))
      
      from task_schema import TaskSchemaError, validate_tasks  # noqa: E402
      
      
      NAME_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
      FRONTMATTER_KEYS = {"name", "description"}
      MAX_DESCRIPTION_CHARS = 240
      MAX_BODY_LINES = 120
      MARKDOWN_LINK_RE = re.compile(r"\[[^\]]+\]\(([^)]+)\)")
      BACKTICK_PATH_RE = re.compile(
          r"`((?:references|scripts|examples)/[^`\s]+|[A-Z][A-Z0-9-]*\.md)`"
      )
      REMOTE_SCHEMES = ("http://", "https://", "mailto:")
      
      
      def _without_fenced_code(text: str) -> str:
          kept: list[str] = []
          fence: str | None = None
          for line in text.splitlines():
              marker = line.lstrip()[:3]
              if marker in {"```", "~~~"}:
                  fence = None if fence == marker else marker if fence is None else fence
                  continue
              if fence is None:
                  kept.append(line)
          return "\n".join(kept)
      
      
      def _local_target(raw: str) -> str | None:
          value = raw.strip()
          if value.startswith("<") and ">" in value:
              target = value[1:value.index(">")]
          else:
              target = value.split(maxsplit=1)[0]
          target = unquote(target)
          if not target or target.startswith("#") or target.startswith(REMOTE_SCHEMES):
              return None
          target = target.split("#", 1)[0]
          if not target:
              return None
          return target
      
      
      def _check_links(skill_dir: Path) -> list[str]:
          errors: list[str] = []
          repo_root = skill_dir.parents[1].resolve()
          for source in sorted(skill_dir.rglob("*.md")):
              text = _without_fenced_code(source.read_text(encoding="utf-8"))
              targets = list(MARKDOWN_LINK_RE.findall(text))
              if source.name == "SKILL.md":
                  targets.extend(BACKTICK_PATH_RE.findall(text))
              for raw in targets:
                  target = _local_target(raw)
                  if target is None:
                      continue
                  resolved = (source.parent / target).resolve()
                  try:
                      resolved.relative_to(repo_root)
                  except ValueError:
                      errors.append(
                          f"{skill_dir.name}: {source.relative_to(skill_dir)} link escapes repository: {target}"
                      )
                      continue
                  if not resolved.exists():
                      errors.append(
                          f"{skill_dir.name}: {source.relative_to(skill_dir)} missing link target: {target}"
                      )
          entrypoint = _without_fenced_code((skill_dir / "SKILL.md").read_text(encoding="utf-8"))
          linked = {
              (skill_dir / target).resolve()
              for raw in MARKDOWN_LINK_RE.findall(entrypoint) + BACKTICK_PATH_RE.findall(entrypoint)
              if (target := _local_target(raw)) is not None
          }
          for support in sorted(skill_dir.glob("*.md")):
              if support.name == "SKILL.md" or support.name.lower() == "readme.md":
                  continue
              if support.resolve() not in linked:
                  errors.append(
                      f"{skill_dir.name}: support file {support.name} is not linked from SKILL.md"
                  )
          return errors
      
      
      def _check_evals(skill_dir: Path) -> list[str]:
          path = skill_dir / "evals.yaml"
          if not path.exists():
              return []
          try:
              data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
              if not isinstance(data, dict):
                  raise ValueError("top level must be a mapping")
              triggers = data.get("triggers", {})
              if not isinstance(triggers, dict):
                  raise ValueError("'triggers' must be a mapping")
              for side in ("positive", "negative"):
                  cases = triggers.get(side) or []
                  if not isinstance(cases, list):
                      raise ValueError(f"triggers.{side} must be a list")
                  for case in cases:
                      if not isinstance(case, dict) or not case.get("phrase"):
                          raise ValueError(f"each triggers.{side} case needs a 'phrase'")
                      if side == "negative" and "expect" in case:
                          expected = case["expect"]
                          if not isinstance(expected, str) or not expected.strip():
                              raise ValueError("negative trigger 'expect' must be a skill name")
                          expected_dir = skill_dir.parent / expected
                          if expected == skill_dir.name or not (expected_dir / "SKILL.md").exists():
                              raise ValueError(
                                  f"negative trigger 'expect' names unknown or current skill: {expected}"
                              )
              validate_tasks(
                  data.get("tasks", []),
                  repo_root=skill_dir.parents[1],
                  skill_dir=skill_dir,
              )
          except TaskSchemaError as exc:
              return [f"{skill_dir.name}: evals.yaml invalid: {exc}"]
          except Exception as exc:
              return [f"{skill_dir.name}: evals.yaml invalid: {exc}"]
          return []
      
      
      def check_skill(skill_dir: Path) -> list[str]:
          errors: list[str] = []
          path = skill_dir / "SKILL.md"
          if not path.exists():
              return [f"{skill_dir.name}: missing SKILL.md"]
      
          text = path.read_text(encoding="utf-8")
          match = re.match(r"^---\r?\n(.*?)\r?\n---\r?\n(.*)$", text, re.DOTALL)
          if not match:
              return [f"{skill_dir.name}: missing or malformed frontmatter"]
          try:
              frontmatter = yaml.safe_load(match.group(1)) or {}
          except yaml.YAMLError as exc:
              return [f"{skill_dir.name}: frontmatter YAML error: {exc}"]
          if not isinstance(frontmatter, dict):
              return [f"{skill_dir.name}: frontmatter must be a mapping"]
      
          missing = FRONTMATTER_KEYS - set(frontmatter)
          extra = set(frontmatter) - FRONTMATTER_KEYS
          if missing:
              errors.append(f"{skill_dir.name}: frontmatter missing {', '.join(sorted(missing))}")
          if extra:
              errors.append(f"{skill_dir.name}: unsupported frontmatter fields: {', '.join(sorted(extra))}")
      
          name = frontmatter.get("name")
          if name != skill_dir.name:
              errors.append(f"{skill_dir.name}: frontmatter name {name!r} != directory name")
          if not isinstance(name, str) or not NAME_RE.fullmatch(name) or len(name) > 64:
              errors.append(f"{skill_dir.name}: name violates Agent Skills constraints")
      
          description = frontmatter.get("description")
          if not isinstance(description, str) or not description.strip():
              errors.append(f"{skill_dir.name}: description missing")
          elif len(description.strip()) > MAX_DESCRIPTION_CHARS:
              errors.append(
                  f"{skill_dir.name}: description {len(description.strip())} chars "
                  f"(>{MAX_DESCRIPTION_CHARS})"
              )
      
          body = match.group(2)
          if not body.strip():
              errors.append(f"{skill_dir.name}: body is empty")
          body_lines = len(body.splitlines())
          if body_lines > MAX_BODY_LINES:
              errors.append(
                  f"{skill_dir.name}: body {body_lines} lines (>{MAX_BODY_LINES}); move conditional depth to support files"
              )
          if re.search(r"^##\s+changelog\s*$", body, re.IGNORECASE | re.MULTILINE):
              errors.append(f"{skill_dir.name}: live skills do not carry changelogs")
          if any(path.name.lower() == "readme.md" for path in skill_dir.iterdir()):
              errors.append(f"{skill_dir.name}: use SKILL.md or a focused support file, not README.md")
      
          errors.extend(_check_links(skill_dir))
          errors.extend(_check_evals(skill_dir))
          return errors
      
      
      def main() -> None:
          skills_root = Path(__file__).resolve().parents[2]
          skill_dirs = sorted(
              path for path in skills_root.iterdir()
              if path.is_dir() and path.name != "_TEMPLATE"
          )
          errors = [error for skill_dir in skill_dirs for error in check_skill(skill_dir)]
          for error in errors:
              print(f"FAIL: {error}")
          print(f"Checked {len(skill_dirs)} skills: {'FAIL' if errors else 'PASS'}")
          raise SystemExit(1 if errors else 0)
      
      
      if __name__ == "__main__":
          main()
      
  • evals.yaml 310 B
    triggers:
      positive:
        - phrase: write a new robium skill for depth cameras
          source: learning-engine Phase 2b restructure
      negative:
        - phrase: absorb these learnings into the skills
          expect: learning-loop
        - phrase: mine the nav2 tutorials repo for patterns
          expect: mining
    tasks: []
    
  • QUALITY.md 2.7 KB
    # A practical quality bar
    
    Use this as a review guide, not as a writing template. Skills can have different
    shapes when their work calls for it.
    
    ## Discovery
    
    - `name` matches the directory and uses lowercase kebab-case.
    - `description` is short, specific, and discriminates the nearest adjacent
      skill.
    - A likely user request can select the skill without an exhaustive keyword
      list.
    
    ## Entrypoint
    
    - One organizing idea makes the guidance easy to remember and extend.
    - The common path and important boundaries are visible without opening another
      file.
    - Every instruction changes a capable agent's decision; generic coding advice
      and repeated repository policy are removed.
    - Bullets sound like useful directions, not a compliance questionnaire.
    - The entrypoint stays comfortably below the mechanical limit. Passing the
      limit is not evidence that the file is lean.
    
    ## Conditional depth
    
    - Commands, failures, tuning, platform profiles, schemas, and long examples
      live in focused files when only some tasks need them.
    - Each support file has a clear reason to load and is linked from a relevant
      decision point.
    - Support files do not duplicate the entrypoint or reproduce an upstream
      manual.
    - Existing examples and scripts remain only when they are reusable and their
      provenance or validation status is clear.
    
    ## Evidence and scope
    
    - Stable concepts may be stated directly. Version-sensitive syntax and APIs
      point to current official documentation.
    - Observed values name the robot, platform, version, workload, or measurement
      that produced them. They are never silently promoted into defaults.
    - One proven application may justify a narrowly scoped platform or
      compatibility note. Require recurrence before turning it into common-path
      advice or a universal default.
    - Adjacent skills are reached only after the relevant subsystem boundary has
      been identified.
    
    ## Testing
    
    - The validator checks frontmatter, size, links, and optional eval structure.
      It deliberately does not prescribe headings or prose.
    - Routing evals cover meaningful ambiguity, not every synonym in the
      description.
    - Task checks verify user-visible behavior or a fragile reusable artifact, not
      Markdown wording.
    - Manual review asks whether the skill helps a capable agent act better while
      loading less context.
    
    ## Repository contract
    
    - Live skill frontmatter contains only `name` and `description`.
    - Live skills do not carry versions or changelogs. Git history is the normal
      record of change.
    - A skill may contain `SKILL.md` alone or the smallest set of support files it
      actually needs. No README or empty placeholder directories are required.
    - Robium provides practical knowledge and real reusable examples, never an
      invented robotics DSL.
    
  • SKILL.md 3.3 KB
    ---
    name: skill-author
    description: Author and structure practical Robium skills without unnecessary context or ceremony.
    ---
    
    # Skill author
    
    Treat every loaded line as a cost. A skill earns that cost by changing an
    ordinary coding agent's decision.
    
    ## Start with the trigger
    
    - Give the skill one clear job and a short name that matches its directory.
    - Write a brief description that says what the skill helps accomplish and
      distinguishes it from its closest neighbors.
    - Do not turn the description into a keyword inventory. Test realistic user
      requests when the boundary is uncertain.
    - If an existing skill already owns the decision, deepen it instead of adding
      another trigger surface.
    
    ## Write the entrypoint
    
    - Frontmatter contains only `name` and `description`.
    - Organize `SKILL.md` around one useful mental model, not a universal template.
    - Prefer short, natural bullets that a human can scan without decoding process
      language.
    - Assume the agent can already code, search a repository, and read ordinary
      documentation. Keep only constraints, choices, and failure patterns that
      materially improve its work.
    - Avoid fixed sequences unless order protects correctness, safety, money, or
      external state.
    - Mention another skill only where evidence crosses that skill's boundary.
    
    ## Put depth behind links
    
    - Keep the common path in `SKILL.md`. Put conditional commands, failure
      diagnosis, tuning, platform compatibility, schemas, and substantial examples
      in focused supporting files.
    - Link each supporting file at the point where it becomes useful and say when
      to read it. Do not load every reference by default.
    - Reuse a focused existing file before creating another layer of navigation.
    - Preserve exact Robium-observed values with their measured conditions. They
      are evidence, not universal defaults.
    - Use current official documentation for volatile APIs, flags, packages, and
      configuration. Do not copy a manual into the skill.
    - Keep executable helpers only when deterministic reuse justifies maintaining
      code; keep examples only when they show something prose cannot.
    
    ## Test usefulness
    
    - Read [QUALITY.md](QUALITY.md) for the review bar and mechanical checks.
    - Run `uv run skills/skill-author/scripts/validate_skills.py` once after a
      coherent batch of skill changes, not after every edit. It checks the
      lightweight contract, not writing quality.
    - For description, routing, or behavioral changes, review one common request,
      one likely failure, and one neighboring request that should route elsewhere.
      A typo or source-link refresh needs only the relevant mechanical check.
    - Start with manual scenario review. Run bounded live-agent evals only for
      unresolved behavioral uncertainty, meaningful regression evidence, or an
      explicit request; do not rerun every model or prompt after each prose edit.
    - Prefer observable behavior checks over tests that assert headings or exact
      prose. Keep `evals.yaml` only when a real routing or task regression is worth
      preserving.
    
    ## Done
    
    - The entrypoint is small enough to load routinely.
    - Optional detail is discoverable without being injected into every task.
    - Every strong claim is either stable, sourced upstream, or tied to observed
      conditions.
    - There is no version field, changelog, README, or format-only section.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related