DEV Community

Mirzalazuardi
Mirzalazuardi

Posted on

I Built a Bash Script That Traces Code Faster Than Your IDE (And Saves AI Tokens)

You're debugging a Rails app. The bug is somewhere in process_payment. You could:

A) Open your IDE, wait for LSP to index, click through 12 files.

B) Paste the whole service into ChatGPT. Hope it doesn't hallucinate the call graph.

C) Run one command:

codetracer process_payment . --mode flow --scope
Enter fullscreen mode Exit fullscreen mode

In under a second: where it's defined, every call site with enclosing method, every assignment, every place the return value goes — across all files.

I chose option C. So I built it.


What is codetracer?

A single-file bash script (~1400 lines) that traces symbols across Ruby and JavaScript/TypeScript codebases. No IDE, no LSP, no AI agent.

Requirements: bash 4+ (or zsh 5+) and ripgrep. That's it.

# Install
curl -fsSL https://raw.githubusercontent.com/mirzalazuardi/codetracer/main/codetracer.sh \
  -o /usr/local/bin/codetracer && chmod +x /usr/local/bin/codetracer
Enter fullscreen mode Exit fullscreen mode

The Killer Feature: Case-Variant Expansion

Type a symbol in any naming convention. codetracer finds all forms automatically:

Input: processPayment

Searches simultaneously:
  process_payment      (snake_case)
  PROCESS_PAYMENT      (SCREAMING_SNAKE)
  processPayment       (camelCase)
  ProcessPayment       (PascalCase)
  process-payment      (kebab-case)
Enter fullscreen mode Exit fullscreen mode

All these commands produce identical results:

codetracer process_payment
codetracer processPayment
codetracer ProcessPayment
Enter fullscreen mode Exit fullscreen mode

No more "I searched for process_payment but the JS file uses processPayment" moments.


Five Modes for Different Questions

1. Where is it defined?

codetracer PaymentService . --mode def
Enter fullscreen mode Exit fullscreen mode

Finds def, class, module, function, const =, async function, etc.

2. Who calls it?

codetracer send_email . --mode call --scope
Enter fullscreen mode Exit fullscreen mode

Every call site with full scope chain:

app/services/order_service.rb:42:    send_email(user, receipt)
  scope -> mod Billing > cls OrderService > def complete_order:38
Enter fullscreen mode Exit fullscreen mode

3. How does data flow?

codetracer current_user . --mode flow
Enter fullscreen mode Exit fullscreen mode

Tracks: assignments, passed as argument, returned/yielded, mutations.

4. Which files touch it?

codetracer stripe_key . --mode file
Enter fullscreen mode Exit fullscreen mode

File map with hit counts per file.

5. Everything at once

codetracer order_total . --mode full --scope
Enter fullscreen mode Exit fullscreen mode

NEW: Rails Route Tracing

Just shipped this week. Trace a route through the full request lifecycle:

codetracer --action "OrdersController#refund" ./app
Enter fullscreen mode Exit fullscreen mode

Output:

━━━ ROUTE TRACE: OrdersController#refund ━━━

OrdersController (app/controllers/orders_controller.rb)
├── before_action :authenticate_user!          :23  [ApplicationController]
├── before_action :set_order                   :8
├── def refund                                 :67
│   ├── params: :reason                        :68  [query]
│   ├── if @order.refundable?                  :69
│   │   ├── call: RefundService.call           :70
│   │   └── enqueue: RefundNotificationJob     :75  [async]
│   └── else                                   :77
│       └── render json: errors                :78
└── after_action :log_refund_attempt           :10
Enter fullscreen mode Exit fullscreen mode

Callbacks, conditionals, params access, service calls, Sidekiq jobs — all in one tree. Perfect for understanding unfamiliar Rails controllers or creating sequence diagrams.

Trace directly from your curl files

Got a directory of curl scripts for testing your API? Point codetracer at them:

# Your existing curl file
cat api_tests/refund.sh
Enter fullscreen mode Exit fullscreen mode
curl -X POST "http://localhost:3000/orders/123/refund?notify=true" \
  -H "Content-Type: application/json" \
  -d '{"reason": "damaged", "amount": 50.00}'
Enter fullscreen mode Exit fullscreen mode
# Trace it
codetracer --route api_tests/refund.sh ./app
Enter fullscreen mode Exit fullscreen mode

codetracer automatically:

  • Extracts the HTTP verb (POST) and path (/orders/:id/refund)
  • Converts numeric IDs to :id (123 → :id)
  • Extracts query params (notify) and JSON body keys (reason, amount)
  • Shows expected params in the trace output
Expected params from curl:
  query: notify
  body: reason amount

├── def refund
    ├── params: :reason    [query]  ← matches!
Enter fullscreen mode Exit fullscreen mode

No more wondering "does this endpoint actually use the params I'm sending?"


Why Not Just Use AI?

I use AI daily. But every question you ask about code structure — "where is this defined?", "who calls this?" — costs tokens, takes seconds, and might be wrong.

codetracer gives those answers instantly, deterministically, for free.

Save Tokens When You Do Use AI

Instead of pasting 500-line files, extract only what matters:

# Get 60 focused lines instead of 2000+ raw lines
codetracer process_payment . --mode flow --scope 2>&1 | head -60
Enter fullscreen mode Exit fullscreen mode

That's a 30x reduction in tokens.


The Scope Chain

This is my favorite feature. Every match shows its full nesting context:

codetracer process_payment . --mode call --scope
Enter fullscreen mode Exit fullscreen mode
fixture_payment_service.rb:40:        process_payment(order, order.amount)
  scope -> mod Billing:5 > cls PaymentService:6 > def batch_process:38 > blk each:39
Enter fullscreen mode Exit fullscreen mode

You instantly know: this call happens inside an each block, inside batch_process method, inside PaymentService class, inside Billing module.

No clicking through files. No mental stack tracing.


Works on macOS and Linux

Tested on:

  • macOS with bash 4+ or zsh 5+
  • Ubuntu/Debian
  • Arch Linux
# macOS
brew install ripgrep

# Ubuntu
sudo apt install ripgrep

# Optional: fzf for interactive mode, ctags for precise indexing
brew install fzf universal-ctags
Enter fullscreen mode Exit fullscreen mode

Interactive Mode with fzf

codetracer render . --inter
Enter fullscreen mode Exit fullscreen mode

Fuzzy-pick any match, preview context, press Enter to open in your editor.


Real Workflow Example

Debugging an unknown bug:

# 1. Where does this symbol exist?
codetracer process_payment . --mode file

# 2. Read the definition
codetracer process_payment . --mode def --ctags

# 3. Find callers and their context
codetracer process_payment . --mode call --scope

# 4. Trace data through the system
codetracer process_payment . --mode flow --scope --ctx 4
Enter fullscreen mode Exit fullscreen mode

Four commands. Full picture. No IDE required.


Try It

# One-liner install
curl -fsSL https://raw.githubusercontent.com/mirzalazuardi/codetracer/main/codetracer.sh \
  -o /usr/local/bin/codetracer && chmod +x /usr/local/bin/codetracer

# Try it
codetracer YourClassName ./your-project --mode def
Enter fullscreen mode Exit fullscreen mode

Links

GitHub: github.com/mirzalazuardi/codetracer

If this looks useful, I'd appreciate a star. And if you have feature requests or find bugs, issues and PRs are welcome.


Built for engineers who prefer a terminal over a GUI and a shell script over a language server.

Top comments (2)

Collapse
 
itskondrat profile image
Mykola Kondratiuk

this is clever. i have been burning tokens sending whole files to Claude when really i only need the relevant call chain. been doing poor mans version of this with grep/ctags but it is janky. the token savings argument alone sold me - context windows feel infinite until they suddenly arent and you are paying for it in latency and cost. will try this on a rails monolith i am working on, curious how it handles deep inheritance.

Collapse
 
devgab profile image
DevGab

The zero-setup portability is the most compelling angle here — being able to drop a single bash script into a bare Docker container or a CI runner where you can't install gems, language servers, or IDE tooling is a real use case. I've been in that situation before.

Curious whether you've tried pairing this with an LLM coding tool like Claude Code, which does similar structural searching (grep, glob, file reads) but with semantic understanding on top. I wonder if codetracer's deterministic output could be useful as a pre-filter — feeding its focused trace into an LLM prompt rather than raw files — or whether the LLM's own search tools make that redundant in practice?