Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Shared infrastructure and documentation.

## Structure
- `docker-compose.yml` — base stack (MCP → Gateway → Core + Redis), loopback-only
- `docker-compose.yml` — base stack (MCP → Gateway → Core), loopback-only
- `docker-compose.prod.yml` — prod overlay: Caddy TLS termination + required inbound auth
- `Caddyfile` — public TLS entry point (reverse proxy to MCP)
- `docs/` — architecture specs and plans
Expand All @@ -16,7 +16,7 @@ Shared infrastructure and documentation.
RUSTOK_KEYRING_PASSWORD=... docker compose up -d
```

Gateway on `127.0.0.1:3000`, MCP on `127.0.0.1:3001`. Core and Redis publish no
Gateway on `127.0.0.1:3000`, MCP on `127.0.0.1:3001`. Core publishes no
ports. MCP inbound auth is disabled (it logs a warning) — fine for loopback.

### Production (TLS via Caddy)
Expand Down
19 changes: 2 additions & 17 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Full Rustok stack: MCP (SSE) -> Gateway (REST) -> Core (gRPC) + Redis.
# Full Rustok stack: MCP (SSE) -> Gateway (REST) -> Core (gRPC).
#
# Usage:
# RUSTOK_KEYRING_PASSWORD=... docker compose up -d
#
# Only Gateway (:3000) and MCP (:3001) are published, loopback-only.
# Core and Redis publish no ports, so they are unreachable from the host;
# Core publishes no ports, so it is unreachable from the host;
# the internal network is NOT `internal: true` because Core needs egress
# to blockchain RPC providers (Alchemy / public RPCs).

Expand All @@ -16,7 +16,6 @@ services:
image: rustok-core:v0.1.0
environment:
RUSTOK_GRPC_ADDR: "0.0.0.0:50051"
RUSTOK_REDIS_URL: "redis://redis:6379"
RUSTOK_KEYRING_PASSWORD: ${RUSTOK_KEYRING_PASSWORD}
RUSTOK_ALLOWED_CHAINS: ${RUSTOK_ALLOWED_CHAINS:-1,8453}
RUSTOK_ALCHEMY_API_KEY: ${RUSTOK_ALCHEMY_API_KEY:-}
Expand All @@ -30,9 +29,6 @@ services:
- /tmp:noexec,nosuid,size=100m
user: "1000:1000"
restart: unless-stopped
depends_on:
redis:
condition: service_started

gateway:
image: rustok-core:v0.1.0
Expand Down Expand Up @@ -108,17 +104,6 @@ services:
gateway:
condition: service_healthy

redis:
image: redis:7-alpine
networks:
- internal
# Hardening
read_only: true
tmpfs:
- /tmp:noexec,nosuid,size=100m
user: "999:999"
restart: unless-stopped

volumes:
rustok-data:

Expand Down
18 changes: 11 additions & 7 deletions docs/PROJECT-OVERVIEW.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Rustok — Project Overview (single source of truth)

> **Updated:** 2026-06-14
> **Updated:** 2026-06-22
> **Purpose:** the master orientation doc. Where everything lives, where we came
> from, what's running now, and where we're going. Read this first.
> Detailed specs live in the per-repo docs/specs; this ties them together.
Expand Down Expand Up @@ -44,9 +44,9 @@ audit, txguard risk analysis.
standards every repo's AGENTS.md references. `standards/`, `commands/` (slash
commands), `agents/` (fleet reviewers). Load before writing code.

### Core crates (`core/crates/`, 13)
### Core crates (`core/crates/`, 12)
`types` · `crypto` · `keyring` · `provider` · `router` · `txguard` · `sign` ·
`wallet` · `audit` · `events` · `grpc` (gRPC server + binary `core-server`) ·
`wallet` · `audit` · `grpc` (gRPC server + binary `core-server`) ·
`gateway` (Axum HTTP + binary `gateway`) · `positions` (DeFi positions, PR-6.1).

---
Expand All @@ -64,7 +64,7 @@ Gateway (core/crates/gateway, Axum) ── auth, rate-limit, CORS, /
│ gRPC (tonic)
Core (core/crates/grpc, tonic server) ── crypto/keyring/provider/router/txguard/sign/positions
publishes tx events → Redis Streams → audit (SQLite)
writes each action directly → audit (SQLite WAL, append-only)
Ethereum RPC (Alchemy primary, public RPC fallback, eth_call)
```
Expand All @@ -76,6 +76,10 @@ Ethereum RPC (Alchemy primary, public RPC fallback, eth_call)
`/api/v1/*` (key = `RUSTOK_MCP_API_KEY`); `/health` open.
- **MCP tools (6):** `get_wallet_context`, `get_balances`, `get_positions`,
`preview_send`, `execute_send`, `sign_message` — capability-gated.
- **Audit:** Core writes each wallet action to an append-only **SQLite WAL** log
(authoritative single source of truth). *The Phase-4 Redis Streams event bus was
decommissioned 2026-06-17 (core #63/#64) — the `events` crate and the `redis`
service are gone.*
- **Observability (opt-in):** OTLP push (traces+metrics+logs) → Alloy → Tempo /
Prometheus / Loki → Grafana. Enabled via `RUSTOK_OTLP_ENDPOINT`. Off by default.

Expand Down Expand Up @@ -105,7 +109,7 @@ meta #20). Optional remaining: PR-5.3 Postgres.

---

## 5. Current state (2026-06-15)
## 5. Current state (2026-06-15; Redis decommissioned 2026-06-17 — see §3 Audit)

- All core gates green; full chain **MCP → Gateway → Core** verified end-to-end
against real mainnet (a real Aave v3 position decodes through `get_positions`).
Expand Down Expand Up @@ -134,7 +138,7 @@ Port 22 closed.
**Running (Docker):**
- New stack — `/opt/rustok/deploy-v2/` (compose project `rustokv2`):
`rustok-core`, `rustok-gateway` (test port `127.0.0.1:3001`), `rustok-mcp`
(`127.0.0.1:3002`), `rustok-redis`. Keystore in volume `rustokv2_rustok-data`
(`127.0.0.1:3002`). Keystore in volume `rustokv2_rustok-data`
(agent wallet `0x0C58C2a797c1c6E966321cD76F3369E13a0357ae`). Secrets in
`/opt/rustok/deploy-v2/.env` (chmod 600). RPC = public, chains `1,8453`.
- `rustok-caddy` (caddy:2-alpine, 80/443) — TLS termination, certs in
Expand Down Expand Up @@ -232,7 +236,7 @@ test port, then Caddy `reverse_proxy` repointed + graceful `caddy reload`
```bash
# Server
ssh rustok-prod
docker ps # rustok-core/gateway/mcp/redis + caddy + (VPN)
docker ps # rustok-core/gateway/mcp + caddy + (VPN)
docker compose -f /opt/rustok/deploy-v2/docker-compose.yml ps
docker logs rustok-core --tail 50
docker logs rustok-caddy --since 10m | grep api.rustokwallet.com # access logs
Expand Down
17 changes: 9 additions & 8 deletions docs/PROJECT-STATUS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Project Status — Rustok Org

> Updated: 2026-06-15
> Updated: 2026-06-22
> Read this at session start to understand where we are.
> Phase numbering follows `core/docs/CORE-MCP-ROADMAP.md` (source of truth for the MVP roadmap).

Expand All @@ -23,7 +23,7 @@
| 7 — Self-Custody Distribution | onboarding, public image, all-in-one MCP image, ClawHub republish | ✅ **SHIPPED 2026-06-15** — onboarding core #53; capability-grant fix mcp #30; de-v1-ify mcp #28/#31; all-in-one stdio image mcp #29; EULA core #58 (RF); SHA-pin fix core #59/mcp #33; images on GHCR (`rustok-wallet` public, `rustok-core` private); **ClawHub skill 0.3.0** (mcp #34, > 0.2.2), smoke-verified |
| Production cutover | new stack on `api.rustokwallet.com` | ✅ done 2026-06-14; audit-consumer #55/#56 + gateway lazy-channel #57 built & deployed; monolith stopped (retained for rollback) |

**Core workspace (13 crates):** `types`, `crypto`, `keyring`, `provider`, `router`, `txguard`, `sign`, `audit`, `events`, `wallet`, `gateway`, `grpc`, `positions` (PR-6.1) (~190 `#[test]` functions as of PR #43; positions added more).
**Core workspace (12 crates):** `types`, `crypto`, `keyring`, `provider`, `router`, `txguard`, `sign`, `audit`, `wallet`, `gateway`, `grpc`, `positions` (PR-6.1) (~190 `#[test]` functions as of PR #43; positions added more). The Phase-4 `events` crate (Redis Streams) was removed 2026-06-17 (core #63/#64).

**End-to-end chain works with real data:** MCP → Gateway → Core returns real address, balances, `tx_hash`, EIP-191 signatures (Phase 4.5 gate passed). All 5 original MCP tools are real since 2026-06-10 (read path: Gateway `GET /api/v1/wallet/context` + `/balance`, core #44; MCP wiring, mcp #22 — verified end-to-end via stdio). Full stack runs via `meta/docker-compose.yml` (meta #11).

Expand All @@ -42,13 +42,13 @@
## Next Immediate Steps

### Primary: cleanup tails (Phase 7 shipped)
1. **GH Actions Node 20→24:** bump the docker actions (v3.10.0/v5.7.0/v6.16.0 run on
Node 20, deprecated 2026-06-16) in `docker-publish` (core) + `wallet-publish` (mcp).
2. **Reproducibility:** commit deploy-v2 compose + `Caddyfile-v2` into `meta`.
3. **Remove the old monolith** (`rustok-api`) after 24–48h prod stability (cutover 2026-06-14).
1. ~~**GH Actions Node 20→24**~~ ✅ **done** — core `docker-publish` (#66), meta `checkout` v6.0.3 (#23); mcp workflows already pin Node-24-era actions (`actions/checkout@v6.0.3`, `docker/build-push-action@v7.2.0`).
2. ~~**Reproducibility:** commit deploy-v2 compose + `Caddyfile-v2` into `meta`~~ ✅ **done** (meta #24; Caddyfile-v2 security headers + body cap #26).
3. **Remove the old monolith** (`rustok-api`) after 24–48h prod stability (cutover 2026-06-14) — *server-side, verify.*
4. **Alchemy RPC:** swap the public RPCs for an Alchemy key (needs the key) —
`/opt/rustok/deploy-v2/.env` → `docker compose up -d core`.
5. **Re-enable GHCR publish workflows** once Actions minutes reset (manual local push was a one-off).
5. **Verify prod is on the post-06-15 core** (#63/#64 Redis removal, #65 gateway hardening, #67 graceful exit) — the repo carries them; confirm the running stack matches and Redis is actually gone from the host.
6. **Re-enable GHCR publish workflows** once Actions minutes reset (manual local push was a one-off; mcp `wallet-publish` is currently manual-trigger #45).

### Done — Phase 5 Production Hardening (PR-5.3 Postgres is the only optional remainder)
1. ~~**PR-5.1 remainder** — reverse proxy + SSL~~ ✅ **done** — Caddy TLS overlay
Expand Down Expand Up @@ -133,14 +133,15 @@
| 2026-06-14 | **Phase 7 self-custody distribution:** onboarding `create_wallet`+recovery mnemonic (core #53, PR-7.3); public Core image → GHCR on `v*` tags (core #54, PR-7.2); mcp de-v1-ify (#28) + all-in-one stdio wallet image (#29, PR-7.1b). |
| 2026-06-14 | **Audit consumer P1 fixed + deployed:** resilient consumer (core #55) + block-compatible `response_timeout` (core #56); prod core rebuilt from `main` & redeployed (core+gateway), verified `audit stream read failed`=0, agent wallet `0x0C58…` intact. Found + worked around the gateway↔core startup race. |
| 2026-06-15 | **"Replace ClawHub" SHIPPED:** capability-grant fix for standard stdio clients (mcp #30) + README de-v1 (mcp #31); proprietary EULA, governing law RF (core #58); gateway↔core lazy/reconnecting channel (core #57) — race fixed & **deployed to prod** (`/health` core:serving, no manual restart); publish-workflow SHA-pin fix (core #59, mcp #33); skill version 0.3.0 (mcp #34). Images built locally + pushed to GHCR (`rustok-wallet` **public**, `rustok-core` private; Actions minutes were exhausted); **ClawHub skill republished at 0.3.0** (> 0.2.2); public image smoke-verified (anon pull → 6 tools). |
| 2026-06-17→19 | **Redis decommission + post-ship hardening:** authoritative SQLite audit, **Redis event path removed** (core #63, 06-17), **Redis decommissioned from the new stack** (core #64, 06-17; deploy-v2 meta #25, 06-17) → `events` crate dropped (**13→12 crates**); gateway startup + CORS hardening (core #65, I6/I7, 06-18); graceful exit on an unknown `core-server` subcommand (core #67, 06-18); CI to **Node 24** docker-publish (core #66) + drop Coverage & macOS/iOS cross-check (core #68, 06-18); Caddyfile-v2 security headers & body cap (meta #26, 06-18); mcp — skill 0.3.1 (#41) / 0.3.2 (#44), keyring-password-in-argv fix (#42), ephemeral MCP API key in entrypoint (direct commit `2dc3bb9`), `wallet-publish` manual-trigger (#45, 06-19). *(Repo state; confirm prod redeploy of the core changes.)* |

---

## Repo Snapshot

| Repo | Visibility | Stack | State |
|------|-----------|-------|-------|
| `core` | Private | Rust 2024 (13 crates) | Phases 0–7 done; prod-deployed (gateway lazy-channel #57); proprietary EULA (RF); image on GHCR (private) |
| `core` | Private | Rust 2024 (12 crates) | Phases 0–7 done; prod-deployed (gateway lazy-channel #57); Redis decommissioned (#63/#64); proprietary EULA (RF); image on GHCR (private) |
| `mcp` | Public | Python 3.12 + FastAPI + uv | Complete: 6 tools, stdio process-trusted (all caps by default); all-in-one wallet image **public on GHCR**; ClawHub skill **0.3.0** |
| `mobile` | Public | React Native 0.76 + TS | Scaffold only (placeholder App.tsx) |
| `llm` | Public (docs say private!) | TBD | Scaffold only; stack undecided |
Expand Down