Add Python Implementation¶
Intermediate
~20 min
Your SKILL.md defines what the skill does. Now write the Python that executes it.
1. Script Structure¶
Every ClawBio skill script follows the same pattern:
#!/usr/bin/env python3
"""my-awesome-skill: one-line description."""
import argparse
import json
from pathlib import Path
from datetime import datetime
import pandas as pd
def parse_input(input_path: Path) -> pd.DataFrame:
"""Read and validate the input file."""
df = pd.read_csv(input_path, sep="\t", comment="#")
required_cols = {"rsid", "chromosome", "position", "genotype"}
if not required_cols.issubset(df.columns):
missing = required_cols - set(df.columns)
raise ValueError(f"Missing columns: {missing}")
return df
def analyse(df: pd.DataFrame) -> dict:
"""Core analysis logic. This is where your domain expertise goes."""
results = {
"total_variants": len(df),
"chromosomes": sorted(df["chromosome"].unique().tolist()),
"timestamp": datetime.now().isoformat(),
}
# Add your analysis here
return results
def generate_report(results: dict, output_dir: Path) -> Path:
"""Write the markdown report."""
output_dir.mkdir(parents=True, exist_ok=True)
report_path = output_dir / "report.md"
lines = [
"# My Awesome Skill Report",
"",
f"**Generated**: {results['timestamp']}",
"",
"## Summary",
"",
f"- Total variants analysed: {results['total_variants']}",
f"- Chromosomes covered: {', '.join(str(c) for c in results['chromosomes'])}",
"",
"---",
"",
'*ClawBio is a research and educational tool. It is not a medical device '
'and does not provide clinical diagnoses. Consult a healthcare professional '
'before making any medical decisions.*',
]
report_path.write_text("\n".join(lines))
return report_path
def main():
parser = argparse.ArgumentParser(description="My Awesome Skill")
parser.add_argument("--input", type=Path, required=False, help="Input file")
parser.add_argument("--output", type=Path, default=Path("/tmp/my_skill_output"), help="Output directory")
parser.add_argument("--demo", action="store_true", help="Run with built-in demo data")
args = parser.parse_args()
if args.demo:
# Use the demo data bundled with the skill
input_path = Path(__file__).parent / "demo_input.txt"
elif args.input:
input_path = args.input
else:
parser.error("Provide --input <file> or use --demo")
print(f"Reading: {input_path}")
df = parse_input(input_path)
print(f"Analysing {len(df)} variants...")
results = analyse(df)
report = generate_report(results, args.output)
print(f"Report written to: {report}")
if __name__ == "__main__":
main()
2. Key Conventions¶
Follow these patterns to keep your skill consistent with the rest of ClawBio:
Paths¶
Use pathlib.Path everywhere. Derive paths from __file__ so the skill works from any working directory:
Demo mode¶
Always support --demo. Hackathon judges and users will run this first.
Output structure¶
Write results to the output directory:
output/
report.md # Main report (required)
figures/ # Any plots (optional)
tables/ # CSV/TSV data tables (optional)
commands.sh # Commands to reproduce (optional)
checksums.sha256 # Integrity verification (optional)
The disclaimer¶
Every report must include the ClawBio safety disclaimer. Copy it from the template above.
No hardcoded paths¶
Never hardcode /Users/yourname/... or absolute paths. Use Path(__file__).parent and CLI arguments.
3. Test It¶
# Run with demo data
python3 skills/my-awesome-skill/my_skill.py --demo --output /tmp/test_output
# Check output
cat /tmp/test_output/report.md
# Run with your own data
python3 skills/my-awesome-skill/my_skill.py \
--input path/to/your/data.txt \
--output /tmp/test_output_2
4. Add a Figure (Optional, Bonus Points)¶
Judges love visual output. Add a matplotlib figure:
import matplotlib
matplotlib.use("Agg") # Non-interactive backend
import matplotlib.pyplot as plt
def plot_summary(results: dict, output_dir: Path):
"""Generate a summary figure."""
fig, ax = plt.subplots(figsize=(8, 5))
# Your plot logic here
ax.set_title("My Awesome Skill: Summary")
fig_path = output_dir / "figures"
fig_path.mkdir(exist_ok=True)
fig.savefig(fig_path / "summary.png", dpi=150, bbox_inches="tight")
plt.close(fig)
print(f"Figure saved: {fig_path / 'summary.png'}")
Next: Test and Submit.