KeiSeiKit-1.0/_primitives/_rust/kei-buddy
Parfii-bot 4435564d3d feat(kei-buddy): provision_decrypt — VPS-side blob decryption
Mirrors keisei-marketplace/src/lib/crypto-box.ts::sealBoxToVps.

Two new subcommands on kei-buddy bin:
  - genkeys --key <path>          → writes PKCS#8 PEM x25519 priv,
                                    prints standard-base64 pub (44 char)
  - decrypt-and-export --vps-key <pem> --blob <json> --env-out <env>
                                  → ECDH(vps_priv, ephPub) → HKDF-SHA256
                                    info=keibuddy-token-v1 → XChaCha20-Poly1305
                                    decrypt → append BOT_TOKEN/TELEGRAM_BOT_TOKEN
                                    to env file (replaces stale, keeps other lines)

Cloud-init in hetzner.ts already calls these. Without this commit the
VPS could decode its own pubkey but had no way to recover the sealed
bot-token blob — the bot would never log into Telegram.

Crypto stack (mirror of @noble in TS):
  - x25519-dalek 2 (static_secrets feature)
  - chacha20poly1305 0.10 (XChaCha20Poly1305)
  - hkdf 0.12, sha2 0.10
  - base64 0.22 (accepts URL_SAFE_NO_PAD + STANDARD)
  - zeroize 1 for priv-key wipe

Tests (6/6 pass):
  - roundtrip_seal_then_decrypt — re-implement marketplace sealing in Rust,
    verify our decryption recovers plaintext
  - decrypt_and_export_writes_env_file — full e2e through CLI surface
  - decrypt_and_export_replaces_existing_token — stale BOT_TOKEN replaced,
    other env lines preserved
  - decrypt_rejects_wrong_key — XChaCha20 AEAD tag fails on wrong key
  - pem_roundtrip — write_pkcs8 + parse_pkcs8 round-trip
  - b64decode_accepts_urlsafe_and_standard — handles both encodings

Cross-verified end-to-end:
  $ node marketplace_seal.mjs <pub> <token>  →  /tmp/blob.json
  $ kei-buddy decrypt-and-export --vps-key ... → BOT_TOKEN matches input

Constructor Pattern: 1 file (provision_decrypt.rs, 344 LOC), 1 module,
1 responsibility (token-blob decryption + key generation).

=== STATUS-TRUTH MARKER ===
shipped: functional
stubs: 0
cargo-check: PASS
behaviour-verified: yes (e2e marketplace-seal → kei-buddy-decrypt round-trip)
follow-up-required:
  - none
2026-05-15 17:49:59 +08:00
..
src feat(kei-buddy): provision_decrypt — VPS-side blob decryption 2026-05-15 17:49:59 +08:00
tests feat(kei-buddy fleet): 5 atomics — google/apple contacts + classifier + tick + slash-commands 2026-05-12 16:33:58 +08:00
Cargo.toml feat(kei-buddy): provision_decrypt — VPS-side blob decryption 2026-05-15 17:49:59 +08:00
README.md feat(kei-buddy): functional MVP — store + state-machine port + serve binary 2026-05-12 14:21:33 +08:00

kei-buddy

Maturity: concept / scaffold — no business logic yet.

Purpose

kei-buddy is the runtime crate that composes existing KeiSeiKit primitives (kei-pet, kei-memory-sqlite, kei-cortex, kei-notify-telegram) into a personal-assistant Telegram bot called KeiBuddy.

On first contact the bot walks the user through an 11-state onboarding flow: name, tone, interests, hobbies, per-topic decomposition (specifics → now-or-later → research preference → source selection), and digest schedule. After onboarding the bot enters ongoing conversation mode, drawing on the stored persona and memory.

This crate provides the state-machine enum and skeleton driver. The onboarding FSM is ported from keisei-marketplace/src/lib/keibuddy/chat-onboard.ts.

Status

Scaffold only. The OnboardState enum and TransitionInput struct are defined. All transition logic is stubbed (next() returns self.clone()). The binary entry point prints a placeholder message and exits 0.

Running

Environment variables

Variable Required Default Description
TELEGRAM_BOT_TOKEN yes (serve) Bot token from @BotFather
TELEGRAM_WEBHOOK_SECRET yes (serve) Secret token for webhook verification
KEI_BUDDY_PORT no 8080 HTTP port to bind
KEI_BUDDY_DB_PATH no ./kei-buddy.db SQLite database path
OPENAI_API_KEY no Enables OpenAiExtractor when set (requires extractor-openai feature)

Subcommands

# Apply schema (idempotent; run once before first serve)
kei-buddy migrate

# Register the webhook URL with Telegram
kei-buddy webhook-set https://your-domain.com/webhook

# Start the HTTP server
kei-buddy serve

# Remove the registered webhook (revert to polling)
kei-buddy webhook-delete

Example systemd unit

[Unit]
Description=KeiBuddy Telegram bot
After=network.target

[Service]
EnvironmentFile=/etc/kei-buddy/env
ExecStart=/usr/local/bin/kei-buddy serve
Restart=on-failure
User=keisei

[Install]
WantedBy=multi-user.target

Roadmap

  • OpenAiExtractor wiring — pass real OPENAI_API_KEY to OpenAiExtractor in serve.rs when feature enabled.
  • Persona binding — read persona manifest via kei-pet; apply tone overlay to outgoing replies.
  • Digest scheduling — wire kei-cron-scheduler for morning/evening digest delivery.