Needle's Bounded Memory Mechanism: How the 256-Token Sliding Window Keeps Inference Memory Constant

Needle caps its runtime memory at approximately 28 MiB regardless of conversation length by pinning tool-related KV entries as permanent "sinks" and restricting the attention KV cache to a configurable sliding window of 256 tokens.

The cactus-compute/needle repository implements a bounded memory mechanism that solves a critical problem in long-context LLM inference: unbounded KV cache growth. By combining a fixed-size sliding window with persistent tool memory, Needle delivers predictable memory usage without sacrificing tool access.

How the Sliding Window Works

KV Window Storage in Model Headers

Needle bakes the sliding-window size directly into the .cact model file format. In needle/model/export.py, the kv_window field stores the window size the model was trained with:


# needle/model/export.py#L27-L30

# The header structure includes:

#   kv_window: int  # sliding window size in tokens (default: 256)

When you load a Needle model, this value is read from the header and used to configure the inference engine. The default 256-token window provides a balance between context retention and memory efficiency.

Runtime Window Budgeting

At inference time, Needle computes the effective KV window by comparing the model's trained window against hardware memory constraints. The kv_budget_window() and effective_kv_window logic in needle/model/architecture.py handles this:


# needle/model/architecture.py#L998-L1016

# Pseudocode of the budgeting logic:

def kv_budget_window():
    # Hardware budget: ~11 MiB reserved for KV cache

    max_tokens_by_budget = kv_memory_budget // bytes_per_token
    return min(max_tokens_by_budget, config.kv_window)

This ensures the actual window never exceeds either the model's trained capacity or the available GPU/TPU memory.

Attention Masking Implementation

The decoder enforces the sliding window through causal masking. In needle/model/decode.py, attention scores are masked so tokens can only attend to:

  • The most recent kv_window positions
  • Permanent tool KV "sinks" that bypass the window limit

# needle/model/decode.py#L81-L108

# The mask construction ensures:

#   1. Standard causal masking within the window

#   2. Full connectivity to pinned tool KV entries

#   3. Zero attention to tokens outside the sliding window

Why Tools Are Pinned as KV Sinks

Tool-calling capability requires random access to tool definitions throughout any conversation. Rather than re-embedding tools repeatedly (expensive) or letting them scroll out of the sliding window (broken), Needle reserves dedicated KV cache slots for tool embeddings.

These KV sinks are:

  • Permanent: Never evicted regardless of window position
  • Small: Constant overhead independent of conversation length
  • Efficient: Embedded once at model load time

The result: tools remain instantly accessible while the conversation history stays bounded.

Configuring the Sliding Window

Inspect an Existing Model

from needle.model.export import read_header

header = read_header("needle2.cact")
print("KV sliding window:", header.kv_window)   # → 256

Export a Custom Window Size

from needle.model.architecture import TransformerConfig
from needle.model.export import export

cfg = TransformerConfig(
    d_model=1024,
    num_heads=8,
    num_layers=12,
    kv_window=512,          # Larger window: more context, more memory

)

export(params, cfg, tokenizer, out_path="wider_needle.cact")

Inference with Bounded Memory

import needle

agent = needle.Needle(
    weights="needle2.cact",
    tools=[calculator, search_api]  # Tool KV sinks allocated at init

)

# Generate indefinitely—memory stays ~28 MiB

for turn in conversation:
    response = agent.run(turn)

Memory Characteristics

Component Size Behavior
Tool KV sinks ~2 MiB (fixed) Never evicted
Sliding window KV ~11 MiB (max) FIFO replacement
Activations/parameters ~15 MiB Constant
Total runtime ~28 MiB Independent of sequence length

Summary

  • Needle's bounded memory mechanism combines a 256-token sliding window with permanent tool KV sinks to achieve constant memory usage.

  • The kv_window parameter in needle/model/export.py stores the trained window size in model headers.

  • kv_budget_window() in needle/model/architecture.py computes the runtime-effective window based on hardware constraints.

  • needle/model/decode.py implements sliding-window attention masking that preserves tool access while limiting history.

  • Total inference memory stays near 28 MiB regardless of conversation length, as documented in the repository's README.

Frequently Asked Questions

What happens if a conversation exceeds 256 tokens?

Earlier tokens beyond the window are attended to via KV cache eviction—their keys and values are overwritten. The model retains access to compressed semantic information through the attention mechanism's recurrent patterns, but specific token-level details from distant history are lost. This mirrors how human conversation works: recent context is vivid, distant context is summarized.

Can I increase the sliding window for longer context?

Yes, by setting a larger kv_window in TransformerConfig during export. However, memory grows linearly with window size: doubling to 512 tokens roughly doubles the KV cache from ~11 MiB to ~22 MiB, pushing total runtime memory toward ~40 MiB. The architecture in needle/model/architecture.py#L998-L1016 enforces the hardware budget ceiling automatically.

Why 256 tokens specifically?

The 256-token default balances three factors according to the cactus-compute/needle source: (1) covering most single-turn tool interactions, (2) fitting comfortably within mobile/edge GPU memory budgets, and (3) matching the pretraining distribution where the model learned to operate. The README explicitly calls this out as the design point for "near 28 MB" memory guarantees.

Do pinned tool sinks reduce the available window for conversation?

No, tool KV sinks are allocated separately from the sliding window budget. The ~11 MiB KV cache is reserved for conversation history; tool embeddings live in their own memory region. This design ensures that activating multiple tools never compresses the available context window—a critical invariant maintained by needle/model/decode.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →