The character-rig as a QALS compute provider (1c = 10cr) · 07_compute_marketplace/GOETICA_RUNPOD_INTEGRATION.md
GOETICA ↔ QALS — RunPod / Credits Integration Map
Authored 2026-09-10. Study target:
~/projects/goetica(read-only). Anchor: this corpus (crypto_currency/). Every claim citespath:line. Goetica's own credits doc (docs/architecture/GOETICA_CREDITS.md) already cites this corpus as its "source of truth for the money model" — this map closes the loop and makes it concrete as a build plan.
1. What goetica is
Goetica (goetica.ai, private repo qalarc/goetica) is the character-truth
workshop + product site: a character is conceived through long midwife-agent
interviews ("sittings"), distilled into structured TRUTH documents (philosophy,
perspectives, interaction, voice, biography), synthesized into an audited
prompt/response corpus, then raised as a character LoRA on GLM-4.7-Flash and served
live (README.md:3-11, pipeline diagram README.md:15-30). The pipeline is:
conversations/ → truth/ → corpus/ → LoRA → tulpas/<slug>/ platform record, with
hard rules that conversations/corpus never leave the machine via git and every truth
line traces to something the founder said (README.md:47-61). As a product it was
repositioned (sitting 03) into a product site for the character-creation studio plus
a downloadable all-in-one media tool, with Stolas as the flagship demo
(PROJECT_PLAN.md:108-115).
Where compute happens — three planes (INFRA_REVIEW.md:44-62): (1) a
Cloudflare control plane (Worker + KV + Workers AI; wrangler.jsonc:14-19 binds
AI and GOETICA_SESSIONS, route goetica.ai at wrangler.jsonc:20-22); (2) a
demo plane on RunPod — serverless endpoints for the weighted Stolas LLM
(RTX 4090 @ $1.10/hr), STT (L4 @ $0.69), TTS Kokoro (INFRA_REVIEW.md:64-75); and
(3) training, which runs on RunPod A100 pods (~$2–3.30/run) via the
battle-tested runpod_train.py v3 automation (METHOD.md:58-59,
INFRA_REVIEW.md:31, COMPUTE_LEDGER.md:11-13: 165 min A100 = $3.30). The Stolas
LoRA (glm-4.7-flash:stolas-t1) is already trained and serving locally;
RunPod serverless serving is designed but not built (INFRA_REVIEW.md:11-15).
2. Current credits system
GOETICA_CREDITS.md is DESIGN only, 2026-09-09 — no billing implemented
(GOETICA_CREDITS.md:3-4). Locked founder canon: 1,000 goetica credits = AU$1
(1 credit = 1 milli-qAUD), creators keep 80% of credits their characters earn
(:20-22). Unit ladder: display = credits; pre-chain ledger = integer credits in D1;
chain phase = doofs (1 credit = 1,000 doofs, assuming the 10⁻⁶ exponent — the doc
flags a stale 10⁻⁹ figure in CREDIT_PLATFORM.md §4 as [verify], :56-80);
underlying asset B-QALS (:61). Ledger mirrors QALS qal_credit: lazy
CreditAccount, Hold with expires_at auto-release, settle-at-actual, refunds as
reversal rows, four SQL tables drafted at :96-121. Flow: top-up mints 1:1,000
against the reserve invariant AUD_held ≥ credits_outstanding × AU$0.001 (:125-130);
chat settle burns user credits, mints creator +0.8N / platform +0.2N born-backed
(:131-141); free tier drips 50 cr/day (proposal, born backed, :198-202). Rate
cards: creator-set flat 10–500 credits/message server-band-enforced, or metered
base + per-1k-output-tokens (:163-172). The chat billing sequence is fully
specified — auth → price → hold (120 s expiry) → proxy → settle/release →
message_id idempotency (:174-189). Enforced vs manual: nothing is enforced
yet. The deployed worker has only a toy KV credits stub — pseudonymous
hashed-session accounts, unauthenticated grant labelled "top-up (pre-payment)",
spend with 402 on insufficient (worker.js:123-161) — no holds, no settlement, no
real payment. Agents get DIDs + capability credentials with hard daily caps
enforced by the ledger, not prompts (:231-258); compliance is Phase-1
closed-loop prepaid — non-transferable, no cash-out, creator payouts are revenue
share (:262-290).
3. The RunPod rig
RUNPOD_SETUP.md describes a deployed-and-waiting state: "The Worker proxy is
deployed and waiting. When the Stolas weights (or any OpenAI-compatible endpoint)
are up," flip two secrets — RUNPOD_CHAT_URL + RUNPOD_API_KEY — and the site
chat goes live automatically (:1-12). The worker's /api/chat/completions proxies
verbatim to the RunPod OpenAI-compatible endpoint with a Bearer secret and tags the
response x-goetica-backend: runpod (worker.js:56-73); /api/ping reports
chat: !!env.RUNPOD_CHAT_URL (worker.js:41-42). TTS routes ?engine=kokoro to a
RUNPOD_TTS_URL sidecar (port 8880 FastAPI) with edge-melo fallback — a five-voice
ladder from local kokoro to captions (RUNPOD_SETUP.md:39-53). Cost guard for
stealth phase: STOP pods between sessions, per-request Workers AI pennies, free-tier
KV (:28-33); fallback chain site → Worker → RunPod, offline canon banks on 503
(:34-37). Target serving architecture (INFRA_REVIEW.md:64-75): load-balancing
serverless endpoints (not queue-based), weights baked into the Docker image to kill
19 GB cold-start downloads, FlashBoot + min_workers=1 during demo hours ≈ $26/mo
floor. Pricing (RunPod, 2026-07-27): L4 $0.69, 4090 $1.10, A100 $2.72, RTX Pro 6000
$3.49, H100 $4.79/hr (:144). Training stays pod-based: runpod_train.py v3
already speaks RunPod REST v2 (catalog → order → monitor) with encrypted kit
delivery and budget guard (INFRA_REVIEW.md:31); tulpa_studio's FOUNDRY TRAIN step
is a "RUNPOD A100 honest stub ~$2/run" (tulpa_studio/README.md:44). Status today:
worker deployed; chat secrets unset; serverless workers unbuilt; training
battle-tested.
4. COMPUTE_LEDGER.md — usage tracking now
Created 2026-09-09 from a $20 campaign post-mortem. The ledger is a JSONL file —
logs/compute_ledger.jsonl, 14 entries itemizing the whole campaign — with one
row per compute event: purpose, gpu, cloud, duration_min, cost_usd,
outcome, category (productive · bug-loss · environment · saved · future
inference/render/eval), artifact, note
(COMPUTE_LEDGER.md:3-16). Campaign 1's productive-compute ratio was 10%
(target >85%) — the exemplar row is "outcome": "trained-adapter-lost", a
$3.30 A100 run destroyed by cleanup-before-verify (:11-14, :28). Four planned
concierge-panel views: IN/OUT balance sheet (pulling RunPod billing API /v2
actuals), WHERE-IT-WENT (cost by category/stage — "points directly at what to
harden next"), DEMAND SIGNALS (per-character compute, "most expensive soul"
leaderboard), TRUST (publicly auditable per-user outcome+artifact trail, "lost-adapter
events = 0 since the contract") (:20-43). Critically, the writer is still a
TODO: "runpod_train.py/fetch_adapter at pod events (one line each — TODO next
session)" (:53); the reader is the concierge panel + RunPod billing API with creds
in ~/.config/tulpa (:54-55). The ledger is also framed as the demand-research
instrument for "the compute marketplace's pricing" (:45-50) — i.e., goetica
already expects a marketplace to sit on this data.
5. THE INTEGRATION MAP
| # | Goetica concept (evidence) | QALS component | Proposed mapping / rate |
|---|---|---|---|
| 1 | Goetica credit = AU$0.001; 1,000 cr = AU$1 (GOETICA_CREDITS.md:20-22,54-80) |
loopd paper ledger, cents-denominated (qmarket/README.md:3 — all prices *_cents) |
1 loopd cent = 10 goetica credits. Keep the milli-unit as goetica's display layer; mirror into loopd as integer cents. Chain phase: 1 credit = 1,000 doofs (10⁻⁶) = 0.001 B-QALS, born backed exactly as :28-30,131-141 already specifies. Do not re-rate to 1 credit = 1c — that would break their locked 1,000:1 canon and the 10–500 cr/message band (:63-65). |
| 2 | RunPod A100 training pods, ~$2–3.30/run (METHOD.md:58-59; COMPUTE_LEDGER.md:12) |
qmarket job, kind="lora-training" (qmarket/test_market_v2.sh:80 shows register --kind render --price 12) |
Price per unit = GPU-hour in cents: A100 272c, 4090 110c, L4 69c, H100 479c (INFRA_REVIEW.md:144). bench.py target-margin logic sets the floor; the escrowed Hold → attested metrics → settle-at-metered × price → 0% platform fee flow (founder policy 2026-09-12 — the buy-spread is the margin) (qmarket/README.md:3) replaces the ad-hoc RunPod billing pull. |
| 3 | Midwife + agent customers with hard caps (GOETICA_CREDITS.md:231-258) |
loopd agents with daily caps — cap-refusal already proven live on Qalnet (:151-153, :250-253) |
Agent capability token goetica:chat, spend-cap:N cr/day maps 1:1 to the loopd/qal_credit cap field; a capped hold is refused by the ledger, never prompt-enforced. Training agents get their own spend-cap in cents. |
| 4 | truth/ → corpus/ provenance, audit bar "unaudited data never trains" (METHOD.md:74-79) |
qalpipe anchors (qmarket/README.md:3 — output hash anchored on-chain) |
Anchor corpus/audit_report.json sha256 and the dataset sha256 before any training job is accepted; the qmarket gateway refuses lora-training jobs whose spec lacks an dataset_anchor. This makes the audit bar machine-checkable instead of honour-system. |
| 5 | Character LoRA outputs, "trained-adapter-lost" disaster (COMPUTE_LEDGER.md:13) |
ComputeReceipt-style anchored artifact | qmarket already writes {tx, object_id, sha256} + receipt per job (qmarket/data/jobs.jsonl:1). The LoRA adapter fetched by fetch_adapter.py becomes the job output whose sha256 is anchored at settle — the ledger's TRUST view "artifact + verification trail" (COMPUTE_LEDGER.md:41-43) falls out for free. |
| 6 | Users' credit balance (KV stub today, D1 design tomorrow) (worker.js:123-161; GOETICA_CREDITS.md:87-121) |
loopd account, dual issuance | Paid top-ups: direct loopd account issued against the reserve (transferred from the pre-endowed issuer supply) (GOETICA_CREDITS.md:125-130). Free-tier drips + promo grants: qalclaim-issued rewards, born backed per the QALS rewards rule (:136-141,198-202). daily_cap_credits ↔ loopd cap field. |
| 7 | The goetica Worker / runpod_train.py automation |
qmarket remote provider adapter (qmarket/provider.py pattern: gateway POSTs {job_id, kind, spec} to :8850 — provider.py:11,24) |
Wrap runpod_train.py (REST v2: catalog→order→monitor, INFRA_REVIEW.md:31,82) in provider.py as provider goetica-runpod; register kinds lora-training and inference (the chat proxy worker.js:56-73 is a ready inference provider). Stake sized above max job value (e.g. 1,000c for A100 work). |
6. What's needed to make it real (ordered)
- Fix the ledger seam first — implement
GOETICA_CREDITS.md:304-317step 1–2 (D1 binding +Ledger {getAccount, placeHold, settle, release, reverse}) but with a second thin impl:LoopdLedgerPOSTing to loopd. The interface is already specified; estimate: days. - COMPUTE_LEDGER writer → qmarket job records — the "one line each" TODO
(
COMPUTE_LEDGER.md:53) becomes: emit the qmarket job event and the JSONL row; categories map to qmarket outcomes. Hours. - RunPod provider adapter —
runpod_train.pyalready exposes everything; wrap it in theprovider.pyPOST/executepattern (register--kind lora-training --price 272), artifact pull from R2 not LAN. Days. - Anchor-before-train gate — qalpipe anchor of audit_report + dataset sha256 in the gateway job validator (§5 row 4). Hours–a day.
- Adapter ComputeReceipt — wire
fetch_adapter.pyoutput into qmarket settle so the receipt carries the anchored adapter hash (§5 row 5). Days (mostly retrieval-hardening, which campaign 1 says is the real friction,COMPUTE_LEDGER.md:49-50). - Rate cards + wallet UI —
GOETICA_CREDITS.md:318-324(price badges, creator dashboard, Resend receipts). Days. - Agent credential issuer — Ed25519 capability tokens + KV revocation
(
:325-326); loopd caps enforce spend. Days. - Swap-to-Qalnet (
:330-337) — later, gated on the VASP phase (:282-288).
Fastest end-to-end win: #2+#3 together — a qmarket-registered RunPod provider that prices A100 training in cents and anchors the adapter it produces. It makes campaign 2 the first metered, escrowed, anchored training run in the ecosystem.
7. Honest gaps / risks
- RunPod cannot reach Tailscale. Pods are public-cloud; the QALS boxen are
behind it. The provider adapter must be poll/webhook-based with artifacts moved
via R2/S3 — which the ledger already anticipates ("first-run friction is
retrieval… the S3-volume design is that answer",
COMPUTE_LEDGER.md:49-50). - Who is billed where. Demo-plane pods bill goetica's RunPod account
(
INFRA_REVIEW.md:53-61); the customer plane is BYOC with their keys (:77-87). qmarket escrow only makes sense for the demo/training plane; BYOC jobs have no provider to slash — license-JWT enforcement is the separate control there (:85). - Stake economics for GPU jobs. A 2000c stake vs a 300c A100 job is fine; but
a runaway pod can burn far more than its estimate — the hold must be
worst-case-capped and
runpod_train.py's budget guard is the real ceiling (INFRA_REVIEW.md:31). - The KV credits stub is not a ledger. Unauthenticated grant, no holds, no
idempotency (
worker.js:140-148) — fine as a demo, dangerous near real money. - Open verifications goetica itself flags: doof exponent 10⁻⁶ vs 10⁻⁹
(
GOETICA_CREDITS.md:77-80); RunPod streamingusagereliability (:170-172); gift-card-law overlay and payout-review window (:275-280,:341-346); written legal opinion before public credit sale (:279-280). - Two chat paths, two price paths. Free Z.ai API serves the unweighted demo
(
INFRA_REVIEW.md:19) while weighted RunPod chat is billed — the meter must key on backend, andx-goetica-backend(worker.js:71) is the natural switch.