← the whole session plugin/skills/how-to-bulk-register-atomic-tools/SKILL.md

Bulk register API endpoints, functions, and skills as discoverable tools in an agent tooling registry, so agents can look things up instead of reinventing them.

How to Bulk Register Atomic Tools

The Problem This Solves

New endpoints/functions/skills get built but never registered anywhere agents can find them. Then an agent searches for "segment compare" (or whatever the capability actually does) and nothing surfaces, so it either reinvents the wheel or asks a human something the codebase already answers.

Prerequisite: what makes a tool findable

If you have a /how-to-register-and-describe-agent-tools skill (or similarly named), read it first. If you don't, here's the short version inline — a registered tool is only as useful as its description:

  • Write the description the way someone would actually ask for it ("compare two user segments"), not just the technical name (GET /segments/compare).
  • Add tags/keywords covering the workflow nouns a person or agent would search with, not only the implementation term.
  • Keep it current — a stale description (one that no longer matches what the code does) is worse than no entry at all, because it actively misleads whoever finds it. When you re-sync, overwrite the old description rather than appending to it.

Where the registry lives — pick one, and it works either way

  • If you've set up your own service for this (a database-backed registry with an admin UI and a sync script — see /alignment-harness:harness-setup), use that. The shapes below (tools: [...], proposedBy, status) carry over; only the URL and auth are yours to fill in.
  • Otherwise (the default, works with nothing extra installed): the harness keeps a local JSON registry. alignment-harness records tool-registry prints the folder; registry.json inside it is a plain array of tool entries. Everything below assumes this local file unless you say "if you have your own service."

Fast Path (Preferred): Route → Registry Sync

If you're registering endpoints that already have route-level docs (@route/@desc/@param comments, or your framework's equivalent), write a small script once for your project that reads those comments and calls the bulk-import step below — that's the same idea as a route-to-registry sync script, generalized to whatever doc-comment convention your code actually uses. This is the safest pattern because re-running it after route changes keeps the registry in sync instead of drifting from hand-maintained entries.

If you have your own service (example shape — replace URL and auth with your own):

curl -s -X POST "https://<your-api-server>/agent-tools/bulk-import/endpoints" \
  -H "x-api-key: $YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{ "tools": [ /* ... */ ], "proposedBy": "bulk-import" }'

Local fallback:

REGISTRY_DIR=$(alignment-harness records tool-registry)
mkdir -p "$REGISTRY_DIR"
node -e '
const fs = require("fs"), path = require("path");
const file = path.join(process.argv[2], "registry.json");
const incoming = JSON.parse(fs.readFileSync(process.argv[3], "utf8")); // { tools: [...], proposedBy }
let registry = [];
try { registry = JSON.parse(fs.readFileSync(file, "utf8")); } catch {}
const bySlug = new Map(registry.map((t) => [t.slug, t]));
for (const t of incoming.tools) {
  bySlug.set(t.slug, { ...t, status: t.status || "proposed", proposedBy: incoming.proposedBy, updatedAt: new Date().toISOString() }); // overwrite, never append-and-drift
}
fs.writeFileSync(file, JSON.stringify([...bySlug.values()], null, 2));
console.log(`Registered ${incoming.tools.length} tool(s) into ${file}`);
' "$REGISTRY_DIR" /path/to/your-tools.json

Each tool entry: { "slug", "title", "description", "tags": [...], "kind": "endpoint|function|skill", "sourcePath", "status": "proposed" }.

Approve in Batch (human step)

With your own service:

curl -s -X POST "https://<your-api-server>/agent-tools/batch/approve" \
  -H "x-api-key: $YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{ "slugs": ["tool-slug-1","tool-slug-2"] }'

Local fallback:

node -e '
const fs = require("fs"), path = require("path");
const file = path.join(process.argv[2], "registry.json");
const slugs = new Set(process.argv.slice(3));
const registry = JSON.parse(fs.readFileSync(file, "utf8"));
for (const t of registry) if (slugs.has(t.slug)) t.status = "approved";
fs.writeFileSync(file, JSON.stringify(registry, null, 2));
console.log("approved:", [...slugs].join(", "));
' "$REGISTRY_DIR" tool-slug-1 tool-slug-2

Discovery Loop (MANDATORY)

After importing, verify natural searches actually surface the tool. This step is the single most important one in this whole skill — an import that doesn't show up in a real search is worse than no import, because it looks done when it isn't.

With your own service:

curl -s "https://<your-api-server>/agent-tools/search?q=segment+compare" -H "x-api-key: $YOUR_API_KEY"

Local fallback (word-overlap scoring against title, description, and tags — no server needed):

node -e '
const fs = require("fs"), path = require("path");
const file = path.join(process.argv[2], "registry.json");
const query = process.argv.slice(3).join(" ").toLowerCase();
const words = query.split(/\s+/).filter(Boolean);
const registry = JSON.parse(fs.readFileSync(file, "utf8"));
const scored = registry.map((t) => {
  const hay = [t.title, t.description, ...(t.tags || [])].join(" ").toLowerCase();
  const score = words.filter((w) => hay.includes(w)).length;
  return { t, score };
}).filter((r) => r.score > 0).sort((a, b) => b.score - a.score);
console.log(JSON.stringify(scored.slice(0, 5).map((r) => ({ slug: r.t.slug, title: r.t.title, score: r.score })), null, 2));
' "$REGISTRY_DIR" "segment compare"

Try the natural phrases a person would actually use — not just the tool's exact name. If it doesn't surface:

  • Add tags that match how agents search (workflow nouns + natural phrasing)
  • Rewrite descriptions to include the key terms
  • Re-run the bulk-import step above — it overwrites by slug, so a corrected description replaces the stale one rather than piling up alongside it

Notes

  • Imports land as status: "proposed" and stay uncertain until approved — this is deliberate, don't auto-approve.
  • This registry is separate from whatever broader institutional-memory search you have set up (agent_find or your own equivalent — see /alignment-harness:harness-setup). If a capability matters broadly across sessions, note it there too, not only here.