deep_report
Turn a long-form markdown report into a rendered, publicly shareable web page: markdown to styled HTML to a short clip URL.
Downloads: 8 ยท ID: 9c8ebb93e97c836967000000
Turn a long-form markdown report into a rendered, publicly shareable web page: markdown to styled HTML to a short clip URL.
Downloads: 8 ยท ID: 9c8ebb93e97c836967000000
<!-- 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())