repo-intake-and-plan
Rigor Intake helper for README-first deep learning repo reproduction. Use when the task is specifically to scan a repository, read the README and common project files, extract documented commands, classify inference, evaluation, and training candidates, and return the smallest tr
Install
npx skills add https://github.com/lllllllama/RigorPilot-Skills/tree/main/skills/repo-intake-and-plan
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lllllllama-rigorpilot-skills@llmmart
git clone https://github.com/lllllllama/RigorPilot-Skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lllllllama/rigorpilot-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
repo-intake-and-plan
Use this as the Rigor Intake helper. The installed slug remains
repo-intake-and-plan for compatibility.
When to apply
- At the beginning of README-first reproduction work.
- When the main skill needs a fast map of repo structure and documented commands.
- When inference, evaluation, and training candidates must be classified conservatively.
- When the user explicitly wants to inspect the repo first and not run anything yet.
When not to apply
- When execution has already started and the task is now about running commands or writing outputs.
- When the target is not a repository-backed reproduction task.
- When the user only wants paper interpretation without repo inspection.
- When the user already has a selected documented command and only needs setup or execution.
Clear boundaries
- This skill scans and plans.
- This skill is helper-tier and should usually be orchestrator-invoked.
- It does not install environments.
- It does not prepare large assets.
- It does not execute substantive reproduction commands.
- It does not decide high-risk patching.
Input expectations
- Target repository path.
- Access to README and common project files if present.
- Optional user hints about desired priority, such as inference-first.
Output expectations
- concise repo structure summary
- documented command inventory
- inferred candidate categories: inference, evaluation, training, other
- minimum trustworthy reproduction recommendation
- notable ambiguity or risk list
Notes
Use references/repo-scan-rules.md and helper scripts under scripts/.
Files (rigorpilot-skills)
-
agents
-
openai.yaml 368 B
display_name: Rigor Intake short_description: Rigor Intake helper for scanning a repo and recommending the smallest trustworthy reproduction target. default_prompt: Scan this repository, read the README and common project files, extract documented commands, classify inference evaluation and training paths, and recommend the smallest trustworthy reproduction target.
-
-
references
-
repo-scan-rules.md 1.1 KB
# Repo Scan Rules ## Primary files Always check these first when present: - `README.md` - `README` - `requirements.txt` - `environment.yml` - `environment.yaml` - `pyproject.toml` - `setup.py` - `setup.cfg` - `Dockerfile` ## High-signal directories Inspect for command or configuration clues: - `configs/` - `config/` - `scripts/` - `tools/` - `examples/` - `notebooks/` - `checkpoints/` ## Extraction priorities 1. explicit README commands 2. setup instructions 3. documented inference or demo entrypoints 4. documented evaluation entrypoints 5. documented training entrypoints 6. config references and asset path hints ## Classification guidance - `inference`: demo, predict, generate, sample, infer, test-time forward use - `evaluation`: eval, validate, benchmark, score, reproduce metrics - `training`: train, finetune, pretrain, launch long-running experiments - `other`: install, download, preprocess, export, convert, utility ## Conservative behavior - prefer explicit README evidence over filename guesses - mark guessed classifications as inferred - record ambiguity instead of overcommitting
-
-
scripts
-
extract_commands.py 12.9 KB
#!/usr/bin/env python3 """Extract shell-like commands from README content and classify them.""" from __future__ import annotations import argparse import json import re from pathlib import Path from typing import Dict, List, Optional CODE_BLOCK_RE = re.compile(r"```(?P<lang>[^\n`]*)\n(?P<body>.*?)```", re.DOTALL | re.IGNORECASE) # Bare ">" is deliberately excluded: it marks markdown blockquotes (prose), # not shell prompts, and matching it turns README notes into commands. INLINE_CMD_RE = re.compile(r"^\s*(?:\$|PS> )\s*(.+)$") # Angle-bracket placeholders (<PATH/TO/DATASET>, <NUM_NODES>) mean the command # cannot run verbatim: it needs researcher-supplied values first. PLACEHOLDER_RE = re.compile(r"<[A-Za-z][A-Za-z0-9 _./:-]*>") HEADING_RE = re.compile(r"^(?P<marks>#{1,6})\s+(?P<title>.+?)\s*$") COMMAND_PREFIXES = ( "python ", "python3 ", "pip ", "pip3 ", "conda ", "bash ", "sh ", "chmod ", "export ", "set ", "CUDA_VISIBLE_DEVICES=", "./", "accelerate ", "torchrun ", "deepspeed ", "make ", "docker ", ) def collect_headings(readme_text: str) -> List[Dict[str, object]]: headings: List[Dict[str, object]] = [] offset = 0 inside_fence = False for line in readme_text.splitlines(keepends=True): if line.lstrip().startswith("```"): inside_fence = not inside_fence offset += len(line) continue if inside_fence: # "# comment" lines inside fenced code blocks are not headings. offset += len(line) continue matched = HEADING_RE.match(line.strip()) if matched: headings.append( { "offset": offset, "level": len(matched.group("marks")), "title": matched.group("title").strip(), } ) offset += len(line) return headings def nearest_heading(headings: List[Dict[str, object]], offset: int) -> Optional[str]: current: Optional[str] = None for heading in headings: if int(heading["offset"]) > offset: break current = str(heading["title"]) return current def infer_section_category(section: Optional[str]) -> Optional[str]: if not section: return None lowered = section.lower() # Training is the highest-risk interpretation. Check it before generic # headings such as "example" or "usage" so they cannot bypass training # authorization when both appear in the same title. if any(word in lowered for word in ["training", "train", "finetune", "fine-tune", "pretrain"]): return "training" if any(word in lowered for word in ["evaluation", "evaluate", "benchmark", "metrics", "validation"]) or re.search( r"\b(?:test|tests|testing)\b", lowered ): return "evaluation" if any(word in lowered for word in ["inference", "usage", "demo", "example", "text-to-image", "image-to-image", "transcribe"]): return "inference" return None def infer_section_kind(section: Optional[str]) -> Optional[str]: if not section: return None lowered = section.lower() if any(word in lowered for word in ["install", "installation", "setup", "environment", "requirements"]): return "setup" if any(word in lowered for word in ["download", "checkpoint", "weights", "dataset", "data preparation"]): return "asset" if any(word in lowered for word in ["usage", "demo", "example", "inference", "evaluation", "training", "text-to-image", "image-to-image", "quick start", "quickstart", "getting started"]): return "run" return None # The entrypoint script name is the strongest category signal: flags like # --eval_iters on a train.py command must not flip training into evaluation # (that would bypass the training-authorization gate downstream). SCRIPT_CATEGORY_HINTS = [ (re.compile(r"\b(?:pre)?train\w*\.py\b"), "training"), (re.compile(r"\b(?:eval\w*|benchmark\w*|validate|test)\.py\b"), "evaluation"), (re.compile(r"\b(?:sample|generate|infer\w*|predict|demo)\w*\.py\b"), "inference"), ] SETUP_PREFIXES = ( "pip install", "pip3 install", "conda install", "conda env create", "conda create", "conda activate", "python -m pip install", "git clone", "cd ", ) ASSET_PREFIXES = ("wget ", "curl ", "mkdir ", "tar ", "unzip ", "7z ", "aria2c ") def classify(command: str, section: Optional[str] = None) -> str: lowered = command.lower().strip() # Unambiguous setup/asset syntax outranks generic headings such as # "Basic Example", which otherwise makes installation look like inference. if lowered.startswith(SETUP_PREFIXES + ASSET_PREFIXES): return "other" section_category = infer_section_category(section) if section_category: return section_category for pattern, category in SCRIPT_CATEGORY_HINTS: if pattern.search(lowered): return category def any_word(words: List[str]) -> bool: return any(re.search(rf"\b{re.escape(word)}\b", lowered) for word in words) if any_word(["infer", "inference", "predict", "generate", "sample", "demo", "transcribe"]) or any( token in lowered for token in ["txt2img", "img2img", "whisper ", "amg.py"] ): return "inference" if any_word(["eval", "evaluate", "evaluation", "validation", "validate", "benchmark", "score", "pytest", "test"]): return "evaluation" if any_word(["train", "training", "finetune", "pretrain"]) or any( token in lowered for token in ["fine-tune", "pre-train"] ): return "training" return "other" def command_kind(command: str, section: Optional[str] = None) -> str: lowered = command.lower().strip() if lowered.startswith(SETUP_PREFIXES): return "setup" if lowered.startswith(ASSET_PREFIXES): return "asset" section_kind = infer_section_kind(section) if section_kind: return section_kind if "--help" in lowered or " -h" in lowered: return "smoke" return "run" def looks_like_command(line: str) -> bool: candidate = re.sub(r"^(?:\$|PS> )\s*", "", line.strip()) if not candidate or candidate.startswith("#"): return False if candidate.startswith(("python", "pip", "conda", "bash", "sh", "make", "docker")): return True if candidate.startswith(COMMAND_PREFIXES): return True if re.search(r"\s--[A-Za-z0-9_-]+", candidate): return True if re.search(r"\b(?:python|pip|conda|torchrun|deepspeed|accelerate|bash|sh)\b", candidate): return True if re.search(r"[\\/].+\.(?:py|sh|bat)", candidate): return True if candidate.startswith(("cd ", "ls ", "mkdir ", "wget ", "curl ", "git ")): return True return False def join_continuations(block: str) -> List[str]: """Join backslash-continued shell lines into single logical commands.""" joined: List[str] = [] buffer = "" for raw_line in block.splitlines(): line = raw_line.strip() buffer = f"{buffer} {line}".strip() if buffer else line if buffer.endswith("\\"): buffer = buffer[:-1].rstrip() continue joined.append(buffer) buffer = "" if buffer: joined.append(buffer) return joined def clean_lines(block: str) -> List[str]: commands: List[str] = [] for line in join_continuations(block): if not line or line.startswith("#"): continue if not looks_like_command(line): continue line = re.sub(r"^(?:\$|PS> )\s*", "", line) commands.append(line) return commands PYTHON_ENTRYPOINT_RE = re.compile( r"(?:^|\s)(?P<path>(?:(?:\.?\.?)[\\/])?(?:[A-Za-z0-9_.-]+[\\/])*[A-Za-z0-9_.-]+\.py)(?=\s|$)" ) TRAINING_STRUCTURE_SIGNALS = [ ("optimizer-step", re.compile(r"\boptimizer\s*\.\s*step\s*\(", re.IGNORECASE), 3), ("backward-pass", re.compile(r"\.\s*backward\s*\(", re.IGNORECASE), 3), ("model-train-mode", re.compile(r"\.\s*train\s*\(", re.IGNORECASE), 2), ("train-function", re.compile(r"\bdef\s+train\w*\s*\(", re.IGNORECASE), 1), ("epoch-loop", re.compile(r"\bfor\s+\w*epoch\w*\s+in\b", re.IGNORECASE), 1), ] def referenced_python_script(command: str, readme_dir: Path) -> Optional[Path]: matched = PYTHON_ENTRYPOINT_RE.search(command) if not matched: return None root = readme_dir.resolve() candidate = (root / matched.group("path")).resolve() try: candidate.relative_to(root) except ValueError: return None if not candidate.is_file() or candidate.stat().st_size > 524_288: return None return candidate def training_structure_evidence(script: Path) -> List[str]: try: content = script.read_text(encoding="utf-8", errors="replace") except OSError: return [] evidence: List[str] = [] score = 0 for label, pattern, weight in TRAINING_STRUCTURE_SIGNALS: if pattern.search(content): evidence.append(label) score += weight return evidence if score >= 4 else [] def apply_entrypoint_structure(commands: List[Dict[str, str]], readme_dir: Optional[Path]) -> None: if readme_dir is None: return for item in commands: if item.get("kind") in {"setup", "asset"} or item.get("category") == "training": continue script = referenced_python_script(item["command"], readme_dir) if script is None: continue evidence = training_structure_evidence(script) if not evidence: continue item["classification_previous_category"] = item["category"] item["category"] = "training" item["classification_source"] = "entrypoint-structure" item["classification_evidence"] = evidence def extract_commands(readme_text: str, readme_dir: Optional[Path] = None) -> Dict[str, object]: commands: List[Dict[str, str]] = [] warnings: List[str] = [] seen = set() headings = collect_headings(readme_text) for match in CODE_BLOCK_RE.finditer(readme_text): lang = (match.group("lang") or "").strip().lower() if lang and lang not in {"bash", "shell", "sh", "zsh", "powershell", "cmd"}: continue section = nearest_heading(headings, match.start()) lines = clean_lines(match.group("body")) if not lines: continue for line in lines: if line not in seen: commands.append( { "command": line, "category": classify(line, section), "kind": command_kind(line, section), "section": section, "source": "code_block", "needs_substitution": bool(PLACEHOLDER_RE.search(line)), } ) seen.add(line) running_offset = 0 for line in readme_text.splitlines(keepends=True): matched = INLINE_CMD_RE.match(line) if not matched: running_offset += len(line) continue command = matched.group(1).strip() if not looks_like_command(command): running_offset += len(line) continue section = nearest_heading(headings, running_offset) if command and command not in seen: commands.append( { "command": command, "category": classify(command, section), "kind": command_kind(command, section), "section": section, "source": "inline", "needs_substitution": bool(PLACEHOLDER_RE.search(command)), } ) seen.add(command) running_offset += len(line) apply_entrypoint_structure(commands, readme_dir) if not commands: warnings.append("No shell-like commands were extracted from the README.") counts: Dict[str, int] = {} for item in commands: category = item["category"] counts[category] = counts.get(category, 0) + 1 return { "commands": commands, "counts": counts, "warnings": warnings, } def main() -> int: parser = argparse.ArgumentParser(description="Extract shell-like commands from a README.") parser.add_argument("--readme", required=True, help="Path to the README file.") parser.add_argument("--json", action="store_true", help="Emit JSON output.") args = parser.parse_args() readme_path = Path(args.readme) text = readme_path.read_text(encoding="utf-8", errors="replace") data = extract_commands(text, readme_path.parent) if args.json: print(json.dumps(data, indent=2, ensure_ascii=False)) else: for item in data["commands"]: print(f"[{item['category']}] {item['command']}") if data["warnings"]: print("Warnings:") for warning in data["warnings"]: print(f"- {warning}") return 0 if __name__ == "__main__": raise SystemExit(main()) -
scan_repo.py 2.9 KB
#!/usr/bin/env python3 """Scan a repository for README-first reproduction signals.""" from __future__ import annotations import argparse import json from datetime import datetime, timezone from pathlib import Path from typing import Dict, List, Optional KEY_FILES = [ "README.md", "README", "requirements.txt", "environment.yml", "environment.yaml", "pyproject.toml", "setup.py", "setup.cfg", "Dockerfile", ] SIGNAL_DIRS = [ "configs", "config", "scripts", "tools", "examples", "notebooks", "checkpoints", ] def first_existing(root: Path, names: List[str]) -> Optional[Path]: for name in names: candidate = root / name if candidate.exists(): return candidate return None def scan_repo(root: Path) -> Dict[str, object]: if not root.exists(): raise FileNotFoundError(f"Repository path does not exist: {root}") top_level = sorted(item.name for item in root.iterdir()) detected_files = [name for name in KEY_FILES if (root / name).exists()] detected_dirs = [name for name in SIGNAL_DIRS if (root / name).exists()] readme = first_existing(root, ["README.md", "README"]) warnings: List[str] = [] if readme is None: warnings.append("No README file was found at the repository root.") if not detected_files: warnings.append("No common environment or packaging files were detected.") return { "generated_at": datetime.now(timezone.utc).isoformat(), "repo_path": str(root.resolve()), "readme_path": str(readme.resolve()) if readme else None, "detected_files": detected_files, "detected_dirs": detected_dirs, "structure": { "top_level": top_level, "top_level_file_count": sum(1 for item in root.iterdir() if item.is_file()), "top_level_dir_count": sum(1 for item in root.iterdir() if item.is_dir()), }, "warnings": warnings, } def main() -> int: parser = argparse.ArgumentParser(description="Scan a repository for key reproduction signals.") parser.add_argument("--repo", required=True, help="Path to the target repository.") parser.add_argument("--json", action="store_true", help="Emit JSON instead of a human summary.") args = parser.parse_args() data = scan_repo(Path(args.repo)) if args.json: print(json.dumps(data, indent=2, ensure_ascii=False)) else: print(f"Repository: {data['repo_path']}") print(f"README: {data['readme_path'] or 'not found'}") print("Detected files:", ", ".join(data["detected_files"]) or "none") print("Detected dirs:", ", ".join(data["detected_dirs"]) or "none") if data["warnings"]: print("Warnings:") for item in data["warnings"]: print(f"- {item}") return 0 if __name__ == "__main__": raise SystemExit(main())
-
-
SKILL.md 2.1 KB
--- name: repo-intake-and-plan description: Rigor Intake helper for README-first deep learning repo reproduction. Use when the task is specifically to scan a repository, read the README and common project files, extract documented commands, classify inference, evaluation, and training candidates, and return the smallest trustworthy reproduction plan to the main orchestrator. Do not use for environment setup, asset download, command execution, final reporting, paper lookup, or end-to-end orchestration. --- # repo-intake-and-plan Use this as the Rigor Intake helper. The installed slug remains `repo-intake-and-plan` for compatibility. ## When to apply - At the beginning of README-first reproduction work. - When the main skill needs a fast map of repo structure and documented commands. - When inference, evaluation, and training candidates must be classified conservatively. - When the user explicitly wants to inspect the repo first and not run anything yet. ## When not to apply - When execution has already started and the task is now about running commands or writing outputs. - When the target is not a repository-backed reproduction task. - When the user only wants paper interpretation without repo inspection. - When the user already has a selected documented command and only needs setup or execution. ## Clear boundaries - This skill scans and plans. - This skill is helper-tier and should usually be orchestrator-invoked. - It does not install environments. - It does not prepare large assets. - It does not execute substantive reproduction commands. - It does not decide high-risk patching. ## Input expectations - Target repository path. - Access to README and common project files if present. - Optional user hints about desired priority, such as inference-first. ## Output expectations - concise repo structure summary - documented command inventory - inferred candidate categories: inference, evaluation, training, other - minimum trustworthy reproduction recommendation - notable ambiguity or risk list ## Notes Use `references/repo-scan-rules.md` and helper scripts under `scripts/`.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.