6.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
kvs-sh is an interactive CLI shell for the KVS (Key-Value Store) distributed database. Think mongosh
, psql
, or redis-cli
but for KVS. Single Go file implementation (~600 lines) with readline support for command history and auto-completion.
KVS Server Reference
The complete KVS server source code is located at ../kvs/
relative to this repository. Reference it when:
- Understanding API contracts and response formats
- Verifying authentication/authorization behavior
- Checking endpoint paths and HTTP methods
- Understanding data structures (StoredValue, Member, User, Group types)
- Implementing new shell commands for backend features
Key server locations:
../kvs/server/handlers.go
- All API endpoint implementations../kvs/server/routes.go
- Route definitions and HTTP methods../kvs/types/types.go
- Canonical type definitions (StoredValue, etc.)../kvs/auth/
- JWT authentication and permission system details../kvs/README.md
- Complete API documentation with curl examples../kvs/CLAUDE.md
- Server architecture and development guidance
When adding new commands to kvs-sh, always verify the actual backend implementation in ../kvs/
rather than making assumptions about API behavior.
Build & Run
# Build
go build -o kvs-shell
# Run
./kvs-shell
# Install to system
go install
Quick Start with Server
# 1. Start KVS server as daemon (in ../kvs/)
cd ../kvs
./kvs start config.yaml
# Check server is running
./kvs status
# View logs to get root token
tail ~/.kvs/logs/kvs_config.yaml.log | grep "Token:"
# 2. Run shell
cd ../kvs-sh
./kvs-shell
# 3. In shell:
# connect http://localhost:8080
# auth <root-token-from-logs>
# put test/data '{"hello":"world"}'
# 4. Stop server when done
cd ../kvs
./kvs stop config
Daemon Commands:
# Start server
./kvs start config.yaml # or just: ./kvs start config
# Check status
./kvs status # Show all instances
./kvs status config # Show specific instance
# View logs
tail -f ~/.kvs/logs/kvs_config.yaml.log
# Stop server
./kvs stop config
# Restart server
./kvs restart config
Important: If auth fails with "token not found", the database has old data. Either:
- Create a new token via the API, or
- Wipe database:
rm -rf ../kvs/data && mkdir ../kvs/data
(restart server to generate root token)
Testing
go test ./...
Architecture
Single-File Design
Everything lives in main.go
- intentionally kept simple. The shell is a stateful REPL that maintains:
- HTTP client connection to KVS backend
- Current JWT auth token
- In-memory profile storage (username, token, server URL combinations)
- Active profile selection
Core Components
KVSClient (main.go:49): Central state container holding:
baseURL
: KVS server endpointcurrentToken
: JWT for authenticationprofiles
: In-memory map of saved user profiles (NOT persisted to disk yet)httpClient
: Reusable HTTP client with 30s timeout
Command Router (main.go:465): Main loop uses switch statement on first word of input, delegates to handle*
methods
Command Parser (main.go:527): Custom parser respecting quotes - critical for JSON arguments like put key '{"foo": "bar"}'
Auto-completion (main.go:503): Prefix tree using readline library for tab completion of commands
HTTP Communication Pattern
All API calls go through doRequest()
(main.go:85) which:
- Serializes body to JSON if present
- Sets
Authorization: Bearer <token>
header if token exists - Returns
(body, statusCode, error)
tuple - Delegates HTTP status interpretation to caller
Key Backend API Mappings
GET /kv/<key>
→ ReturnsStoredValue
with UUID, timestamp, dataPUT /kv/<key>
→ Accepts raw JSON, returns UUID + timestampDELETE /kv/<key>
→ Returns 204 on successGET /members/
→ Returns array of clusterMember
objectsGET /api/users/<uuid>
→ ReturnsUser
objectGET /health
→ Returns service status map
Type Definitions (main.go:18-46)
Backend response structures are mirrored in the client:
StoredValue
: The core KV response with UUID, timestamp (int64 unix millis), andjson.RawMessage
dataMember
: Cluster member info with ID, address, last_seen timestampUser
: User record with nickname hash, groups array, created/updated timestampsGroup
: Group definition (defined but not yet used in commands)
Profile System
Profiles are in-memory only (see roadmap for persistence plan). When you profile use <name>
, it swaps the client's token, userUUID, and baseURL atomically. The *
marker in profile listings indicates active profile.
Color Scheme
Uses fatih/color package with semantic coloring:
- Cyan: labels, headers, structured data keys
- Green: success messages, confirmations
- Yellow: warnings, "not found" states
- Red: errors, invalid usage
- Magenta: banner/title text
Command Parsing - Critical Implementation Details
parseCommand() (main.go:527-570): Handles both single ('
) and double ("
) quotes intelligently.
Key behavior:
- Quotes are only stripped when they delimit an entire argument (start and end)
- Supports both
'
and"
as quote delimiters - Tracks which quote type started the argument to handle nesting correctly
- Preserves quotes that appear mid-argument (for unquoted JSON)
Examples:
put key '{"foo":"bar"}' # ✅ Strips outer ', preserves inner "
put key {"foo":"bar"} # ✅ Works (no spaces, compact JSON)
put key {"foo": "bar"} # ❌ Fails - spaces split into multiple args
put key "{\"foo\":\"bar\"}" # ✅ Works (escaped quotes in double-quoted arg)
JSON Error Handling (main.go:393-425):
printJSONError()
provides user-friendly error messages with examples- Detects error type (invalid chars, incomplete JSON, etc.) and shows context-specific tips
- Shows what input was received to help debug quoting issues
Backend Assumptions
The shell expects the KVS backend to:
- Accept JWT tokens in
Authorization: Bearer <token>
header - Return timestamps as Unix milliseconds (int64)
- Use standard REST semantics (404 for not found, 204 for delete, 200/201 for success)
- Accept raw JSON payloads for PUT operations (not wrapped in metadata)
Known Limitations & Roadmap Items
- No persistent profiles - restart loses all
profile add
data (roadmap #1) - No metadata commands - backend supports owner/group/permissions but shell doesn't expose yet (roadmap #6)
- No group management -
Group
type defined but no CRUD operations (roadmap #5) - No TLS support - HTTP only, no certificate handling (roadmap #8)
- No tab completion for keys - only completes command names, not dynamic keys from server (roadmap #10)
- user create not implemented - Listed in help but just shows "not implemented" message