Skip to content

RECTOR-LABS/kami

Repository files navigation

██╗  ██╗  █████╗  ███╗   ███╗ ██╗
██║ ██╔╝ ██╔══██╗ ████╗ ████║ ██║
█████╔╝  ███████║ ██╔████╔██║ ██║
██╔═██╗  ██╔══██║ ██║╚██╔╝██║ ██║
██║  ██╗ ██║  ██║ ██║ ╚═╝ ██║ ██║
╚═╝  ╚═╝ ╚═╝  ╚═╝ ╚═╝     ╚═╝ ╚═╝

Kami — AI Co-Pilot for Kamino DeFi on Solana

🤖 Type plain English. Get a signed mainnet transaction. Every time. Seven Kamino tools · Real APYs · Health-factor projection · LLM auto-recovery · Preflight simulation · Sign & Send · Live mainnet

CI GitLab Mirror Uptime Heartbeat Tests Solana Live Bounty License: MIT

TypeScript React Vite Tailwind AI SDK klend-sdk @solana/kit

🚀 Live Demo · 📖 Integration Deep-Dive · 🎬 Demo Script · 🐦 Tweet Thread


🎬 What is Kami?

Kami is a conversation-driven Kamino Finance frontend on Solana. The user types in plain English — "best USDC yield right now", "will this borrow liquidate me?", "deposit 5 USDC", "repay everything" — an LLM orchestrates real @kamino-finance/klend-sdk calls, and when the request is actionable, returns a ready-to-sign mainnet transaction.

No raw transaction JSON. No protocol jargon. No hand-rolled instructions. Every write tool maps one-to-one to a real KaminoAction.build*Txns primitive, and every read tool is backed by live on-chain Scope-oracle data.

Kami architecture — plain English to signed mainnet tx


✅ Proof of Life

Deposited live on mainnet through the deployed UI:

The full deposit → repay → withdraw round-trip (with NetValueRemainingTooSmall auto-recovery) was validated on 2026-04-24 — three archived signatures in docs/kamino-integration.md → Hero moment.


📚 Table of Contents


✨ Features

🔍 Read-only tools (no signing)

Tool What it does klend-sdk primitive
getPortfolio Connected wallet's live Kamino position: deposits, borrows, APYs, LTV, health factor KaminoMarket.getObligationByAddress
findYield Top reserves ranked by live supply / borrow APY, filterable by symbol KaminoMarket.reserves + Reserve.calculateSupplyAPY
simulateHealth Project the user's health factor after a hypothetical deposit / borrow / withdraw / repay KaminoObligation.simulateBorrowAndWithdrawAction

✍️ Write actions (produce a signable transaction)

Tool What it does klend-sdk primitive
buildDeposit Construct an unsigned Deposit transaction with proper account inits KaminoAction.buildDepositTxns
buildBorrow Construct an unsigned Borrow with health-factor preflight KaminoAction.buildBorrowTxns
buildWithdraw Construct an unsigned Withdraw (principal + accrued interest) KaminoAction.buildWithdrawTxns
buildRepay Construct an unsigned Repay; LLM auto-recovers from NetValueRemainingTooSmall KaminoAction.buildRepayTxns

Each build* tool produces a versioned v0 transaction server-side: fresh blockhash, proper compute budget, all required account initializations for first-time users, then base64-encoded wire bytes returned to the client. The UI renders a Sign & Send card; the user signs in their wallet; the client submits and HTTP-polls confirmation until confirmed or blockhash expiry.

🛡️ Safety rails

  • Preflight simulation — every build* tool runs simulateTransaction before returning. If the wallet is short on SOL for account rent, Kami surfaces a precise shortfall before the user burns a failed-tx fee.
  • Oracle staleness gate — borrows and deposits reject if the price feed is more than ~600 slots stale (matches Pyth/Switchboard convention).
  • LLM auto-recoverybuildRepay failure on Kamino's NetValueRemainingTooSmall dust floor triggers an automatic getPortfolio refresh + retry with a small buffer. No hand-coded retry loop; the system prompt teaches the LLM to reason about the error.
  • Server-side AbortSignal — client cancellation propagates all the way through the streaming pipeline.
  • RPC method allowlist — the /api/rpc proxy passes only 10 explicitly-allowed JSON-RPC methods. Anything else gets a structured 403.
  • Rate-limited — 30/min on /api/chat, 120/min on /api/rpc, fail-open on backend outage so a Redis blip never 500s the app.
  • ErrorBoundary at root — uncaught render errors surface a recovery panel instead of a white screen.

🎨 UX polish

  • Clickable empty-state cards fire representative queries with one click — "Best USDC yield", "Will this liquidate me?", and two more.
  • Inline waiting dots (no separate typing-indicator component) for a calmer streaming feel.
  • Hover sidebar to see full conversation titles via native title tooltip (no JS overhead).
  • Hover-pencil rename on each conversation in the sidebar.
  • Settings menu with bulk-clear conversations.
  • Yield table risk chips (:risk-high: / :risk-medium: / :risk-low:) auto-render as colored badges.
  • Wallet-not-connected modal + inline CTA + yellow status pill — every guarded action surfaces a clear path forward.

🏗️ Architecture

Kami end-to-end data flow

Single source of truth. server/chat.ts exports a Web ReadableStream powered by Vercel AI SDK streamText + fullStream. The same factory wires the LLM, the seven tool definitions, the system prompt, and the streaming protocol — consumed by Fastify in local dev (server/index.ts) and a Node-style Vercel Function in production (api/chat.ts).

Same-origin RPC. Every browser RPC call hits /api/rpc, a Vercel Function that proxies JSON-RPC to Helius server-side. Keeps the API key off the client, sidesteps CORS, and avoids new-domain reputation issues. Method allowlist + batch-size guard + 120/min rate-limit live on the proxy.

No private keys server-side. Transaction build uses createNoopSigner(walletAddress) + compileTransaction + getBase64EncodedWireTransaction. The wallet signs on the client. The server never holds a secret.

Confirmation by HTTP polling. Vercel Functions can't upgrade WebSockets, so the default subscription-based confirmTransaction would hang. Kami polls getSignatureStatuses + getBlockHeight over HTTP until confirmed or blockhash expiry — exposed as a generator hook in SignTransactionCard.tsx.

Modern wallet discovery. Featured wallet is Solflare via Wallet Standard auto-discovery — no explicit adapter package is imported. wallets = [] in WalletProvider.tsx; modern Solflare registers itself globally and any other Wallet-Standard-compliant wallet (Phantom, Backpack, etc.) shows up under "Use another wallet".


🚀 Quick Start

# 1. Clone + install
git clone https://github.com/RECTOR-LABS/kami.git
cd kami
pnpm install

# 2. Configure environment
cp .env.example .env.local
# Edit .env.local — fill KAMI_OPENROUTER_API_KEY + SOLANA_RPC_URL

# 3. Run dev server (web :5173 + api :3001 concurrently)
pnpm dev

# 4. Open http://localhost:5173

Required environment variables:

Variable Purpose Where to get
KAMI_OPENROUTER_API_KEY LLM access openrouter.ai/keys
SOLANA_RPC_URL Mainnet RPC (recommended: Helius) helius.dev
KAMI_MODEL (optional) Override default model Defaults to anthropic/claude-sonnet-4.6

Optional rate-limit (production-grade):

Variable Purpose
UPSTASH_REDIS_REST_URL Upstash REST endpoint or SRH shim URL
UPSTASH_REDIS_REST_TOKEN Bearer token

If the rate-limit env vars are unset, the app runs without rate-limiting locally (still safe — the production deployment enforces them).


🛠️ Tech Stack

Layer Tech Notes
Frontend Vite 6 + React 18 + TypeScript 5 + Tailwind 3 Solflare via Wallet Standard auto-discovery
Chat handler Node-style Vercel Function (prod) + Fastify (local dev) One source of truth in server/chat.ts
LLM anthropic/claude-sonnet-4.6 via OpenRouter Swappable via KAMI_MODEL
AI SDK Vercel AI SDK v6 — streamText + fullStream Tool-call / tool-result events surface to client
DeFi @kamino-finance/klend-sdk 7.3 on @solana/kit v2 Kamino Main Market
Tx build createNoopSigner + compileTransaction + getBase64EncodedWireTransaction No private keys server-side
Confirmation HTTP polling (getSignatureStatuses + getBlockHeight) Vercel Functions can't upgrade WebSockets
RPC proxy Same-origin /api/rpc Vercel Function Helius mainnet, allowlist-guarded, 120/min
Rate limit @upstash/ratelimit + self-hosted Redis (Upstash REST shim) VPS-hosted; fail-open on outage
Streaming Web ReadableStream piped via Readable.fromWeb Node-style handler protocol
Tests Vitest 4 + happy-dom 186 tests across 21 files
Hosting Vercel (Fluid Compute) Cloudflare DNS-only → Vercel auto-SSL

🧪 Testing & Quality

  • 186 vitest tests across 21 files — handlers, RPC guards, rate-limit, kamino helpers, streaming hook, ErrorBoundary, wallet-error classifier, markdown renderer, sidebar, and more
  • Continuous integration — typecheck (client + server) → tests → build → klend-sdk major-pin guard. The pin guard fails CI if @kamino-finance/klend-sdk jumps a major version (e.g., 7.x → 8.x), ensuring breaking SDK changes get a deliberate review.
  • Project-mode TypeScriptpnpm exec tsc -b validates client; pnpm exec tsc -p server/tsconfig.json --noEmit validates server + Vercel Functions. Both must pass before push.
  • Coverage focus — Day 5–8 production-critical surfaces (handlers, guards, ratelimit, walletError, ErrorBoundary) are ≥ 80% covered. Solana SDK orchestration in server/tools/kamino.ts is validated via mainnet round-trips, not unit tests — see archived signatures in Hero moment.
  • 27 issues closed across 10 PRs in the QA backlog umbrella (#3). Two-stage code review per task, cluster-level review per sprint, mutation-tested invariants on every cluster.

🔒 Security & Production Hardening

Surface Hardening
HTTP headers CSP, HSTS (2y, preload), X-Content-Type-Options=nosniff, X-Frame-Options=DENY, Referrer-Policy, Permissions-Policy, COOP — all in vercel.json
RPC proxy Method allowlist (10 methods) + batch size cap + 120/min rate limit + same-origin only
Chat endpoint Zod-validated request schema + 30/min rate limit + server-side AbortSignal propagation
Oracle staleness Borrows / deposits reject if price feed > ~600 slots stale (matches Pyth/Switchboard)
Top-level boundary React ErrorBoundary at root catches uncaught render errors with a recovery panel
No keys client-side Transaction build via no-op signer; the wallet signs
No keys browser-side Helius RPC key never leaves the Vercel Function
Rate-limit fail-open If Upstash/SRH fails, requests serve unenforced rather than 500
Uptime heartbeat GitHub Actions ping the Redis backend every 15 minutes

Full security review notes live in docs/kamino-integration.md and the project-internal QA backlog (umbrella #3).


🚢 Deployment

  • Vercel auto-deploys from mainkami.rectorspace.com. Custom domain on Cloudflare DNS-only with Vercel auto-SSL.
  • Function timeouts: api/chat.ts = 60s, api/rpc.ts = 30s.
  • VPS-hosted Redis behind a Cloudflare tunnel (redis-kami.rectorspace.com) backs the rate-limit. iad1 → ams adds ~100–120 ms per API call (acceptable cost; fail-open on outage).
  • GitLab mirror via mirror-gitlab.yml force-pushes main to a backup remote on every commit (resilience after Dec-2025 platform-flag incident).
  • Uptime workflow (uptime-redis.yml) PINGs the Redis backend every 15 min; failures alert via the workflow run.
  • Environment variables managed via Vercel CLI (vercel env) — never checked into the repo.

📖 Documentation

  • Kamino Integration Deep-Dive — bounty deliverable. Tool-by-tool SDK primitive mapping, architecture walkthrough, hero-moment auto-recovery, edge-case catalog, mainnet validation signatures.
  • Demo Script — 2:30–2:50 shot list + voice-over for the bounty submission video.
  • Tweet Thread — 5-tweet launch draft + handle verification + posting checklist.
  • CLAUDE.md — project context for AI-assisted development sessions.

🏆 Bounty Context

  • Bounty: Eitherway Track — Frontier Hackathon 2026
  • Submission deadline: 2026-05-12
  • Sponsors: Eitherway · Kamino · Solflare · Helius
  • Track angle: Build a live dApp with Solflare, Kamino, DFlow, or Quicknode, with Eitherway. Kami builds with Eitherway (scaffold + deploy pipeline), Kamino (klend SDK + Main Market), Solflare (featured wallet via Wallet Standard), and Helius (RPC proxy). Three sponsor surfaces, one focused product.

🙏 Acknowledgments

Special thanks to the protocols, platforms, and people who made Kami possible:

🔗 Solana Ecosystem

  • Kamino Finance@kamino-finance/klend-sdk, the Main Market, the protocol that this entire project celebrates
  • Solflare — featured wallet, Wallet Standard pioneer, and one of the cleanest Solflare-Web3.js bridges in the ecosystem
  • Helius — fast and reliable RPC infrastructure, plus the DAS API that makes Solana asset queries pleasant
  • Anza@solana/kit v2, the modern tree-shakeable JS SDK that klend 7.x runs on

🛠️ Infrastructure

  • Eitherway — initial scaffold + deploy pipeline (tagged eitherway-v0 on 2026-04-19)
  • Vercel — hosting, Fluid Compute, AI SDK v6, and the cleanest Node-style Function runtime in the business
  • Anthropic — Claude Sonnet 4.6 (the model that powers Kami's reasoning)
  • OpenRouter — model gateway

🏗️ Tooling

📡 Community

  • Superteam — bounty platform that hosts the Frontier Hackathon
  • Solana developer community — endless docs, examples, and patience

🌱 Origin

Initial scaffold generated by Eitherway on 2026-04-19 (tagged eitherway-v0). Everything after is custom: Fastify + Vercel Function backends, Kamino SDK integration, the seven-tool suite, same-origin RPC proxy, preflight simulation, oracle-staleness gate, Sign & Send card, polling-based confirmation, top-level ErrorBoundary, rate-limit infrastructure, and the entire UX polish layer (Sprints 1–4 of the QA backlog).


📜 License

Released under the MIT License — see LICENSE for the full text.

You're free to fork, study, modify, and redistribute Kami for any purpose, including commercial use. Attribution is appreciated but not required by the license.


🏆 Built for the Eitherway Track · Frontier Hackathon 2026

Bismillah. Built with care, shipped with rigor.

Live Repo Bounty License: MIT

🐛 Report a bug · 📖 Integration docs · 🎬 Demo script

About

AI co-pilot for Kamino DeFi on Solana — chat-driven lending, yield, and health-factor assistant. Built for the Eitherway Track, Frontier Hackathon 2026.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages