Install
openclaw skills install @globalcaos/tinker-backlink-auditDiscover all inbound links (backlinks) to a domain, subdomain, or GitHub repo, then classify each as "ours" (we created/control the source) vs "organic" (someone else). Use when the user asks to find/audit backlinks or inbound links to a site, check who links to a domain or a GitHub repo, separate self-made links from organic ones, or refresh an inbound-links graph. Wraps four sources (GitHub repo referrers, a list of URLs you found, the backlinks.sh Common-Crawl API, and a Google Search Console CSV export) behind one classify-and-report CLI. Two of the four need no account at all; the one optional API key is stored in your OS keychain and cleared by --logout. Built for the TinkerClaw fork — github.com/globalcaos/tinkerclaw. See Permissions, Data Flow & Consent.
openclaw skills install @globalcaos/tinker-backlink-auditOne of dozens of skills and plugins in TinkerClaw — a self-improving OpenClaw fork that's been running 24/7 for months.
Who actually links to you — and how much of that did you build yourself?
Every backlink report you can buy gives you one number. That number is two very different things added together: links strangers made because your work was worth linking, and links you made because you were doing your own marketing. The first is traction. The second is homework. A tool that adds them up is telling you a flattering lie.
This one separates them. You get ours, organic, and an honest ambiguous bucket for the cases a hostname genuinely cannot settle — because a link from github.com might be your comment or a stranger's, and pretending otherwise is how a growth chart starts lying to you.
Two of the four sources need no account and no key. The one that does keeps it in your OS keychain — or refuses to store it at all, rather than dropping an API key into a file in the clear — and hands you a --logout that actually removes it.
Finding inbound links and telling "ours" from "organic" is two jobs: (1) get a link list from a real index, (2) match each source against surfaces you control. This skill does both via scripts/backlink-audit.mjs and an editable allowlist.
S=~/.openclaw/workspace/skills/backlink-audit/scripts/backlink-audit.mjs
# GitHub repo (works now — no extra auth; referrers, not raw backlinks)
node "$S" globalcaos/tinkerclaw --source github
# Discovered links (poor-man's backlink finder, works now): web-search the target
# term yourself, collect referring URLs, classify them — best source at small scale
node "$S" globalcaos/tinkerclaw --source urls --urls "https://a.com/x,https://b.com/y"
# Any owned domain via backlinks.sh (needs a key; 3 free calls, then ~$0.01/call)
BACKLINKS_SH_API_KEY=… node "$S" thetinkerzone.com --source backlinks --json
# Owned site, authoritative + free: export GSC Links→Top linking sites to CSV, then
node "$S" sprintpaper.com --source gsc-csv --csv ./gsc-export.csv
# Feed the Inbound-links pulse graph for one target:
node "$S" globalcaos/tinkerclaw --source github --write-state --target-key tinkerclaw
Storing the one optional credential, and taking it back:
printf %s "$BACKLINKS_SH_API_KEY" | node "$S" --login # → OS keychain (stdin, never argv)
node "$S" --logout # → clears the keychain (and any legacy file)
| Target | Source | Auth | Cost | Notes |
|---|---|---|---|---|
| GitHub repo | github | none (gh) | free | referrers/traffic proxy, repo-scoped |
| Anything | urls | none | free | classify a list of links you found (e.g. via web search); works now, best at small scale |
| Owned domain, one-shot | backlinks | backlinks.sh API key | 3 free calls, then ~$0.01/call | Common-Crawl backlink list |
| Owned domain, authoritative | gsc-csv | a CSV export (no OAuth) | free | Google's own link report |
Read references/sources.md before picking — it has the auth setup, the backlinks.sh signup/limits, how to export the GSC CSV, and the per-source caveats.
Edit assets/ours-allowlist.json. A link is ours if its source host (+ optional path_prefix) matches a rule; hosts listed in ambiguous_domains with no resolving path-rule are reported ambiguous (e.g. a github.com link could be a comment you wrote or a stranger's — resolve it by hand, then pin the resolved URL in ours_urls); everything else is organic. Keep the allowlist current as new owned surfaces appear.
The shipped allowlist is the author's, kept as a worked example of the rule shapes. Replace the domains with yours.
--write-state --target-key <key> writes inbound_targets.<key>.{external,ours} into inbound-campaign-state.json; the control-panel pollers render it (solid=external, dashed=ours, one hue per target). Ambiguous links are excluded from the written counts. Without --write-state the tool writes nothing at all — it just prints.
At small scale, crawl indexes (backlinks.sh/Common Crawl) return ~0 for new sites, so the search strategy is the workhorse. To count inbound links to a target:
"github.com/globalcaos/tinkerclaw", tinkerclaw, "thetinkerzone.com", plus site: excluded variants to find third-party mentions.node scripts/backlink-audit.mjs <target> --source urls --urls "u1,u2,…" → ours/organic/ambiguous counts.--write-state --target-key <k> to push the count to the graph.scripts/build-history.mjs writes dated cumulative ours observations so the graph shows real growth, not just today. Its dataset is derived (not invented) from:
gh api repos/<r>/issues/<n>/comments, filter by your login, body contains your URL → dated by each thread's first backlink-bearing comment (one thread = one linking page).git log -S "<domain>" in the linking repo → when an outbound link to your site (e.g. README→yourdomain.com) first went live.Re-derive by re-running those two mines, updating SERIES in the script, and re-running it.
Two things to know before you run it. The SERIES in the file is the author's dataset, shipped as a worked example of the shape and the provenance discipline — replace it with yours or your graph will show someone else's history. And it is opt-in: bare (or with --dry-run) it prints exactly what it would write and writes nothing; --yes is what actually sends the points to your control-panel store.
Short version: this reads public link data, classifies it against a list you edit, and prints the result. Two of its four sources never touch the network. The one credential it can use is optional, keychain-first, and revocable. Longer version, because you should not have to take that on trust:
What data it touches. Referring URLs — from the GitHub traffic API, from a list you paste, from a CSV you exported, or from backlinks.sh. Plus the allowlist you edit. That is the whole input surface. It does not read your repos, your mail, your browser, your shell history or your source tree.
What leaves your machine. Only what the source you picked requires:
--source urls and --source gsc-csv: nothing. Fully offline; the CSV is parsed locally.--source github: the gh CLI you already authenticated calls api.github.com for your repo's referrer list.--source backlinks: one HTTPS GET to https://api.backlinks.sh/v1/backlinks?target=<domain> with your API key in an x-api-key header. The URL is a constant in the script, not something the target string can redirect.There is no telemetry, no analytics, no "phone home", and no other endpoint anywhere in the code.
What it costs. Nothing, except --source backlinks: backlinks.sh gives 3 free calls, then charges roughly $0.01 per call. Every other source is free. Nothing subscribes you to anything.
What credentials it reads. One, optional: your backlinks.sh API key, and only for --source backlinks. There are exactly two places it can come from — BACKLINKS_SH_API_KEY (transient, nothing on disk) or your OS keychain (secret-tool on Linux, security on macOS; service backlinks-sh, account api-key).
There is no plaintext fallback, by design. An earlier version wrote the key to ~/.config/backlinks-sh/credentials.json when no keychain was present, warning on every use. A warning is not a control: the thing it warned about was still a long-lived API key sitting in the clear, readable by anything running as you. Now --login refuses when there is no keychain and writes nothing, telling you to install libsecret or pass the key per-run through the environment. If an older version left a file behind, it is detected and explained — so you learn why your key stopped working — but it is never read as a credential, and --logout still deletes it.
--login reads the key from stdin, never from argv, because argv is visible in ps. That now holds on both platforms: macOS security add-generic-password -w <key> would have put the key in an argv element, so the key is piped to security -i instead and the entry is verified by reading it back (-i exits 0 even when a command inside it fails).
The off switch. node scripts/backlink-audit.mjs --logout clears the keychain entry and deletes any legacy plaintext file, tells you which of the two actually existed, and reminds you if BACKLINKS_SH_API_KEY is still set in your environment (it cannot reach into your shell to unset it). Local removal does not revoke the key server-side — rotate or delete it in your backlinks.sh account at https://backlinks.sh.
What it needs, and why.
| Capability | Why | Scope |
|---|---|---|
| Network | Fetch the link list | api.backlinks.sh (constant URL) and api.github.com via gh — only for those two sources |
| Local shell exec | gh, secret-tool/security, openclaw | argv arrays, no shell interpreter, no string interpolation |
| Env read | BACKLINKS_SH_API_KEY | that one variable; no env file is sourced |
| Credential read | backlinks.sh API key | env var or OS keychain only — no file fallback; sent only to api.backlinks.sh |
| File read | Allowlist, your --csv / --urls-file, the credentials file, the state file | the paths you name, plus those two fixed ones |
| File write | --write-state state file; build-history.mjs --yes | both are opt-in; nothing is written on a plain run, and no credential is ever written to disk |
| File delete | --logout removes the credentials file | that single path — no recursive or glob delete exists in the skill |
The consent steps, and what each is protecting you from:
node "$S" <target> --source urls --urls "…" # reads nothing, writes nothing, sends nothing
node "$S" <target> --source backlinks # spends a paid API call, sends your key
node "$S" <target> --source github --write-state --target-key k # writes one JSON file under ~/.openclaw
node scripts/build-history.mjs # DRY RUN — prints what it would write
node scripts/build-history.mjs --yes # actually writes to your control-panel store
node "$S" --logout # removes the stored key
Read it before you run it. scripts/backlink-audit.mjs is ~250 lines of plain Node and scripts/build-history.mjs about 90. Every claim above is visible in them. That is the whole security model: short enough to audit over a coffee.
ambiguous bucket is a real answer, not a failure. A hostname alone cannot tell your comment from a stranger's; resolving it takes a human, and the tool refuses to guess in your favour.Part of TinkerClaw — real-time token tracking, self-improving crons, persistent cognitive memory. This is one piece of that stack; the repo has dozens more.
👉 https://github.com/globalcaos/tinkerclaw
Clone it. Fork it. Break it. Make it yours.