diff --git a/crates/llm/Cargo.toml b/crates/llm/Cargo.toml
new file mode 100644
index 0000000..15c9458
--- /dev/null
+++ b/crates/llm/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "kon-llm"
+version = "0.1.0"
+edition = "2021"
+description = "Local LLM inference via llama.cpp for Kon"
+
+[dependencies]
+kon-core = { path = "../core" }
+llama-cpp-2 = "0.1"
+tokio = { version = "1", features = ["rt", "sync"] }
+reqwest = { version = "0.12", features = ["stream"] }
+futures-util = "0.3"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+log = "0.4"
diff --git a/crates/llm/src/inference.rs b/crates/llm/src/inference.rs
new file mode 100644
index 0000000..91aee40
--- /dev/null
+++ b/crates/llm/src/inference.rs
@@ -0,0 +1,144 @@
+use std::path::Path;
+use std::sync::Mutex;
+
+use llama_cpp_2::context::params::LlamaContextParams;
+use llama_cpp_2::llama_backend::LlamaBackend;
+use llama_cpp_2::llama_batch::LlamaBatch;
+use llama_cpp_2::model::params::LlamaModelParams;
+use llama_cpp_2::model::{AddBos, LlamaModel, Special};
+use llama_cpp_2::sampling::LlamaSampler;
+
+use kon_core::error::{KonError, Result};
+
+/// Thread-safe LLM inference engine wrapping llama.cpp.
+pub struct LlmEngine {
+ backend: LlamaBackend,
+ model: Mutex