Skip to content

Architecture

A message comes in from Telegram or Discord, gets processed by an LLM with tools, and a reply goes back out. Everything in between is Krill.

System Layers

Message Flow

Tool Assembly

Core Components

Types

The runtime boundary types shared by all subsystems:

  • InboundMessage, OutboundMessage

  • content parts: TextPart, BinaryPart, ToolCallPart, ToolResultPart

  • DeliveryPolicy, ErrorEnvelope

  • tool lifecycle events

MessageHub

MessageHubState decouples producers from consumers.

  • inbound channel for normalized user/platform events

  • outbound channel for generated replies or tool-originated messages

  • blocking and non-blocking APIs for backpressure-aware wiring

ChannelManager

ChannelManagerState owns outbound dispatch.

  • sender registration by channel symbol

  • retry / timeout / priority / drop_if_late

  • dead-letter capture

  • dispatch events and counters

ChannelInterface

AbstractChannel keeps integrations minimal: identify, normalize, send, start/stop.

Sessions and Memory

Session history and durable assistant memory are separated on purpose.

  • SessionStore writes ordered turn history to JSONL

  • MemoryStore writes per-session MEMORY.md, HISTORY.md, and state.json — the consolidator periodically compresses durable facts out of long histories

  • GlobalMemoryStore writes a per-user MEMORY.md keyed by user_id — shared across all channels and sessions for the same user, updated explicitly via /remember

Tools, Skills, and MCP

The intelligence surface is layered rather than monolithic.

  • ToolRegistry holds local tool definitions and validation

  • skills provide markdown instructions — always-on or on-demand via read_skill

  • MCP connections discover external tools and register them into the same registry

Note: Julia has no official MCP SDK. Krill's MCP client (src/tools/mcp.jl) implements JSON-RPC initialize / list / call over stdio and HTTP from scratch. It covers common cases well but may have edge-case issues with unusual servers. See Known Limitations.

PromptContext

Krill composes the instruction stack explicitly on every turn:

  1. base system prompt

  2. workspace bootstrap docs (SOUL.md, AGENTS.md, USER.md, TOOLS.md)

  3. skill metadata summary

  4. always-on skill bodies

  5. global memory (## User Profile) — cross-channel user profile, written via /remember

  6. session memory (## Session Memory) — per-chat consolidated memory

  7. tool-output safety notice

  8. runtime metadata (channel, session key, chat ID, UTC timestamp)

LLM

  • OpenAI Responses API payloads

  • Gemini native generateContent

  • Gemini OpenAI-compatible chat completions

  • context-window trimming and dropped-history summarization

  • tool call extraction and continuation loops

Cron and Subagent

Both inject work back into the same runtime rather than creating a separate orchestration layer.

  • cron jobs publish synthetic inbound messages back into MessageHub

  • subagents run in isolated sessions and inject a summarized result into the origin conversation

RuntimeState — Composition Root

RuntimeState(...) is where the whole stack is assembled: channels, tool registry, MCP connections, prompt builder, LLM processor, memory hooks, cron, and subagents. Startup and shutdown are owned here.

Filesystem Layout

Agent file sandbox (<project>/context)

PathOwned byPurpose
SOUL.md, AGENTS.md, USER.md, TOOLS.mdPrompt contextbootstrap docs injected into system prompt
skills/Skills loadercontext-local skill definitions

The agent can read and write inside this directory. File tools are restricted to it by default.

Krill internal state (~/.krill)

PathOwned byPurpose
sessions/.../history.jsonlSessionStoreordered user/assistant turns
memory/.../MEMORY.mdMemoryStoreconsolidated per-session memory
memory/.../HISTORY.mdMemoryStorearchived consolidation batches
memory/.../state.jsonMemoryStoreconsolidation offsets and failures
global_memory/<user_id>/MEMORY.mdGlobalMemoryStorecross-channel user profile, written via /remember
cron/jobs.jsonCronServicepersisted schedules
dead_letters.jsonlChannelManagerfailed dispatch records

Krill manages this directory itself — it is never exposed to the agent's file tools.