Copyright (c) 2026 Anubhab Banerjee (AnubhabBanerjee/swarmkv)
All rights reserved. No part of this repository may be used, redistributed, or modified in any form or by any means without the prior written permission of the author.
Single-process C++20 orchestration over llama.cpp with DAG-ordered stages, copy-on-fork host KV buffers, and RoPE-aware branch offsetsβwithout pretending an unsupported upstream KV βbindβ API exists. SwarmKV is a systems-style inference runtime skeleton for sequential analytical graphs: prefill once, then run branch decodes whose batch positions continue after the shared prefix. It is not a Python agent framework and not a multi-tenant serving stack; it is deliberately scoped so you can build, run, and reason about pipeline-level KV reuse on one machine.
This repository is Part 1 of the Production-Grade Agentic Inference series (Towards Data Science). Please see below for other parts in this series.
- Part 1 β this repository
Full deep-dive: https://towardsdatascience.com/kv-cache-reuse-for-multi-agent-llm-inference-i-built-a-c-orchestrator-so-my-gpu-would-stop-reading-the-same-document-twice/;
Repository link: https://github.com/AnubhabBanerjee/swarmkv
- Part 2 β Kube-Timeslice-Profiler
Full deep-dive: https://towardsdatascience.com/gpu-time-slicing-for-concurrent-llm-agents-on-kubernetes/
Repository link: https://github.com/AnubhabBanerjee/Kube-Timeslice-Profiler
- Part 3 β CUDA-TopK-Retrieval
Full deep-dive: https://towardsdatascience.com/gpu-resident-top-k-for-agentic-rag-i-built-a-cuda-kernel-so-my-retrieval-step-would-stop-bouncing-off-the-gpu/
Repository link: https://github.com/AnubhabBanerjee/CUDA-TopK-Retrieval
- Part 4 β ILCP (future): persist agent state across hand-offs (not implemented yet)
Full deep-dive: TBA
Repository link: https://github.com/AnubhabBanerjee/ILCP-for-Agents
SwarmKV runs as a single-process runtime with a join barrier before VRAM/host buffer teardown:
MemoryPoolβ Ownsggml_backend_buffer_tallocations on the CPU host backend. Sizes come fromllama_state_get_sizeon a disposablellama_context, with a small fallback if the engine reports0.Orchestratorβ RegistersExecutionNodeinstances, keeps forward + reverse adjacency for dependencies, runs DFS cycle detection, spawnsstd::async(..., std::launch::async)workers, waits on all futures, then callsMemoryPool::free_all().PrefillNode/AnalyticalNodeβ Constructllama_batchmanually, callllama_decodein chunks bounded byllama_n_batch(required for multi-k token documents).PrefillNodeloads text from a filesystem path (e.g.examples/base_doc.txt), setsPipelineState::prefix_seq_len, and exports KV viallama_state_get_data. EachAnalyticalNodememcpyβs the prefix snapshot into a per-branch buffer,llama_state_set_data, then decodes with RoPE positions starting atprefix_seq_len.KVHandoffβmaterialize_branch_cacheperforms a bytememcpybetween host buffer bases (the copy-on-fork hook).bind_contiguous_cacheis currently a documented no-op: the pinnedllama.hsurface used here does not expose a stablellama_kv_cache_bind-style attachment API, so decode uses the contextβs internal KV while the call site stays stable for future engine hooks.context_budget.hβ Fail-fast validation thatdoc_tokens + branch_tokens + headroom β€ n_ctxbeforellama_decode(used bycodebase_audit, nodes, and the benchmark harness).llama_guard.hβ Global mutex serializing allllama_*calls from worker threads (llama.cpp is not safe for concurrent GPU decode on one device without external locking).swarmkv_benchmarkβ Baseline vs SwarmKV wall-clock harness with structuredKey: Valuemetrics on stdout; seescripts/benchmark_campaign.py.examplefor a full 4K campaign (plots +final_result.docx).
The orchestration graph is a DAG (dependencies only); there is no feedback edge from decode back into the scheduler in V1.
Designed for a local developer loop first; GPU offload inside llama.cpp remains optional and orthogonal to SwarmKVβs host-buffer copy path:
- Host (default path) β
MemoryPoolallocates viaggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_CPU)somemcpybetween buffers is well-defined for the smoke build. - GPU (optional) β You can configure
llama.cppwith CUDA/Metal backends for fasterllama_decode, but you must treatmaterialize_branch_cacheas device-aware in that deployment (replacememcpywith a backend copy) or keep weights/KV on host-mapped memory. - Third-party tree β
third_party/llama.cppis expected as a local checkout (clone or submodule). This README does not vendor upstream sources beyond what you place in that directory. - ~8β―GiB VRAM class GPUs β Default pipeline context is
kSwarmkvDefaultPipelineCtx= 4096 (include/swarmkv/defaults.h) so Qwen2.5β7B Q4_K_M (~4.4β―GiB weights) plus two concurrent analyticalllama_contexts after prefill stay under typical 8β―GiB budgets. Raise the constant on 12β―GiB+ cards if you need longer shared prefixes.
- CMake 3.20+ and a C++20 toolchain (GCC 13+ tested).
- Git β to fetch
third_party/llama.cppconsistently across machines. - A local GGUF model path passed on the command line to
swarmkv_demo,codebase_audit,swarmkv_benchmark, and the smoke tests when you want them to run (not skip). - Optional:
nvcc/ GPU stack only if you configurellama.cppfor CUDA; SwarmKV itself is CMakeLANGUAGES CXXonly.
git clone <github-repo-url> swarm-kv
cd swarm-kv
# Populate llama.cpp (submodule OR manual clone into third_party/llama.cpp)
git submodule update --init --recursive
# CPU-only (default). For interview-grade TTFT/VRAM numbers, use NVIDIA CUDA:
# cmake -S . -B build -DGGML_CUDA=ON -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF
cmake -S . -B build -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF
cmake --build build -jAll llama_model_load_from_file call sites use swarmkv_default_model_params() (include/swarmkv/model_params.h), which sets n_gpu_layers = -1 (offload all layers when the llama target is built with CUDA). Reconfigure with -DGGML_CUDA=ON or layers stay on CPU.
This repository does not assume a particular llama.cpp commit is redistributed inside SwarmKV beyond your own checkout policy.
- Ensure
third_party/llama.cppexists and CMakeadd_subdirectory(third_party/llama.cpp)succeeds. - Record the exact commit hash you validated in
projectdocs/project_planning.md(and your paper/demo appendix) so reviewers can reproduce allocator andllama_batchsemantics.
Run the minimal demo (two analytical nodes with a simple dependency edge):
./build/swarmkv_demo /path/to/model.ggufRun the codebase audit example (prefill root feeding two branches):
./build/codebase_audit /path/to/model.ggufRun CTest smoke targets (they skip with exit code 77 when no model argv is wired through ctest; invoke binaries directly for full runs):
cd build
ctest --output-on-failure
./test_rope /path/to/model.gguf
./test_memory /path/to/model.ggufRun the benchmark harness directly (metrics on stdout; llama_perf_context_print on stderr):
export LD_LIBRARY_PATH=build/bin:$LD_LIBRARY_PATH
export GGML_LOG_LEVEL=ERROR
./build/swarmkv_benchmark /path/to/model.gguf 3500 examples/base_doc.txtRun the full benchmark campaign (3 trials, CSV/JSON, plots, narrative final_result.docx):
cp scripts/benchmark_campaign.py.example scripts/benchmark_campaign.py
python3 -m venv scripts/.venv
scripts/.venv/bin/pip install matplotlib python-docx
scripts/.venv/bin/python scripts/benchmark_campaign.pyArtifacts land under examples/example-run-results/. See examples/example-run-results/REPRODUCE.md and scripts/README.md.
$ ./build/swarmkv_demo ./models/TinyLlama-1.1B-Chat-v1.0.Q4_K_M.gguf
Pipeline finished successfully.
$ cd build && ctest --output-on-failure
100% tests passed, 0 tests failed out of 2
The following tests did not run:
1 - RopeInvariantTest (Skipped)
2 - MemoryLifecycleTest (Skipped)
$ ./build/test_rope ../models/TinyLlama-1.1B-Chat-v1.0.Q4_K_M.gguf
SUCCESS: materialize_branch_cache byte identity verified.
swarm-kv/
βββ CMakeLists.txt # swarmkv static lib + demos + benchmark + CTest
βββ README.md
βββ main.cpp # swarmkv_demo entry point
βββ benchmarks/
β βββ swarmkv_benchmark.cpp # baseline vs DAG timing harness
βββ examples/
β βββ base_doc.txt # shared document written by benchmark (β3.5K tokens)
β βββ codebase_audit_pipeline.cpp
β βββ example-run-results/ # benchmark CSV/JSON/plots/final_result.docx (see REPRODUCE.md)
βββ include/swarmkv/
β βββ context_budget.h # n_ctx fail-fast validation
β βββ execution_node.h
β βββ kv_handoff.h
β βββ llama_guard.h # serialize llama API across worker threads
β βββ memory_pool.h
β βββ orchestrator.h
β βββ orchestrator_context.h
β βββ pipeline_state.h
β βββ defaults.h
β βββ model_params.h
β βββ nodes/
β βββ analytical_node.h
β βββ prefill_node.h
βββ src/
β βββ core/
β β βββ kv_handoff.cpp # memcpy materialize + documented bind no-op
| | βββ pipeline_state.cpp
β β βββ orchestrator.cpp # DAG + async workers + join + free_all
β βββ memory/
β β βββ memory_pool.cpp # host buffers + llama_state_get_size sizing
β βββ nodes/
β βββ analytical_node.cpp
β βββ prefill_node.cpp
βββ tests/
β βββ test_rope_invariant.cpp
β βββ test_memory_lifecycle.cpp
βββ third_party/llama.cpp/ # local llama.cpp checkout (not redistributed here)
Captured with scripts/benchmark_campaign.py (~3501-token shared document, two analytical branches). Best of 3 trials:
| Metric | Baseline | SwarmKV | Improvement |
|---|---|---|---|
| End-to-end (ms) | 10,275 | 5,272 | 48.7% (~1.95Γ) |
| Branch-2 TTFT proxy (ms) | 4,339 | 83 | 98.1% (~52Γ) |
Full narrative, methodology, and charts: examples/example-run-results/final_result.docx. Raw numbers: best_run.json, all_trials.csv.
Active work-in-progress items already on the bench:
- Speculative branching (streaming prefill). Readiness watermark so branches that only need a prefix slice can start decode before the full document prefill finishes (see
projectdocs/project_planning.md). - Real KV bind hook. Replacing the
bind_contiguous_cacheno-op with a pin-verified upstream API when a stable external-KV attachment path existsβplus a golden-string regression vs a single vanilla context. - Device-aware materialize. Backend-scheduled copy when KV buffers live on CUDA/Metal without host mapping.
- KV snapshot to disk. Serializing prefilled prefix state for fast cold start with explicit (model hash, quant, n_ctx, commit) identity in the file header.
- Bounded thread pool. Migrating from one
std::asyncper node to a fixed worker pool for large DAGs while preserving theLlamaGuardpolicy. - PrefillNode timing fix. Per-node
timings_msforPrefillercurrently reports0in the benchmark harness (instrumentation gap; effective prefill cost is derivable from end-to-end metrics).
Built on ggml-org/llama.cpp and the ggml backend layer it ships with. Upstream tensor, batch, and memory APIs evolve quicklyβpin a commit when you freeze a demo, paper, or interview artifact. GGUF model weights and upstream documentation remain the property of their respective licensors and are not redistributed by this project.