Skill Tracer
Skills › Scientific Agent Skills › venue-templates › query_template.py

query_template.py

202 lines · skills/venue-templates/scripts/query_template.py at 5f2bc03

1#!/usr/bin/env python3
2"""List and query the templates actually bundled with venue-templates.
3
4Examples:
5 python scripts/query_template.py --list-all
6 python scripts/query_template.py --venue NeurIPS --requirements
7 python scripts/query_template.py --type grants
8 python scripts/query_template.py --keyword author-year
9"""
11from __future__ import annotations
13import argparse
14import json
15from pathlib import Path
18CHECKED_DATE = "2026-10-01"
20TEMPLATES = {
21 "journals": {
22 "nature": {
23 "file": "nature_article.tex",
24 "full_name": "Nature-oriented article scaffold",
25 "status": "Generic writing scaffold; not an official Nature template.",
26 "source": "https://www.nature.com/nature/for-authors/initial-submission",
27 "requirements": "Initial submissions are format-flexible within reason; check the exact article type.",
28 },
29 "plos-one": {
30 "file": "plos_one.tex",
31 "full_name": "PLOS ONE-oriented article scaffold",
32 "status": "Drafting scaffold; compare with the current official PLOS LaTeX package.",
33 "source": "https://journals.plos.org/plosone/s/submission-guidelines",
34 "requirements": "Follow the current PLOS ONE submission and file-upload instructions.",
35 },
36 "neurips-2026": {
37 "file": "neurips_article.tex",
38 "full_name": "NeurIPS 2026 paper wrapper",
39 "status": "Requires the official neurips_2026.sty and checklist files.",
40 "source": "https://neurips.cc/Conferences/2026/MainTrackHandbook",
41 "requirements": (
42 "Main track initial submission: 9 content pages; references, checklist, "
43 "and optional technical appendices do not count. Initial submission is anonymous."
44 ),
45 },
46 "elsevier-numeric": {
47 "file": "elsarticle-template-num.tex",
48 "full_name": "Elsevier elsarticle numeric example",
49 "status": "Bundled example; the journal's Guide for Authors controls.",
50 "source": "https://www.elsevier.com/researcher/author/policies-and-guidelines/latex-instructions",
51 "requirements": "Numeric citations using the bundled elsarticle-num.bst.",
52 },
53 "elsevier-numeric-names": {
54 "file": "elsarticle-template-num-names.tex",
55 "full_name": "Elsevier elsarticle numeric-with-names example",
56 "status": "Bundled example; the journal's Guide for Authors controls.",
57 "source": "https://www.elsevier.com/researcher/author/policies-and-guidelines/latex-instructions",
58 "requirements": "Numeric citations with author names supported by elsarticle-num-names.bst; sorting/compression is a natbib option.",
59 },
60 "elsevier-author-year": {
61 "file": "elsarticle-template-harv.tex",
62 "full_name": "Elsevier elsarticle author-year example",
63 "status": "Bundled example; the journal's Guide for Authors controls.",
64 "source": "https://www.elsevier.com/researcher/author/policies-and-guidelines/latex-instructions",
65 "requirements": "Author-year citations using the bundled elsarticle-harv.bst.",
66 },
67 },
68 "posters": {
69 "beamerposter": {
70 "file": "beamerposter_academic.tex",
71 "full_name": "Venue-agnostic beamerposter scaffold",
72 "status": "Set dimensions and orientation from the event's current presenter instructions.",
73 "source": None,
74 "requirements": "A0 portrait by default; customize size before use.",
75 }
76 },
77 "grants": {
78 "nsf": {
79 "file": "nsf_proposal_template.tex",
80 "full_name": "NSF narrative planning scaffold",
81 "status": "Not an NSF-issued upload package; split components in the submission portal.",
82 "source": "https://www.nsf.gov/policies/pappg",
83 "requirements": (
84 "Check the current PAPPG and solicitation. Use SciENcv for required "
85 "senior/key-person forms."
86 ),
87 },
88 "nih-specific-aims": {
89 "file": "nih_specific_aims.tex",
90 "full_name": "NIH Specific Aims writing scaffold",
91 "status": "Drafting scaffold; the NOFO and current application guide control.",
92 "source": (
93 "https://grants.nih.gov/grants-process/write-application/"
94 "how-to-apply-application-guide/page-limits"
95 ),
96 "requirements": "Specific Aims is generally limited to one page unless the NOFO says otherwise.",
97 },
98 },
102def skill_path() -> Path:
103 return Path(__file__).resolve().parent.parent
106def template_path(category: str, filename: str) -> Path:
107 return skill_path() / "assets" / category / filename
110def search_templates(
111 venue: str | None = None,
112 template_type: str | None = None,
113 keyword: str | None = None,
114) -> list[dict]:
115 results = []
116 for category_name, category in TEMPLATES.items():
117 if template_type and template_type != "all" and category_name != template_type:
118 continue
120 for template_id, template in category.items():
121 searchable = json.dumps(
122 {"id": template_id, "category": category_name, **template}
123 ).lower()
124 if venue and venue.lower() not in searchable:
125 continue
126 if keyword and keyword.lower() not in searchable:
127 continue
129 results.append(
130 {
131 "id": template_id,
132 "category": category_name,
133 **template,
134 }
135 )
136 return results
139def print_template(template: dict, detailed: bool = True) -> None:
140 path = template_path(template["category"], template["file"])
141 print(f"\n{template['full_name']}")
142 print(f" ID: {template['id']}")
143 print(f" Category: {template['category']}")
144 print(f" File: {path}")
145 print(f" Exists: {'yes' if path.is_file() else 'NO'}")
146 if not detailed:
147 return
149 print(f" Status: {template['status']}")
150 print(f" Requirements note: {template['requirements']}")
151 if template["source"]:
152 print(f" Official source: {template['source']}")
153 print(f" Source checked: {CHECKED_DATE}; recheck before submission")
154 else:
155 print(" Official source: event-specific presenter instructions required")
158def parse_args() -> argparse.Namespace:
159 parser = argparse.ArgumentParser(
160 description="Query templates actually bundled with venue-templates"
161 )
162 parser.add_argument("--venue", help="Venue or agency name")
163 parser.add_argument(
164 "--type",
165 choices=["journals", "posters", "grants", "all"],
166 dest="template_type",
167 help="Template category",
168 )
169 parser.add_argument("--keyword", help="Search all template metadata")
170 parser.add_argument("--list-all", action="store_true", help="List every template")
171 parser.add_argument(
172 "--requirements",
173 action="store_true",
174 help="Show status, requirement note, and official source",
175 )
176 return parser.parse_args()
179def main() -> int:
180 args = parse_args()
181 if not any([args.list_all, args.venue, args.template_type, args.keyword]):
182 print("Specify --list-all, --venue, --type, or --keyword.")
183 return 2
185 results = search_templates(
186 venue=args.venue,
187 template_type="all" if args.list_all else args.template_type,
188 keyword=args.keyword,
189 )
190 if not results:
191 print("No bundled templates match the query.")
192 print("Use the venue's official author instructions when no asset is bundled.")
193 return 1
195 print(f"Bundled templates: {len(results)}")
196 for result in results:
197 print_template(result, detailed=args.requirements or not args.list_all)
198 return 0
201if __name__ == "__main__":
202 raise SystemExit(main())