Cross-platform chat bot using:
- Kspec for task/memory persistence (shadow branch)
- Kynetic ACP for agent execution
- Moltbot-inspired channel abstraction
kynetic-bot/
├── packages/
│ ├── core/ # Shared types and utilities
│ │ └── src/
│ │ ├── types/ # NormalizedMessage, SessionKey, ChannelAdapter
│ │ └── utils/ # session-key.ts, errors.ts, logger.ts
│ │
│ ├── messaging/ # Message handling (@messaging module)
│ │ └── src/
│ │ ├── router.ts # SessionKeyRouter
│ │ ├── transformer.ts # MessageTransformer
│ │ ├── streaming.ts # StreamCoalescer
│ │ └── history.ts # ConversationHistory
│ │
│ ├── channels/ # Platform adapters (@channels module)
│ │ └── src/
│ │ ├── registry.ts # ChannelRegistry
│ │ ├── lifecycle.ts # ChannelLifecycle
│ │ ├── dm-policy.ts # DMPolicyManager
│ │ ├── media.ts # MediaHandler
│ │ └── adapters/ # whatsapp.ts, discord.ts, slack.ts
│ │
│ ├── memory/ # Persistent state (@memory module)
│ │ └── src/
│ │ ├── kspec-sync.ts # KspecSync
│ │ ├── conversation.ts # ConversationStorage
│ │ └── context-window.ts # ContextWindowManager
│ │
│ ├── agent/ # Agent orchestration (@agent module)
│ │ └── src/
│ │ ├── lifecycle.ts # AgentLifecycle
│ │ ├── autonomous.ts # AutonomousLoop
│ │ ├── skills.ts # SkillsRegistry
│ │ ├── escalation.ts # EscalationHandler
│ │ └── acp/ # Import from @kynetic/lifeline
│ │
│ └── bot/ # Main application
│ └── src/
│ ├── bot.ts # KyneticBot main class
│ ├── config.ts # Configuration loading
│ └── cli.ts # CLI entry point
| Task | Title | Complexity | Dependencies |
|---|---|---|---|
| 0.1 | Initialize pnpm monorepo workspace | 2 | None |
| 0.2 | Configure TypeScript project references | 2 | 0.1 |
| 0.3 | Set up Vitest with test utilities | 2 | 0.2 |
| 0.4 | Configure ESLint + Prettier | 1 | 0.1 |
| 0.5 | Copy kynetic ACP modules | 2 | 0.2 |
| Task | Title | Complexity | Dependencies |
|---|---|---|---|
| 1.1 | Core types, session keys, error utilities | 2 | 0.5 |
| 1.2 | SessionKeyRouter for @msg-routing | 2 | 1.1 |
| 1.3 | ChannelRegistry for @channel-registry | 2 | 1.1 |
| 1.4 | KspecSync for @mem-kspec-sync | 3 | 1.1 |
| 1.5 | AgentLifecycle for @agent-lifecycle | 3 | 1.1 |
| 1.6 | Discord channel adapter | 3 | 1.3 |
| 1.7 | Basic bot integration | 3 | 1.2, 1.3, 1.4, 1.5, 1.6 |
Goal: Basic message flow Discord -> Agent -> Discord with session persistence
| Task | Title | Complexity | Dependencies |
|---|---|---|---|
| 2.1 | MessageTransformer for @msg-transform | 2 | 1.1 |
| 2.2 | DMPolicyManager for @channel-dm-policy | 3 | 1.3, 1.4 |
| 2.3 | ConversationStorage for @mem-conversation | 3 | 1.4 |
| 2.4 | SkillsRegistry for @agent-skills | 2 | 1.5 |
| 2.5 | ConversationHistory for @msg-history | 3 | 2.3 |
| 2.6 | Transform integration into bot | 2 | 2.1, 1.7 |
Goal: Message transformation, DM policies, conversation storage, skills, history
| Task | Title | Complexity | Dependencies |
|---|---|---|---|
| 3.1 | StreamCoalescer for @msg-streaming | 3 | 1.1 |
| 3.2 | ChannelLifecycle for @channel-lifecycle | 3 | 1.3 |
| 3.3 | ContextWindowManager for @mem-context-window | 3 | 2.3, 2.5 |
| 3.4 | AutonomousLoop for @agent-autonomous | 3 | 1.5, 2.4 |
| 3.5 | Streaming integration into bot | 2 | 3.1, 1.7 |
Goal: Streaming, health monitoring, context management, autonomous mode
| Task | Title | Complexity | Dependencies |
|---|---|---|---|
| 4.1 | MediaHandler for @channel-media | 3 | 1.3 |
| 4.2 | EscalationHandler for @agent-escalation | 3 | 1.5 |
| 4.3 | End-to-end integration test suite | 3 | All |
| 4.4 | Additional channel adapters (WhatsApp/Slack) | 3 | 1.3 |
Goal: Media handling, human escalation, comprehensive testing, more platforms
Files: package.json, pnpm-workspace.yaml, packages/*/package.json
AC:
- pnpm workspace configured with all 6 packages
- Each package has package.json with name, main, types
pnpm installsucceeds from root
Files: tsconfig.base.json, packages/*/tsconfig.json
AC:
- Base config with strict mode, ES2022 target
- Project references for incremental builds
- Path aliases for
@kynetic-bot/*imports pnpm buildcompiles all packages
Files: vitest.config.ts, packages/*/vitest.config.ts, test utilities
AC:
- Vitest configured for each package
- Test utilities: mock factories, test fixtures
pnpm testruns all tests- Coverage reporting enabled
Files: eslint.config.js, .prettierrc
AC:
- ESLint with TypeScript rules
- Prettier for formatting
pnpm lintandpnpm formatwork
Files: packages/agent/src/acp/*
AC:
- Copy ACPClient, JsonRpcFraming, types from kynetic/lifeline/src/acp
- Adapt imports to local structure
- All copied modules compile without errors
- Document which files were copied and from where
Files: packages/core/src/**
AC:
NormalizedMessage: text, sender, timestamp, channel, metadataSessionKey: agent, channel, peerKind, peerId segmentsparseSessionKey("agent:main:whatsapp:user:+1234")returns structured objectbuildSessionKey({...})returns formatted string- Error types:
KyneticErrorbase,UnknownAgentError,InvalidSessionKeyError - Unit tests for parsing edge cases (missing segments, invalid format)
Files: packages/messaging/src/router.ts
AC (from spec):
- AC-1: Given message from WhatsApp user to agent, when router processes, then resolves to unique session key
- AC-2: Given existing session, when new message with same key, then appends to context
- AC-3: Given unknown agent, when router resolves, then returns UnknownAgentError
- Session store with get/create semantics
- Unit tests for all 3 AC
Files: packages/channels/src/registry.ts, types.ts
AC (from spec):
- AC-1: Given valid adapter, when register(), then added to registry
- AC-2: Given registered platform, when getAdapter(), then returns correct adapter
- AC-3: Given invalid adapter, when register(), then returns validation error with missing methods
ChannelAdapterinterface: name, sendMessage, parseIncoming, normalizeTarget- Unit tests including invalid adapter validation
Files: packages/memory/src/kspec-sync.ts
AC (from spec):
- AC-1: Given state change, when commitState(), then commits to shadow branch with timestamp
- AC-2: Given bot restart, when loadState(), then recovers all state from shadow branch
- AC-3: Given merge conflict, when detected, then applies strategy and logs resolution
- Uses kspec programmatic API or CLI
- Integration test with real .kspec worktree
Files: packages/agent/src/lifecycle.ts, acp/client-wrapper.ts
AC (from spec):
- AC-1: Given session needs agent, when spawn(), then creates process with KYNETIC_* env vars
- AC-2: Given agent unresponsive, when health check fails, then terminates and respawns
- AC-3: Given session end, when cleanup(), then terminates gracefully with state save
- Import ACPClient from @kynetic/lifeline
- Use JsonRpcFraming for stdio
- Unit tests for lifecycle state transitions
Files: packages/channels/src/adapters/discord.ts
AC:
- Implements ChannelAdapter interface
parseIncoming(interaction)extracts sender, text, attachments from Discord messagesendMessage(channelId, content)sends via discord.jsnormalizeTarget("user:123456")handles Discord user/channel IDs- Error handling: rate limits, permissions, API failures
- Integration test with mock Discord client
Files: packages/bot/src/bot.ts, config.ts, cli.ts
AC:
- Given WhatsApp webhook, when received, then parses and routes to session
- Given routed message, when agent needed, then spawns via AgentLifecycle
- Given agent response, when ready, then sends via WhatsApp adapter
- Given agent error, when caught, then logs and returns error message to user
- Configuration loading with Zod validation
- E2E test: mock webhook -> mock agent -> mock send
Files: packages/messaging/src/transformer.ts
AC (from spec):
- AC-1: Given platform message, when normalize(), then produces NormalizedMessage
- AC-2: Given normalized message, when denormalize(platform), then converts to platform format
- AC-3: Given unsupported type, when normalize(), then returns UnsupportedTypeError
- Transformer registry for adding platform transformers
- Unit tests for round-trip transformation
Files: packages/channels/src/dm-policy.ts
AC (from spec):
- AC-1: Given pairing_required policy, when new user message, then creates pending request
- AC-2: Given pending request, when admin approves, then creates session and processes message
- AC-3: Given open policy, when user message, then creates session immediately
- AC-4: Given pending request, when rejected, then removes request and notifies user
- Pending requests stored in kspec notes
- Pairing codes with TTL (60 min default)
- Unit tests for all 4 AC
Files: packages/memory/src/conversation.ts
AC (from spec):
- AC-1: Given turn complete, when persist(), then appends note with timestamp
- AC-2: Given 50+ notes, when new turn, then triggers compaction
- AC-3: Given agent crash, when recover(), then loads from kspec notes
- Uses kspec note append API
- Compaction threshold configurable
- Integration tests with compaction
Files: packages/agent/src/skills.ts
AC (from spec):
- AC-1: Given startup, when discoverSkills(), then registers all available skills
- AC-2: Given capability request, when getSkill(), then returns appropriate tool
- AC-3: Given skill error, when executeSkill(), then catches and returns structured error
- Skill interface: name, capabilities[], execute()
- Unit tests for discovery and error handling
Files: packages/messaging/src/history.ts
AC (from spec):
- AC-1: Given session, when getHistory(), then returns messages chronologically
- AC-2: Given topic change, when boundary analysis, then marks semantic boundary
- AC-3: Given session timeout, when cleanup(), then archives and releases
- Boundary detection using semantic patterns
- Integration with ConversationStorage
Files: packages/bot/src/bot.ts
AC:
- Given incoming message, when processed, then normalized before routing
- Given outgoing response, when sending, then denormalized for platform
- Given unknown content type, when detected, then logged and skipped gracefully
Files: packages/messaging/src/streaming.ts
AC (from spec):
- AC-1: Given long response, when streaming, then delivers in chunks (minChars/idleMs)
- AC-2: Given client disconnect, when detected, then cleans up and logs
- AC-3: Given non-streaming platform, when response ready, then buffers complete
- Configurable minChars (1500 default), idleMs (1000 default)
- Unit tests for chunking and disconnect
Files: packages/channels/src/lifecycle.ts
AC (from spec):
- AC-1: Given start(), when called, then establishes connection and begins health monitoring
- AC-2: Given N health failures, when threshold exceeded, then marks unhealthy and reconnects
- AC-3: Given shutdown(), when called, then drains pending and closes cleanly
- Configurable health interval and failure threshold
- Unit tests for health check and reconnection
Files: packages/memory/src/context-window.ts
AC (from spec):
- AC-1: Given new message, when approaching limit, then compacts older context
- AC-2: Given compaction, when executed, then preserves semantic boundaries
- AC-3: Given topic query, when retrieveContext(), then returns relevant archived context
- Token estimation (~4 chars per token)
- Soft (70%) and hard (85%) thresholds
- Uses semantic units from 2.5
Files: packages/agent/src/autonomous.ts
AC (from spec):
- AC-1: Given eligible tasks, when runLoop(), then processes autonomously
- AC-2: Given N consecutive errors, when threshold hit, then circuit breaker trips
- AC-3: Given cooldown elapsed, when half-open, then attempts single task
- Circuit breaker states: closed, open, half-open
- Uses kspec task polling
- Failure tracking with escalation
Files: packages/bot/src/bot.ts
AC:
- Given agent streaming response, when received, then passes through coalescer
- Given platform supports streaming, when chunks ready, then sends incrementally
- Given platform doesn't stream, when complete, then sends buffered response
- Given disconnect mid-stream, when detected, then cleans up properly
Files: packages/channels/src/media.ts
AC (from spec):
- AC-1: Given image message, when received, then extracts and stores with metadata
- AC-2: Given file to send, when preparing, then uploads and includes reference
- AC-3: Given oversized attachment, when validated, then rejects with error
- Size limits per platform (configurable)
- Unit tests for size validation
Files: packages/agent/src/escalation.ts
AC (from spec):
- AC-1: Given error, when escalate(), then notifies configured humans
- AC-2: Given acknowledgment, when received, then pauses agent and provides handoff
- AC-3: Given timeout, when elapsed, then follows configured fallback
- Configurable escalation channels
- Timeout and fallback state machine
Files: packages/bot/test/integration/*.test.ts
AC:
- Test: Full message flow (webhook -> route -> agent -> response)
- Test: Session persistence across bot restart
- Test: Streaming response delivery
- Test: Error escalation path
- Test: DM pairing approval flow
- All tests pass with mocks
- Optional: tests with real credentials (manual)
Files: packages/channels/src/adapters/whatsapp.ts, slack.ts
AC:
- WhatsApp adapter implements ChannelAdapter (Meta Cloud API)
- Slack adapter implements ChannelAdapter
- Both have normalizeTarget, parseIncoming, sendMessage
- Integration tests with mock APIs
| Component | Source File | Destination |
|---|---|---|
| ACPClient | ../kynetic/packages/lifeline/src/acp/client.ts |
packages/agent/src/acp/client.ts |
| JsonRpcFraming | ../kynetic/packages/lifeline/src/acp/framing.ts |
packages/agent/src/acp/framing.ts |
| ACP Types | ../kynetic/packages/lifeline/src/acp/types.ts |
packages/agent/src/acp/types.ts |
| Component | Source File | Adaptation |
|---|---|---|
| SemanticUnits | session/semantic-units.ts |
Context boundary detection |
| CompactionTrigger | session/compaction-trigger.ts |
Token budget management |
- MVP Channel: Discord (not WhatsApp) - simpler API, free, easy to test
- Agent Execution: Local subprocess - spawn claude-code as child process
- Kynetic Access: Copy source files - copy needed ACP modules into kynetic-bot
-
Kspec API Approach
- Options: CLI spawning, direct YAML parsing, programmatic API
- Affects: Task 1.4, 2.2, 2.3
- Recommendation: Start with CLI spawning, refactor if needed
-
Token Counting Strategy
- Options: Tiktoken, char estimation, model-specific
- Affects: Task 3.3
- Recommendation: Char estimation (~4 chars/token) initially
-
Compaction/Summary Model
- Options: Same model as agent, smaller model, local
- Affects: Task 2.3, 3.3
- Recommendation: Same model for simplicity
- Media Storage
- Options: S3, local filesystem, kspec-managed
- Affects: Task 4.1
- Phase 0:
pnpm build && pnpm test && pnpm lintall pass - Phase 1: Send WhatsApp message, get agent response back
- Phase 2: DM pairing works, messages persist across restart
- Phase 3: Streaming works, agent crashes recover, autonomous loop runs
- Phase 4: Full test suite passes, multiple platforms work
- 27 tasks across 5 phases
- Phase 0: 5 tasks (infrastructure)
- Phase 1: 7 tasks (MVP)
- Phase 2: 6 tasks (core features)
- Phase 3: 5 tasks (robustness)
- Phase 4: 4 tasks (polish)
All tasks map to spec features with explicit AC. Tasks are scoped for Ralph automation (2-3 complexity average, clear scope, testable).