Skip to main content

Overview

Karen can be imported as a TypeScript library into your Node.js application, giving you programmatic access to all wallet management, transaction execution, and DeFi capabilities. This is ideal for:
  • Building custom AI agents with full control over the decision loop
  • Integrating Solana wallets into existing applications
  • Creating trading bots with custom strategies
  • Developing autonomous systems that need Solana blockchain interactions
Karen is built with TypeScript and provides full type definitions for all classes and methods.

Installation

npm install karen
Package name is tentative. For now, clone the repo and import directly:
git clone https://github.com/Don-Vicks/karen.git
cd karen
npm install
npm run build
Then in your project:
import { WalletManager, TransactionEngine } from '../path/to/karen/src'

Core Exports

Karen exports the following modules from src/index.ts:
// Agent runtime and orchestration
export * from './agent'
export { ApiServer } from './api/server'

// Core wallet and transaction infrastructure
export * from './core'

// MCP server
export { startMCPServer } from './mcp/server'

// DeFi protocol adapters
export * from './protocols'

Main Classes

WalletManager

Create and manage Solana wallets, HD derivation, balance queries

TransactionEngine

Execute transactions with guardrails, audit logging, history

AgentRuntime

Autonomous agent loop with LLM integration and skill execution

Orchestrator

Manage multiple agents, create/start/stop, chat interface

ApiServer

REST API server for HTTP access to all Karen features

Guardrails

Security policies for spending limits, rate limiting, program whitelist

Quick Start

Basic Wallet Operations

import { WalletManager, TransactionEngine, Guardrails, AuditLogger } from 'karen'

// Initialize services
const password = 'your-secure-password'
const walletManager = new WalletManager(password)
const logger = new AuditLogger()
const guardrails = new Guardrails(undefined, logger)
const txEngine = new TransactionEngine(walletManager, guardrails, logger)

// Create a wallet
const wallet = await walletManager.createWallet('my-bot', ['trading', 'automated'])
console.log('Wallet created:', wallet.publicKey)

// Check balance
const balance = await walletManager.getBalances(wallet.id)
console.log('SOL balance:', balance.sol)
console.log('Tokens:', balance.tokens)

// Request devnet airdrop
const airdropRecord = await txEngine.airdrop(wallet.id, 2)
if (airdropRecord.status === 'confirmed') {
  console.log('Airdrop successful:', airdropRecord.signature)
}

// Transfer SOL
const transferRecord = await txEngine.transferSol(
  wallet.id,
  '7xKKzD8qHa...', // recipient address
  0.5 // amount
)

if (transferRecord.status === 'confirmed') {
  console.log('Transfer successful:', transferRecord.signature)
} else if (transferRecord.status === 'blocked') {
  console.error('Blocked by guardrails:', transferRecord.error)
}

WalletManager

Manages encrypted keystores, wallet creation, and balance queries.

Constructor

import { WalletManager } from 'karen'

const walletManager = new WalletManager(
  password: string,           // Keystore encryption password
  keystorePath?: string       // Optional custom path (default: ~/.karen/keystore.enc)
)

Methods

Create a new standalone wallet.
async createWallet(
  name: string,
  tags?: string[]
): Promise<WalletInfo>
Example:
const wallet = await walletManager.createWallet('trading-bot', ['automated'])
console.log('Wallet ID:', wallet.id)
console.log('Address:', wallet.publicKey)
Create an HD-derived wallet from a mnemonic.
async createDerivedWallet(
  name: string,
  mnemonic: string,
  index: number
): Promise<WalletInfo>
Example:
const mnemonic = WalletManager.generateMnemonic()
const wallet = await walletManager.createDerivedWallet(
  'agent-1',
  mnemonic,
  0 // derivation index
)
Get SOL and SPL token balances.
async getBalances(walletId: string): Promise<{
  sol: number
  tokens: Array<{
    mint: string
    symbol?: string
    uiBalance: string
    rawBalance: string
  }>
}>
Example:
const { sol, tokens } = await walletManager.getBalances(wallet.id)
console.log(`Balance: ${sol} SOL`)
tokens.forEach(t => console.log(`  ${t.symbol}: ${t.uiBalance}`))
List all managed wallets.
listWallets(): WalletInfo[]
Get wallet by ID.
getWallet(walletId: string): WalletInfo | undefined
Find wallet by name.
findWalletByName(name: string): WalletInfo | undefined
Get Solana keypair for signing (internal use).
getKeypair(walletId: string): Keypair

TransactionEngine

Executes transactions with guardrails, audit logging, and transaction history.

Constructor

import { TransactionEngine, Guardrails, AuditLogger } from 'karen'

const txEngine = new TransactionEngine(
  walletManager: WalletManager,
  guardrails: Guardrails,
  logger: AuditLogger
)

Methods

Send SOL to another address.
async transferSol(
  walletId: string,
  to: string,
  amount: number,
  source?: string  // Optional context (e.g., 'api', 'agent')
): Promise<TransactionRecord>
Example:
const record = await txEngine.transferSol(
  wallet.id,
  '7xKKzD8qHa...',
  0.5,
  'my-app'
)

if (record.status === 'confirmed') {
  console.log('Tx signature:', record.signature)
} else if (record.status === 'blocked') {
  console.error('Blocked:', record.error)
}
Request devnet SOL airdrop.
async airdrop(
  walletId: string,
  amount: number,
  source?: string
): Promise<TransactionRecord>
Get transaction history.
getTransactionHistory(
  walletId?: string,  // Optional: filter by wallet
  limit: number = 20
): TransactionRecord[]
Example:
const txs = txEngine.getTransactionHistory(wallet.id, 50)
txs.forEach(tx => {
  console.log(`${tx.type} - ${tx.status} - ${tx.timestamp}`)
})

DeFi Protocol Adapters

Karen includes adapters for common Solana DeFi operations.

JupiterAdapter - Token Swaps

import { JupiterAdapter, KNOWN_TOKENS } from 'karen'

const jupiter = new JupiterAdapter()

// Execute swap
const result = await jupiter.executeSwap(
  walletManager,
  wallet.id,
  'SOL',        // input token
  'USDC',       // output token
  0.5,          // amount
  50            // slippage in bps (0.5%)
)

console.log('Swapped:', result.inputAmount, '→', result.outputAmount)
console.log('Signature:', result.signature)

// Known token addresses
console.log(KNOWN_TOKENS.USDC)  // EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

TokenLauncherAdapter - Create SPL Tokens

import { TokenLauncherAdapter } from 'karen'

const launcher = new TokenLauncherAdapter()

// Create a new token
const token = await launcher.createToken(
  walletManager,
  wallet.id,
  'Agent Coin',   // name
  'AGT',          // symbol
  9,              // decimals
  1_000_000       // initial supply
)

console.log('Mint address:', token.mint)
console.log('Supply:', token.supply)

// Mint additional supply
const mintResult = await launcher.mintAdditionalSupply(
  walletManager,
  wallet.id,
  token.mint,
  500_000,        // amount
  9               // decimals
)

// Revoke mint authority (irreversible!)
const sig = await launcher.revokeMintAuthority(
  walletManager,
  wallet.id,
  token.mint
)

StakingAdapter - Native Staking

import { StakingAdapter } from 'karen'

const staking = new StakingAdapter()

// Stake SOL
const stakeResult = await staking.stakeSOL(
  walletManager,
  wallet.id,
  1.0,  // amount
  'BeachiopjxQxL7CaHNSZsynRdj6vY5vCeaTXGKqfCZTP'  // validator (optional)
)

console.log('Stake account:', stakeResult.stakeAccount)

// List stake accounts
const stakes = await staking.getStakeAccounts(wallet.publicKey)
stakes.forEach(s => {
  console.log(`${s.address}: ${s.solBalance} SOL (${s.state})`)
})

// Unstake
await staking.unstakeSOL(walletManager, wallet.id, stakeResult.stakeAccount)

// Withdraw (after 1 epoch)
await staking.withdrawStake(walletManager, wallet.id, stakeResult.stakeAccount)

WrappedSolAdapter - wSOL Operations

import { WrappedSolAdapter } from 'karen'

const wsol = new WrappedSolAdapter()

// Wrap SOL
const wrapResult = await wsol.wrapSOL(walletManager, wallet.id, 1.0)
console.log('Wrapped:', wrapResult.amount, 'SOL')

// Unwrap all wSOL
const unwrapResult = await wsol.unwrapSOL(walletManager, wallet.id)
console.log('Unwrapped:', unwrapResult.amount, 'wSOL')

SplTokenAdapter - Token Account Management

import { SplTokenAdapter } from 'karen'

const spl = new SplTokenAdapter()

// Burn tokens
const burnResult = await spl.burnTokens(
  walletManager,
  wallet.id,
  '7xKKzD8qHa...',  // mint address
  100               // amount
)

// Close empty token account (reclaim rent)
const closeResult = await spl.closeTokenAccount(
  walletManager,
  wallet.id,
  '7xKKzD8qHa...'
)

console.log('Rent reclaimed:', closeResult.rentReclaimed, 'SOL')

Building Custom Agents

Using AgentRuntime

import { AgentRuntime, createDefaultSkillRegistry, MemoryStore } from 'karen'

const config = {
  id: 'agent-1',
  name: 'Trading Bot',
  walletId: wallet.id,
  strategy: 'Buy low, sell high on SOL/USDC',
  llmProvider: 'openai' as const,
  llmModel: 'gpt-4',
  loopIntervalMs: 30000,
  maxSolPerTransaction: 2,
  dailySpendingLimitSol: 10
}

const skillRegistry = createDefaultSkillRegistry(walletManager, txEngine)
const memory = new MemoryStore()

const agent = new AgentRuntime(
  config,
  skillRegistry,
  walletManager,
  txEngine,
  guardrails,
  logger,
  memory
)

// Start autonomous loop
agent.start()

// Chat with agent
const response = await agent.chat('What is your current balance?')
console.log('Agent:', response)

// Stop agent
agent.stop()

Using Orchestrator (Multiple Agents)

import { Orchestrator } from 'karen'

const orchestrator = new Orchestrator(
  walletManager,
  txEngine,
  guardrails,
  logger
)

// Create agent
const agentConfig = await orchestrator.createAgent({
  name: 'trader-1',
  strategy: 'Momentum trading on SOL/USDC',
  llmProvider: 'anthropic',
  llmModel: 'claude-3-5-sonnet-20241022',
  loopIntervalMs: 60000
})

// Start agent
orchestrator.startAgent(agentConfig.id)

// List all agents
const agents = orchestrator.listAgents()
console.log('Running agents:', agents.filter(a => a.status === 'running'))

// Stop all
orchestrator.stopAll()

Guardrails Configuration

import { Guardrails, AuditLogger } from 'karen'

const customGuardrails = new Guardrails(
  {
    maxSolPerTransaction: 5,
    maxTransactionsPerMinute: 10,
    dailySpendingLimitSol: 50,
    allowedPrograms: [
      '11111111111111111111111111111111',  // System
      'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',  // Token Program
      'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'   // Jupiter
    ]
  },
  new AuditLogger()
)

API Server Integration

import { ApiServer } from 'karen'

const apiServer = new ApiServer(
  walletManager,
  txEngine,
  guardrails,
  logger,
  orchestrator
)

apiServer.start(3001)
// Server running on http://localhost:3001

Type Definitions

WalletInfo

type WalletInfo = {
  id: string
  name: string
  publicKey: string
  tags: string[]
  createdAt: string
  metadata?: Record<string, any>
}

TransactionRecord

type TransactionRecord = {
  id: string
  type: string
  walletId: string
  status: 'pending' | 'confirmed' | 'failed' | 'blocked'
  signature?: string
  error?: string
  metadata?: Record<string, any>
  guardrailsApplied?: string[]
  timestamp: string
}

AgentConfig

type AgentConfig = {
  id: string
  name: string
  walletId: string
  strategy: string
  llmProvider: 'openai' | 'anthropic' | 'grok' | 'gemini'
  llmModel?: string
  loopIntervalMs: number
  maxSolPerTransaction: number
  dailySpendingLimitSol: number
  status: 'idle' | 'running' | 'stopped' | 'error'
  createdAt: string
}

Complete Example: Trading Bot

import {
  WalletManager,
  TransactionEngine,
  Guardrails,
  AuditLogger,
  JupiterAdapter
} from 'karen'

async function main() {
  // Setup
  const walletManager = new WalletManager('secure-password')
  const logger = new AuditLogger()
  const guardrails = new Guardrails(undefined, logger)
  const txEngine = new TransactionEngine(walletManager, guardrails, logger)
  const jupiter = new JupiterAdapter()

  // Create wallet
  const wallet = await walletManager.createWallet('trading-bot')
  console.log('Wallet:', wallet.publicKey)

  // Fund with devnet SOL
  await txEngine.airdrop(wallet.id, 2)
  console.log('Funded with 2 SOL')

  // Trading loop
  setInterval(async () => {
    const { sol, tokens } = await walletManager.getBalances(wallet.id)
    const usdc = tokens.find(t => t.symbol === 'USDC')

    console.log(`Balance: ${sol} SOL, ${usdc?.uiBalance || 0} USDC`)

    // Simple strategy: buy USDC if SOL > 1, sell if USDC > 20
    if (sol > 1) {
      const result = await jupiter.executeSwap(
        walletManager,
        wallet.id,
        'SOL',
        'USDC',
        0.5,
        50
      )
      console.log('Bought USDC:', result.outputAmount)
    } else if (parseFloat(usdc?.uiBalance || '0') > 20) {
      const result = await jupiter.executeSwap(
        walletManager,
        wallet.id,
        'USDC',
        'SOL',
        10,
        50
      )
      console.log('Bought SOL:', result.outputAmount)
    }
  }, 60000)  // Every minute
}

main().catch(console.error)

Next Steps

API Reference

Detailed class and method documentation

CLI

Command-line interface reference

MCP Server

Integrate with Claude Desktop

Build Agents

Create autonomous AI agents

Build docs developers (and LLMs) love