ComposioHQ/logo-cdn is a public GitHub repo with more than 1,400 SVG files in it. Every Composio integration card renders from it — and so does every product built on top of Composio. AI agents, dashboards, customer apps: they all fetch from logos.composio.dev/api/{slug} and show the same logos.
When a new integration ships, the card is blank until the right SVG lands. Composio adds integrations agentically — the upstream pipeline is bots, not a human team — so the volume scales with whatever the bots shipped this week, not a fixed monthly cadence. I'm the only designer. There's no version of this where I keep up by hand.
Most of the requests landed as Slack pings. The #design channel was a slow drip of need logo / missing logo / can you fix this — same texture, scattered across weeks. Multiply by fifty a month and the backlog never quite emptied.
Eventually I put it in Linear, where each request had a state and the queue had a bottom. The manual flow was eight steps, five to ten minutes per logo. Then I built the agent, and now it takes about three seconds and the request doesn't reach me at all.
The agent is about 600 lines of TypeScript on a single Railway box, with no UI of its own. Below are the design decisions that got it to that shape.
The first version of this in my head had a dashboard — a queue, a Process button, a settings panel for the API keys. The obvious instinct, and a couple of weeks of work.
Every step of the manual flow was already happening in a tool the company already had open. The request lived in Linear. The merge lived in GitHub. The preview lived on the CDN. A dashboard would have been a fourth place to remember to look.
So I built no interface at all. The whole agent runs off events from Linear and writes back to Linear. There's nothing to click.
There's a Linear issue template called Logo Request with two fields — slug and (optional) website. Filling it is the entire human side of the workflow.

The agent listens for issue.created, pulls the URL out of the body, and gets to work — fetch, vectorise, PR, merge, comment. Whoever filed the ticket doesn't move the card or approve the PR. They file and forget.
The agent posts one comment on the issue and edits it in place as the work progresses. ✅ Favicon fetched → ✅ Vectorised to SVG → ⏳ Creating PR → ✅ done, merged. Failure uses the same comment with a red emoji. Same channel, same format — you trust the agent not because it never fails, but because you can always tell when it has, in the same place success would have been.
The favicon route is heuristics — scrape link tags, probe common paths, fall back to the Google Favicon API. Most of the time it picks something usable. When it doesn't, whoever filed the ticket drops a replacement into the same comment thread — a file attachment, a public image URL, or raw <svg> markup pasted into the body — and the agent reruns against that. The fix lives in the same place as the result; there's nowhere else to go.
Auto-merge. The agent owns its own PRs end-to-end. Squash merge, delete branch, no human review. Acceptable because every PR touches one SVG file under src/assets/ and the worst case is git revert.
Self-cleanup. Every comment the agent posts starts with Logo Agent. On rerun it finds and deletes its own old comments instead of stacking new ones.
SSRF filter. Anyone with comment access in the project could otherwise drop an internal URL and have the server fetch arbitrary endpoints. URLs are restricted to public IPs only.
Format pre-processing. ICO and WebP favicons get re-encoded through sharp before being sent to vectorizer.ai, which chokes on them otherwise.

Two things, really.
Every surface the agent uses is one the team already had open — the Linear ticket, the GitHub PR, the comment thread. The agent isn't a new product to learn; it's a thing that listens to gestures people were already making and answers them.
And failure is always visible in the same place success would have been. That symmetry is what builds trust over time. You start relying on the agent not because it never fails, but because you always know where things stand.
It also helps that the team is small and the project is trusted. Anyone with comment access can drop a URL into a thread and the agent will commit it into a public CDN. I would not ship this same shape against a codebase or a privileged API. The audit trail is borrowed from tools the team already trusts; that's also what limits where you can take it.

Eight steps for me became one ticket for whoever needed the logo. Five to ten minutes per logo became three seconds. There is no dashboard. The agent doesn't have a name; it has a place.
Built with Claude Code, Composio, vectorizer.ai, and sharp. Running on Railway.