Skip to content

Commit 712d020

Browse files
authored
docs: clean up internal docs and refresh CRD specs (#344)
Co-authored-by: bussyjd <bussyjd@users.noreply.github.com>
1 parent 431ea27 commit 712d020

27 files changed

+365
-5942
lines changed

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ Obol Stack: framework for AI agents to run decentralised infrastructure locally.
99
## Conventions
1010

1111
- **Commits**: Conventional commits — `feat:`, `fix:`, `docs:`, `test:`, `chore:`, `security:` with optional scope
12-
- **Branches**: `feat/`, `fix/`, `research/`, `codex/` prefixes
13-
- **GitHub branch policy**: never push `codex/`-prefixed branches to GitHub from this repository; use `feat/`, `fix/`, `research/`, or another non-codex branch name before pushing
12+
- **Branches**: `feat/`, `fix/`, `research/`, `docs/`, `chore/` prefixes
13+
- **GitHub branch policy**: never push `codex/`-prefixed branches to GitHub from this repository; rename to `feat/`, `fix/`, `research/`, `docs/`, `chore/`, or another non-codex branch name before pushing
1414
- **Detailed architecture reference**: `@.claude/skills/obol-stack-dev/SKILL.md` (invoke with `/obol-stack-dev`)
1515
- **Review scope**: Avoid broad, vague review/delegation boundaries. State the exact files, invariants, and expected evidence before reviewing or spawning agents. Prefer concrete checks such as "controller cannot access signer/Secrets", "agent write RBAC is namespace-scoped", and "flow uses real obol CLI path" over generic "review architecture".
1616

docs/guides/monetize-inference.md

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,27 @@ This guide walks you through exposing a local LLM as a paid API endpoint using t
1010
> [!NOTE]
1111
> `--per-mtok` is supported for inference pricing, but phase 1 still charges an
1212
> approximate flat request price derived as `perMTok / 1000` using a fixed
13-
> `1000 tok/request` assumption. Exact token metering is deferred to the
14-
> follow-up `x402-meter` design described in
15-
> [`docs/plans/per-token-metering.md`](../plans/per-token-metering.md).
13+
> `1000 tok/request` assumption. Exact token metering is not implemented yet.
1614
1715
> [!IMPORTANT]
18-
> The monetize subsystem is alpha software on the `feat/secure-enclave-inference` branch.
16+
> The monetize subsystem is alpha software.
1917
> If you encounter an issue, please open a
2018
> [GitHub issue](https://github.com/ObolNetwork/obol-stack/issues).
2119
2220
> [!IMPORTANT]
23-
> The current implementation is event-driven. `ServiceOffer` is the source of truth, `serviceoffer-controller` owns reconciliation, `RegistrationRequest` isolates registration side effects, and `x402-verifier` derives live routes directly from published ServiceOffers.
24-
> Older references below to the obol-agent reconcile loop, heartbeat polling, or direct `x402-pricing` route mutation are historical.
21+
> `ServiceOffer` is the source of truth. `serviceoffer-controller` owns
22+
> reconciliation, `RegistrationRequest` isolates registration side effects, and
23+
> `x402-verifier` derives live routes directly from published ServiceOffers.
2524
2625
## System Overview
2726

2827
```
2928
SELLER (obol stack cluster)
3029
31-
obol sell http --> ServiceOffer CR --> Agent reconciles:
30+
obol sell http --> ServiceOffer CR --> serviceoffer-controller reconciles:
3231
1. ModelReady (pull model in Ollama)
3332
2. UpstreamHealthy (health-check Ollama)
34-
3. PaymentGateReady (create x402 Middleware + pricing route)
33+
3. PaymentGateReady (create x402 Middleware)
3534
4. RoutePublished (create HTTPRoute -> Traefik gateway)
3635
5. Registered (ERC-8004 on-chain, optional)
3736
6. Ready (all conditions True)
@@ -177,12 +176,12 @@ That stores both values in the pricing config:
177176
- enforced phase-1 charge: `price = 0.00125 USDC / request`
178177
- approximation input: `approxTokensPerRequest = 1000`
179178

180-
The agent automatically reconciles the offer through six stages:
179+
The controller automatically reconciles the offer through six stages:
181180

182181
```
183-
ModelReady [check] Agent checks /api/tags, model already cached
184-
UpstreamHealthy [check] Agent health-checks ollama:11434
185-
PaymentGateReady [check] Creates Middleware x402-my-qwen + adds pricing route
182+
ModelReady [check] Controller verifies the model is available
183+
UpstreamHealthy [check] Controller health-checks ollama:11434
184+
PaymentGateReady [check] Creates Middleware x402-my-qwen
186185
RoutePublished [check] Creates HTTPRoute so-my-qwen -> ollama backend
187186
Registered -- Skipped (--register not set)
188187
Ready [check] All required conditions True
@@ -191,7 +190,7 @@ Ready [check] All required conditions True
191190
Watch the progress:
192191

193192
```bash
194-
# Check conditions (wait ~60s for agent heartbeat)
193+
# Check conditions
195194
obol sell status my-qwen --namespace llm
196195

197196
# Verify Kubernetes resources
@@ -534,7 +533,7 @@ obol sell status
534533

535534
### Pausing
536535

537-
Stop serving an offer without deleting it. This removes the pricing route so requests pass through without payment:
536+
Pause an offer without deleting it:
538537

539538
```bash
540539
obol sell stop my-qwen --namespace llm
@@ -556,7 +555,6 @@ Deletion:
556555

557556
- Removes the ServiceOffer CR
558557
- Cascades Middleware and HTTPRoute via OwnerReferences
559-
- Removes the pricing route from the x402 verifier
560558
- Deactivates the ERC-8004 registration (sets `active=false`)
561559

562560
Verify cleanup:
@@ -585,7 +583,7 @@ Traefik Gateway
585583
|
586584
--> ForwardAuth to x402-verifier.x402.svc:8080
587585
| |
588-
| +-- Match request path against pricing routes
586+
| +-- Match request path against published ServiceOffers
589587
| +-- No match? Return 200 (allow, free route)
590588
| +-- Match + no payment header? Return 402 + requirements
591589
| +-- Match + payment header? Verify with facilitator
@@ -612,7 +610,7 @@ Traefik Gateway
612610
+--------+---------+
613611
|
614612
+----------v-----------+
615-
| PaymentGateReady | (create Middleware + pricing route)
613+
| PaymentGateReady | (create Middleware)
616614
+----------+-----------+
617615
|
618616
+---------v----------+
@@ -630,67 +628,57 @@ Traefik Gateway
630628

631629
### Kubernetes Resources per ServiceOffer
632630

633-
When the agent reconciles a ServiceOffer named `my-qwen` in namespace `llm`:
631+
When `serviceoffer-controller` reconciles a ServiceOffer named `my-qwen` in namespace `llm`:
634632

635633
| Resource | Kind | Namespace | Name |
636634
|----------|------|-----------|------|
637635
| ServiceOffer | `obol.org/v1alpha1` | `llm` | `my-qwen` |
638636
| Middleware | `traefik.io/v1alpha1` | `llm` | `x402-my-qwen` |
639637
| HTTPRoute | `gateway.networking.k8s.io/v1` | `llm` | `so-my-qwen` |
640-
| ConfigMap patch | `v1` | `x402` | `x402-pricing` (route added) |
641638

642639
The Middleware and HTTPRoute have `ownerReferences` pointing at the ServiceOffer, so they are garbage-collected on deletion.
643640

644641
### Pricing Configuration
645642

646-
The x402 verifier reads its config from the `x402-pricing` ConfigMap:
643+
The x402 verifier reads cluster-wide payment defaults from the
644+
`x402-pricing` ConfigMap:
647645

648646
```yaml
649647
wallet: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
650648
chain: "base-sepolia"
651649
facilitatorURL: "https://facilitator.x402.rs"
652650
verifyOnly: false
653-
routes:
654-
- pattern: "/services/my-qwen/*"
655-
price: "0.001"
656-
description: "my-qwen inference"
657-
payTo: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
658-
network: "base-sepolia"
659651
```
660652
661-
This configuration is used by the `litellm-config` ConfigMap in the `llm` namespace, which LiteLLM reads for model_list configuration.
662-
663-
Per-route `payTo` and `network` override the global values, enabling multiple ServiceOffers with different wallets or chains.
653+
Published offer routes are derived from `ServiceOffer` resources rather than
654+
being maintained manually in this ConfigMap. Per-offer `payTo` and `network`
655+
can still override the cluster defaults.
664656

665657
---
666658

667659
## Troubleshooting
668660

669-
### Agent not reconciling
661+
### Offer not reconciling
670662

671-
The agent reconciles on a heartbeat (~60 seconds). Check agent logs:
663+
Check ServiceOffer conditions and controller logs:
672664

673665
```bash
674-
obol kubectl logs -n openclaw-* -l app=openclaw --tail=50
666+
obol sell status my-qwen --namespace llm
667+
obol kubectl logs -n x402 -l app=serviceoffer-controller --tail=50
675668
```
676669

677670
### x402 verifier returning 200 instead of 402
678671

679-
The pricing route may not have been added, or was overwritten. Check the ConfigMap:
680-
681-
```bash
682-
obol kubectl get cm x402-pricing -n x402 -o jsonpath='{.data.pricing\.yaml}'
683-
```
684-
685-
Ensure a route matching your path exists in the `routes` list. The verifier logs its route count at startup:
672+
The ServiceOffer may not be `Ready`, or the request path may not match the
673+
published offer. Check the offer and the resources it owns:
686674

687675
```bash
676+
obol sell status my-qwen --namespace llm
677+
obol kubectl get middleware x402-my-qwen -n llm
678+
obol kubectl get httproute so-my-qwen -n llm
688679
obol kubectl logs -n x402 -l app=x402-verifier --tail=10
689-
# Look for: "routes: 1" (or however many you expect)
690680
```
691681

692-
If routes are missing, the agent may not have reconciled yet (heartbeat is ~60s). You can also re-trigger reconciliation by deleting and re-creating the ServiceOffer.
693-
694682
### Facilitator unreachable from cluster
695683

696684
If using a self-hosted facilitator on the host, verify the k3d bridge:
@@ -788,7 +776,7 @@ Replace `openclaw-obol-agent` with your actual OpenClaw namespace if different.
788776
| `obol sell http <name> --wallet ... --chain ... --per-request ... --upstream ... --port ...` | Create a ServiceOffer |
789777
| `obol sell list` | List all ServiceOffers |
790778
| `obol sell status <name> -n <ns>` | Show conditions for an offer |
791-
| `obol sell stop <name> -n <ns>` | Pause an offer (remove pricing route) |
779+
| `obol sell stop <name> -n <ns>` | Pause an offer without deleting it |
792780
| `obol sell delete <name> -n <ns>` | Delete an offer and cleanup |
793781
| `obol sell status` | Show cluster pricing and registration |
794782
| `obol sell register --private-key-file ...` | Register on ERC-8004 |
@@ -797,9 +785,10 @@ Replace `openclaw-obol-agent` with your actual OpenClaw namespace if different.
797785

798786
| Resource | Namespace | Purpose |
799787
|----------|-----------|---------|
800-
| `x402-pricing` ConfigMap | `x402` | Pricing routes and wallet config |
788+
| `x402-pricing` ConfigMap | `x402` | Cluster-wide wallet, chain, and facilitator settings |
801789
| `x402-secrets` Secret | `x402` | Wallet address |
802790
| `x402-verifier` Deployment | `x402` | ForwardAuth payment verifier |
791+
| `serviceoffer-controller` Deployment | `x402` | Reconciles ServiceOffers into published resources |
803792
| `serviceoffers.obol.org` CRD | (cluster) | ServiceOffer custom resource definition |
804793
| `traefik-gateway` Gateway | `traefik` | Main ingress gateway |
805794

0 commit comments

Comments
 (0)