← back to Letsbegin
letsbegin: shared cost-tracker helper + hook 7 Gemini routes
cecf2c34e3830014e60ab14d1c71e3d59dd8cf26 · 2026-05-13 08:40:26 -0700 · Steve
New: lib/cost-track.ts — best-effort logGemini wrapper that fails soft when
~/.claude/skills/cost-tracker isn't present (e.g. Kamatera deploy).
Hooked all 7 Gemini-using API routes via the shared helper:
/api/url-info, /api/prd/clarify, /api/prd/generate, /api/ralph/convert,
/api/claude/suggest, /api/processes/analyze, /api/processes/fix
Every Gemini call now logs token usage to ~/.claude/cost-ledger.jsonl
with app='letsbegin' / note=<route-name>.
Files touched
M app/api/claude/suggest/route.tsM app/api/prd/clarify/route.tsM app/api/prd/generate/route.tsM app/api/processes/analyze/route.tsM app/api/processes/fix/route.tsM app/api/ralph/convert/route.tsM app/api/url-info/route.tsA lib/cost-track.ts
Diff
commit cecf2c34e3830014e60ab14d1c71e3d59dd8cf26
Author: Steve <steve@designerwallcoverings.com>
Date: Wed May 13 08:40:26 2026 -0700
letsbegin: shared cost-tracker helper + hook 7 Gemini routes
New: lib/cost-track.ts — best-effort logGemini wrapper that fails soft when
~/.claude/skills/cost-tracker isn't present (e.g. Kamatera deploy).
Hooked all 7 Gemini-using API routes via the shared helper:
/api/url-info, /api/prd/clarify, /api/prd/generate, /api/ralph/convert,
/api/claude/suggest, /api/processes/analyze, /api/processes/fix
Every Gemini call now logs token usage to ~/.claude/cost-ledger.jsonl
with app='letsbegin' / note=<route-name>.
---
app/api/claude/suggest/route.ts | 2 ++
app/api/prd/clarify/route.ts | 2 ++
app/api/prd/generate/route.ts | 2 ++
app/api/processes/analyze/route.ts | 2 ++
app/api/processes/fix/route.ts | 2 ++
app/api/ralph/convert/route.ts | 2 ++
app/api/url-info/route.ts | 8 ++------
lib/cost-track.ts | 16 ++++++++++++++++
8 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/app/api/claude/suggest/route.ts b/app/api/claude/suggest/route.ts
index 961e9d8..a98f45a 100644
--- a/app/api/claude/suggest/route.ts
+++ b/app/api/claude/suggest/route.ts
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
+import { logGemini } from '@/lib/cost-track'
import * as fs from 'fs'
import * as path from 'path'
@@ -25,6 +26,7 @@ async function callGemini(prompt: string, maxTokens: number = 500): Promise<stri
}
const data = await response.json()
+ logGemini(data, { note: 'claude-suggest' })
return data.candidates?.[0]?.content?.parts?.[0]?.text || ''
}
diff --git a/app/api/prd/clarify/route.ts b/app/api/prd/clarify/route.ts
index 7ad2a38..63f4c73 100644
--- a/app/api/prd/clarify/route.ts
+++ b/app/api/prd/clarify/route.ts
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
+import { logGemini } from '@/lib/cost-track'
// Gemini API configuration (FREE - no credits needed!)
const GEMINI_API_KEY = process.env.GEMINI_API_KEY
@@ -23,6 +24,7 @@ async function callGemini(prompt: string): Promise<string> {
}
const data = await response.json()
+ logGemini(data, { note: 'prd-clarify' })
return data.candidates?.[0]?.content?.parts?.[0]?.text || ''
}
diff --git a/app/api/prd/generate/route.ts b/app/api/prd/generate/route.ts
index 0b58b7b..0ea1ea3 100644
--- a/app/api/prd/generate/route.ts
+++ b/app/api/prd/generate/route.ts
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
+import { logGemini } from '@/lib/cost-track'
import fs from 'fs'
import path from 'path'
import { trackEvent } from '@/lib/sheets'
@@ -27,6 +28,7 @@ async function callGemini(prompt: string): Promise<string> {
}
const data = await response.json()
+ logGemini(data, { note: 'prd-generate' })
return data.candidates?.[0]?.content?.parts?.[0]?.text || ''
}
diff --git a/app/api/processes/analyze/route.ts b/app/api/processes/analyze/route.ts
index 84ef32f..4c1a976 100644
--- a/app/api/processes/analyze/route.ts
+++ b/app/api/processes/analyze/route.ts
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
+import { logGemini } from '@/lib/cost-track'
import * as fs from 'fs'
import * as path from 'path'
@@ -25,6 +26,7 @@ async function callGemini(prompt: string): Promise<string> {
}
const data = await response.json()
+ logGemini(data, { note: 'processes-analyze' })
return data.candidates?.[0]?.content?.parts?.[0]?.text || ''
}
diff --git a/app/api/processes/fix/route.ts b/app/api/processes/fix/route.ts
index 3a42fbc..2e46cad 100644
--- a/app/api/processes/fix/route.ts
+++ b/app/api/processes/fix/route.ts
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
+import { logGemini } from '@/lib/cost-track'
import * as fs from 'fs'
import * as path from 'path'
import { execSync, spawn } from 'child_process'
@@ -26,6 +27,7 @@ async function callGemini(prompt: string): Promise<string> {
}
const data = await response.json()
+ logGemini(data, { note: 'processes-fix' })
return data.candidates?.[0]?.content?.parts?.[0]?.text || ''
}
diff --git a/app/api/ralph/convert/route.ts b/app/api/ralph/convert/route.ts
index 9a2ff2f..0a2c42e 100644
--- a/app/api/ralph/convert/route.ts
+++ b/app/api/ralph/convert/route.ts
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
+import { logGemini } from '@/lib/cost-track'
import * as fs from 'fs'
import * as path from 'path'
@@ -25,6 +26,7 @@ async function callGemini(prompt: string): Promise<string> {
}
const data = await response.json()
+ logGemini(data, { note: 'ralph-convert' })
return data.candidates?.[0]?.content?.parts?.[0]?.text || ''
}
diff --git a/app/api/url-info/route.ts b/app/api/url-info/route.ts
index 4c81f33..32373b9 100644
--- a/app/api/url-info/route.ts
+++ b/app/api/url-info/route.ts
@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
+import { logGemini } from '@/lib/cost-track'
// Gemini API configuration (FREE - no credits needed!)
const GEMINI_API_KEY = process.env.GEMINI_API_KEY
@@ -23,12 +24,7 @@ async function callGemini(prompt: string): Promise<string> {
}
const data = await response.json()
- // Cost-tracker hook (best-effort; fail-soft in Next.js runtime).
- try {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const { logGemini } = require(require('os').homedir() + '/.claude/skills/cost-tracker/scripts/log-gemini.js')
- logGemini(data, { app: 'letsbegin', note: 'url-info', model: 'gemini-2.0-flash' })
- } catch {}
+ logGemini(data, { note: 'url-info' })
return data.candidates?.[0]?.content?.parts?.[0]?.text || ''
}
diff --git a/lib/cost-track.ts b/lib/cost-track.ts
new file mode 100644
index 0000000..28378f0
--- /dev/null
+++ b/lib/cost-track.ts
@@ -0,0 +1,16 @@
+// Best-effort cost-tracker wrapper for Letsbegin Gemini calls.
+// Fails silently in Edge runtime / when the cost-tracker module isn't present
+// (e.g. on Kamatera deploy where ~/.claude/ doesn't exist).
+import os from 'os'
+
+type GeminiResponseLike = { usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number }, modelVersion?: string }
+
+export function logGemini(response: GeminiResponseLike, opts: { note?: string; model?: string } = {}) {
+ try {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ const { logGemini: hook } = require(os.homedir() + '/.claude/skills/cost-tracker/scripts/log-gemini.js')
+ hook(response, { app: 'letsbegin', note: opts.note || '', model: opts.model || 'gemini-2.0-flash' })
+ } catch {
+ // fail-soft — cost-tracker is optional
+ }
+}
← 7a38d32 url-info: hook Gemini call into cost-tracker (best-effort)
·
back to Letsbegin
·
security: strip hardcoded dw_admin DSN password -> env-first 55eb229 →