diff --git a/agents/.agents/skills/doc/LICENSE.txt b/agents/.agents/skills/doc/LICENSE.txt
new file mode 100644
index 0000000..13e25df
--- /dev/null
+++ b/agents/.agents/skills/doc/LICENSE.txt
@@ -0,0 +1,201 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf of
+ any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don\'t include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/agents/.agents/skills/doc/SKILL.md b/agents/.agents/skills/doc/SKILL.md
new file mode 100644
index 0000000..c6d9612
--- /dev/null
+++ b/agents/.agents/skills/doc/SKILL.md
@@ -0,0 +1,80 @@
+---
+name: "doc"
+description: "Use when the task involves reading, creating, or editing `.docx` documents, especially when formatting or layout fidelity matters; prefer `python-docx` plus the bundled `scripts/render_docx.py` for visual checks."
+---
+
+
+# DOCX Skill
+
+## When to use
+- Read or review DOCX content where layout matters (tables, diagrams, pagination).
+- Create or edit DOCX files with professional formatting.
+- Validate visual layout before delivery.
+
+## Workflow
+1. Prefer visual review (layout, tables, diagrams).
+ - If `soffice` and `pdftoppm` are available, convert DOCX -> PDF -> PNGs.
+ - Or use `scripts/render_docx.py` (requires `pdf2image` and Poppler).
+ - If these tools are missing, install them or ask the user to review rendered pages locally.
+2. Use `python-docx` for edits and structured creation (headings, styles, tables, lists).
+3. After each meaningful change, re-render and inspect the pages.
+4. If visual review is not possible, extract text with `python-docx` as a fallback and call out layout risk.
+5. Keep intermediate outputs organized and clean up after final approval.
+
+## Temp and output conventions
+- Use `tmp/docs/` for intermediate files; delete when done.
+- Write final artifacts under `output/doc/` when working in this repo.
+- Keep filenames stable and descriptive.
+
+## Dependencies (install if missing)
+Prefer `uv` for dependency management.
+
+Python packages:
+```
+uv pip install python-docx pdf2image
+```
+If `uv` is unavailable:
+```
+python3 -m pip install python-docx pdf2image
+```
+System tools (for rendering):
+```
+# macOS (Homebrew)
+brew install libreoffice poppler
+
+# Ubuntu/Debian
+sudo apt-get install -y libreoffice poppler-utils
+```
+
+If installation isn't possible in this environment, tell the user which dependency is missing and how to install it locally.
+
+## Environment
+No required environment variables.
+
+## Rendering commands
+DOCX -> PDF:
+```
+soffice -env:UserInstallation=file:///tmp/lo_profile_$$ --headless --convert-to pdf --outdir $OUTDIR $INPUT_DOCX
+```
+
+PDF -> PNGs:
+```
+pdftoppm -png $OUTDIR/$BASENAME.pdf $OUTDIR/$BASENAME
+```
+
+Bundled helper:
+```
+python3 scripts/render_docx.py /path/to/file.docx --output_dir /tmp/docx_pages
+```
+
+## Quality expectations
+- Deliver a client-ready document: consistent typography, spacing, margins, and clear hierarchy.
+- Avoid formatting defects: clipped/overlapping text, broken tables, unreadable characters, or default-template styling.
+- Charts, tables, and visuals must be legible in rendered pages with correct alignment.
+- Use ASCII hyphens only. Avoid U+2011 (non-breaking hyphen) and other Unicode dashes.
+- Citations and references must be human-readable; never leave tool tokens or placeholder strings.
+
+## Final checks
+- Re-render and inspect every page at 100% zoom before final delivery.
+- Fix any spacing, alignment, or pagination issues and repeat the render loop.
+- Confirm there are no leftovers (temp files, duplicate renders) unless the user asks to keep them.
diff --git a/agents/.agents/skills/doc/agents/openai.yaml b/agents/.agents/skills/doc/agents/openai.yaml
new file mode 100644
index 0000000..27ce451
--- /dev/null
+++ b/agents/.agents/skills/doc/agents/openai.yaml
@@ -0,0 +1,6 @@
+interface:
+ display_name: "Word Docs"
+ short_description: "Edit and review docx files"
+ icon_small: "./assets/doc-small.svg"
+ icon_large: "./assets/doc.png"
+ default_prompt: "Edit or review this .docx file and return the updated file plus a concise change summary."
diff --git a/agents/.agents/skills/doc/assets/doc-small.svg b/agents/.agents/skills/doc/assets/doc-small.svg
new file mode 100644
index 0000000..97289eb
--- /dev/null
+++ b/agents/.agents/skills/doc/assets/doc-small.svg
@@ -0,0 +1,3 @@
+
diff --git a/agents/.agents/skills/doc/assets/doc.png b/agents/.agents/skills/doc/assets/doc.png
new file mode 100644
index 0000000..e165178
Binary files /dev/null and b/agents/.agents/skills/doc/assets/doc.png differ
diff --git a/agents/.agents/skills/doc/scripts/render_docx.py b/agents/.agents/skills/doc/scripts/render_docx.py
new file mode 100755
index 0000000..907ec89
--- /dev/null
+++ b/agents/.agents/skills/doc/scripts/render_docx.py
@@ -0,0 +1,296 @@
+import argparse
+import os
+import re
+import subprocess
+import tempfile
+import xml.etree.ElementTree as ET
+from os import makedirs, replace
+from os.path import abspath, basename, exists, expanduser, join, splitext
+from shutil import which
+import sys
+from typing import Sequence, cast
+from zipfile import ZipFile
+
+from pdf2image import convert_from_path, pdfinfo_from_path
+
+TWIPS_PER_INCH: int = 1440
+
+
+def ensure_system_tools() -> None:
+ missing: list[str] = []
+ for tool in ("soffice", "pdftoppm"):
+ if which(tool) is None:
+ missing.append(tool)
+ if missing:
+ tools = ", ".join(missing)
+ raise RuntimeError(
+ f"Missing required system tool(s): {tools}. Install LibreOffice and Poppler, then retry."
+ )
+
+
+def calc_dpi_via_ooxml_docx(input_path: str, max_w_px: int, max_h_px: int) -> int:
+ """Calculate DPI from OOXML `word/document.xml` page size (w:pgSz in twips).
+
+ DOCX stores page dimensions in section properties as twips (1/1440 inch).
+ We read the first encountered section's page size and compute an isotropic DPI
+ that fits within the target max pixel dimensions.
+ """
+ with ZipFile(input_path, "r") as zf:
+ xml = zf.read("word/document.xml")
+ root = ET.fromstring(xml)
+ ns = {"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"}
+
+ # Common placements: w:body/w:sectPr or w:body/w:p/w:pPr/w:sectPr
+ sect_pr = root.find(".//w:sectPr", ns)
+ if sect_pr is None:
+ raise RuntimeError("Section properties not found in document.xml")
+ pg_sz = sect_pr.find("w:pgSz", ns)
+ if pg_sz is None:
+ raise RuntimeError("Page size not found in section properties")
+
+ # Values are in twips
+ w_twips_str = pg_sz.get(
+ "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}w"
+ ) or pg_sz.get("w")
+ h_twips_str = pg_sz.get(
+ "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}h"
+ ) or pg_sz.get("h")
+
+ if not w_twips_str or not h_twips_str:
+ raise RuntimeError("Page size attributes missing in pgSz")
+
+ width_in = int(w_twips_str) / TWIPS_PER_INCH
+ height_in = int(h_twips_str) / TWIPS_PER_INCH
+ if width_in <= 0 or height_in <= 0:
+ raise RuntimeError("Invalid page size values in document.xml")
+ return round(min(max_w_px / width_in, max_h_px / height_in))
+
+
+def calc_dpi_via_pdf(input_path: str, max_w_px: int, max_h_px: int) -> int:
+ """Convert input to PDF and compute DPI from its page size."""
+ with tempfile.TemporaryDirectory(prefix="soffice_profile_") as user_profile:
+ with tempfile.TemporaryDirectory(prefix="soffice_convert_") as convert_tmp_dir:
+ stem = splitext(basename(input_path))[0]
+ pdf_path = convert_to_pdf(input_path, user_profile, convert_tmp_dir, stem)
+ if not (pdf_path and exists(pdf_path)):
+ raise RuntimeError("Failed to convert input to PDF for DPI computation.")
+
+ info = pdfinfo_from_path(pdf_path)
+ size_val = info.get("Page size")
+ if not size_val:
+ for k, v in info.items():
+ if isinstance(v, str) and "size" in k.lower() and "pts" in v:
+ size_val = v
+ break
+ if not isinstance(size_val, str):
+ raise RuntimeError("Failed to read PDF page size for DPI computation.")
+
+ m = re.search(r"(\d+)\s*x\s*(\d+)\s*pts", size_val)
+ if not m:
+ raise RuntimeError("Unrecognized PDF page size format.")
+ width_pts = int(m.group(1))
+ height_pts = int(m.group(2))
+ width_in = width_pts / 72.0
+ height_in = height_pts / 72.0
+ if width_in <= 0 or height_in <= 0:
+ raise RuntimeError("Invalid PDF page size values.")
+ return round(min(max_w_px / width_in, max_h_px / height_in))
+
+
+def run_cmd_no_check(cmd: list[str]) -> None:
+ subprocess.run(
+ cmd,
+ check=False,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ env=os.environ.copy(),
+ )
+
+
+def convert_to_pdf(
+ doc_path: str,
+ user_profile: str,
+ convert_tmp_dir: str,
+ stem: str,
+) -> str:
+ # Try direct DOC(X) -> PDF
+ cmd_pdf = [
+ "soffice",
+ "-env:UserInstallation=file://" + user_profile,
+ "--invisible",
+ "--headless",
+ "--norestore",
+ "--convert-to",
+ "pdf",
+ "--outdir",
+ convert_tmp_dir,
+ doc_path,
+ ]
+ run_cmd_no_check(cmd_pdf)
+
+ pdf_path = join(convert_tmp_dir, f"{stem}.pdf")
+ if exists(pdf_path):
+ return pdf_path
+
+ # Fallback: DOCX -> ODT, then ODT -> PDF
+ cmd_odt = [
+ "soffice",
+ "-env:UserInstallation=file://" + user_profile,
+ "--invisible",
+ "--headless",
+ "--norestore",
+ "--convert-to",
+ "odt",
+ "--outdir",
+ convert_tmp_dir,
+ doc_path,
+ ]
+ run_cmd_no_check(cmd_odt)
+
+ odt_path = join(convert_tmp_dir, f"{stem}.odt")
+
+ if exists(odt_path):
+ cmd_odt_pdf = [
+ "soffice",
+ "-env:UserInstallation=file://" + user_profile,
+ "--invisible",
+ "--headless",
+ "--norestore",
+ "--convert-to",
+ "pdf",
+ "--outdir",
+ convert_tmp_dir,
+ odt_path,
+ ]
+ run_cmd_no_check(cmd_odt_pdf)
+ if exists(pdf_path):
+ return pdf_path
+
+ return ""
+
+
+def rasterize(
+ doc_path: str,
+ out_dir: str,
+ dpi: int,
+) -> Sequence[str]:
+ """Rasterise DOCX (or similar) to images placed in out_dir and return their paths.
+
+ Images are named as page-. with pages starting at 1.
+ """
+ makedirs(out_dir, exist_ok=True)
+ doc_path = abspath(doc_path)
+ stem = splitext(basename(doc_path))[0]
+
+ # Use a unique user profile to avoid LibreOffice profile lock when running concurrently
+ with tempfile.TemporaryDirectory(prefix="soffice_profile_") as user_profile:
+ # Write conversion outputs into a temp directory to avoid any IO oddities
+ with tempfile.TemporaryDirectory(prefix="soffice_convert_") as convert_tmp_dir:
+ pdf_path = convert_to_pdf(
+ doc_path,
+ user_profile,
+ convert_tmp_dir,
+ stem,
+ )
+
+ if not pdf_path or not exists(pdf_path):
+ raise RuntimeError(
+ "Failed to produce PDF for rasterization (direct and ODT fallback)."
+ )
+ paths_raw = cast(
+ list[str],
+ convert_from_path(
+ pdf_path,
+ dpi=dpi,
+ fmt="png",
+ thread_count=8,
+ output_folder=out_dir,
+ paths_only=True,
+ output_file="page",
+ ),
+ )
+
+ # Rename convert_from_path's output format f'page{thread_id:04d}-{page_num:02d}.' to 'page-.'
+ pages: list[tuple[int, str]] = []
+ for src_path in paths_raw:
+ base = splitext(basename(src_path))[0]
+ page_num_str = base.split("-")[-1]
+ page_num = int(page_num_str)
+ dst_path = join(out_dir, f"page-{page_num}.png")
+ replace(src_path, dst_path)
+ pages.append((page_num, dst_path))
+ pages.sort(key=lambda t: t[0])
+ final_paths = [path for _, path in pages]
+ return final_paths
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(description="Render DOCX-like file to PNG images.")
+ parser.add_argument(
+ "input_path",
+ type=str,
+ help="Path to the input DOCX file (or compatible).",
+ )
+ parser.add_argument(
+ "--output_dir",
+ type=str,
+ default=None,
+ help=(
+ "Output directory for the rendered images. "
+ "Defaults to a folder next to the input named after the input file (without extension)."
+ ),
+ )
+ parser.add_argument(
+ "--width",
+ type=int,
+ default=1600,
+ help=(
+ "Approximate maximum width in pixels after isotropic scaling (default 1600). "
+ "The actual value may exceed slightly."
+ ),
+ )
+ parser.add_argument(
+ "--height",
+ type=int,
+ default=2000,
+ help=(
+ "Approximate maximum height in pixels after isotropic scaling (default 2000). "
+ "The actual value may exceed slightly."
+ ),
+ )
+ parser.add_argument(
+ "--dpi",
+ type=int,
+ default=None,
+ help=("Override computed DPI. If provided, skips DOCX/PDF-based DPI calculation."),
+ )
+ args = parser.parse_args()
+
+ try:
+ ensure_system_tools()
+
+ input_path = abspath(expanduser(args.input_path))
+ out_dir = (
+ abspath(expanduser(args.output_dir)) if args.output_dir else splitext(input_path)[0]
+ )
+
+ if args.dpi is not None:
+ dpi = int(args.dpi)
+ else:
+ try:
+ if input_path.lower().endswith((".docx", ".docm", ".dotx", ".dotm")):
+ dpi = calc_dpi_via_ooxml_docx(input_path, args.width, args.height)
+ else:
+ raise RuntimeError("Skip OOXML DPI; not a DOCX container")
+ except Exception:
+ dpi = calc_dpi_via_pdf(input_path, args.width, args.height)
+
+ rasterize(input_path, out_dir, dpi)
+ print("Pages rendered to " + out_dir)
+ except RuntimeError as exc:
+ print(f"Error: {exc}", file=sys.stderr)
+ raise SystemExit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/agents/.agents/skills/jupyter-notebook/LICENSE.txt b/agents/.agents/skills/jupyter-notebook/LICENSE.txt
new file mode 100644
index 0000000..13e25df
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/LICENSE.txt
@@ -0,0 +1,201 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf of
+ any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don\'t include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/agents/.agents/skills/jupyter-notebook/SKILL.md b/agents/.agents/skills/jupyter-notebook/SKILL.md
new file mode 100644
index 0000000..e1d1748
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/SKILL.md
@@ -0,0 +1,107 @@
+---
+name: "jupyter-notebook"
+description: "Use when the user asks to create, scaffold, or edit Jupyter notebooks (`.ipynb`) for experiments, explorations, or tutorials; prefer the bundled templates and run the helper script `new_notebook.py` to generate a clean starting notebook."
+---
+
+
+# Jupyter Notebook Skill
+
+Create clean, reproducible Jupyter notebooks for two primary modes:
+
+- Experiments and exploratory analysis
+- Tutorials and teaching-oriented walkthroughs
+
+Prefer the bundled templates and the helper script for consistent structure and fewer JSON mistakes.
+
+## When to use
+- Create a new `.ipynb` notebook from scratch.
+- Convert rough notes or scripts into a structured notebook.
+- Refactor an existing notebook to be more reproducible and skimmable.
+- Build experiments or tutorials that will be read or re-run by other people.
+
+## Decision tree
+- If the request is exploratory, analytical, or hypothesis-driven, choose `experiment`.
+- If the request is instructional, step-by-step, or audience-specific, choose `tutorial`.
+- If editing an existing notebook, treat it as a refactor: preserve intent and improve structure.
+
+## Skill path (set once)
+
+```bash
+export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
+export JUPYTER_NOTEBOOK_CLI="$CODEX_HOME/skills/jupyter-notebook/scripts/new_notebook.py"
+```
+
+User-scoped skills install under `$CODEX_HOME/skills` (default: `~/.codex/skills`).
+
+## Workflow
+1. Lock the intent.
+Identify the notebook kind: `experiment` or `tutorial`.
+Capture the objective, audience, and what "done" looks like.
+
+2. Scaffold from the template.
+Use the helper script to avoid hand-authoring raw notebook JSON.
+
+```bash
+uv run --python 3.12 python "$JUPYTER_NOTEBOOK_CLI" \
+ --kind experiment \
+ --title "Compare prompt variants" \
+ --out output/jupyter-notebook/compare-prompt-variants.ipynb
+```
+
+```bash
+uv run --python 3.12 python "$JUPYTER_NOTEBOOK_CLI" \
+ --kind tutorial \
+ --title "Intro to embeddings" \
+ --out output/jupyter-notebook/intro-to-embeddings.ipynb
+```
+
+3. Fill the notebook with small, runnable steps.
+Keep each code cell focused on one step.
+Add short markdown cells that explain the purpose and expected result.
+Avoid large, noisy outputs when a short summary works.
+
+4. Apply the right pattern.
+For experiments, follow `references/experiment-patterns.md`.
+For tutorials, follow `references/tutorial-patterns.md`.
+
+5. Edit safely when working with existing notebooks.
+Preserve the notebook structure; avoid reordering cells unless it improves the top-to-bottom story.
+Prefer targeted edits over full rewrites.
+If you must edit raw JSON, review `references/notebook-structure.md` first.
+
+6. Validate the result.
+Run the notebook top-to-bottom when the environment allows.
+If execution is not possible, say so explicitly and call out how to validate locally.
+Use the final pass checklist in `references/quality-checklist.md`.
+
+## Templates and helper script
+- Templates live in `assets/experiment-template.ipynb` and `assets/tutorial-template.ipynb`.
+- The helper script loads a template, updates the title cell, and writes a notebook.
+
+Script path:
+- `$JUPYTER_NOTEBOOK_CLI` (installed default: `$CODEX_HOME/skills/jupyter-notebook/scripts/new_notebook.py`)
+
+## Temp and output conventions
+- Use `tmp/jupyter-notebook/` for intermediate files; delete when done.
+- Write final artifacts under `output/jupyter-notebook/` when working in this repo.
+- Use stable, descriptive filenames (for example, `ablation-temperature.ipynb`).
+
+## Dependencies (install only when needed)
+Prefer `uv` for dependency management.
+
+Optional Python packages for local notebook execution:
+
+```bash
+uv pip install jupyterlab ipykernel
+```
+
+The bundled scaffold script uses only the Python standard library and does not require extra dependencies.
+
+## Environment
+No required environment variables.
+
+## Reference map
+- `references/experiment-patterns.md`: experiment structure and heuristics.
+- `references/tutorial-patterns.md`: tutorial structure and teaching flow.
+- `references/notebook-structure.md`: notebook JSON shape and safe editing rules.
+- `references/quality-checklist.md`: final validation checklist.
diff --git a/agents/.agents/skills/jupyter-notebook/agents/openai.yaml b/agents/.agents/skills/jupyter-notebook/agents/openai.yaml
new file mode 100644
index 0000000..8832dea
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/agents/openai.yaml
@@ -0,0 +1,6 @@
+interface:
+ display_name: "Jupyter Notebooks"
+ short_description: "Create Jupyter notebooks for experiments and tutorials"
+ icon_small: "./assets/jupyter-small.svg"
+ icon_large: "./assets/jupyter.png"
+ default_prompt: "Create a Jupyter notebook for this task with clear sections, runnable cells, and concise takeaways."
diff --git a/agents/.agents/skills/jupyter-notebook/assets/experiment-template.ipynb b/agents/.agents/skills/jupyter-notebook/assets/experiment-template.ipynb
new file mode 100644
index 0000000..a4a0323
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/assets/experiment-template.ipynb
@@ -0,0 +1,110 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Experiment: TITLE\n",
+ "\n",
+ "Objective:\n",
+ "- State the question you want to answer.\n",
+ "- Define the success criteria.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Setup: imports and reproducibility\n",
+ "from __future__ import annotations\n",
+ "\n",
+ "import random\n",
+ "import statistics\n",
+ "\n",
+ "SEED = 7\n",
+ "random.seed(SEED)\n",
+ "SEED\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Plan\n",
+ "\n",
+ "- Hypothesis:\n",
+ "- Variables to sweep:\n",
+ "- Metrics to record:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Define parameters and lightweight helpers\n",
+ "sample_size = 20\n",
+ "values = [random.random() for _ in range(sample_size)]\n",
+ "summary = {\n",
+ " \"count\": len(values),\n",
+ " \"mean\": statistics.fmean(values),\n",
+ " \"min\": min(values),\n",
+ " \"max\": max(values),\n",
+ "}\n",
+ "summary\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Results\n",
+ "\n",
+ "- Key observations:\n",
+ "- Surprises or failure modes:\n",
+ "- Decision: continue, pivot, or stop:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Record findings in a minimal, copy-pasteable structure\n",
+ "result = {\n",
+ " \"seed\": SEED,\n",
+ " \"mean\": summary[\"mean\"],\n",
+ " \"range\": summary[\"max\"] - summary[\"min\"],\n",
+ "}\n",
+ "result\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Next steps\n",
+ "\n",
+ "- What to try next:\n",
+ "- What to document elsewhere (PRD, notes, issue):\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/agents/.agents/skills/jupyter-notebook/assets/jupyter-small.svg b/agents/.agents/skills/jupyter-notebook/assets/jupyter-small.svg
new file mode 100644
index 0000000..472d07f
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/assets/jupyter-small.svg
@@ -0,0 +1,3 @@
+
diff --git a/agents/.agents/skills/jupyter-notebook/assets/jupyter.png b/agents/.agents/skills/jupyter-notebook/assets/jupyter.png
new file mode 100644
index 0000000..51cdf7d
Binary files /dev/null and b/agents/.agents/skills/jupyter-notebook/assets/jupyter.png differ
diff --git a/agents/.agents/skills/jupyter-notebook/assets/tutorial-template.ipynb b/agents/.agents/skills/jupyter-notebook/assets/tutorial-template.ipynb
new file mode 100644
index 0000000..7001309
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/assets/tutorial-template.ipynb
@@ -0,0 +1,107 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Tutorial: TITLE\n",
+ "\n",
+ "Audience:\n",
+ "- Describe who this is for.\n",
+ "\n",
+ "Prerequisites:\n",
+ "- List required concepts or setup.\n",
+ "\n",
+ "Learning goals:\n",
+ "- By the end, the reader can...\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Outline\n",
+ "\n",
+ "1. Setup\n",
+ "2. A minimal working example\n",
+ "3. Variations and pitfalls\n",
+ "4. Exercises\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Setup cell: keep it short and deterministic\n",
+ "from __future__ import annotations\n",
+ "\n",
+ "import math\n",
+ "import random\n",
+ "\n",
+ "SEED = 21\n",
+ "random.seed(SEED)\n",
+ "SEED\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 1 - Start with a tiny example\n",
+ "\n",
+ "Explain what the next cell does in plain language.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Minimal working example\n",
+ "angles = [0, math.pi / 4, math.pi / 2]\n",
+ "sines = [math.sin(a) for a in angles]\n",
+ "list(zip(angles, sines))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Exercises\n",
+ "\n",
+ "- Try a different input.\n",
+ "- Predict the output before running the code.\n",
+ "- Note one common mistake and how to fix it.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Exercise answer scaffold\n",
+ "def describe(values: list[float]) -> dict[str, float]:\n",
+ " return {\"min\": min(values), \"max\": max(values)}\n",
+ "\n",
+ "describe(sines)\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/agents/.agents/skills/jupyter-notebook/references/experiment-patterns.md b/agents/.agents/skills/jupyter-notebook/references/experiment-patterns.md
new file mode 100644
index 0000000..2d5093b
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/references/experiment-patterns.md
@@ -0,0 +1,10 @@
+# Experiment Patterns
+
+Use this structure for exploratory and experimental work:
+
+- Title and objective: state the question and the success criteria.
+- Setup and reproducibility: import only what you need, set a seed early, and keep configuration in one short cell.
+- Plan: list hypotheses, sweeps, and metrics before running code.
+- Minimal baseline: start with the smallest runnable example and confirm it runs end-to-end before adding complexity.
+- Results and notes: summarize findings in markdown near the relevant code and record key metrics in a small dictionary or table-like structure.
+- Next steps: decide whether to continue, pivot, or stop, and capture follow-up ideas as short bullets.
diff --git a/agents/.agents/skills/jupyter-notebook/references/notebook-structure.md b/agents/.agents/skills/jupyter-notebook/references/notebook-structure.md
new file mode 100644
index 0000000..681d36f
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/references/notebook-structure.md
@@ -0,0 +1,17 @@
+# Notebook Structure
+
+Jupyter notebooks are JSON documents with this high-level shape:
+
+- `nbformat` and `nbformat_minor`
+- `metadata`
+- `cells` (a list of markdown and code cells)
+
+When editing `.ipynb` files programmatically:
+
+- Preserve `nbformat` and `nbformat_minor` from the template.
+- Keep `cells` as an ordered list; do not reorder unless intentional.
+- For code cells, set `execution_count` to `null` when unknown.
+- For code cells, set `outputs` to an empty list when scaffolding.
+- For markdown cells, keep `cell_type="markdown"` and `metadata={}`.
+
+Prefer scaffolding from the bundled templates or `new_notebook.py` (for example, `$CODEX_HOME/skills/jupyter-notebook/scripts/new_notebook.py`) instead of hand-authoring raw notebook JSON.
diff --git a/agents/.agents/skills/jupyter-notebook/references/quality-checklist.md b/agents/.agents/skills/jupyter-notebook/references/quality-checklist.md
new file mode 100644
index 0000000..5482f28
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/references/quality-checklist.md
@@ -0,0 +1,11 @@
+# Quality Checklist
+
+Before delivering a notebook:
+
+- Run it top-to-bottom at least once (or as much as the environment allows).
+- Ensure early cells set all required state; avoid hidden state from prior runs.
+- Keep outputs tidy. Avoid giant outputs when a short summary works.
+- Prefer small tables, key metrics, or short printouts.
+- Keep the narrative skimmable. Use headings and short bullets, and avoid long paragraphs.
+- Leave helpful TODOs only when necessary, and label them clearly.
+- If execution is not possible, call out the risk and how to validate locally.
diff --git a/agents/.agents/skills/jupyter-notebook/references/tutorial-patterns.md b/agents/.agents/skills/jupyter-notebook/references/tutorial-patterns.md
new file mode 100644
index 0000000..2a360b0
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/references/tutorial-patterns.md
@@ -0,0 +1,9 @@
+# Tutorial Patterns
+
+Use this structure for teaching and walkthroughs:
+
+- Audience, prerequisites, and learning goals: say who it is for, list what they should already know, and state what they will be able to do by the end.
+- Outline: provide a short numbered outline so readers can skim.
+- Step-by-step flow: pair a short markdown explanation with a small code cell that runs on its own and a brief interpretation of the result.
+- Exercises: include at least one exercise that reinforces the key concept and provide an answer scaffold in the next cell.
+- Pitfalls and extensions: call out one common mistake and how to fix it, and suggest one optional extension for curious readers.
diff --git a/agents/.agents/skills/jupyter-notebook/scripts/new_notebook.py b/agents/.agents/skills/jupyter-notebook/scripts/new_notebook.py
new file mode 100644
index 0000000..0aba209
--- /dev/null
+++ b/agents/.agents/skills/jupyter-notebook/scripts/new_notebook.py
@@ -0,0 +1,130 @@
+from __future__ import annotations
+
+import argparse
+import json
+import re
+from pathlib import Path
+from typing import Any
+
+
+def slugify(text: str) -> str:
+ lowered = text.strip().lower()
+ cleaned = re.sub(r"[^a-z0-9]+", "-", lowered)
+ collapsed = re.sub(r"-+", "-", cleaned).strip("-")
+ return collapsed or "notebook"
+
+
+def find_repo_root(start: Path) -> Path:
+ for candidate in (start, *start.parents):
+ if (candidate / ".git").exists():
+ return candidate
+ return start
+
+
+def load_template(skill_dir: Path, kind: str) -> dict[str, Any]:
+ asset_name = "experiment-template.ipynb" if kind == "experiment" else "tutorial-template.ipynb"
+ template_path = skill_dir / "assets" / asset_name
+ if not template_path.exists():
+ raise SystemExit(f"Missing template: {template_path}")
+ with template_path.open("r", encoding="utf-8") as f:
+ data = json.load(f)
+ if not isinstance(data, dict):
+ raise SystemExit(f"Unexpected template shape: {template_path}")
+ return data
+
+
+def update_title(notebook: dict[str, Any], kind: str, title: str) -> None:
+ prefix = "Experiment" if kind == "experiment" else "Tutorial"
+ expected = f"# {prefix}: {title}\n"
+
+ cells = notebook.get("cells")
+ if not isinstance(cells, list) or not cells:
+ raise SystemExit("Template notebook has no cells")
+
+ first_cell = cells[0]
+ if not isinstance(first_cell, dict) or first_cell.get("cell_type") != "markdown":
+ raise SystemExit("Template notebook must start with a markdown title cell")
+
+ source = first_cell.get("source", [])
+ if isinstance(source, str):
+ source_lines = [source]
+ elif isinstance(source, list):
+ source_lines = [str(line) for line in source]
+ else:
+ source_lines = []
+
+ if source_lines:
+ source_lines[0] = expected
+ else:
+ source_lines = [expected]
+
+ first_cell["source"] = source_lines
+
+ metadata = notebook.setdefault("metadata", {})
+ if not isinstance(metadata, dict):
+ raise SystemExit("Notebook metadata must be a mapping")
+
+ language_info = metadata.setdefault("language_info", {})
+ if isinstance(language_info, dict):
+ language_info.setdefault("name", "python")
+ language_info.setdefault("version", "3.12")
+
+
+def default_output(repo_root: Path, title: str) -> Path:
+ filename = f"{slugify(title)}.ipynb"
+ return repo_root / "output" / "jupyter-notebook" / filename
+
+
+def parse_args() -> argparse.Namespace:
+ parser = argparse.ArgumentParser(description="Scaffold a Jupyter notebook for experiments or tutorials.")
+ parser.add_argument(
+ "--kind",
+ choices=["experiment", "tutorial"],
+ default="experiment",
+ help="Notebook style to scaffold (default: experiment).",
+ )
+ parser.add_argument(
+ "--title",
+ required=True,
+ help="Human-readable notebook title used in the first markdown cell.",
+ )
+ parser.add_argument(
+ "--out",
+ type=Path,
+ default=None,
+ help="Output path for the notebook. Defaults to output/jupyter-notebook/.ipynb.",
+ )
+ parser.add_argument(
+ "--force",
+ action="store_true",
+ help="Overwrite the output file if it already exists.",
+ )
+ return parser.parse_args()
+
+
+def main() -> None:
+ args = parse_args()
+
+ script_path = Path(__file__).resolve()
+ skill_dir = script_path.parents[1]
+ repo_root = find_repo_root(skill_dir)
+
+ notebook = load_template(skill_dir, args.kind)
+ update_title(notebook, args.kind, args.title)
+
+ out_path = args.out or default_output(repo_root, args.title)
+ out_path = out_path.resolve()
+
+ if out_path.exists() and not args.force:
+ raise SystemExit(f"Refusing to overwrite existing file without --force: {out_path}")
+
+ out_path.parent.mkdir(parents=True, exist_ok=True)
+ with out_path.open("w", encoding="utf-8") as f:
+ json.dump(notebook, f, indent=2)
+ f.write("\n")
+
+ print(f"Wrote {out_path} using kind={args.kind}.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/agents/.agents/skills/pdf/LICENSE.txt b/agents/.agents/skills/pdf/LICENSE.txt
new file mode 100644
index 0000000..13e25df
--- /dev/null
+++ b/agents/.agents/skills/pdf/LICENSE.txt
@@ -0,0 +1,201 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf of
+ any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don\'t include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/agents/.agents/skills/pdf/SKILL.md b/agents/.agents/skills/pdf/SKILL.md
new file mode 100644
index 0000000..fd5d560
--- /dev/null
+++ b/agents/.agents/skills/pdf/SKILL.md
@@ -0,0 +1,67 @@
+---
+name: "pdf"
+description: "Use when tasks involve reading, creating, or reviewing PDF files where rendering and layout matter; prefer visual checks by rendering pages (Poppler) and use Python tools such as `reportlab`, `pdfplumber`, and `pypdf` for generation and extraction."
+---
+
+
+# PDF Skill
+
+## When to use
+- Read or review PDF content where layout and visuals matter.
+- Create PDFs programmatically with reliable formatting.
+- Validate final rendering before delivery.
+
+## Workflow
+1. Prefer visual review: render PDF pages to PNGs and inspect them.
+ - Use `pdftoppm` if available.
+ - If unavailable, install Poppler or ask the user to review the output locally.
+2. Use `reportlab` to generate PDFs when creating new documents.
+3. Use `pdfplumber` (or `pypdf`) for text extraction and quick checks; do not rely on it for layout fidelity.
+4. After each meaningful update, re-render pages and verify alignment, spacing, and legibility.
+
+## Temp and output conventions
+- Use `tmp/pdfs/` for intermediate files; delete when done.
+- Write final artifacts under `output/pdf/` when working in this repo.
+- Keep filenames stable and descriptive.
+
+## Dependencies (install if missing)
+Prefer `uv` for dependency management.
+
+Python packages:
+```
+uv pip install reportlab pdfplumber pypdf
+```
+If `uv` is unavailable:
+```
+python3 -m pip install reportlab pdfplumber pypdf
+```
+System tools (for rendering):
+```
+# macOS (Homebrew)
+brew install poppler
+
+# Ubuntu/Debian
+sudo apt-get install -y poppler-utils
+```
+
+If installation isn't possible in this environment, tell the user which dependency is missing and how to install it locally.
+
+## Environment
+No required environment variables.
+
+## Rendering command
+```
+pdftoppm -png $INPUT_PDF $OUTPUT_PREFIX
+```
+
+## Quality expectations
+- Maintain polished visual design: consistent typography, spacing, margins, and section hierarchy.
+- Avoid rendering issues: clipped text, overlapping elements, broken tables, black squares, or unreadable glyphs.
+- Charts, tables, and images must be sharp, aligned, and clearly labeled.
+- Use ASCII hyphens only. Avoid U+2011 (non-breaking hyphen) and other Unicode dashes.
+- Citations and references must be human-readable; never leave tool tokens or placeholder strings.
+
+## Final checks
+- Do not deliver until the latest PNG inspection shows zero visual or formatting defects.
+- Confirm headers/footers, page numbering, and section transitions look polished.
+- Keep intermediate files organized or remove them after final approval.
diff --git a/agents/.agents/skills/pdf/agents/openai.yaml b/agents/.agents/skills/pdf/agents/openai.yaml
new file mode 100644
index 0000000..fe2876a
--- /dev/null
+++ b/agents/.agents/skills/pdf/agents/openai.yaml
@@ -0,0 +1,5 @@
+interface:
+ display_name: "PDF Skill"
+ short_description: "Create, edit, and review PDFs"
+ icon_large: "./assets/pdf.png"
+ default_prompt: "Create, edit, or review this PDF and summarize the key output or changes."
diff --git a/agents/.agents/skills/pdf/assets/pdf.png b/agents/.agents/skills/pdf/assets/pdf.png
new file mode 100644
index 0000000..dd16ba2
Binary files /dev/null and b/agents/.agents/skills/pdf/assets/pdf.png differ
diff --git a/agents/.agents/skills/slides/LICENSE.txt b/agents/.agents/skills/slides/LICENSE.txt
new file mode 100644
index 0000000..cefe596
--- /dev/null
+++ b/agents/.agents/skills/slides/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright (c) Microsoft Corporation.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/agents/.agents/skills/slides/SKILL.md b/agents/.agents/skills/slides/SKILL.md
new file mode 100644
index 0000000..f64a86f
--- /dev/null
+++ b/agents/.agents/skills/slides/SKILL.md
@@ -0,0 +1,71 @@
+---
+name: slides
+description: Create and edit presentation slide decks (`.pptx`) with PptxGenJS, bundled layout helpers, and render/validation utilities. Use when tasks involve building a new PowerPoint deck, recreating slides from screenshots/PDFs/reference decks, modifying slide content while preserving editable output, adding charts/diagrams/visuals, or diagnosing layout issues such as overflow, overlaps, and font substitution.
+---
+
+# Slides
+
+## Overview
+
+Use PptxGenJS for slide authoring. Do not use `python-pptx` for deck generation unless the task is inspection-only; keep editable output in JavaScript and deliver both the `.pptx` and the source `.js`.
+
+Keep work in a task-local directory. Only copy final artifacts to the requested destination after rendering and validation pass.
+
+## Bundled Resources
+
+- `assets/pptxgenjs_helpers/`: Copy this folder into the deck workspace and import it locally instead of reimplementing helper logic.
+- `scripts/render_slides.py`: Rasterize a `.pptx` or `.pdf` to per-slide PNGs.
+- `scripts/slides_test.py`: Detect content that overflows the slide canvas.
+- `scripts/create_montage.py`: Build a contact-sheet style montage of rendered slides.
+- `scripts/detect_font.py`: Report missing or substituted fonts as LibreOffice resolves them.
+- `scripts/ensure_raster_image.py`: Convert SVG/EMF/HEIC/PDF-like assets into PNGs for quick inspection.
+- `references/pptxgenjs-helpers.md`: Load only when you need API details or dependency notes.
+
+## Workflow
+
+1. Inspect the request and determine whether you are creating a new deck, recreating an existing deck, or editing one.
+2. Set the slide size up front. Default to 16:9 (`LAYOUT_WIDE`) unless the source material clearly uses another aspect ratio.
+3. Copy `assets/pptxgenjs_helpers/` into the working directory and import the helpers from there.
+4. Build the deck in JavaScript with an explicit theme font, stable spacing, and editable PowerPoint-native elements when practical.
+5. Run the bundled scripts from this skill directory or copy the needed ones into the task workspace. Render the result with `render_slides.py`, review the PNGs, and fix layout issues before delivery.
+6. Run `slides_test.py` for overflow checks when slide edges are tight or the deck is dense.
+7. Deliver the `.pptx`, the authoring `.js`, and any generated assets that are required to rebuild the deck.
+
+## Authoring Rules
+
+- Set theme fonts explicitly. Do not rely on PowerPoint defaults if typography matters.
+- Use `autoFontSize`, `calcTextBox`, and related helpers to size text boxes; do not use PptxGenJS `fit` or `autoFit`.
+- Use bullet options, not literal `•` characters.
+- Use `imageSizingCrop` or `imageSizingContain` instead of PptxGenJS built-in image sizing.
+- Use `latexToSvgDataUri()` for equations and `codeToRuns()` for syntax-highlighted code blocks.
+- Prefer native PowerPoint charts for simple bar/line/pie/histogram style visuals so reviewers can edit them later.
+- For charts or diagrams that PptxGenJS cannot express well, render SVG externally and place the SVG in the slide.
+- Include both `warnIfSlideHasOverlaps(slide, pptx)` and `warnIfSlideElementsOutOfBounds(slide, pptx)` in the submitted JavaScript whenever you generate or substantially edit slides.
+- Fix all unintentional overlap and out-of-bounds warnings before delivering. If an overlap is intentional, leave a short code comment near the relevant element.
+
+## Recreate Or Edit Existing Slides
+
+- Render the source deck or reference PDF first so you can compare slide geometry visually.
+- Match the original aspect ratio before rebuilding layout.
+- Preserve editability where possible: text should stay text, and simple charts should stay native charts.
+- If a reference slide uses raster artwork, use `ensure_raster_image.py` to generate debug PNGs from vector or odd image formats before placing them.
+
+## Validation Commands
+
+Examples below assume you copied the needed scripts into the working directory. If not, invoke the same script paths relative to this skill folder.
+
+```bash
+# Render slides to PNGs for review
+python3 scripts/render_slides.py deck.pptx --output_dir rendered
+
+# Build a montage for quick scanning
+python3 scripts/create_montage.py --input_dir rendered --output_file montage.png
+
+# Check for overflow beyond the original slide canvas
+python3 scripts/slides_test.py deck.pptx
+
+# Detect missing or substituted fonts
+python3 scripts/detect_font.py deck.pptx --json
+```
+
+Load `references/pptxgenjs-helpers.md` if you need the helper API summary or dependency details.
diff --git a/agents/.agents/skills/slides/agents/openai.yaml b/agents/.agents/skills/slides/agents/openai.yaml
new file mode 100644
index 0000000..6f77e49
--- /dev/null
+++ b/agents/.agents/skills/slides/agents/openai.yaml
@@ -0,0 +1,6 @@
+interface:
+ display_name: "Slides"
+ short_description: "Create and edit PPTX slide decks"
+ icon_small: "./assets/slides-small.svg"
+ icon_large: "./assets/slides.png"
+ default_prompt: "Use $slides to create or update this PPTX slide deck with PptxGenJS and validate the layout."
diff --git a/agents/.agents/skills/slides/assets/pptxgenjs_helpers/code.js b/agents/.agents/skills/slides/assets/pptxgenjs_helpers/code.js
new file mode 100644
index 0000000..951ce13
--- /dev/null
+++ b/agents/.agents/skills/slides/assets/pptxgenjs_helpers/code.js
@@ -0,0 +1,104 @@
+// Copyright (c) OpenAI. All rights reserved.
+"use strict";
+
+const fs = require("fs");
+const Prism = require("prismjs");
+let THEME_MAP;
+
+function loadPrismLanguage(lang) {
+ const normalized = String(lang || "plaintext").toLowerCase();
+ const known = new Set([
+ "markup",
+ "html",
+ "xml",
+ "svg",
+ "mathml",
+ "css",
+ "clike",
+ "javascript",
+ "js",
+ "typescript",
+ "ts",
+ "python",
+ "py",
+ "bash",
+ "sh",
+ "json",
+ "yaml",
+ "yml",
+ ]);
+ const map = {
+ js: "javascript",
+ ts: "typescript",
+ py: "python",
+ sh: "bash",
+ yml: "yaml",
+ html: "markup",
+ xml: "markup",
+ };
+ const id = map[normalized] || normalized;
+ if (!Prism.languages[id]) {
+ try {
+ require(`prismjs/components/prism-${id}`);
+ } catch (_e) {}
+ }
+ return Prism.languages[id] || Prism.languages.plain || {};
+}
+
+function buildThemeMap(themeCssModule = "prismjs/themes/prism-okaidia.css") {
+ try {
+ const css = fs.readFileSync(require.resolve(themeCssModule), "utf8");
+ return Object.fromEntries(
+ [
+ ...css.matchAll(
+ /\.token\.([\w-]+)[^{]*\{[^}]*color:\s*([^;\s]+)[^}]*\}/g
+ ),
+ ].map(([, t, c]) => [t, c.replace(/#|!important/g, "").trim()])
+ );
+ } catch (err) {
+ return { plain: "FFFFFF", comment: "999999" };
+ }
+}
+
+function getThemeMap() {
+ if (!THEME_MAP) THEME_MAP = buildThemeMap();
+ return THEME_MAP;
+}
+
+function run(text, type = "plain") {
+ const theme = getThemeMap();
+ return {
+ text,
+ options: {
+ fontFace: "Consolas",
+ color: theme[type] || theme.plain || "FFFFFF",
+ fontSize: 14,
+ },
+ };
+}
+
+function tokensToRuns(tokens) {
+ return tokens.flatMap((t) =>
+ typeof t === "string"
+ ? [run(t)]
+ : Array.isArray(t.content)
+ ? tokensToRuns(t.content)
+ : [run(t.content, t.type)]
+ );
+}
+
+function codeToRuns(code, lang) {
+ const grammar = loadPrismLanguage(lang);
+ const lines = String(code || "").split("\n");
+ const pad = lines.length.toString().length;
+ return lines.flatMap((line, i) => [
+ run(`${(i + 1).toString().padStart(pad, " ")} `, "comment"),
+ ...tokensToRuns(Prism.tokenize(line, grammar)),
+ ...(i < lines.length - 1 ? [run("\n")] : []),
+ ]);
+}
+
+module.exports = {
+ codeToRuns,
+ buildThemeMap,
+};
diff --git a/agents/.agents/skills/slides/assets/pptxgenjs_helpers/image.js b/agents/.agents/skills/slides/assets/pptxgenjs_helpers/image.js
new file mode 100644
index 0000000..16fdc16
--- /dev/null
+++ b/agents/.agents/skills/slides/assets/pptxgenjs_helpers/image.js
@@ -0,0 +1,333 @@
+// Copyright (c) OpenAI. All rights reserved.
+"use strict";
+
+const fs = require("fs");
+
+// Accept either a filesystem path, a data URI, raw SVG string, or a Buffer
+// and normalize to a Buffer for type/size probing.
+function readInputAsBuffer(source) {
+ if (!source) throw new Error("Image source is empty");
+ if (Buffer.isBuffer(source)) return { buffer: source, type: "buffer" };
+ if (typeof source === "string") {
+ // data URI (we primarily emit base64 data URIs for SVG via helpers)
+ if (source.startsWith("data:")) {
+ const type = "dataUri";
+ const comma = source.indexOf(",");
+ const payload = comma !== -1 ? source.slice(comma + 1) : source;
+ // Our helpers use base64; if not, try URI decode then treat as raw text
+ try {
+ return { buffer: Buffer.from(payload, "base64"), type: type };
+ } catch (_e) {
+ try {
+ return {
+ buffer: Buffer.from(decodeURIComponent(payload), "utf8"),
+ type: type,
+ };
+ } catch (_e2) {
+ return { buffer: Buffer.from(payload, "utf8"), type: type };
+ }
+ }
+ }
+ // Raw inline SVG string
+ if (source.includes("