claude-report-skill

agent
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 7 GitHub stars
Code Warn
  • network request — Outbound network request in bin/report_common.py
  • network request — Outbound network request in viewer/serve.py
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

A Claude Code skill that generates beautiful HTML reports instead of long terminal output

README.md

/report — HTML reports for agent sessions

A Claude Code skill (usable by any agent that can run shell commands) that
produces self-contained, dark-themed HTML reports instead of dumping long
output into your terminal — plus a standalone viewer that makes those
reports interactive: reply boxes, live task lists, one-click next-step cards,
and archive/restore.

report screenshot

What you get

  • /report skill — auto-triggers on long output; 5 report types
    (task-completion, research, audit, error-blocker, comparison) with a strict,
    accessible Aurora theme.
  • bin/report CLI — paths, indexing, archive/restore, the tiny task store,
    and the marker-wrapped blocks the viewer splices live.
  • viewer/serve.py — a stdlib-only viewer (python3, no deps): report
    index, themed serving, per-task reply forms, a report-level reply box,
    "Do it" prompt cards, .md linkification, archive with unbreakable links.
  • Reply relay — replies are composed into self-describing messages and
    appended to replies.jsonl (+ stdout), or piped to any command you choose.

Zero dependencies beyond Python 3.9+.

Quick start (demo in one command)

./examples/make-demo.sh

That seeds a throwaway REPORT_DIR with a fictional acme-widgets report,
three fake tasks, and starts the viewer on
http://127.0.0.1:8765. Open the report and try the
reply box, the per-task forms, and the Do it cards — everything lands in
$REPORT_DIR/replies.jsonl.

Install

git clone <this repo> && cd claude-report-skill

# 1. the skill (Claude Code)
mkdir -p ~/.claude/skills/report
ln -s "$PWD/SKILL.md" ~/.claude/skills/report/SKILL.md

# 2. the CLI + its shared module (keep them together)
mkdir -p ~/.local/bin
ln -s "$PWD/bin/report" "$PWD/bin/report_common.py" ~/.local/bin/

# 3. the viewer — run it from the repo, or copy viewer/ + bin/ somewhere
python3 viewer/serve.py

Make sure ~/.local/bin is on your PATH. report --help should work.

How it works

Writing a report (what the skill does)

report --template                                # themed HTML template
report --path --project myproj --title "Audit" --type audit
#  → ~/.local/share/claude-reports/myproj/2026-09-24/143022-audit.html
report related-tasks myproj --link "$(report --url <file>)" --title "Audit"
report next-prompts "Run the suite." "Tag the release."
report --open <file>                             # viewer URL if up, else file://

Reports live under $REPORT_DIR/<project>/<date>/<time>-<slug>.html with an
embedded report-meta JSON block that drives indexing, task splicing and
reply routing. Images sit next to the HTML as relative <img> links.

The viewer

python3 viewer/serve.py                # 127.0.0.1:8765
python3 viewer/serve.py --port 9000    # or REPORT_VIEWER_PORT=9000
  • GET / — index of live + archived reports.
  • GET /view/<rel> — serves the report and splices at view time: theme
    rewrite, .md path linkification, a fresh related-tasks block (markers
    <!-- related-tasks:start/end --> baked by the CLI), an injected reply box,
    rendered prompt cards, and Archive/Restore controls.
  • A live miss falls back to _archive/<rel> — old links and reply targets
    keep working after archiving (with an "archived" banner).
  • GET /md/<path> — allow-listed markdown rendered inside a sandboxed iframe
    (strict CSP).

Tasks

A minimal sqlite store at $REPORT_DIR/tasks.db (no daemon):

report task add myproj "Approve the deploy window" --link "$VIEW_URL" --blocking
report task list [myproj] [--all] [--json]
report task done 3

Linking a task to a report's view URL sorts it first in that report's
Related-tasks block.

How replies reach an agent session

Nothing executes in the viewer. Every reply is composed into a
self-describing message (task id / report title / view URL included) and
relayed:

  1. appended as one JSON line to $REPORT_DIR/replies.jsonl — the durable
    record, always written first;

  2. printed to the viewer's stdout; or

  3. piped on stdin to $REPORT_RELAY_CMD when set — e.g. straight into a
    tmux session:

    export REPORT_RELAY_CMD='tmux send-keys -t agent-session -l -- "$(cat)" \
        && tmux send-keys -t agent-session Enter'
    python3 viewer/serve.py
    

    (or xargs-style: REPORT_RELAY_CMD='xargs -0 -I{} tmux send-keys -t agent-session {} Enter')

Two origins exist and are recorded on every line:

  • human — the reply boxes: the user typed it; treat as their answer.
  • card — the "Do it" prompt cards: model-written text relayed verbatim.

Security notes

  • The viewer binds 127.0.0.1 by default and warns on any wider bind.
  • All POSTs are origin-checked (Origin/Sec-Fetch-Site must match the
    viewer or be absent, i.e. same-machine tools).
  • Every served path is validated against traversal/symlink escape; .md
    serving is restricted to $REPORT_DIR, REPORT_MD_ROOTS, and registered
    project roots; markdown renders in a sandboxed iframe with a strict CSP.
  • Reply POSTs use redirect:'error' and a server-side byte-count echo, so a
    redirected or truncated send fails visibly instead of delivering a
    silent/empty message.
  • Trust model: a reply-box message relays as the user — but it is still
    just text on a loopback page, so on a shared machine anything that can POST
    to localhost could fake one. The mitigation is receiver-side: a card
    (origin=card) is model-authored and must never trigger irreversible
    actions on its own
    , and even human replies should name the concrete
    action before a session treats them as authorization. replies.jsonl
    records every relay either way.

Configuration

Env var Default Purpose
REPORT_DIR ${XDG_DATA_HOME:-~/.local/share}/claude-reports report root (index, tasks.db, replies.jsonl, _archive/)
REPORT_THEME_DIR <repo>/themes aurora css location
REPORT_VIEWER_PORT 8765 viewer port
REPORT_VIEWER_URL http://127.0.0.1:$REPORT_VIEWER_PORT base for --open/--url/baked links
REPORT_BIND 127.0.0.1 viewer bind address
REPORT_RELAY_CMD (unset) shell cmd receiving each reply on stdin
REPORT_REPLIES_FILE $REPORT_DIR/replies.jsonl reply sink
REPORT_TASKS_DB $REPORT_DIR/tasks.db task store
REPORT_PROJECT (unset) default --project
REPORT_PROJECTS_FILE (unset) optional name→path JSON registry for project validation + bare .md resolution
REPORT_MD_ROOTS (unset) :-separated extra roots allowed for .md links

CLI reference

report --path --project P --title T --type {task-completion|research|audit|error-blocker|comparison} [--force]
report --open FILE [--force-open]     # viewer URL when the viewer is up, else file://
report --url FILE                     # print the viewer URL
report --template                     # print the themed template (theme path filled)
report --theme-dir                    # print resolved theme dir
report --list [--project P --type T --days N]
report --list --archived   (or: report list --archived)
report --index                        # rebuild index.json from disk
report archive <rel>                  # -> _archive/<rel>
report restore <rel>
report related-tasks P [--link URL] [--title T]
report next-prompts [prompt ...]      # argv or newline-separated stdin
report task add|list|done ...

Tests

python3 -m unittest discover tests

Covers path-traversal refusal, the relay file append, task add/reply,
archive/restore, prompt-card rendering, markdown serving, and POST origin
enforcement — all against a real server on an ephemeral port.

Author

Marcin Dudek — MIT (see LICENSE)

Reviews (0)

No results found