Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions docs/GTM-LAUNCH-COPY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Launch copy β€” drafts

Ready-to-post drafts for the coordinated launch. **Post Show HN + Reddit + Twitter the same morning** (US Eastern Tue–Thu, 8–10am) so the day's traffic stacks into GitHub Trending. Edit in your own voice before posting β€” authenticity outperforms polish.

**Red lines:** never ask for upvotes (auto-flag/ban on HN + Reddit). Never buy stars. Reply to every comment for the first few hours β€” engagement is the ranking signal.

---

## 1. Show HN

**Title** (≀80 chars, no hype/caps, no trailing period):
```
Show HN: TakoAPI – One API to discover and call any AI agent (A2A directory)
```

**Body** (the text field β€” or paste as your first comment right after posting):
```
Hi HN β€” I built TakoAPI, an open directory + unified gateway for AI agents.

The problem: the agent-to-agent (A2A) space is fragmenting fast β€” every agent
has its own endpoint, auth, and card format, and there's no neutral place to
discover them or call them uniformly. It feels like the pre-npm, pre-OpenRouter
moment for agents.

TakoAPI is two things:

- Directory β€” hosted A2A agents (described by open AgentCards) alongside
thousands of open-source agent projects. Browsable, plus a registry API:
`GET /api/registry` returns the whole catalog as Markdown or JSON (handy to
paste straight into an LLM).
- Gateway β€” call any hosted agent through one API: A2A passthrough, SSE
streaming, and an OpenAI-compatible /v1/chat/completions shim, metered per key.

It also installs into coding agents (Claude Code, Codex, OpenCode) with one
command, and runs as a hosted MCP server (search_agents, invoke_agent, …).

Live: https://takoapi.com β€” open source (MIT): https://github.com/oratis/TakoAPI
Stack: Next.js + Postgres/Prisma on Cloud Run.

Honest status: early. The directory is real (dozens of hosted agents + thousands
of indexed projects), the gateway + per-key metering work, prepaid credits are
live. Two-sided payouts and smart routing across agents are next.

I'd love feedback on two things especially: (1) the directory model β€” is a
neutral catalog useful, or does everyone just want their own storefront? and
(2) the A2A-vs-MCP framing β€” where do you see the line?
```

---

## 2. Reddit β€” r/AI_Agents, r/LocalLLaMA, r/LLMDevs

Read each sub's rules first; some require a flair or ban links in the title. Lead with the problem, not the product.

**Title:**
```
I built an open directory + gateway for AI agents (A2A) β€” one API to discover and call any agent
```

**Body:**
```
The A2A ("agent-to-agent") ecosystem is growing fast but there's no neutral
place to *find* agents or call them the same way β€” every one has its own
endpoint, auth, and card format.

So I built TakoAPI (open source, MIT):
- a directory of hosted A2A agents + thousands of open-source agent projects
- a gateway that calls any hosted agent through one API (A2A, SSE streaming, or
an OpenAI-compatible endpoint), metered per key
- a registry API that dumps the whole catalog as Markdown/JSON for LLMs
- one-command install into Claude Code / Codex / OpenCode, and an MCP server

It's live at takoapi.com. It's early and I'm looking for blunt feedback:
what would make a neutral agent directory actually useful to you β€” or is this a
problem you don't have yet? What's missing?
```

---

## 3. Twitter / X β€” thread

```
1/ The AI-agent world has an npm problem: hundreds of agents, no shared place to
discover them and no common way to call them.

So I built TakoAPI β€” one open API to discover and call any AI agent. πŸ™
https://takoapi.com

2/ It's a directory: hosted A2A agents (open AgentCards) + thousands of
open-source agent projects, all browsable β€” plus a registry API that returns
the whole catalog as Markdown you can paste into an LLM.

3/ And a gateway: call any hosted agent through one API β€” A2A passthrough, SSE
streaming, or an OpenAI-compatible /v1/chat/completions shim. Metered per key.

4/ Bonus: one-command install into Claude Code / Codex / OpenCode, and it runs
as a hosted MCP server (search_agents, get_agent, invoke_agent).

5/ Open source (MIT), built on Next.js + Postgres, live on Cloud Run.
Early days β€” I'd love your feedback on the directory model.
⭐ https://github.com/oratis/TakoAPI
```

---

## Posting checklist
- [ ] README polished, repo has a clear description + topics (ai-agents, a2a, llm, openrouter, mcp)
- [ ] Analytics + Search Console live (so you can measure the spike)
- [ ] Screenshot/OG image looks right when the link unfurls
- [ ] Free to browse with no signup wall on the landing path
- [ ] You have ~3 hours free after posting to reply to every comment
- [ ] Show HN + top Reddit + Twitter fired within the same 1–2 hour window
106 changes: 106 additions & 0 deletions scripts/badge-adoption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* Badge adoption report for the "Listed on TakoAPI" campaign. Two signals:
*
* 1) Outreach funnel β€” reads scripts/notify-ledger.json and checks each opened
* PR's live state (merged / open / closed) via the GitHub API.
* 2) Footprint β€” GitHub code-search for repos whose README links back to the
* directory (takoapi.com/agents, or the /api/badge endpoint).
*
* NOTE: GitHub serves README images through its camo proxy (referer stripped +
* cached), so per-repo attribution from badge *renders* is impossible β€” code
* search is the reliable adoption measure. Run periodically to track the campaign.
*
* npx tsx scripts/badge-adoption.ts
*
* Auth: `gh auth token` (falls back to GITHUB_TOKEN).
*/
import { execSync } from "node:child_process";
import { readFileSync, existsSync } from "node:fs";
import { join } from "node:path";

const LEDGER = join(process.cwd(), "scripts", "notify-ledger.json");

const TOKEN = (() => {
try {
return execSync("gh auth token", { encoding: "utf8" }).trim();
} catch {
if (process.env.GITHUB_TOKEN) return process.env.GITHUB_TOKEN;
console.error("Need a GitHub token: run `gh auth login` or set GITHUB_TOKEN.");
process.exit(1);
}
})();

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

async function gh<T = unknown>(path: string): Promise<{ status: number; data: T }> {
const url = path.startsWith("http") ? path : `https://api.github.com${path}`;
const res = await fetch(url, {
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${TOKEN}`,
"User-Agent": "takoapi-badge-adoption",
"X-GitHub-Api-Version": "2022-11-28",
},
});
const data = (await res.json().catch(() => null)) as T;
return { status: res.status, data };
}

async function ledgerFunnel() {
console.log("── outreach funnel (from ledger) ──");
if (!existsSync(LEDGER)) {
console.log("no ledger yet β€” run `notify-listed-repos.ts --send` first.\n");
return;
}
const led = JSON.parse(readFileSync(LEDGER, "utf8")) as {
repos: Record<string, { slug: string; status: string; prUrl?: string; date: string }>;
};
const entries = Object.entries(led.repos);
const opened = entries.filter(([, e]) => e.status === "pr-opened" && e.prUrl);
console.log(`ledger entries: ${entries.length} | PRs opened: ${opened.length}`);

let merged = 0,
open = 0,
closed = 0;
for (const [repo, e] of opened) {
const m = e.prUrl!.match(/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/);
if (!m) continue;
const pr = await gh(`/repos/${m[1]}/${m[2]}/pulls/${m[3]}`);
if (pr.status === 200) {
const state = pr.data.merged_at ? "merged" : pr.data.state;
if (state === "merged") merged++;
else if (state === "open") open++;
else closed++;
console.log(` ${repo.padEnd(40)} ${state}`);
}
await sleep(300);
}
console.log(`\n merged: ${merged} | still open: ${open} | closed w/o merge: ${closed}`);
}

async function footprint() {
console.log("\n── footprint (GitHub code search) ──");
const queries = ['"takoapi.com/agents"', '"takoapi.com/api/badge"'];
const repos = new Set<string>();
for (const q of queries) {
const res = await gh(`/search/code?q=${encodeURIComponent(q)}&per_page=100`);
if (res.status !== 200) {
console.log(` ${q} β†’ HTTP ${res.status} ${res.data?.message || ""}`);
await sleep(6000);
continue;
}
console.log(` ${q}: ${res.data.total_count} code hits`);
for (const it of res.data.items || []) repos.add(it.repository.full_name);
await sleep(6000); // code search is limited to ~10 req/min
}
console.log(`\n distinct repos linking back: ${repos.size}`);
for (const r of [...repos].sort()) console.log(` ${r}`);
}

(async () => {
await ledgerFunnel();
await footprint();
})().catch((e) => {
console.error(e);
process.exitCode = 1;
});
Loading