Claude API CLI Tool for Developers: Build Your Own
What a Claude API CLI tool actually does
A Claude API CLI tool lets you send prompts, pipe files, and get completions without leaving the terminal. Instead of opening a browser tab or writing a full application, you call Claude from a shell script, a git hook, a CI pipeline, or a one-liner like cat error.log | claude "summarize this". For developers, that's the whole point: Claude becomes another Unix tool you compose with grep, jq, and xargs, not a separate app you context-switch into.
There isn't one official "Claude CLI" binary that covers every workflow, but building a reliable one is a 30-line shell script once you have an HTTPS API key and a JSON endpoint. This article walks through building that tool, what it needs to handle (streaming, tool use, auth), and how a service like SubToAPI gives you the API key and endpoint shape to make it work without managing your own proxy infrastructure.
Why developers want a CLI over a chat UI
- Scriptability — commit message generation, log summarization, code review comments, changelog drafts, all triggered from
package.jsonscripts or Makefiles. - Composability — pipe
git diffinto a prompt, pipe the output intopbcopyor a file, chain it withjqto extract fields. - CI/CD integration — run Claude as a step in GitHub Actions to lint PR descriptions or flag risky diffs.
- Speed — no UI load time, no copy-paste round trips between browser and editor.
If your team already lives in the terminal, a CLI tool removes the friction that stops people from actually using the API day to day.
Building a minimal CLI with curl and jq
The simplest version is a shell function. It takes a prompt as an argument, sends it to the Messages endpoint, and prints the text response.
claude() {
local prompt="$*"
curl -s https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "content-type: application/json" \
-d "$(jq -n --arg p "$prompt" '{
model: "claude-sonnet-4-5",
max_tokens: 1024,
messages: [{role: "user", content: $p}]
}')" | jq -r '.content[0].text'
}
Add that to your .bashrc or .zshrc, export SUBTOAPI_KEY, and you have:
claude "explain this regex: ^(?=.*[A-Z]).{8,}$"
That's a complete, working CLI tool. Everything else — streaming, file input, tool use — is an extension of this same pattern. See the quickstart and messages docs for the full request/response shape.
Piping files and context into the prompt
Most real usage isn't typing prompts inline — it's feeding Claude a file, a diff, or command output.
claude_review() {
local diff=$(git diff --cached)
curl -s https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "content-type: application/json" \
-d "$(jq -n --arg d "$diff" '{
model: "claude-sonnet-4-5",
max_tokens: 1024,
messages: [{role: "user", content: ("Review this staged diff for bugs and style issues:\n\n" + $d)}]
}')" | jq -r '.content[0].text'
}
Wire that into a pre-commit hook and you get an automated review step before every commit, no editor plugin required.
Adding streaming for long outputs
For anything longer than a short answer, streaming makes the CLI feel responsive instead of hanging for several seconds. With curl --no-buffer and a simple SSE parser you can print tokens as they arrive:
claude_stream() {
curl -N -s https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "content-type: application/json" \
-d "$(jq -n --arg p "$*" '{
model: "claude-sonnet-4-5",
max_tokens: 1024,
stream: true,
messages: [{role: "user", content: $p}]
}')" | grep --line-buffered '^data:' | sed 's/^data: //'
}
In a Node script you'd parse the same SSE stream with EventSource-style handling instead of grep. The streaming docs cover the exact event types (content_block_delta, message_stop, etc.) if you want to build a proper parser instead of a sed hack.
Calling tools from the command line
If your CLI needs Claude to run actions — fetch a ticket, query a database, hit an internal API — you pass tool definitions in the same request and handle the tool_use response in your script:
curl -s https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"tools": [{
"name": "get_ticket",
"description": "Fetch a Jira ticket by ID",
"input_schema": {
"type": "object",
"properties": {"id": {"type": "string"}},
"required": ["id"]
}
}],
"messages": [{"role": "user", "content": "What is the status of ticket DEV-412?"}]
}'
Your script checks the response for a tool_use block, runs the actual lookup, and sends the result back in a follow-up request. This is how you build a CLI that doesn't just summarize text but actually does things. Details on the schema are in the tools docs.
Packaging it properly
Once the shell function works, turn it into something your team can install:
- A single executable script in
/usr/local/bin/claude(bash, no dependencies beyondcurlandjq). - A small Node.js package published internally with
npxsupport if your team prefers JavaScript. - Config read from
~/.claudercfor default model, max tokens, and system prompt, so nobody hardcodes values.
Keep the API key out of the script itself — always read it from an environment variable or a secrets manager, never commit it.
Where SubToAPI fits
The CLI examples above all hit the same endpoint shape regardless of who manages the underlying access. SubToAPI turns your Claude access into a standard HTTPS API with sub_live_... keys, so the CLI tool you build works the same way whether one person uses it or a whole team does. You get streaming, tool use, and usage metadata out of the box, plus a dashboard to see which key (and which script or CI job) is making requests. Team and Scale plans add seats so each developer gets their own key without sharing credentials in a shared .env file. Start with a free trial and check the pricing page for Solo, Team, and Scale options.
questions
Do I need an official Claude CLI, or can I build my own? You can build your own in under an hour with curl and jq — there's no requirement to use a specific binary. Most teams end up with a custom script because it matches their exact workflow (git hooks, CI steps, internal tooling) better than a generic tool would.
Can a CLI tool handle streaming responses? Yes. The API returns server-sent events when you set stream: true. A CLI can parse these line by line and print tokens as they arrive instead of waiting for the full response, which matters for longer outputs.
How do I avoid hardcoding API keys in CLI scripts? Store the key in an environment variable (SUBTOAPI_KEY) or a secrets manager, and reference it in the script with $SUBTOAPI_KEY. Never commit keys to version control, and rotate them from your dashboard if a script leaks.