kit/plugins/social-media-tools/skills/save-artifact/SKILL.md
Saves an HTML Artifact page to the local artifacts inbox. Copies a local .html or fetches a claude.ai artifact URL, scrubs, then publishes. Use when asked to save or share an artifact or its URL.
npx skillsauth add shawn-sandy/agentics save-artifactInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Copy an HTML Artifact page into the local artifacts inbox at .claude/artifacts/
under a dated filename, then publish it to the deployed artifacts gallery, so a
page you just built can be handed off and shared in one step.
Claude's Artifact tool produces self-contained HTML pages, but each lives only
in the chat session. This skill copies one into .claude/artifacts/ with a
<name>-YYYY-MM-DD.html filename, then runs plan-agent's
build-artifacts-index.sh to publish it into the deployed docs/artifacts/
tree and rebuild the standalone Artifacts gallery.
.claude/artifacts/ is a gitignored local inbox; the durable, committable copy
is the one published under docs/artifacts/ (which GitHub Pages serves). This
keeps saved artifacts out of the plans tree — they get their own gallery,
separate from implementation plans.
ExitPlanMode is a deferred tool. Only call it if currently in plan mode —
skip this step entirely when not in plan mode. When calling: use ToolSearch
with select:ExitPlanMode first, then call ExitPlanMode silently.
The source is the .html file to save. Resolve it in this order:
Artifact URL — if the user gave a https://claude.ai/code/artifact/<uuid>
URL, fetch it with WebFetch, prompt: "Return the page's raw HTML
verbatim." Use WebFetch and nothing else — a shell fetch such as curl
gets the SPA shell or a Cloudflare 403, because only WebFetch carries the
claude.ai login. Then:
[Artifact <uuid> "<title>" — ...]
header. Discard it, but keep the <uuid> and <title> — both are used
for the filename below.<!-- frame-runtime -->…<!-- /frame-runtime --> block in
<head>. It is claude.ai's iframe plumbing, not part of the artifact, and
it imports /_runtime/*.js paths that resolve on claude.ai and nowhere
else. Removing it is what makes the saved copy self-contained; keeping it
would also mean transcribing ~25 KB of minified script by hand.Write what remains — from <!doctype through </html> — to
<scratchpad>/<slug>.html. <slug> is the <title> kebab-cased; if the
page has no <title>, or the title is generic enough to collide (report,
untitled, demo), append the first 8 characters of the <uuid> so two
saved artifacts stay distinguishable in the gallery.Use that file as $SRC. A failed fetch does not look like an error. For
a deleted or unshared artifact you get a plain sentence
(artifact not found — it may have been deleted...), and for a malformed URL
WebFetch silently falls back to ordinary page-summary mode and answers in
prose. Neither contains <!doctype. Treat the absence of <!doctype as the
failure signal, say what happened, and stop — never save a partial page.
Explicit path — if the user gave a path to an .html file, use it.
In-chat artifact — if the artifact was just generated in this
conversation and does not exist on disk (the common "stash the artifact I
just built" case), materialize it first: Write the artifact's full HTML
to a temporary file (e.g. <scratchpad>/<slug>.html) and use that file as
the source.
Ask — otherwise, look for candidate .html files with
Glob (e.g. docs/**/*.html, *.html) and ask the user which to save via
AskUserQuestion. Never guess silently.
Store the resolved path as $SRC. If $SRC does not exist, tell the user and
stop.
Before copying anything, run the scrub on $SRC. Step 4 publishes into
docs/artifacts/, which the user commits and GitHub Pages serves publicly — a
secret in the page becomes a public secret.
Skill(skill: "social-media-tools:security-scrub", args: "Scan the file at $SRC for secrets before saving and publishing.")
Check the returned GATE RESULT line (the gate runs inside security-scrub):
GATE RESULT: BLOCKED or GATE RESULT: CANCELLED → STOP. Do not copy,
do not publish.GATE RESULT: APPROVED → proceed to Step 2.GATE RESULT → STOP and report an error (treat as
gate failure). Never fall through to the copy on an unread result.This gate matters most for the URL branch: a fetched artifact is remote content, and it need not be the user's own (claude.ai artifacts can be shared with an account), so nobody in this session has necessarily read the page before it is published.
The destination is a fixed local inbox, .claude/artifacts/, under the project
root. There is no plansDirectory lookup — artifacts no longer live in the plans
tree; the publish step (Step 4) copies them into docs/artifacts/.
DEST=".claude/artifacts"
mkdir -p "$DEST" || { echo "Error: could not create $DEST" >&2; exit 1; }
Paths are resolved relative to the current working directory, which is the
project root the skill is invoked from (same convention as the sibling
export-session skill).
SRC="<resolved source path>"
base=$(basename "$SRC" .html)
day=$(date +%F)
target="$DEST/${base}-${day}.html"
n=2
while [ -e "$target" ]; do
target="$DEST/${base}-${day}-${n}.html"
n=$((n + 1))
done
cp "$SRC" "$target" || { echo "Error: copy failed — nothing saved" >&2; exit 1; }
echo "Saved artifact → $target"
The copy above lands in the gitignored inbox and is not yet deployed. Run
plan-agent's build-artifacts-index.sh to copy every inbox artifact into the
committed docs/artifacts/ tree and rebuild docs/artifacts/index.html. This is
best-effort: the script always exits 0, and if plan-agent is not installed the
save still succeeds (the inbox copy is kept).
Locate the bundled script the same way setup-sites does (versioned cache,
direct install, or --plugin-dir load), then run it with the project root:
BUILD_ARTIFACTS=$( { \
find ~/.claude/plugins -path "*/plan-agent/*/hooks/build-artifacts-index.sh" -type f 2>/dev/null | sort -rV; \
find ~/.claude/plugins -path "*/plan-agent/hooks/build-artifacts-index.sh" -type f 2>/dev/null; \
find "$PWD" -path "*/plan-agent/hooks/build-artifacts-index.sh" -type f 2>/dev/null; \
} | head -1 )
if [ -n "$BUILD_ARTIFACTS" ]; then
bash "$BUILD_ARTIFACTS" "$PWD" && echo "Published artifact to docs/artifacts/"
else
echo "plan-agent not found — artifact saved to .claude/artifacts/ but not yet published"
fi
Tell the user the inbox path ($target) and the published copy under
docs/artifacts/. Remind them to commit the docs/artifacts/ changes (the
inbox itself is gitignored). Note whether the gallery was published (Step 4) or
plan-agent was not found and publishing still needs to run.
development
Checks whether the branch's PR is ready and merges it when green. Runs the readiness gate, lint, and an approval prompt. Use when the user asks "merge?" or if a PR is ready to merge.
development
Implements a plan file that already exists. Walks its steps, ticks the spec, re-renders, and runs the completion gates. Use when asked to implement an existing plan.
development
Audits and optimizes CLAUDE.md project memory files. Checks adherence to Claude Code best practices and produces actionable fixes. Use when the user asks to audit, optimize, or diagnose a CLAUDE.md.
development
Converts an HTML artifact or Markdown file into a draft post for a static site. Scopes CSS to keep interactive blocks alive and escapes prose for MDX. Use when asked to turn an artifact into a post.