[+] [S] -6 points 8 months ago (6 children)

Waybar with Claude Code & Codex Usage Display

This guide shows how to configure Waybar (for Wayland/Hyprland) with live status displays for Claude Code and Codex. The modules show current usage and rate limits in real-time in the status bar.

📸 Example

Waybar displays two modules:

  • CC (Claude Code): Shows 5h-block status with progress bar
  • COD (Codex): Shows rate-limit status with progress bar

Example output:

CC 🕐2h45m  67% ████████░  │  COD 🕐4h12m  23% ██░░░░░░

🔧 Prerequisites

System

  • Waybar (for Wayland/Hyprland)
  • Linux (Arch Linux, Ubuntu, etc.)
  • Bash Shell
  • jq (JSON Processor)

Node.js Tools

One of the following package managers:

  • npx (comes with Node.js)
  • bunx (Bun)
  • pnpm

Claude Code & Codex Tools

  • ccusage: npm install -g ccusage or via npx ccusage
  • @ccusage/codex: npm install -g @ccusage/codex or via npx @ccusage/codex

📁 File Structure

~/.config/waybar/
├── config.jsonc              # Waybar main configuration
├── style.css                 # Waybar styling
└── scripts/
    ├── ccusage-statusline.sh    # Claude Code status script
    ├── codex-statusline.sh      # Codex status script
    └── api-config.sh (optional) # API configuration

📝 Step 1: Waybar Configuration

Open ~/.config/waybar/config.jsonc and add the two modules:

1.1 Add modules to modules-center

{
  "modules-center": [
    // ... other modules ...
    "custom/ccusage",
    "custom/codex-usage",
    // ... other modules ...
  ],

  // ... rest of config ...

  "custom/ccusage": {
    "exec": "~/.config/waybar/scripts/ccusage-statusline.sh",
    "interval": 300,
    "format": "{}",
    "tooltip-format": "ccusage daily + monthly totals (Claude Code)\nClick to refresh",
    "on-click": "~/.config/waybar/scripts/ccusage-statusline.sh"
  },

  "custom/codex-usage": {
    "exec": "~/.config/waybar/scripts/codex-statusline.sh",
    "interval": 300,
    "format": "{}",
    "tooltip-format": "ccusage codex daily + monthly totals\nClick to refresh",
    "on-click": "~/.config/waybar/scripts/codex-statusline.sh"
  }
}

Explanation:

  • exec: Path to the script that provides the data
  • interval: Update interval in seconds (300s = 5min)
  • format: Display format (here directly the script output)
  • on-click: Clicking triggers a manual script update

📝 Step 2: Waybar Styling

Add the styling for the modules in ~/.config/waybar/style.css:

#custom-ccusage {
  background-color: rgba(40, 42, 54, 0.8);
  padding: 4px 10px;
  margin: 2px 4px;
  border-radius: 8px;
  font-family: 'JetBrainsMono Nerd Font Mono';
  font-size: 11px;
  color: #ff6ac1;  /* Pink for Claude Code */
}

#custom-codex-usage {
  background-color: rgba(40, 42, 54, 0.8);
  padding: 4px 10px;
  margin: 2px 4px;
  border-radius: 8px;
  font-family: 'JetBrainsMono Nerd Font Mono';
  font-size: 11px;
  color: #6ef2d0;  /* Turquoise for Codex */
}

Customizations:

  • color: Text color (can be changed as desired)
  • font-family: Nerd Font for icons (install JetBrainsMono Nerd Font)
  • font-size: Adjust font size

📝 Step 3: Create Scripts

3.1 Create script directory

mkdir -p ~/.config/waybar/scripts
chmod +x ~/.config/waybar/scripts/*.sh

3.2 Claude Code Script

Create ~/.config/waybar/scripts/ccusage-statusline.sh:

#!/bin/bash

# Compact ccusage summary for Waybar (daily totals).

CONFIG_FILE="$HOME/.config/waybar/scripts/api-config.sh"
[ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE"

# Prefer explicitly set binary, then cached npx installs, then package runners.
choose_runner() {
  if [ -n "$CCUSAGE_BIN" ] && command -v "$CCUSAGE_BIN" >/dev/null 2>&1; then
    echo "$CCUSAGE_BIN"
    return
  fi

  # Reuse first cached npx install if present to avoid network lookups.
  CACHE_BIN=$(find "$HOME/.npm/_npx" -path '*/node_modules/.bin/ccusage' -maxdepth 5 -print -quit 2>/dev/null)
  if [ -n "$CACHE_BIN" ]; then
    echo "$CACHE_BIN"
    return
  fi

  if command -v ccusage >/dev/null 2>&1; then
    echo "ccusage"
    return
  fi
  if command -v bunx >/dev/null 2>&1; then
    echo "bunx ccusage@latest"
    return
  fi
  if command -v pnpm >/dev/null 2>&1; then
    echo "pnpm dlx ccusage"
    return
  fi
  if command -v npx >/dev/null 2>&1; then
    echo "npx --yes ccusage@latest"
    return
  fi
}

RUNNER=$(choose_runner)
[ -z "$RUNNER" ] && { echo "CC ?"; exit 0; }

# Run command with a timeout to avoid hanging on network fetches.
run_cmd() {
  local cmd=$1
  if command -v timeout >/dev/null 2>&1; then
    timeout 20s bash -lc "$cmd"
  else
    bash -lc "$cmd"
  fi
}

# Helper: call ccusage command and emit cost/tokens TSV.
get_totals() {
  local cmd=$1
  local json
  json=$(NO_COLOR=1 run_cmd "$RUNNER $cmd --json --offline" 2>/dev/null)
  if [ -z "$json" ]; then
    return 1
  fi
  printf '%s' "$json" | jq -r '(.totals.totalCost // .totals.costUSD // 0) as $c | (.totals.totalTokens // 0) as $t | [$c, $t] | @tsv' 2>/dev/null
}

format_tokens_short() {
  local tokens=$1
  if awk -v t="$tokens" 'BEGIN { exit (t >= 1000000000) ? 0 : 1 }'; then
    awk -v t="$tokens" 'BEGIN { printf("%.1fB", t/1000000000) }'
  elif awk -v t="$tokens" 'BEGIN { exit (t >= 1000000) ? 0 : 1 }'; then
    awk -v t="$tokens" 'BEGIN { printf("%.1fM", t/1000000) }'
  elif awk -v t="$tokens" 'BEGIN { exit (t >= 1000) ? 0 : 1 }'; then
    awk -v t="$tokens" 'BEGIN { printf("%.0fk", t/1000) }'
  else
    printf "%s" "$tokens"
  fi
}

build_progress_bar() {
  local percent=$1
  local segments=8
  local filled=$((percent * segments / 100))
  local empty=$((segments - filled))
  [ $filled -gt $segments ] && filled=$segments
  [ $empty -lt 0 ] && empty=0

  local bar=""
  for ((i = 0; i < filled; i++)); do bar+="█"; done
  for ((i = 0; i < empty; i++)); do bar+="░"; done
  printf "%s" "$bar"
}

block_progress() {
  # Show current active 5h billing block status
  local json
  json=$(NO_COLOR=1 run_cmd "$RUNNER blocks --json --offline" 2>/dev/null)
  if [ -z "$json" ]; then
    return 1
  fi

  # Extract active block info: cost, end time
  local block_info
  block_info=$(printf '%s' "$json" | jq -r '
    .blocks[]
    | select(.isActive == true and .isGap == false)
    | [.costUSD, .endTime, .tokenCounts.inputTokens + .tokenCounts.outputTokens] | @tsv
  ' 2>/dev/null) || return 1

  if [ -z "$block_info" ]; then
    # No active block, show "idle"
    printf "⏸ idle"
    return 0
  fi

  local cost end_time tokens
  read -r cost end_time tokens <<<"$block_info"

  # Estimate block limit: Claude Code typically allows ~$15-20 per 5h block
  # We'll use $15 as baseline (adjustable via CLAUDE_BLOCK_LIMIT_USD)
  local block_limit="${CLAUDE_BLOCK_LIMIT_USD:-15}"

  local percent
  percent=$(awk -v c="$cost" -v l="$block_limit" 'BEGIN { if (l <= 0) { print 0 } else { printf("%.0f", (c / l) * 100) } }') || percent=0
  [ -z "$percent" ] && percent=0
  [ "$percent" -gt 100 ] && percent=100
  [ "$percent" -lt 0 ] && percent=0

  # Calculate time remaining until block ends
  local now_epoch end_epoch time_remaining
  now_epoch=$(date +%s)
  end_epoch=$(date -d "$end_time" +%s 2>/dev/null)
  if [ -n "$end_epoch" ] && [ "$end_epoch" -gt "$now_epoch" ]; then
    time_remaining=$((end_epoch - now_epoch))
    local hours=$((time_remaining / 3600))
    local mins=$(( (time_remaining % 3600) / 60 ))
    local time_str="${hours}h${mins}m"
  else
    local time_str="ending"
  fi

  local bar
  bar=$(build_progress_bar "$percent")
  printf "🕐%s %3d%% %s" "$time_str" "$percent" "$bar"
}

format_line() {
  local label=$1
  local cost=$2
  printf "%s $%.2f" "$label" "$cost"
}

BLOCK_STATUS=$(block_progress)

if [ -z "$BLOCK_STATUS" ]; then
  echo "CC …"
  exit 0
fi

echo "CC $BLOCK_STATUS"

3.3 Codex Script

Create ~/.config/waybar/scripts/codex-statusline.sh:

#!/bin/bash

# Compact @ccusage/codex summary for Waybar (daily + monthly).

CONFIG_FILE="$HOME/.config/waybar/scripts/api-config.sh"
[ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE"

choose_runner() {
  # Explicit override.
  if [ -n "$CCUSAGE_CODEX_BIN" ] && command -v "$CCUSAGE_CODEX_BIN" >/dev/null 2>&1; then
    echo "$CCUSAGE_CODEX_BIN"
    return
  fi

  # Local install via npm prefix.
  LOCAL_BIN="$HOME/.local/share/ccusage-codex/node_modules/.bin/ccusage-codex"
  if [ -x "$LOCAL_BIN" ]; then
    echo "$LOCAL_BIN"
    return
  fi

  # Cached npx install.
  CACHE_BIN=$(find "$HOME/.npm/_npx" -path '*@ccusage/codex*/node_modules/.bin/codex' -maxdepth 5 -print -quit 2>/dev/null)
  [ -z "$CACHE_BIN" ] && CACHE_BIN=$(find "$HOME/.npm/_npx" -path '*@ccusage/codex*/node_modules/.bin/ccusage-codex' -maxdepth 5 -print -quit 2>/dev/null)
  if [ -n "$CACHE_BIN" ]; then
    echo "$CACHE_BIN"
    return
  fi

  if command -v bunx >/dev/null 2>&1; then
    echo "bunx @ccusage/codex@latest"
    return
  fi
  if command -v pnpm >/dev/null 2>&1; then
    echo "pnpm dlx @ccusage/codex"
    return
  fi
  if command -v npx >/dev/null 2>&1; then
    echo "npm_config_offline=true npx --yes @ccusage/codex@latest"
    return
  fi

  # Last resort: plain codex in PATH (may collide with other tools).
  if command -v codex >/dev/null 2>&1; then
    echo "codex"
    return
  fi
}

RUNNER=$(choose_runner)
[ -z "$RUNNER" ] && { echo "codex ?"; exit 0; }

run_cmd() {
  local cmd=$1
  if command -v timeout >/dev/null 2>&1; then
    timeout 20s bash -lc "$cmd"
  else
    bash -lc "$cmd"
  fi
}

get_totals() {
  local cmd=$1
  local json
  json=$(NO_COLOR=1 run_cmd "$RUNNER $cmd --json --offline" 2>/dev/null)
  if [ -z "$json" ]; then
    return 1
  fi
  printf '%s' "$json" | jq -r '(.totals.totalCost // .totals.costUSD // 0) as $c | (.totals.totalTokens // 0) as $t | [$c, $t] | @tsv' 2>/dev/null
}

format_tokens_short() {
  local tokens=$1
  if awk -v t="$tokens" 'BEGIN { exit (t >= 1000000000) ? 0 : 1 }'; then
    awk -v t="$tokens" 'BEGIN { printf("%.1fB", t/1000000000) }'
  elif awk -v t="$tokens" 'BEGIN { exit (t >= 1
  • source
  • submitted 11 months ago* (last edited 11 months ago) by to c/magictcg@lemmy.world
     

    Hi everyone,

    I’ve built a lightweight MTG Arena Deck Builder as a side project and would love some feedback – especially around the deck generation logic and any bugs or feature ideas you might have!

    👉 https://mtg-arena-deck-builder.web.app/ 💡 What it offers:

    🧱 Deck building UI: Easily add/remove cards by name or quantity
    
    🔍 Search by card name, set code or type (basic auto-complete included)
    
    📤 Export to MTGA import format with 1 click
    
    📦 Deck generation based on mana curve, colors & land ratio (still experimental – needs feedback!)
    
    ⚠️ Deck weakness analysis – highlights color imbalances, mana issues, and missing curve components
    
    💾 Optional login (via Google) to save decks – no requirement to use the core features
    
    📱 Works great on both mobile & desktop (PWA support)
    

    🧪 Still in early development

    The deck auto-generation feature still needs balancing and better heuristics – all input is welcome!
    
    I'm also looking for ideas for new features or any bugs you run into while testing.
    

    If you play MTGA or just enjoy building decks, I'd be super happy to hear what you think.

    Thanks & enjoy brewing!

     

    Hey everyone! I’d love to share my latest hobby project: Dota Player Rating 🚀

    What is it? A Progressive Web App that lets Dota 2 players rate and discover amazing teammates while fighting toxicity through community-based reviews. But here’s the exciting part - it’s fully integrated with the Fediverse! 🐘

    🌐 Fediverse Features (The Cool Part!) Our automated Mastodon Community Bot brings the gaming community directly into the Fediverse: 📊 Daily Updates (8:00 PM) - Community stats, top players, positive gaming highlights 🌟 Weekly MVP Posts (Sundays) - Celebrating the week’s best teammates and reviews 🎉 Milestone Celebrations - Automatic posts when we hit 100, 500, 1000+ reviews 🤝 Community Building - Real engagement in the decentralized social web

    🛠️ Built for Learning I’m just a hobbyist, not a professional developer - this is purely a learning project! I chose: GitHub Pages for free hosting and learning deployment Firebase to understand modern backend services Vanilla JavaScript to really understand the fundamentals PWA technology because I wanted to learn about offline-first apps

    ⭐ Core Features Multi-category player ratings (teamwork, communication, skill, behavior) Steam ID integration via OpenDota API Real-time analytics and community stats Progressive Web App (installable on mobile!) Admin panel for community moderation

    🎯 Mission Help create positive gaming experiences by highlighting great players and reducing toxic behavior through transparency and community accountability.

    🌍 Open Source & Community-Driven Everything is completely open source and built with the community in mind. The Fediverse integration ensures we’re not locked into any single platform - we’re part of the decentralized web! Try it out: https://hendkai.github.io/dota-player-rating/ Would love feedback from fellow developers and gamers! How do you think we could improve Fediverse integration in gaming communities?

     

    Hey everyone! I’d love to share my latest hobby project: Dota Player Rating 🚀

    What is it? A Progressive Web App that lets Dota 2 players rate and discover amazing teammates while fighting toxicity through community-based reviews. But here’s the exciting part - it’s fully integrated with the Fediverse! 🐘

    🌐 Fediverse Features (The Cool Part!) Our automated Mastodon Community Bot brings the gaming community directly into the Fediverse: 📊 Daily Updates (8:00 PM) - Community stats, top players, positive gaming highlights 🌟 Weekly MVP Posts (Sundays) - Celebrating the week’s best teammates and reviews 🎉 Milestone Celebrations - Automatic posts when we hit 100, 500, 1000+ reviews 🤝 Community Building - Real engagement in the decentralized social web

    🛠️ Built for Learning I’m just a hobbyist, not a professional developer - this is purely a learning project! I chose: GitHub Pages for free hosting and learning deployment Firebase to understand modern backend services Vanilla JavaScript to really understand the fundamentals PWA technology because I wanted to learn about offline-first apps

    ⭐ Core Features Multi-category player ratings (teamwork, communication, skill, behavior) Steam ID integration via OpenDota API Real-time analytics and community stats Progressive Web App (installable on mobile!) Admin panel for community moderation

    🎯 Mission Help create positive gaming experiences by highlighting great players and reducing toxic behavior through transparency and community accountability.

    🌍 Open Source & Community-Driven Everything is completely open source and built with the community in mind. The Fediverse integration ensures we’re not locked into any single platform - we’re part of the decentralized web! Try it out: https://hendkai.github.io/dota-player-rating/ Would love feedback from fellow developers and gamers! How do you think we could improve Fediverse integration in gaming communities?

     

    Hey everyone! I'd love to share my latest hobby project: Dota Player Rating 🚀

    What is it? A Progressive Web App that lets Dota 2 players rate and discover amazing teammates while fighting toxicity through community-based reviews. But here's the exciting part - it's fully integrated with the Fediverse! 🐘

    🌐 Fediverse Features (The Cool Part!) Our automated Mastodon Community Bot brings the gaming community directly into the Fediverse: 📊 Daily Updates (8:00 PM) - Community stats, top players, positive gaming highlights 🌟 Weekly MVP Posts (Sundays) - Celebrating the week's best teammates and reviews 🎉 Milestone Celebrations - Automatic posts when we hit 100, 500, 1000+ reviews 🤝 Community Building - Real engagement in the decentralized social web

    🛠️ Built for Learning I'm just a hobbyist, not a professional developer - this is purely a learning project! I chose: GitHub Pages for free hosting and learning deployment Firebase to understand modern backend services Vanilla JavaScript to really understand the fundamentals PWA technology because I wanted to learn about offline-first apps

    ⭐ Core Features Multi-category player ratings (teamwork, communication, skill, behavior) Steam ID integration via OpenDota API Real-time analytics and community stats Progressive Web App (installable on mobile!) Admin panel for community moderation

    🎯 Mission Help create positive gaming experiences by highlighting great players and reducing toxic behavior through transparency and community accountability.

    🌍 Open Source & Community-Driven Everything is completely open source and built with the community in mind. The Fediverse integration ensures we're not locked into any single platform - we're part of the decentralized web! Try it out: https://hendkai.github.io/dota-player-rating/ Would love feedback from fellow developers and gamers! How do you think we could improve Fediverse integration in gaming communities?

    submitted 2 years ago* (last edited 2 years ago) by to c/warhammer40k@lemmy.world
     

    Hello people,

    Im new in the Warhammer 40 000 Universe. My wife has one set of this coloring pencil sets. Im not good at drawing but my idea was to fill out some pictures while my kids also draw. Do you know a good quality source for coloring book? What do you think about creating coloring pictures with ai?

    submitted 2 years ago* (last edited 2 years ago) by to c/linux@lemmy.ml
     

    Would it be possible to have a linux DE with that high quality like macOS? The last 3 years i did a lot of distro hopping. Im really Happy with gnome and ubuntu now ( reason was the rocm Installation script for my 7900xtx). Currently i donate whenever i use a Software more frequent. So i also would pay for a such good Look like on an iMac from my wife. Currently i use 4k Resolution and coloring settings with my spyder color camera. Edit: Im talking about sharpness of font rendering

    Final Edit: I switched from ubuntu to cachy os with native KDE: The soltuion is really nice so thanks for the community feedback!

     

    I want to access i2p on my vps without a always connected ssh tunnel. to tried to configure the client.config according to this: https://geti2p.net/en/faq "Configuring your console to be available on a Public IP address with a username & password

    Open ~/.i2p/clients.config and replace
    
                    clientApp.0.args=7657 ::1,127.0.0.1 ./webapps/
              
    
    with
    
                    clientApp.0.args=7657 ::1,127.0.0.1,(System_IP) ./webapps/
              
    
    where you replace (System_IP) with your system's public IP address
    Go to http://localhost:7657/configui and add a console username and password if desired - Adding a username & password is highly recommended to secure your I2P console from tampering, which could lead to de-anonymization.
    Go to http://localhost:7657/index and hit "Graceful restart", which restarts the JVM and reloads the client applications
    

    After that fires up, you should now be able to reach your console remotely. Load the router console at http://(System_IP):7657 and you will be prompted for the username and password you specified in step 2 above if your browser supports the authentication popup. NOTE: You can specify 0.0.0.0 in the above configuration. This specifies an interface, not a network or netmask. 0.0.0.0 means "bind to all interfaces", so it can be reachable on 127.0.0.1:7657 as well as any LAN/WAN IP. Be careful when using this option as the console will be available on ALL addresses configured on your system." Is this possible or do i missunderstood something? i want to use yunohost with redirect to redirect fom 127.0.0.1:7657 to my domainexample routersubdomain.mydomain.com. Is this even possible? Setting clientApp.0.args=7657 ::1,127.0.0.1,(System_IP) ./webapps/ wont work for me. I guess its a chain of misstakes i do :S

    view more: next ›