agentleFS
jamestexasjamestexas/agents/skills/repo-topic-tagger/SKILL.md

repo-topic-tagger

Skill2 starsChanged 6 months agoApache-2.0View on GitHub

Audit and apply GitHub topic tags for discoverability — proposes tags from code signals, deduplicates against current tags, applies via gh api after explicit approval. Sub-skill of repo-seo-curator.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If --dry-run (default): stop.

    line 132
  2. Very specific:

    If --apply: print "Apply these N topic changes?

    line 133
  3. Distinctive:

    One PR-equivalent per repo per pass: Don't bundle topic changes with description or README rewrites — those are separate skills.

    line 177

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md
<!-- Author: jamestexas — drafted by claude-opus-4-7 (2026-05-16) -->

/repo-topic-tagger — GitHub Topic Curation

Apply a curated, discoverability-optimized set of GitHub topics to one or more repositories.

Arguments

$ARGUMENTS

  • <owner/repo> — one or more target repos (e.g. agentic-research/mache). If omitted, defaults to the repo containing the current working directory.
  • --dry-run (default) — propose changes but do not apply. Always the default. The user must explicitly pass --apply to write.
  • --apply — after presenting the proposal, prompt for approval and call gh api to write the new topic set.
  • --max=N — cap proposed tag count at N (default 12; GitHub allows 20 max).

What this solves

Many of the user's public repos ship with zero topics. This kills discoverability:

  • They never surface in GitHub's topic browser (github.com/topics/<x>)
  • They never appear in "related repositories" cards
  • LLM-based repo discovery tools weight topic metadata heavily
  • Human searchers filtering by topic on GitHub never see them

Topics are cheap to set, never break anything, and compound over time as GitHub's index picks them up.

Reference: a good topic set

agentic-research/cloister is the canonical good example:

capnproto, cloudflare-workers, durable-objects, gateway,
hypervisor, mcp, model-context-protocol, rust, typescript, workerd

Why it works:

  • Language(s): rust, typescript
  • Framework / runtime: cloudflare-workers, workerd, durable-objects
  • Substrate / protocol: capnproto, mcp, model-context-protocol
  • Problem-space label: hypervisor, gateway

Ten tags, every one of them is something a real searcher would type.

GitHub topic rules (hard constraints)

The GitHub API will reject violations. Validate before submitting:

  • Lowercase only
  • Alphanumerics, hyphens, +, . allowed; no underscores, no spaces
  • Each topic ≤ 50 chars
  • ≤ 20 topics per repo
  • Convention: prefer hyphens (code-intelligence, not codeintelligence)

Workflow

Phase 1: Inventory

For each target repo:

gh repo view <owner/repo> --json name,description,repositoryTopics,visibility,isFork,isArchived,homepageUrl,primaryLanguage,languages

Skip with a printed reason if:

  • visibility != PUBLIC (unless user explicitly overrides)
  • isFork == true
  • isArchived == true

Phase 2: Signal gathering

For each remaining repo, collect signals from the codebase (use gh for remote; if a local clone is available, prefer reading files directly):

  1. Language metadata — primaryLanguage and the languages map. The top 1–3 languages are almost always topics.
  2. Package manifests — detect framework signals:
    • Cargo.toml → rust, plus notable deps (tokio, axum, serde, tree-sitter, wasmtime, …)
    • package.json → typescript or nodejs, plus framework deps (next, react, hono, workerd, vite, …)
    • go.mod → go, plus deps (cobra, bubbletea, cgo, tree-sitter, …)
    • pyproject.toml / requirements.txt → python, plus deps (fastapi, pytorch, transformers, …)
    • flake.nix / shell.nix → nix
    • Dockerfile / docker-compose.yml → docker
    • apko.yaml / melange.yaml → apko, chainguard
    • .github/workflows/* → CI signals (usually not topic-worthy alone)
  3. README + description — extract domain nouns. Look specifically for:
    • Protocol names (mcp, lsp, oauth, webauthn, cms, pkcs7)
    • System category (cli, tui, library, framework, daemon, mcp-server)
    • Problem-space (observability, vulnerability-scanning, code-intelligence, identity, signing, knowledge-graph)
  4. Project family / org context — the user's ecosystems. If repo is in agentic-research, propose agentic-research and art-ecosystem. If in jamestexas and references rosary/mache/ley-line, propose art-ecosystem.
  5. Existing topics — keep, don't fight. Only remove if actively misleading.

Phase 3: Proposal

Produce a structured proposal per repo:

## <owner/repo>

Description: <current description>
Current topics: <list or "(none)">

Proposed topics (N total):
  Language:   rust, typescript
  Framework:  cloudflare-workers, workerd, durable-objects
  Protocol:   capnproto, mcp, model-context-protocol
  Domain:     hypervisor, gateway
  Ecosystem:  agentic-research, art-ecosystem

Add:    [list]
Remove: [list, or "(none)"]
Keep:   [list]

Rationale: <1–2 sentences>

Rationale rules:

  • Add ≤ --max (default 12). Quality beats quantity.
  • Prefer canonical names — model-context-protocol over mcp-protocol, cloudflare-workers over cf-workers. Check https://github.com/topics/<x> exists if uncertain.
  • Avoid singletons that only describe this one repo. Topics are for finding kin.
  • Avoid promotional adjectives — no fast, modern, lightweight unless they're an established topic (high-performance is borderline; usually skip).

Phase 4: Approval

Print the full proposal across all in-scope repos. Then:

  • If --dry-run (default): stop. Output a hint that the user can re-run with --apply to write.
  • If --apply: print "Apply these N topic changes? (yes/no)" and wait. Only proceed on explicit affirmative.

Phase 5: Apply

For each approved repo:

gh api -X PUT "repos/<owner>/<repo>/topics" \
  -H "Accept: application/vnd.github.mercy-preview+json" \
  --input - <<EOF
{"names": ["tag1", "tag2", "..."]}
EOF

Or equivalently with field args:

gh api -X PUT "repos/<owner>/<repo>/topics" \
  -f "names[]=tag1" -f "names[]=tag2" ...

After each call:

  • Re-read with gh repo view <owner/repo> --json repositoryTopics to confirm
  • Report success or failure with the exact diff that landed

Phase 6: Report

End with a compact summary:

Applied:
  agentic-research/mache       — +8 topics, -0
  agentic-research/rosary      — +9 topics, -0
  jamestexas/agents            — +5 topics, -0
Skipped:
  agentic-research/x-ray       — empty repo, no signals to tag
  agentic-research/.github     — meta-repo, not user-facing
Deferred (no signals / needs human input):
  jamestexas/papers            — unclear scope

Important rules

  • Default to --dry-run. The user must explicitly opt in to writes. Topics are public and indexed by third parties.
  • One PR-equivalent per repo per pass. Don't bundle topic changes with description or README rewrites — those are separate skills.
  • Do not touch private repos unless the user explicitly names them. They get no discoverability benefit.
  • Do not touch forks or archived repos unless explicitly named.
  • If a repo has a working topic set (≥ 5 tags spanning ≥ 3 categories), leave it alone unless the user asked to revise it.
  • No emoji in topics. GitHub strips them silently and they're not searchable.

Examples

/repo-topic-tagger agentic-research/mache
→ dry-run proposal for mache only

/repo-topic-tagger agentic-research/mache agentic-research/rosary --apply
→ proposal for both, then prompts for approval, then writes

/repo-topic-tagger
→ uses current working directory's GitHub remote (derived via `gh repo view`)

Bulk mode (orgs)

For a whole-org sweep:

gh repo list <owner> --limit 100 --json name,visibility,isFork,isArchived,repositoryTopics \
  | jq -r '.[] | select(.visibility=="PUBLIC" and .isFork==false and .isArchived==false) | .name'

Iterate, but produce all proposals first, present them as a single document, and only apply after a single batched approval. Do not stream-apply.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.