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

@animakit/homeostasis

v0.1.1

Published

Give your LLM agent a mood — Yerkes-Dodson stress modeling, Russell affect mapping, allostatic regulation, and a self-tuning 3-arm bandit. Sub-µs core ops, every op <1ms, 0 tokens, fully serializable.

Readme

@animakit/homeostasis

Give your agent a mood — modeled on 100 years of psychology. Stress curves (Yerkes-Dodson 1908), affect mapping (Russell 1980), allostatic regulation (Sterling & Eyer 1988), and a self-tuning 3-arm bandit. Sub-µs core ops, every op <1ms, 0 tokens, fully serializable.

license types

Most agent frameworks are stateless between turns: every message is processed with the same intensity, no matter how many tasks are queued, how many errors just happened, or what time it is. The result is an agent that doesn't know when it's overloaded, doesn't modulate its tone, and needs hand-tuned rate limits to avoid overspending.

homeostasis gives an agent a persistent internal state (stress × dopamine) that:

  • modulates whether it accepts or defers a task (acceptance sigmoid),
  • modulates the tone of its responses (2D affective state),
  • modulates behavioral biases across sub-agents/roles (somatic markers, Damasio),
  • and self-regulates without hard-coded rate limits — the "calm" set-point moves with anticipated context (allostasis).

All of it with sub-microsecond core ops (every op p99 < 1ms), 0 tokens, 0 LLM calls, fully serializable (toJSON/fromJSON). Extracted from Anima's production agent — 53 sprints of real traffic. See BENCHMARKS.md for the numbers.

"Cost control through biology, not rate limits."

Install

npm i @animakit/homeostasis

Quickstart

import { HomeostasisEngine } from '@animakit/homeostasis';

const homeo = new HomeostasisEngine();

// An error just happened → stress rises.
homeo.recordInteraction({ success: false, responseTimeMs: 800 });

// Should we take on this low-priority task right now?
if (homeo.evaluateTaskAcceptance(0.3)) {
  // ...do the work
}

// What tone should the agent take? (inject into your system prompt)
console.log(homeo.emotionalState.tone_instruction_en);
// → "Calm, resolving tone. There is pressure — help reduce it ..."

// Decay back toward the set-point on your own schedule (e.g. every 60s).
setInterval(() => homeo.tick(), 60_000);

// Persist anywhere — the engine is 100% in-memory.
await db.save(homeo.toJSON());

Why this exists

The engine is a digital Yerkes-Dodson state machine: dS/dt = α·I(t) − β·P(t) − γ·(S − target). Stress rises with events, decays toward a set-point, and gates task acceptance through a sigmoid — so an overloaded agent naturally sheds low-priority work instead of melting down. Battle-tested across 53 production sprints.

"500 million years of evolution already solved the problems your agent framework is struggling with."

API

HomeostasisEngine (core, stateful, serializable)

const h = new HomeostasisEngine(config?, snapshot?);

h.stress; h.dopamine; h.mode;       // 'zen' | 'flow' | 'panic'
h.allostaticTarget; h.emotionalState;

h.addStress(delta); h.addDopamine(delta);
h.evaluateTaskAcceptance(priority?);          // P_accept(S) sigmoid
h.recordInteraction({ success, responseTimeMs, appraisal? });
h.tick(allostaticTarget?);                     // natural decay — caller owns scheduling

h.getEffectiveVetoThreshold();                 // refractory circuit-breaker T(t) = T_base + ΔT·e^(−t/τ)
h.recordVeto(constraints?);
h.getSomaticBias();                            // per-role bias (only when somaticBias is configured)
h.setProfile(profile);

h.toJSON(); HomeostasisEngine.fromJSON(snapshot, config?);

Allostasis — dynamic set-point (Sterling & Eyer 1988)

import { computeAllostaticTarget } from '@animakit/homeostasis';

const { target } = computeAllostaticTarget({
  fepMode: 'active', kappa: 0.5, ceScore: 0.5, recentIgnitions: 1, hourLocal: 10,
});
homeo.tick(target); // decay toward an anticipated set-point, not a fixed one

kappa and ceScore are optional numeric inputs (e.g. from @animakit/causal-emergence); pass null when unavailable.

Appraisal — cognitive evaluation (Lazarus / Scherer)

import { AppraisalEngine } from '@animakit/homeostasis';

const appraisal = new AppraisalEngine(); // bilingual EN+ES by default
const result = appraisal.evaluate('I need a go-to-market strategy for the product', {
  intentionHint: 'action_planning',
  goals: ['product launch'],
});
homeo.recordInteraction({ success: true, responseTimeMs: 1200, appraisal: result });

Profiles & 3-arm bandit (Thompson Sampling)

import { updateBanditState, getProfile } from '@animakit/homeostasis';

// Once per period (night/sprint), learn which profile fits your usage pattern:
const next = updateBanditState(episodes, banditState);
homeo.setProfile(getProfile(next.activeArm)); // Conservative | Balanced | Proactive

updateBanditState accepts an optional rng for deterministic tests; sampling is exact Beta(α,β) via a Gamma ratio.

Load prediction (no I/O)

import { predictLoad } from '@animakit/homeostasis';

const p = predictLoad(history, { utcOffsetHours: -5 }); // you pre-load the history; it never queries a DB

Vocabulary — presets.bilingual vs presets.animaProduction

AppraisalEngine ships a generic bilingual (EN+ES) vocabulary by default. presets.animaProduction exposes the exact vocabulary running in production (Colombian tax/legal + SaaS) as a reference for building your own:

import { AppraisalEngine, presets } from '@animakit/homeostasis';

const a = new AppraisalEngine({ language: 'es', vocabulary: presets.animaProduction });
// or extend the defaults:
const b = new AppraisalEngine({ vocabulary: { highCopingDomains: { extend: ['kubernetes', 'terraform'] } } });

Roles & somatic bias

When you configure somaticBias, the engine biases each role/sub-agent by the smoothed (EMA) stress/dopamine signal — but only inside the flow zone (predictability is preserved at the extremes). presets.animaProductionRoles reproduces how Anima biases its 5 sub-agents:

const h = new HomeostasisEngine({ somaticBias: presets.animaProductionRoles });
h.getSomaticBias(); // { biases: { JEFE, VIGIA, ARQUITECTO, OFICIAL, NEGOCIADOR }, active, reason }

OFICIAL is never biased (weight = 0) — legal decisions stay outside the affective bias.

@animakit/homeostasis/valence

The Russell-circumplex affect mapper is also a standalone sub-module — any app with a 2D "mood" score (arousal × valence) can use it:

import { computeEmotionalState } from '@animakit/homeostasis/valence';

const s = computeEmotionalState(0.4, 0.6);
// { emotion: 'engaged', label_en, label_es, tone_instruction_en, tone_instruction_es, ... }

Design notes

  • tick() replaces the original's internal setInterval — the caller owns scheduling; no hidden loops, no circular dependencies. Compute a dynamic set-point with computeAllostaticTarget() and pass it in.
  • toJSON()/fromJSON() replace sync()/persist() — the engine is 100% in-memory; persistence (Postgres, Redis, a file) is yours.
  • Pure & deterministic — every module is pure (given an rng where sampling is involved); 0 LLM calls, 0 network, 0 hidden state.

License

MIT © Justine Serna