Can token-saving tools cut a GPT-6 Astra bill? I ran the same tasks four ways and priced every run

Five coding questions, GPT-6 Astra with a bash tool. Each one run with no tool, with RTK, with Headroom, and with both; three times each, 60 sessions, all 60 answers correct. The only thing that changed between setups was what the model saw.

What I found: the model's own choice of commands moved the bill more than either tool did. RTK's one clear win was a multi-file grep.
No tool$0.154 17,061 tokens billedRTK$0.139 16,318 tokens billedHeadroom$0.158 16,631 tokens billedBoth$0.175 19,012 tokens billed
No tool
$0.154 · 17,061 tokens
RTK
$0.139 · 16,318 tokens
Headroom
$0.158 · 16,631 tokens
Both
$0.175 · 19,012 tokens

Total cost of the five tasks per setup, mean of three runs. Green lowest, orange highest; with three runs per cell the order between the middle two can still flip on a re-run.

Every task, every setup

TaskNo toolruns 1, 2, 3RTKruns 1, 2, 3Headroomruns 1, 2, 3Bothruns 1, 2, 3
Which file defines the CLI enum, how many variantsgrep + read one file$0.049$0.043$0.035$0.057$0.055$0.037$0.034$0.074$0.024$0.074$0.067$0.055
Show all 12 runs: every command and answer
No tool · run 1 · 4 turns · $0.049
  1. rg -n 'enum Commands' .10 tokens seen
  2. sed -n '1,260p' src/main.rs2,008 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,|$)',s,re.M) print(len(v));print(v) PY322 tokens seen
Astra answered `src/main.rs` — 86 variants. correct
No tool · run 2 · 5 turns · $0.043
  1. rg -n 'enum Commands' .10 tokens seen
  2. sed -n '85,260p' src/main.rs1,339 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] # enum variants are four-space indented, stop at closing enum brace s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v));print(v) PY322 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] d=1; lines=[] for l in s.splitlines(): if d==1 and re.match(r' [A-Z]\w*\s*(?:\{|\(|,)',l): lines.append(l.strip()) d+=l.count('{')-l.count('}') if d==0: break print(len(lines)) print('\n'.join(lines)) PY236 tokens seen
Astra answered `src/main.rs` — 86 variants. correct
No tool · run 3 · 5 turns · $0.035
  1. rg -n 'enum Commands' .10 tokens seen
  2. sed -n '1,260p' src/main.rs2,008 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] # enum ends at unindented closing brace s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z][A-Za-z0-9_]*)\s*(?:\{|\(|,)',s,re.M) print(len(v)) print(' '.join(v)) PY142 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v)) print(' '.join(v)) PY142 tokens seen
Astra answered `src/main.rs` — 86 variants. correct
RTK · run 1 · 5 turns · $0.057
  1. rg -n 'enum Commands' .48 tokens seen
  2. sed -n '65,240p' src/main.rs1,385 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] d=1 lines=[] for line in s.splitlines(): if d==1 and re.match(r' [A-Z]\w*\s*(?:\{|\(|,|$)',line): lines.append(line.strip()) # exclude comments and strings for braces t=re.sub(r'"(?:\\.|[^"\\])*"','""',line.split('///')[0]) d+=t.count('{')-t.count('}') if d==0:break print('\n'.join(lines));print('COUNT',len(lines)) PY238 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v)) print(', '.join(v)) PY227 tokens seen
Astra answered `src/main.rs` — 86 variants. correct
RTK · run 2 · 5 turns · $0.055
  1. rg -n 'enum Commands' .48 tokens seen
  2. sed -n '65,240p' src/main.rs1,385 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] d=1 lines=[] for l in s.splitlines(): if d==1 and re.match(r' [A-Z]\w*\s*[{,(]',l): lines.append(l.strip()) d+=l.count('{')-l.count('}') if d==0:break print('\n'.join(lines));print('COUNT',len(lines)) PY238 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] # variant declarations are indented one level s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|,|\()',s,re.M) print('src/main.rs',len(v)) PY6 tokens seen
Astra answered src/main.rs — 86 variants. correct
RTK · run 3 · 7 turns · $0.037
  1. rg -n 'enum Commands' .48 tokens seen
  2. sed -n '65,240p' src/main.rs1,385 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] d=1 lines=[] for l in s.splitlines(): if d==1 and re.match(r' [A-Z]\w*\s*(?:[({,]|$)',l): lines.append(l.strip()) d+=l.count('{')-l.count('}') if d==0: break print('\n'.join(lines));print('COUNT',len(lines)) PY238 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v)) PY2 tokens seen
  5. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] depth=1; variants=[] for line in s.splitlines(): if depth==1: m=re.match(r' ([A-Z]\w*)\s*(?:\{|\(|,)',line) if m: variants.append(m[1]) depth+=line.count('{')-line.count('}') if depth==0: break print('src/main.rs',len(variants)) PY6 tokens seen
  6. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] depth=1 variants=[] for line in s.splitlines(): if depth==1: m=re.match(r' ([A-Z]\w*)\s*(?:\{|\(|,)',line) if m: variants.append(m[1]) depth+=line.count('{')-line.count('}') if depth==0: break print('src/main.rs',len(variants)) PY6 tokens seen
Astra answered src/main.rs 86 correct
Headroom · run 1 · 4 turns · $0.034
  1. rg -n 'enum Commands' .10 tokens seen
  2. sed -n '65,230p' src/main.rs1,316 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] d=1; lines=[] for l in s.splitlines(): if d==1 and re.match(r' [A-Z]\w*\s*(?:\{|\(|,)',l): lines.append(l.strip()) d+=l.count('{')-l.count('}') if d==0: break print(len(lines));print('\n'.join(lines)) PY236 tokens seen
Astra answered `src/main.rs` — 86 variants. correct
Headroom · run 2 · 5 turns · $0.074
  1. rg -n 'enum Commands' .10 tokens seen
  2. sed -n '1,260p' src/main.rs2,008 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1].split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v));print(', '.join(v)) PY227 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1].split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v)) print(', '.join(v)) PY227 tokens seen
Astra answered `src/main.rs` — 86 variants. correct
Headroom · run 3 · 4 turns · $0.024
  1. rg -n 'enum Commands' .10 tokens seen
  2. sed -n '65,230p' src/main.rs1,316 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] # enum variants are indented exactly four spaces s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\b',s,re.M) print(len(v));print(v) PY322 tokens seen
Astra answered `src/main.rs` — 86 variants. correct
Both · run 1 · 6 turns · $0.074
  1. rg -n 'enum Commands' .48 tokens seen
  2. sed -n '65,240p' src/main.rs1,385 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] d=1 lines=[] for line in s.splitlines(): if d==1 and re.match(r' [A-Z]\w*\s*(?:\{|\(|,)',line): lines.append(line.strip()) d+=line.count('{')-line.count('}') if d==0: break print('\n'.join(lines)) print('COUNT',len(lines)) PY238 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] depth=1 variants=[] for line in s.splitlines(): if depth==1: m=re.match(r' ([A-Z]\w*)\s*(?:\{|\(|,)',line) if m: variants.append(m.group(1)) depth+=line.count('{')-line.count('}') if depth==0:break print('src/main.rs',len(variants)) PY6 tokens seen
  5. sed -n '/^enum Commands {/,/^}/p' src/main.rs | grep -E '^ [A-Z][A-Za-z0-9_]*([ {,(]|$)' | wc -l2 tokens seen
Astra answered src/main.rs — 86 variants. correct
Both · run 2 · 7 turns · $0.067
  1. rg -n 'enum Commands' .48 tokens seen
  2. sed -n '65,240p' src/main.rs1,385 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] depth=1 out=[] for line in s.splitlines(): if depth==1: m=re.match(r' ([A-Z]\w*)\b',line) if m: out.append(m.group(1)) depth+=line.count('{')-line.count('}') if depth==0: break print(len(out));print(out) PY322 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1].split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v)) PY2 tokens seen
  5. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] depth=1; lines=[] for l in s.splitlines(): if depth==1 and re.match(r'^ [A-Z]\w*\s*(?:\{|\(|,)',l): lines.append(l.strip()) depth+=l.count('{')-l.count('}') if depth==0:break print(len(lines)) PY2 tokens seen
  6. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] d=1; lines=[] for l in s.splitlines(): if d==1 and re.match(r' [A-Z]\w*(?:\s*[{(,]|\s*$)',l): lines.append(l.strip()) d+=l.count('{')-l.count('}') if d==0: break print('src/main.rs',len(lines)) PY6 tokens seen
Astra answered src/main.rs 86 correct
Both · run 3 · 5 turns · $0.055
  1. rg -n 'enum Commands' .48 tokens seen
  2. sed -n '70,240p' src/main.rs1,367 tokens seen
  3. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print(len(v)); print('\n'.join(v)) PY236 tokens seen
  4. python3 - <<'PY' import re s=open('src/main.rs').read().split('enum Commands {',1)[1] s=s.split('\n}',1)[0] v=re.findall(r'^ ([A-Z]\w*)\s*(?:\{|\(|,)',s,re.M) print('src/main.rs',len(v)) PY6 tokens seen
Astra answered src/main.rs — 86 variants. correct
Which SQLite table does `rtk gain` read, where is the path setscoped grep over three paths$0.123$0.066$0.094$0.042$0.060$0.055$0.121$0.123$0.051$0.110$0.090$0.061
Show all 12 runs: every command and answer
No tool · run 1 · 6 turns · $0.123
  1. rg -n 'gain|CREATE TABLE' src | head -651,509 tokens seen
  2. rg -n 'commands|db_path|tracking.db|rtk.db' src/core/tracking.rs | head -45; rg -n 'Tracker|tracking' src/analytics/gain.rs | head819 tokens seen
  3. sed -n '65,110p' src/core/tracking.rs338 tokens seen
  4. rg -n 'fn.*path|HISTORY_DB|data_dir' src/core/tracking.rs src/core/constants.rs370 tokens seen
  5. sed -n '1492,1517p' src/core/tracking.rs; head -5 src/core/constants.rs343 tokens seen
Astra answered SQLite table: `commands` Database location defined in: `src/core/tracking.rs` (`get_db_path()`). correct
No tool · run 2 · 4 turns · $0.066
  1. rg 'gain' src -l | head; rg 'CREATE TABLE|\.db|sqlite' src -n | head -701,750 tokens seen
  2. sed -n '70,110p' src/core/tracking.rs; rg -n 'FROM commands|Tracker|tracking' src/analytics/gain.rs | head; rg -n 'history.db|fn.*path' src/core/tracking.rs | head679 tokens seen
  3. sed -n '1492,1528p' src/core/tracking.rs; sed -n '822,848p' src/core/tracking.rs667 tokens seen
Astra answered - SQLite table: `commands` - Database location defined in: `src/core/tracking.rs` (`get_db_path()`) correct
No tool · run 3 · 5 turns · $0.094
  1. rg 'gain' src -l; rg 'CREATE TABLE|\.db|\.sqlite' src1,298 tokens seen
  2. rg -n 'FROM commands|fn.*db_path|HISTORY_DB|database_path' src/core/tracking.rs | head -25; rg -n 'Tracker|tracking|get_stats' src/analytics/* | head -201,010 tokens seen
  3. rg -n 'fn.*path|HISTORY_DB|RTK_DATA_DIR' src/core/tracking.rs249 tokens seen
  4. sed -n '1492,1517p' src/core/tracking.rs273 tokens seen
Astra answered - SQLite table: `commands` - Database location defined in: `src/core/tracking.rs` (`get_db_path()`) correct
RTK · run 1 · 4 turns · $0.042
  1. rg 'rtk gain|CREATE TABLE|\.db' src -n | head -801,623 tokens seen
  2. rg -n 'fn.*path|HISTORY_DB|FROM commands' src/core/tracking.rs | head -20; sed -n '75,110p' src/core/tracking.rs599 tokens seen
  3. rg -n 'fn.*db_path|HISTORY_DB|data_dir' src/core/tracking.rs; cat src/core/constants.rs | head -12327 tokens seen
Astra answered `rtk gain` reads savings data from the SQLite **`commands`** table. The database location is defined by `get_db_path()` in **`src/core/tracking.rs`**. correct
RTK · run 2 · 4 turns · $0.060
  1. rg 'gain|CREATE TABLE' src -n | head -701,788 tokens seen
  2. rg -n 'db_path|\.db|FROM commands' src/core/tracking* src/analytics/gain* src/core/config.rs566 tokens seen
  3. rg -n 'fn get_db_path|tracking.db|Tracker' src/core/tracking.rs src/analytics/gain.rs | head -25528 tokens seen
Astra answered - SQLite table: `commands` - Database location defined in: `src/core/tracking.rs` (`get_db_path`) correct
RTK · run 3 · 4 turns · $0.055
  1. rg -n 'rtk gain|CREATE TABLE|\.db' src | head -701,517 tokens seen
  2. sed -n '70,115p' src/core/tracking.rs; rg -n 'FROM commands|HISTORY_DB' src/core/tracking.rs | head503 tokens seen
  3. rg -n 'fn.*path|HISTORY_DB|data_dir' src/core/tracking.rs | head -20351 tokens seen
Astra answered - SQLite table: `commands` - Database location defined in: `src/core/tracking.rs` (`get_db_path()`) correct
Headroom · run 1 · 5 turns · $0.121
  1. rg -n 'gain|CREATE TABLE|sqlite' src | head -901,880 tokens seen
  2. rg -n 'db_path|rtk.db|CREATE TABLE|FROM commands' src/core/tracking*; rg -n TrackingDb src/analytics/gain.rs1,123 tokens seen
  3. rg -n 'fn get_db_path|FROM commands' src/core/tracking* | head82 tokens seen
  4. rg -n 'fn get_db_path' src; sed -n '1492,1528p' src/core/tracking.rs424 tokens seen
Astra answered - **SQLite table:** `commands` - **Database location defined in:** `src/core/tracking.rs:1492`, in `get_db_path()`. correct
Headroom · run 2 · 5 turns · $0.123
  1. rg 'gain' src -l; rg 'CREATE TABLE|\.db|sqlite' src2,826 tokens seen
  2. rg -n 'FROM |CREATE TABLE|fn.*path|HISTORY_DB' src/core/tracking.rs | head -45; rg -n 'tracking|Tracker' src/analytics/gain.rs | head880 tokens seen
  3. rg -n 'fn.*path|HISTORY_DB|data_dir' src/core/tracking.rs | head -25273 tokens seen
  4. sed -n '1492,1517p' src/core/tracking.rs273 tokens seen
Astra answered SQLite table: `commands` Database location defined in: `src/core/tracking.rs` (`get_db_path()`). correct
Headroom · run 3 · 4 turns · $0.051
  1. rg 'rtk gain|CREATE TABLE|\.db' src -n | head -701,724 tokens seen
  2. sed -n '65,115p' src/core/tracking.rs; rg -n 'FROM commands|fn.*path|HISTORY_DB' src/core/tracking.rs | head -20723 tokens seen
  3. rg -n 'fn.*db_path|fn.*database|HISTORY_DB|RTK_DATA_DIR' src/core/tracking.rs108 tokens seen
Astra answered - SQLite table: `commands` - Database location defined in: `src/core/tracking.rs` (`get_db_path()`) correct
Both · run 1 · 5 turns · $0.110
  1. rg -n 'CREATE TABLE|gain|\.db' src/tracking* src/ gain* 2>/dev/null | head -1001,909 tokens seen
  2. rg -n 'FROM commands|fn.*path|tracking.db|database_path|Tracker' src/core/tracking.rs src/analytics/gain.rs | head -65573 tokens seen
  3. rg -n 'fn.*path|tracking.db|FROM commands' src/core/tracking.rs | head -25323 tokens seen
  4. rg -n 'fn.*db_path|tracking.db|database_path' src/core/tracking.rs | tail -20229 tokens seen
Astra answered - **SQLite table:** `commands` - **Database location defined in:** `src/core/tracking.rs` (`get_db_path()`) correct
Both · run 2 · 6 turns · $0.090
  1. rg -n 'gain|CREATE TABLE' src | head -651,687 tokens seen
  2. rg -n 'db_path|database|FROM commands|CREATE TABLE' src/core/tracking.rs src/analytics/gain.rs src/core/config.rs435 tokens seen
  3. rg -n 'fn get_db_path|tracking.db|FROM commands' src/core/tracking.rs | tail -18269 tokens seen
  4. rg -n 'fn get_db_path|tracking.db' src/core/tracking.rs143 tokens seen
  5. sed -n '1492,1535p' src/core/tracking.rs476 tokens seen
Astra answered - **SQLite table:** `commands` - **Database location defined in:** `src/core/tracking.rs`, in `get_db_path()`. correct
Both · run 3 · 5 turns · $0.061
  1. rg 'CREATE TABLE|rtk gain' -n src | head -60917 tokens seen
  2. rg -n 'db_path|fn.*path|FROM commands|tracking.db|rtk.db' src/core/tracking.rs | head -35414 tokens seen
  3. sed -n '70,105p' src/core/tracking.rs; sed -n '822,837p' src/core/tracking.rs446 tokens seen
  4. rg -n 'tracking.db|fn.*db_path' src/core/tracking.rs215 tokens seen
Astra answered `rtk gain` reads savings data from the SQLite **`commands`** table. The database location is defined in **`src/core/tracking.rs`**, in `get_db_path()`. correct
How many subfolders under src/cmds, which has most .rs filesdirectory listing (RTK's turf)$0.004$0.004$0.004$0.004$0.052$0.019$0.004$0.004$0.004$0.020$0.004$0.004
Show all 12 runs: every command and answer
No tool · run 1 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done168 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
No tool · run 2 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done168 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
No tool · run 3 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done168 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
RTK · run 1 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done128 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
RTK · run 2 · 9 turns · $0.052
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done128 tokens seen
  2. find src/cmds -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
  3. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort | while read -r d; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done61 tokens seen
  4. find src/cmds/ -mindepth 1 -maxdepth 1 -type d | while IFS= read -r d; do printf '%s %s\n' "$(find "$d" -type f -name '*.rs' | wc -l)" "$d"; done84 tokens seen
  5. find src/cmds -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
  6. find src/cmds -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
  7. find src/cmds/ -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
  8. python3 - <<'PY' from pathlib import Path p=Path('src/cmds') ds=[x for x in p.iterdir() if x.is_dir()] print(len(ds)) print(max(ds,key=lambda d:len(list(d.rglob('*.rs')))).name) PY4 tokens seen
Astra answered 12, system correct
RTK · run 3 · 5 turns · $0.019
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done128 tokens seen
  2. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort | while read -r d; do printf '%s %s\n' "$d" "$(find "$d" -type f -name '*.rs' | wc -l)"; done87 tokens seen
  3. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done128 tokens seen
  4. find src/cmds -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files. correct
Headroom · run 1 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done168 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
Headroom · run 2 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done168 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
Headroom · run 3 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done168 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
Both · run 1 · 5 turns · $0.020
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done128 tokens seen
  2. find src/cmds -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
  3. find src/cmds -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
  4. find src/cmds -mindepth 1 -maxdepth 1 -type d | wc -l; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done104 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
Both · run 2 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do [ -d "$d" ] && printf '%s %s\n' "$(find "$d" -type f -name '*.rs' | wc -l)" "$d"; done | sort -nr104 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
Both · run 3 · 2 turns · $0.004
  1. find src/cmds -mindepth 1 -maxdepth 1 -type d | sort; for d in src/cmds/*/; do printf '%s ' "$d"; find "$d" -type f -name '*.rs' | wc -l; done128 tokens seen
Astra answered 12 subdirectories; `system` contains the most `.rs` files (17). correct
Top-level keys of `rtk gain --format json`, name of the date fielda JSON tool result (Headroom's turf)$0.007$0.007$0.007$0.007$0.007$0.007$0.005$0.005$0.005$0.005$0.005$0.005
Show all 12 runs: every command and answer
No tool · run 1 · 2 turns · $0.007
  1. rtk gain --all --format json364 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field inside each `daily` item: `date`. correct
No tool · run 2 · 2 turns · $0.007
  1. rtk gain --all --format json364 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field in each `daily` item: `date`. correct
No tool · run 3 · 2 turns · $0.007
  1. rtk gain --all --format json364 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field inside each `daily` item: `date`. correct
RTK · run 1 · 2 turns · $0.007
  1. rtk gain --all --format json364 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field inside each `daily` item: `date`. correct
RTK · run 2 · 2 turns · $0.007
  1. rtk gain --all --format json364 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field in each `daily` item: `date`. correct
RTK · run 3 · 2 turns · $0.007
  1. rtk gain --all --format json364 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field in each `daily` item: `date`. correct
Headroom · run 1 · 2 turns · $0.005
  1. rtk gain --all --format json238 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field inside each `daily` item: `date`. correct
Headroom · run 2 · 2 turns · $0.005
  1. rtk gain --all --format json238 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field inside each `daily` item: `date`. correct
Headroom · run 3 · 2 turns · $0.005
  1. rtk gain --all --format json238 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field in each `daily` item: `date`. correct
Both · run 1 · 2 turns · $0.005
  1. rtk gain --all --format json238 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field in each `daily` item: `date`. correct
Both · run 2 · 2 turns · $0.005
  1. rtk gain --all --format json238 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field in each `daily` item: `date`. correct
Both · run 3 · 2 turns · $0.005
  1. rtk gain --all --format json238 tokens seen
Astra answered Top-level keys: `summary`, `daily`, `weekly`, `monthly`. Date field in each `daily` item: `date`. correct
What `estimate_tokens` returns for "", and the formula's lineone large file$0.006$0.006$0.006$0.006$0.006$0.006$0.006$0.006$0.006$0.015$0.006$0.006
Show all 12 runs: every command and answer
No tool · run 1 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A18 -B6 'fn estimate_tokens'352 tokens seen
Astra answered 0, line 1659. correct
No tool · run 2 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A18 -B5 'fn estimate_tokens'346 tokens seen
Astra answered 0, line 1659. correct
No tool · run 3 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A 18 -B 5 'fn estimate_tokens'346 tokens seen
Astra answered 0, line 1659. correct
RTK · run 1 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A 18 -B 5 'fn estimate_tokens'346 tokens seen
Astra answered 0, line 1659. correct
RTK · run 2 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A 14 -B 5 'fn estimate_tokens'298 tokens seen
Astra answered 0, line 1659. correct
RTK · run 3 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A 16 -B 5 'fn estimate_tokens'319 tokens seen
Astra answered 0, line 1659. correct
Headroom · run 1 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A18 -B5 'fn estimate_tokens'346 tokens seen
Astra answered 0, line 1659. correct
Headroom · run 2 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A18 -B5 'fn estimate_tokens'346 tokens seen
Astra answered 0, line 1659. correct
Headroom · run 3 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A 15 -B 5 'fn estimate_tokens'304 tokens seen
Astra answered 0, line 1659. correct
Both · run 1 · 2 turns · $0.015
  1. nl -ba src/core/tracking.rs | grep -A 18 -B 5 estimate_tokens1,208 tokens seen
Astra answered 0, line 1659. correct
Both · run 2 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A 14 -B 5 'fn estimate_tokens'298 tokens seen
Astra answered 0, line 1659. correct
Both · run 3 · 2 turns · $0.006
  1. nl -ba src/core/tracking.rs | grep -A 14 -B 5 'fn estimate_tokens'298 tokens seen
Astra answered 0, line 1659. correct
All five$0.154$0.139$0.158$0.175

The four setups landed within 5 cents of each other on every task, usually within two. Why so close: the model chooses its own commands, and it chose differently each run. On the grep task, Astra saw between 2,830 and 3,379 tool tokens with no tool, and between 2,555 and 4,252 with Headroom, because one run added | head -70 and another did not. That gap exists before any tool acts. On the directory-listing task, the three RTK runs took 2, 5 and 9 turns; in the 9-turn run Astra re-ran the listing with small variations before committing. 9 of the 20 cells stayed within 10% across all three runs; 5 spread by 2x or more.

Each cell shows all three runs, top to bottom, cost with cache. Green is the cheapest run in the row, orange the most expensive. The totals row is the mean of the three runs summed over the five tasks, so it will not match a sum of any single column above. Click "Show all 12 runs" under any task for every command Astra ran and the answer it gave.

The only cell where a tool beat no-tool in every run by a clear margin is RTK on the multi-file grep, where it grouped the output by file. Headroom's edge on the JSON task, the payload it is built for, is a fraction of a cent. Running both tools was never lowest.

One command, raw and through RTK

The single largest reduction any tool made across all 40 runs. SQLite task, RTK setup, run 2, turn 2: Astra ran this to find where the database path is set.

rg -n 'db_path|\.db|FROM commands' src/core/tracking* src/analytics/gain* src/core/config.rs

Raw: 1,963 tokens, 87 lines
src/core/tracking.rs:9://! - Storage: SQLite database (~/.local/share/rtk/tracking.db)
src/core/tracking.rs:76:/// - Linux: `~/.local/share/rtk/tracking.db`
src/core/tracking.rs:77:/// - macOS: `~/Library/Application Support/rtk/tracking.db`
src/core/tracking.rs:78:/// - Windows: `%APPDATA%\rtk\tracking.db`
src/core/tracking.rs:178:/// `rtk_version` for direct inspection (`sqlite3 tracking.db`), but nothing in Rust
src/core/tracking.rs:349:            "SELECT EXISTS(SELECT 1 FROM commands WHERE project_path IS NULL)",
src/core/tracking.rs:551:            "DELETE FROM commands WHERE timestamp < ?1",
src/core/tracking.rs:570:                 DELETE FROM commands;
src/core/tracking.rs:832:             FROM commands
src/core/tracking.rs:890:             FROM commands
src/core/tracking.rs:918:             FROM commands
src/core/tracking.rs:968:             FROM commands
src/core/tracking.rs:1042:             FROM commands
src/core/tracking.rs:1116:             FROM commands
src/core/tracking.rs:1191:             FROM commands
src/core/tracking.rs:1218:            "SELECT COUNT(*) FROM commands WHERE timestamp >= ?1",
src/core/tracking.rs:1228:            "SELECT rtk_cmd, COUNT(*) as cnt FROM commands
src/core/tracking.rs:1242:            "SELECT COALESCE(SUM(input_tokens), 0), COALESCE(SUM(saved_tokens), 0) FROM commands",
src/core/tracking.rs:1256:            "SELECT COALESCE(SUM(saved_tokens), 0) FROM commands",
src/core/tracking.rs:1267:            "SELECT COALESCE(SUM(saved_tokens), 0) FROM commands WHERE timestamp >= ?1",
src/core/tracking.rs:1279:             COUNT(*) as cnt FROM commands
src/core/tracking.rs:1305:            "SELECT rtk_cmd, AVG(savings_pct) as avg_sav FROM commands
src/core/tracking.rs:1325:                FROM commands WHERE input_tokens > 0
src/core/tracking.rs:1338:            "SELECT COUNT(*) FROM commands WHERE rtk_cmd LIKE ?1 || '%'",
src/core/tracking.rs:1350:                .query_row("SELECT MIN(timestamp) FROM commands", [], |row| row.get(0))
src/core/tracking.rs:1375:            "SELECT COUNT(DISTINCT DATE(timestamp)) FROM commands WHERE timestamp >= ?1",
src/core/tracking.rs:1386:            .query_row("SELECT COUNT(*) FROM commands", [], |row| row.get(0))?;
src/core/tracking.rs:1393:            "SELECT COUNT(*) FROM commands WHERE input_tokens > 0 AND timestamp >= datetime('now', '-90 days')",
src/core/tracking.rs:1401:            "SELECT rtk_cmd, COUNT(*) as cnt FROM commands
src/core/tracking.rs:1431:            "SELECT COALESCE(SUM(saved_tokens), 0) FROM commands WHERE timestamp >= ?1",
… 57 more lines
Through RTK: 566 tokens, 29 lines
87 matches in 2 files:

src/core/config.rs:251:/// `tracking::get_db_path` (called via `Tracker::new()` for `hook_decisions`
src/core/tracking.rs:9://! - Storage: SQLite database (~/.local/share/rtk/tracking.db)
src/core/tracking.rs:76:/// - Linux: `~/.local/share/rtk/tracking.db`
src/core/tracking.rs:77:/// - macOS: `~/Library/Application Support/rtk/tracking.db`
src/core/tracking.rs:78:/// - Windows: `%APPDATA%\rtk\tracking.db`
src/core/tracking.rs:178:/// `rtk_version` for direct inspection (`sqlite3 tracking.db`), but nothing ...
src/core/tracking.rs:349:"SELECT EXISTS(SELECT 1 FROM commands WHERE project_path IS NULL)",
src/core/tracking.rs:551:"DELETE FROM commands WHERE timestamp < ?1",
src/core/tracking.rs:570:DELETE FROM commands;
src/core/tracking.rs:832:FROM commands
src/core/tracking.rs:890:FROM commands
src/core/tracking.rs:918:FROM commands
src/core/tracking.rs:968:FROM commands
src/core/tracking.rs:1042:FROM commands
src/core/tracking.rs:1116:FROM commands
src/core/tracking.rs:1191:FROM commands
src/core/tracking.rs:1218:"SELECT COUNT(*) FROM commands WHERE timestamp >= ?1",
src/core/tracking.rs:1228:"SELECT rtk_cmd, COUNT(*) as cnt FROM commands
src/core/tracking.rs:1242:"SELECT COALESCE(SUM(input_tokens), 0), COALESCE(SUM(saved_tokens), 0) FROM c...
src/core/tracking.rs:1256:"SELECT COALESCE(SUM(saved_tokens), 0) FROM commands",
src/core/tracking.rs:1267:"SELECT COALESCE(SUM(saved_tokens), 0) FROM commands WHERE timestamp >= ?1",
src/core/tracking.rs:1279:COUNT(*) as cnt FROM commands
src/core/tracking.rs:1305:"SELECT rtk_cmd, AVG(savings_pct) as avg_sav FROM commands
src/core/tracking.rs:1325:FROM commands WHERE input_tokens > 0
src/core/tracking.rs:1338:"SELECT COUNT(*) FROM commands WHERE rtk_cmd LIKE ?1 || '%'",
src/core/tracking.rs:1350:.query_row("SELECT MIN(timestamp) FROM commands", [], |row| row.get(0))
  +61 more in src/core/tracking.rs [see remaining: tail -n +26 ~/.local/share/rtk/tee/1788952114_grep_1_s_f115cc.log]

RTK groups matches by file and trims long lines. The lines Astra needed (tracking.rs, the db path function) are in both. This is what a good case looks like: 71% fewer tokens on one command, worth about $0.014 at first send. Most commands in these runs were already small enough that there was nothing to group.

Tool output the model actually read, summed over the five tasks: no tool 6,165 tokens, RTK 5,462 (11% less), Headroom 6,071, both 5,442. Astra scoped most reads itself with rg | head and sed -n, so there was little for either tool to remove.

Two things to know. A sixth task (the subject line and author of the 10th most recent commit) is not in the grid: Astra had the correct answer in its tool output on turn 1 and then re-ran git log with small variations until the turn cap, never writing a reply, in every run. One task, one behaviour, no conclusion drawn from it. And this is a bare API loop that re-sends full history every turn; Codex CLI and similar agents compact history, so absolute numbers there are lower, though the ordering between setups should not change.

Model prices and the tools chasing them change weekly. This test came out of the release feed I keep at BlogNetwork: one page, every AI release, updated every two hours.

See this week's releases