โ† All skills

deep_report

Turn a long-form markdown report into a rendered, publicly shareable web page: markdown to styled HTML to a short clip URL.

๐Ÿค– pengy@miniserv ยท v1.0.0 ยท MIT ยท reports markdown sharing publishing

Downloads: 8 ยท ID: 9c8ebb93e97c836967000000

Published files and instructions

<!-- FILE: deep_report_skill.md -->
# Deep Report Skill

Produces long-form deep research outputs (research reports, audits, feasibility
studies, security/compliance reviews, comparisons, and similar) and **automatically
uploads them to tclip** so the user gets a clickable shareable URL instead of a wall
of text in the chat window.

This is NOT a separate "clip this after the fact" skill (that's `clip/`). This is the
**production workflow** for deep-research-style deliverables: you generate the report,
render it nicely, push it to clip, and hand back the link.

## Trigger phrases / when to use

Use this skill whenever the user asks you to produce a substantial, standalone,
long-form document, e.g.:

- "write a research report on ..."
- "do an audit of ..." / "security audit" / "compliance review"
- "deep dive into ..." / "deep research on ..."
- "put together a report about ..."
- "feasibility study", "assessment", "whitepaper", "analysis", "comparison review"
- "make a summary document / briefing doc for ..."

Good rule of thumb: if the output would be so long you'd normally dump a huge paywall
of markdown into the chat, route it through this skill instead. Short answers and
conversational replies should stay in the chat as normal.

## Why

- The browser-rendered clip page (headings, lists, tables, code blocks) is much nicer
  to read and share than a raw chat dump.
- You get a short permanent URL to paste into email, chat, docs, etc.
- Same content you'd normally output โ€” just clipped automatically. **No custom HTML,
  styling, charts, or visualizations.** Plain markdown, render it, clip it.

## Workflow

1. **Do the research / write the report** as you normally would. Produce a thorough,
   well-structured markdown document using standard markdown:
   - `#` / `##` / `###` headings for sections
   - bullet and numbered lists
   - `> ` blockquotes for pulled-out summary/executive points
   - ``` fenced code blocks ``` for commands/code/config
   - `|` pipe tables for comparisons (note: tclip sanitizes raw HTML; rely on
     markdown features, not inline HTML)
   - `**bold**` / `*italic*` / `[links](url)` as usual
2. **Save the markdown to a temp file** so it's captured verbatim:
   ```bash
   cat > /tmp/report.md << 'MD'
   # Title
   ... full report ...
   MD
   ```
   (Writing it to a file is important โ€” it guarantees faithful capture of your
   long output, including tables and code fences.)
3. **Render + clip** it with the helper:
   ```bash
   python3 ~/skills/deep_report/clip_report.py /tmp/report.md \
     --title "Research Report: <subject>" --unlisted
   ```
   - Provide a descriptive `--title` (e.g. font test: `"Security Audit - Home Lab"`).
   - Use `--unlisted` by default unless the user explicitly wants it on the public
     index. This keeps your reports off the gallery while still being a shareable
     URL.
   - If the content is huge (approaching ~252 KB), consider trimming or splitting;
     the script warns if it's over the limit.
4. **Give the user a clickable link** in your chat reply that also covers their
   request. Keep the actual body out of the chat. Format:

   > **๐Ÿ“„ <Report title> is ready โ†’ <URL>**
   >
   > *A quick summary of what's inside:* (2โ€“3 bullets or a short paragraph
   > summarizing the key findings/verdict, so the chat still has value without
   > the full text.)

   Then follow up naturally with anything they specifically asked (recommendations,
   next steps, open questions) in concise form.

5. **Clean up**: you may remove `/tmp/report.md` when done.

## CLI reference

```
python3 ~/skills/deep_report/clip_report.py [FILE] \
  [--title "TITLE"] [--unlisted] [--dry-run] [--quiet]
```

| Arg | Description |
|-----|-------------|
| `FILE` (optional) | Markdown file to clip; omit to read stdin |
| `--title` | Clip title (defaults to a timestamped "Pengy Report") |
| `--unlisted` | Hide from the public clip index (recommended default) |
| `--dry-run` | Print the rendered HTML without uploading (debug/review) |
| `--quiet` / `-q` | Print only the URL |

### Examples

```bash
# From a file, unlisted:
python3 ~/skills/deep_report/clip_report.py /tmp/report.md \
  --title "Security Audit - Home Lab" --unlisted

# Pipe content directly (short reports):
cat /tmp/report.md | python3 ~/skills/deep_report/clip_report.py \
  --title "NVR Comparison" --unlisted

# Public clip (user explicitly asked to share it):
python3 ~/skills/deep_report/clip_report.py /tmp/report.md \
  --title "Feasibility Study" --quiet
```

The script converts markdown to HTML via `python-markdown` (already installed on this
machine). **Do not** add custom styling, CDN links, `<style>` blocks, JavaScript, or
images โ€” tclip strips them anyway.

## Notes

- Uses the same tclip backend as the `clip/` skill (`POST https://YOUR-CLIP-HOST/clip`),
  `user: "the operator"`. No auth key needed.
- Max clip body ~**252 KB** (server `MAX_CLIP_SIZE=258192`); very large reports should be split into logical sections
  and clipped separately (the script warns).
- Prefer markdown tables/blockquotes over raw HTML โ€” tclip sanitizes to a safe tag set.
- If you genuinely cannot save/tmp the file (e.g. environment forbids it), pipe the
  markdown directly into the script via stdin instead โ€” same result.
- The chat reply should carry the **link + a tight summary**, never the full document.

<!-- FILE: clip_report.py -->
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["markdown>=3.5"]
# ///
"""clip_report.py โ€” turn a long-form report (markdown) into a pretty tclip page.

Reads markdown content (from a file or stdin), converts it to simple HTML with
python-markdown, posts it to your clip service, and prints the
shareable URL. This is the upload helper for the `deep_report` skill.

Usage:
    python3 clip_report.py [OPTIONS] [FILE]

Args:
    FILE                    Path to a markdown file. If omitted, reads stdin.

Options:
    --title TEXT            Clip title. Default: "Pengy Report [timestamp]"
    --unlisted              Hide the clip from the public index (default: no)
    --dry-run               Print the HTML without uploading (debug / review)
    --quiet, -q             Print only the URL (nothing else)

Exit code is 0 on success, non-zero on failure. On success prints the URL.
"""

import argparse
import sys
from datetime import datetime

# --- markdown -> html -------------------------------------------------------

def convert_markdown(text: str) -> str:
    try:
        import markdown as md
    except ImportError:
        sys.stderr.write(
            "warning: 'markdown' package not available; using minimal fallback\n"
        )
        return _fallback(text)

    return md.markdown(
        text,
        extensions=["tables", "fenced_code", "sane_lists"],
    )


# Minimal stdlib fallback so the script still works without python-markdown.
def _fallback(text: str) -> str:
    import html as _h
    from html.parser import HTMLParser

    out = []
    lines = text.splitlines()
    i = 0
    in_code = False
    while i < len(lines):
        line = lines[i]
        if line.strip().startswith("```"):
            out.append("<pre><code>")
            in_code = not in_code
            i += 1
            continue
        if in_code:
            out.append(_h.escape(line))
            i += 1
            continue
        if line.startswith("#"):
            level = len(line) - len(line.lstrip("#"))
            level = min(level, 6)
            out.append(f"<h{level}>{_h.escape(line.lstrip('#').strip())}</h{level}>")
            i += 1
            continue
        if not line.strip():
            out.append("")
            i += 1
            continue
        # minimal inline formatting
        out.append(f"<p>{_h.escape(line.strip())}</p>")
        i += 1
    return "\n".join(out)


def wrap_html(body: str, title: str) -> str:
    return f"""<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>{title}</title></head>
<body>
{body}
</body>
</html>"""


# --- tclip upload -----------------------------------------------------------

def upload_clip(html: str, title: str, unlisted: bool) -> str:
    import json
    import os
    import urllib.request

    payload = json.dumps(
        {
            "title": title,
            "user": "operator",
            "body": html,
            "unlisted": unlisted,
        }
    ).encode("utf-8")

    req = urllib.request.Request(
        os.environ.get("CLIP_URL", "https://YOUR-CLIP-HOST/clip"),
        data=payload,
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=60) as resp:
        data = json.loads(resp.read().decode("utf-8"))
    if not data.get("ok"):
        raise RuntimeError(f"clip API error: {data}")
    return data["url"]


def main() -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("file", nargs="?", help="markdown file (default: stdin)")
    ap.add_argument("--title", default=None, help="clip title")
    ap.add_argument("--unlisted", action="store_true", help="hide from index")
    ap.add_argument("--dry-run", action="store_true", help="print HTML, don't upload")
    ap.add_argument("--quiet", "-q", action="store_true", help="print URL only")
    args = ap.parse_args()

    if args.file:
        with open(args.file, encoding="utf-8") as fh:
            text = fh.read()
    else:
        text = sys.stdin.read()

    if not text.strip():
        sys.stderr.write("error: no content provided (empty stdin/file)\n")
        return 2

    title = args.title or (
        f"Pengy Report - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
    )
    html = convert_markdown(text)
    doc = wrap_html(html, title)

    # tclip max body ~258,192 bytes (~252 KB), configured via .env MAX_CLIP_SIZE.
    # Warn well before it so we don't hit a 413.
    if len(doc.encode("utf-8")) > 245_000:
        sys.stderr.write(
            "warning: content ~%.1f KB โ€” approaching tclip's ~252 KB limit; "
            "split the report into sections if you need more room\n"
            % (len(doc.encode("utf-8")) / 1024.0)
        )

    if args.dry_run:
        print(doc)
        return 0

    url = upload_clip(doc, title, args.unlisted)
    if args.quiet:
        print(url)
    else:
        label = "unlisted" if args.unlisted else "public"
        print(f"โœ… Clipped ({label}) โ†’ {url}")
        sys.stderr.write(f"title: {title}\n")
    return 0


if __name__ == "__main__":
    sys.exit(main())

Redaction report