npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

scp-protocol

v0.5.0

Published

Spatial Context Protocol -- real-time AI execution runtime for embodied systems

Readme


Demo: MuJoCo cart-pole

Watch the demo

Real MuJoCo physics. The brain is asked every cache miss; over time the pattern store answers locally and brain calls drop.


Overview

An SCPBody runs a tick loop and owns a four-layer decision stack. Only the top layer calls the LLM; the lower three never leave the process.

1. Reflex            hard rules in the body           0-5 ms
2. PatternStore      exact / very-similar cache       0.1 ms
3. AdaptiveMemory    similarity-scored generalizer    1-5 ms
4. LLM brain         novel situations only            500 ms+

Every LLM decision is written back to layers 2 and 3, so layer 4 gets quieter over time.

npm install scp-protocol

Node >= 18. One production dependency: better-sqlite3 (for pattern persistence). LLM bridges and network transports are optional peer deps, installed only when you use them.


Architecture

Adapters


What it does

  • Split control into three layers with different latency budgets: reflex (in-body, sub-millisecond), muscle (local pattern cache, microseconds), brain (LLM, hundreds of milliseconds).
  • Cache brain decisions keyed by feature vectors, replay them locally when the same situation recurs, invalidate them when outcomes stop matching.
  • Provide one base class (SCPBody) that works both standalone (body owns an LLM) and managed (an orchestrator such as Plexa owns the LLM). The body keeps its local cache in both modes.

It does not ship an agent framework, a planner, or a safety layer. It is a caching layer around LLM tool calls, with a tick-loop body contract.


Install

npm install scp-protocol

Optional peer dependencies, install only if you use them:

npm install ws                                # for WebSocketTransport
npm install @aws-sdk/client-bedrock-runtime   # for BedrockBridge

Ollama and OpenAI bridges use only node:http/node:https and require no extra packages.


Quick start

const { SCPBody, PatternStore } = require("scp-protocol")
const { OllamaBridge }          = require("scp-protocol/bridges/ollama")

class PatrolBody extends SCPBody {
  static bodyName = "patrol"
  static tools = {
    halt:    { description: "stop motion",  parameters: {} },
    advance: {
      description: "move forward",
      parameters: { speed: { type: "number", min: 0, max: 1, required: true } },
    },
  }

  async halt()              { /* drive hardware */ }
  async advance({ speed })  { /* drive hardware */ }
}

const store = new PatternStore({
  featureExtractor: (entity) => ({ kind: entity.kind, close: entity.distance < 5 }),
  failureThreshold: 3,   // auto-invalidate a cached pattern after 3 consecutive failures
})

const body = new PatrolBody({ patternStore: store, brain: new OllamaBridge({ model: "llama3.2" }) })

// After every action resolves:
store.report(entity, succeeded)   // true or false

That is the full surface the body code touches. Pattern lookup and brain fallback happen inside the body.


PatternStore

A feature-keyed cache for brain decisions.

| Operation | What it does | |---------------|----------------------------------------------------------------------------------| | lookup | Exact-hash match, falls back to k-NN similarity over numeric/string/bool fields. Returns { decision, confidence, source } where source is "exact" or "similar". | | learn | Store a decision against an entity's feature vector. Bumps count on repeat. | | report | Record outcome for the last served pattern. Tracks consecutive failures. | | save/load | Persist via localStorage (browser) or SQLite (Node, via better-sqlite3). |

Tunables: similarityThreshold, explorationRate (epsilon-greedy), maxPatterns (LRU-ish eviction by hit count), failureThreshold.

Emits: pattern_invalidated when a pattern crosses the failure threshold.

stats() returns: hits, misses, explorations, corrections, invalidations, totalReports, totalSuccesses, totalFailures, averageSuccessRate, lowConfidencePatterns, hitRate.


AdaptiveMemory

A similarity-scored decision store that generalizes from brain decisions when the PatternStore misses. Plain JavaScript; no neural network.

const { AdaptiveMemory } = require("scp-protocol")

const mem = new AdaptiveMemory({
  threshold: 0.8,
  k: 5,
  maxHistory: 500,
  storage: "sqlite",
  storageKey: "scp_adaptive.db",
})

mem.store(features, decision)          // record a decision
const hit = mem.lookup(features)        // returns { decision, confidence } or null
mem.report(features, success)           // reinforce / penalize; auto-purge at N failures

Scoring: weighted euclidean distance in normalized feature space, blended with the fraction of top-k neighbors that agree on the decision. Weights are per-feature and configurable.

Confidence decays on failure and recovers on success. After failureThreshold consecutive failures an entry is purged; an entry_purged event fires.

stats() returns: entries, hits, misses, hitRate, avgConfidence, successReports, failureReports, purged.


SCPBody

A body is a class with a static tools map and one async method per tool.

class Arm extends SCPBody {
  static bodyName = "arm"
  static transport = "inprocess"   // default. Set "http" to run the body in another process.
  static tools = {
    grasp:  { description: "close gripper", parameters: {} },
    move:   {
      description: "move end-effector",
      parameters: {
        x: { type: "number", required: true },
        y: { type: "number", required: true },
      },
    },
  }

  async grasp()        { /* ... */ }
  async move({ x, y }) { /* ... */ }

  async tick() {
    // sensor read loop, called by whoever drives the body
    await super.tick()
    this.setState({ pose: readJointAngles() })
  }

  // Override to auto-report outcomes after every tool call.
  evaluateOutcome(state) {
    return state.pose_error < 0.01
  }
}

invokeTool(name, params) calls the method, records an outcome against the last cached entity, and returns the result.

Wiring all four layers

const body = new Arm({
  patternStore:    new PatternStore({ featureExtractor: (e) => ({ kind: e.kind }) }),
  adaptiveMemory:  new AdaptiveMemory({ threshold: 0.8 }),
})

// In your tick / decide loop:
const local = body.decideLocally(entity)
if (local) {
  // Pattern or adaptive memory had a confident answer.
  execute(local.decision)
} else {
  const fromBrain = await brain.call(entity)
  body.learnFromBrain(entity, fromBrain)   // writes to both cache layers
  execute(fromBrain)
}

decideLocally(entity) returns { decision, confidence, source } where source is "exact", "similar", "adaptive", or null on miss. learnFromBrain(entity, decision) stores in both the PatternStore and AdaptiveMemory.

Graceful shutdown

body.installShutdownHandlers()   // saves patternStore + adaptiveMemory on SIGINT / SIGTERM

Modes

| Mode | Who calls the LLM | Pattern store | Reflex | |--------------|-------------------------|---------------|--------| | standalone | the body | local | local | | managed | an orchestrator (Plexa) | local | local |

In managed mode the body still consults its local cache on every decision it makes. It notifies the orchestrator of local decisions; it does not defer to the orchestrator for them.


Bridges

| Bridge | Package needed | Models | |------------------|-------------------------------------|---------------------------------| | OllamaBridge | none (uses node:http) | any local ollama model | | OpenAIBridge | none (uses node:https) | gpt-4o, gpt-4o-mini | | BedrockBridge | @aws-sdk/client-bedrock-runtime | Nova Micro, Claude via Bedrock |

All bridges extend SCPBridge, which tracks call count, total time, average latency, and errors.


Transports

| Transport | Package needed | Purpose | |----------------------|----------------|----------------------------------------------------| | (default, none) | — | Body methods are called directly (zero HTTP). | | HTTPTransport | none | Body exposes /emit, /poll, /health over HTTP.| | WebSocketTransport | ws | Full-duplex stream between body and controller. |

A body declares static transport = "http" and a static port to opt into a transport. Otherwise it is in-process.


Working with Plexa

Drop an SCPBody into a Plexa Space to put one LLM in front of several bodies:

const { Space } = require("@srk0102/plexa")
const { SCPBody } = require("scp-protocol")

class Arm    extends SCPBody { /* ... */ }
class Camera extends SCPBody { /* ... */ }

const space = new Space("pick_and_place")
space.addBody(new Arm())
space.addBody(new Camera())
await space.run()

Each body keeps its own pattern store and decides at muscle speed; Plexa handles brain-tier calls and cross-body coordination.


Tests

npm test

145 tests across 10 suites. Built-in node:test, no test framework dependency.

| Suite | Tests | |------------------------|------:| | pattern-store | 23 | | success-rate | 28 | | adaptive-memory | 28 | | adapter | 14 | | bridge | 10 | | bridges | 10 | | transports | 10 | | managed-mode | 8 | | integration | 7 | | persistence | 5 |

persistence.test.js requires better-sqlite3 to be compiled; it skips gracefully otherwise.

persistence.test.js is skipped automatically if better-sqlite3 fails to build on the host.


What is not in this package

So you do not have to go looking:

  • No multi-body orchestrator. See @srk0102/plexa for safety gates, approval hooks, cross-session vertical memory, lateral body-to-body events, and LLM brains with cost tracking and retry.
  • No Python client. SCP bodies written in Python coordinate via HTTPTransport and expose /discover, /health, /state, /events, /tool.
  • No CRDT or cross-body shared state.

Links

  • Source: https://github.com/srk0102/SCP
  • npm: https://npmjs.com/package/scp-protocol
  • Orchestrator: https://npmjs.com/package/@srk0102/plexa

License

MIT