Who needs a UI when you have a CLI and Agents? I built a CLI for Segment.
2,434 lines of TypeScript, 25 commands, and one feature that streams live events to your terminal
Who needs a UI when you have a CLI and Agents? I built a CLI for Segment.
2,434 lines of TypeScript, 25 commands, and one feature that streams live events to your terminal

In the continuity of my (quite successful!) post https://sderosiaux.substack.com/p/claude-code-told-me-what-tools-it, I realized that something, there is just no tool available for what you need, so just build it! This is the story of what happened.
Last week, someone on Slack asked which of our sources were sending events with schema violations. In the Segment dashboard, answering this means: open Protocols, check each tracking plan, cross-reference source IDs, then go back to Sources to find the names. For a workspace with 21 sources, 11 tracking plans, and 29 destinations, this takes about fifteen minutes of clicking.
With the CLI I built:
$ segment violations --json | jq '[.[] | .sourceName]'
["API Backend [Prod]", "My App [Prod]"]
Two seconds. Two sources. Done.
Yes, you could do this with curl and jq. You’d need to handle Bearer auth, cursor-based pagination (the violations endpoint paginates), and then make additional API calls to resolve source IDs to names. You could also write a Python script with Segment’s SDK. I tried both. After the third time I rewrote the same pagination loop, I figured I should just build a proper tool.
segment-cli is (was) a read-only command-line tool wrapping Segment’s Public API. 25+ read-only commands covering most of the API surface: sources, destinations, tracking plans, transformations, Reverse ETL, violations, delivery metrics, audit trail, event volume.
Who needs a UI when you have a CLI and Agents?
The gap
Segment has a very very light CLI but they provide REST endpoints, API docs, and client libraries for Node, Python, Go, and Java. I got tired of using their UI, too slow, too cumbersome. I have no time to lose.
I wanted kubectl-style access to my Segment workspace: type a command, get an answer. Combine with agentic workflows, done.
Design decisions
- Read-only. Our Segment workspace is production infrastructure at Conduktor. I didn’t want a tool that could accidentally disable a destination or modify a tracking plan. Every command is a GET request. The single exception is
sources tap, which creates and deletes a temporary webhook (more below). — edit: eventually, I’ve added non-readonly because YOLO. - Humans & JSON. Every command renders two ways: human-readable with formatting for the terminal, and json for structured output. Any output can be piped to
jqor consumed by a script (that agents will love), while still being readable when you’re just poking around. - Token-conscious. I use this CLI from inside Claude Code. An LLM agent’s context window is the real bottleneck: if a single API response eats 100K tokens, you’ve burned half your conversation on one command. Our full sources list comes back at 534KB from the Segment API. With
— compact, it’s about 5KB (just id, name, and enabled).— limit Ncaps the result count.— resolveswaps opaque UUIDs for human-readable names so the agent doesn’t need a second lookup. These flags exist because I realized the tool’s most frequent consumer wasn’t me, it was Claude.
I published the CLI as a Claude Code skill, which gives any agent the full command reference, flag documentation, and workflow patterns without reading source code
Just do this in your terminal or in Claude:
npx skills add sderosiaux/segment-cli
Bun, TypeScript, and two dependencies

Bun runs TypeScript directly. This matters for a CLI because startup time is noticeable: you feel the difference between 50ms and 300ms on every invocation.
A pain with segment is that endpoints aren’t consistent:
- some return data inside
{ data: { sources: […] } } - others use
{ data: { models: […] } }. - The audit endpoint returns
events, notauditEvents. - Reverse ETL returns
models, notreverseEtlModels. - The usage API returns
apiCallsas a string instead of a number. - Ingress delivery endpoints return 404 on the EU API.
- Schema-settings returns 404 on most sources.
You only learn these things by hitting the API and dealing with what comes back. That accumulated knowledge is the real value of wrapping an API in a CLI, not the wrapper itself.
Live event tap

One fun feature for agentic workflows was: segment sources tap <sourceId> streams real events to your terminal. To do this, the CLI adds a temporary callback in segment configuration.
$ segment sources tap xxxxxxxx
Tapping My App [Prod] (xxxxxxxx)
4:04:11 PM page app.dashboard.Viewed [1b52f875]
path=/dashboard title=My App
4:04:14 PM track app.feature.Used [f9957...]
feature=export format=csv
^C
Webhook destination deleted.
Total events received: 23
The mechanism:
- Start a local HTTP server on port 9876
- Spawn a cloudflared tunnel (free, no account required) to expose it publicly
- Create a temporary Webhooks (Actions) destination on Segment, pointed at the tunnel URL
- Events arrive as HTTP POSTs, displayed color-coded (green for track, blue for identify, cyan for page)
- Ctrl+C: delete the destination, kill the tunnel, stop the server
I used this last week to debug why a destination wasn’t receiving certain events. Turned out the source was sending page calls with a property we expected only on track calls. Seeing the raw payloads flow through made it obvious in about two minutes. In the dashboard, I would have been reading delivery logs and guessing.
cloudflared makes this possible. It creates a public tunnel with no config, no account, no DNS. I spawn it as a child process, parse the tunnel URL from its stderr output, and point Segment’s webhook there.
What I’d do differently
- Design
— jsonoutput first. I built the human formatters first, then retrofitted— jsonto 25+ commands. The structured output should be the source of truth, with the formatted view as a presentation layer. - Add Biome strict mode on commit one. I added it later on and Claude had to fix many things. Linting is Caring.
Was it worth it
The next time I need to check something in Segment, it takes a command and a couple of seconds. That’s what this project gives me.
The CLI became how Claude interacts with Segment.
If you use Segment: sderosiaux/segment-cli on GitHub, or npx skills add sderosiaux/segment-cli for Claude Code.
메타데이터
- post_id
- 65a5defa3ffb
- slug
- who-needs-a-ui-when-you-have-a-cli-and-agents-i-built-a-cli-for-segment-65a5defa3ffb
- url
- https://medium.com/@sderosiaux/who-needs-a-ui-when-you-have-a-cli-and-agents-i-built-a-cli-for-segment-65a5defa3ffb
- canonical_url
- https://medium.com/@sderosiaux/who-needs-a-ui-when-you-have-a-cli-and-agents-i-built-a-cli-for-segment-65a5defa3ffb
- author_url
- https://medium.com/@sderosiaux
- status
- ok
- fetched_at
- 2026-06-09 15:37:30