agentsclimarketplace

Shelf save

Skill Ranveersingh1113/shelf-skills/skills/shelf-save

Save links, articles, documents, or screenshots into the user's tool library as searchable notes. USE THIS whenever the user says "process my inbox", "save this", "save these links", "ingest my newsletter links", "add to my tool library", "/shelf-save", "file these", "keep this for later" — or pastes a batch of URLs, pastes article or newsletter text, or hands over a PDF, doc, or screenshot with any intent to keep it. A URL is only the common case; pasted text and uploaded files are first-class inputs, and are the right answer whenever a link is paywalled, login-walled, or a tracking redirect. Also use when the user mentions their inbox.md, their tool library, or newsletter links piling up. Writes one note per thing, dedupes, rebuilds the index.From its SKILL.md

Install
npx -y skills add Ranveersingh1113/shelf-skills --skill shelf-save

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 22 days oldThe repository was created 22 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

12.4 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it

shelf-save

Turn raw URLs into a searchable tool library of markdown notes.

Tools are named by what they do, with the Claude Code name in brackets. Use whatever your harness calls the equivalent.

Step 0 — find the library (always do this first)

Read ~/.tool-library-path (in the user's home directory). It holds one line: the library folder. Call it <LIB> below.

If it exists, use that path.

If it's missing, this is a first run:

  1. Ask: "Where should your tool library live? Give me a folder path — an Obsidian vault subfolder works, or any normal folder."
  2. Write their answer as a single line to ~/.tool-library-path. Use forward slashes even on Windows.
  3. Create this structure under it, then tell the user the full path you created and what goes where — they'll need to find it without you.
<LIB>/
├── inbox.md            # user dumps URLs and pasted text here
├── upload_documents/   # user drops PDFs, docs, screenshots here
├── _processed.md       # append-only archive; dedupe source of truth
├── _index.md           # auto-generated, grouped by category
└── notes/              # one file per tool

_processed.md starts with a | date | source | table header. inbox.md starts with this comment, verbatim:

<!--
Dump here. No formatting, no thinking.

  URLs        one per line
  Articles    paste the text, as messy as you like
  Documents   drop the file in the upload_documents/ folder next to this file

Then say "process my inbox".

Paste the text whenever a link won't load — paywalls, logins, newsletter
tracking redirects. It makes a better note than fetching would.

Everything that works becomes a note and leaves this file. Anything that
fails stays behind under a "Failed" heading.
-->

Never create or touch anything outside <LIB>.

Inputs — a URL is only the common case

Anything that carries the content works. Same note schema, same folder, every time. Never turn one of these away or ask the user to find a link instead.

InputWhat to do
URLFetch it [WebFetch]. The default path.
Pasted text — an article, an email, a newsletter body, release notesRead it as given. Do not fetch anything. Set source: paste.
A file — PDF, docx, markdown, txt, a saved pageRead the file directly. Set source: file and record the filename in the Notes section. Read the whole document, not the first page.
A screenshot or imageRead the image. Set source: screenshot. If text in it is unreadable, say which parts you couldn't make out rather than guessing.

Each arrives one of two ways — in chat ("save this: …", or handing over a file path), or dropped in the library for later, which is the point of the inbox and needs no session open:

  • Text → pasted straight into inbox.md, no syntax required.
  • Files → dropped into <LIB>/upload_documents/. Any format. Filename doesn't matter.

confidence: high for all of these — you saw the real content, which is a stronger source than a fetched page, not a weaker one.

Paste beats a dead link. Many URLs can't be fetched: newsletter tracking redirects, paywalls, login walls, JS-only pages, PDFs behind a CDN. When a link fails, tell the user the fix is to open it themselves and paste the text or drop the file in. That's a first-class path, not a workaround.

A document may hold several things worth saving. A conference PDF or a newsletter issue can cover five tools. Write one note per thing, not one note per file. If it's really a single work — a paper, a spec, a long essay — that's one note, category: reading or research.

Longer documents get more room. The schema is a floor, not a ceiling. For a paper or a spec, keep the frontmatter exactly as specified, then write as much in the body as the thing deserves — arguments, findings, numbers, caveats. A ## Key points section is a good addition here. The problem_solved rule never relaxes: still one sentence, still the user's problem.

Run

If the user handed you content directly (paste, file, or image), skip to step 5 — build the note from what they gave you. Steps 1–4 are for the inbox. Still do steps 6–9 so it's archived and indexed like anything else. For a paste or file with no URL, put unknown in the url: field.

  1. Read <LIB>/inbox.md and collect two kinds of item, ignoring the comment header and anything under the ## Failed heading:

    • URLs — any line starting with http, on its own line.
    • Pasted text — everything else. Use judgment about where one item ends and the next begins. Do not split on blank lines — a real pasted article is full of them, and splitting on them would shred one article into dozens of fake notes. Read the content: one coherent piece of writing is one item, however long. Two obviously unrelated pieces are two items. A --- on its own line, if the user bothers to add one, is an explicit separator you should honour.
    • URLs inside a pasted article are part of that article, not separate items. Only treat a URL as its own item when it stands alone.
  2. List <LIB>/upload_documents/ if it exists. Every file there is an item.

  3. Read <LIB>/_processed.md. Drop anything already listed — by URL, by (pasted) <title>, or by filename. Count the drops.

    Compare URLs with tracking parameters stripped, not as literal strings. Newsletter links arrive carrying utm_*, ref, dub_id, mid, cid and similar, and the same article forwarded twice will have different ones — a literal match sees two URLs and writes two notes for one thing. Strip the tracking params, drop any trailing #fragment, ignore a trailing slash, and compare what's left. Store the clean URL in _processed.md and in the note's url: field, so the archive stays comparable over time.

  4. Announce what you found, broken down by kind: "Found 3 links, 2 pasted items, 1 file (4 already processed). Processing now." The breakdown matters — it's the user's chance to catch a stray note-to-self that got read as an item, before any notes are written. Then go. Do not ask for per-item approval.

  5. Process in batches of 5. For each item:

    • URL → fetch the page [WebFetch]. Pasted text → read it as given. File → read the file.
    • Extract into the schema below.
    • List <LIB>/notes/*.md [Glob] and check for a near-duplicate by title. If one exists, update it instead of creating a second file, and say so in the summary.
    • Write <LIB>/notes/<kebab-case-name>.md.
  6. Append each success to the _processed.md table as | YYYY-MM-DD | x |, where x is the URL, (pasted) <title>, or (file) <filename>.

  7. Clear inbox.md — carefully. This is the one destructive step in the run.

    Re-read inbox.md in full immediately before writing it. The user may have pasted more into it while you were processing — runs take minutes, and dumping into the inbox is a thing they do without thinking. Then write back: the header, anything in the re-read that you did not just process, and the failures under ## Failed — retry or add manually. A clean run with nothing newly added leaves it empty apart from the header.

    If a write to inbox.md fails with a "file has been modified" error, that is not a stale handle — it means the user just edited the file. Re-read the whole file, never a truncated view, and diff it against what you collected in step 1 before writing anything. Content you never saw is content you are about to destroy.

    Processed files in <LIB>/upload_documents/ stay where they are — never delete a source file. They're skipped on the next run because _processed.md has their filenames. Tell the user they can clear the folder themselves whenever they like.

  8. Regenerate _index.md — read every note's frontmatter, group by category, one line each: - [[note-name]] — <problem_solved>.

  9. Summarize: saved / updated / skipped-duplicate / failed. Flag every note that landed in category: other — those need a human decision.

Note schema

Exactly this, at <LIB>/notes/<kebab-case-name>.md:

---
title: Resend
url: https://resend.com
source: inbox
date_saved: 2026-07-22
category: dev-tool
problem_solved: Sending transactional email from an app without deliverability headaches
pricing: Free tier 3k emails/mo; paid from $20/mo
maturity: stable
confidence: high
tags: [email, api, backend, saas]
---
## What it is

Two to three sentences, plain language. What it actually does.

## Use this when

- Concrete situation 1
- Concrete situation 2

## Don't use this when

- Concrete situation where it's the wrong choice

## Notes

Anything else worth remembering — alternatives, gotchas, integrations.

problem_solved — get this right, nothing else matters as much

This is the field shelf-find matches on. A bad one makes the note invisible forever.

Write the user's problem, not the product's feature list. Phrase it as the situation they'd be in, in their words, not the vendor's marketing.

  • Good: Sending transactional email without fighting deliverability
  • Bad: A modern email API for developers — that answers "what is this". Retrieval asks "what do I need right now".

One sentence. No product name in it.

Other fields

fieldrule
categoryexactly one of dev-tool ai-agent marketing design data fundraising ops research reading. No fit → other, and flag it in the summary. This list is the user's to change — it's a starting set, not a fixed taxonomy. If they want a category added or removed, edit it here and in shelf-find; recall goes blind to any category only one file knows about.
sourceinbox | paste | file | screenshot — where the content came from.
urlthe source URL. unknown for a paste or file with no link.
maturityexperimental | stable | enterprise
confidencehigh if fetched and parsed clean. low if it came from fallback search, paywall, or JS-blocked page.
tags3–6 lowercase keywords. Reuse existing tags over inventing near-synonyms — auth/authentication/authn as three tags means three partial matches instead of one good one. Check first by searching the notes for existing tags: lines.
pricingwrite unknown if not findable. Do not guess.

Never invent facts. Any field you can't determine: unknown.

Failures

  • Paywall / 403 / JS-only: fall back to a web search [WebSearch] on the page title or domain. Build the note from that, set confidence: low, and put this at the top of the note body: > [!warning] Fetched indirectly — verify before relying on this.
  • Total failure (search turns up nothing usable): leave the URL in inbox.md under the failed heading. Never write a hallucinated note. When reporting failures, tell the user they can open the link themselves and paste the text, or drop the file in — that always works and produces a better note than a fetch would have. Newsletter tracking redirects and CDN-hosted PDFs fail this way constantly; they are not worth retrying.
  • Never delete a note. Never clear _processed.md.
  • Note already exists and you're updating it: preserve the original date_saved, overwrite the rest.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,537. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.