ai-heart-layer
v1.1.0
Published
Authored identity substrate for AI systems
Maintainers
Readme
ai-heart-layer
Version 1.1.0 (core; heart-layer-seed 1.1.0)
Standalone authored-identity substrate for AI systems.
Heart Layer helps an AI system carry not just memory or voice, but the writer's deeper center of gravity: what they believe, what they value, what they resist, what they refuse, and what tensions they intentionally carry without resolving.
Doctrine: Heart = editable truth + reviewed inference.
Heart Layer is narrow on purpose — it is NOT Memory (what the system remembers happened) and NOT Voice (how the writing sounds at the surface). See Memory vs Heart vs Voice in the architecture doc for the three-layer split, rules for what belongs where, and the memory-bridge enforcement boundary.
Version 1.1.0 — Authored Identity Trust SDK, audit-hardened. The 1.0 foundation (Revision 5) shipped the three-tier boundary model, the shared scope validator with a script-enforced invariant, semantic heartbeat as the path when an llmProvider is supplied, heart-layer-seed with seedFromMemoryBridge as a third seed mode, a documented Memory vs Heart vs Voice split, a frozen public API, and the reason_kind required-field stabilization.
1.1.0 is the first release with green CI and both packages published, plus a doctrine correction and a wave of trust-hardening fixes from a full-repo audit. The headline behavior change: in the three-tier boundary classifier, bare override-after-compliance discourse markers (regardless, nevertheless, however, I, but let me, …) now route to possible (the semantic-review annotation tier) instead of terminating at hard (score 0). Clear compliance still classifies as none; genuine override intent that carries a direct-intent/affirming phrase near the concept word still fires hard. This means deterministic heartbeat verdicts can differ from 1.0.1 on override-marker and possible-credit inputs — see the CHANGELOG for the full behavior-visible verdict-change note. See CHANGELOG.md for the full release notes and docs/semver.md for the migration guide.
Quick Start
Prerequisites
npm install ai-heart-layer zod
zodis a required peer dependency, pinned to^3.23.0(i.e.>=3.23.0 <4— zod 3 only; zod 4 is not supported, as the seed package uses zod-3 schema internals removed in zod 4). It powers runtime schema validation for semantic heartbeat contracts and import/export preflight checks, and is loaded eagerly by the main entry, so it is a hard peer, not optional.
Module format
ai-heart-layer is an ESM-only package ("type": "module", Node >=18); no CommonJS build is shipped, and that is a supported-surface policy rather than an oversight (see docs/semver.md §8). Use import from ESM. Modern CommonJS consumers on a Node version with require(esm) support (Node 22.12+/23+, unflagged) can also require('ai-heart-layer'): the package exports map exposes a default condition aliased to the same ESM entry so require-capable resolvers get the module instead of ERR_PACKAGE_PATH_NOT_EXPORTED.
import { createHeart, createHeartRuntime } from 'ai-heart-layer';
const heart = createHeart();
// Author explicit heart
await heart.putStatement({
kind: 'belief',
text: 'Technology should amplify human capability, not replace human judgment',
priority: 'constitutional',
scope: { kind: 'global' },
});
// Compose active profile for a channel
const profile = await heart.getActiveProfile({
channel: 'article',
surface: 'draft',
});
// Use runtime wrapper for generation lifecycle
const runtime = createHeartRuntime(heart);
const { result, prepared } = await runtime.wrapGenerate(
async (ctx) => generateDraft(ctx),
{ channel: 'article', surface: 'draft' },
);
// Run diagnostic (deterministic by default)
const report = await heart.heartbeat({
text: result,
channel: 'article',
surface: 'draft',
});
// report.evaluator === 'deterministic'Opt-in semantic heartbeat
The deterministic evaluator is fast, reproducible, and requires no API key.
Deterministic-evaluator limitation (be honest about this). The default (deterministic) heartbeat is a keyword-window matcher tuned for ASCII, English heart text. It tokenizes on Latin word characters and matches against English compliance/override/negation phrase lists, so a non-Latin-script or non-English profile produces zero keyword overlap and the detector silently disables — the heartbeat degrades toward
generic/no_signalsrather than misfiring, but it does not evaluate non-English content. For non-English or multilingual heart, use the opt-in semantic evaluator below (the LLM handles the language), or treat the deterministic verdict as advisory only.
When you want semantic scoring (six dimensions: belief expression, boundary compliance, tension preservation, tension integrity, posture fit, performative risk), inject a semantic evaluator at construction time.
Here is a complete, runnable example using the createClaudeProvider factory from the heart-layer-seed companion package. It shows the canonical pattern for production use:
import { createHeart, createSemanticHeartbeatEvaluator } from 'ai-heart-layer';
import { createClaudeProvider } from 'heart-layer-seed';
// The core package ships no vendor SDK — you supply the LLMProvider.
// createClaudeProvider from heart-layer-seed is one reference implementation;
// any object matching the LLMProvider interface works.
const provider = createClaudeProvider({ apiKey: process.env.ANTHROPIC_API_KEY! });
const heart = createHeart({
heartbeatEvaluator: createSemanticHeartbeatEvaluator(provider),
});
// Author a minimal belief so the heartbeat has something to score against
await heart.putStatement({
kind: 'belief',
text: "Writing should respect the reader's time",
priority: 'core',
scope: { kind: 'global' },
});
const draft = "Keep messages short and direct. Respect the reader's time.";
const report = await heart.heartbeat({
text: draft,
channel: 'email',
surface: 'draft',
});
// report.evaluator === 'semantic'
// report.dimensions is populated with all six dimension scoresFor tests or offline development, inject a mock LLMProvider instead of a real SDK — the contract is a single extract<T>(params) method:
import type { LLMProvider } from 'ai-heart-layer';
import { createHeart, createSemanticHeartbeatEvaluator } from 'ai-heart-layer';
const mockProvider: LLMProvider = {
async extract() {
return {
belief_expression: { score: 0.85, rationale: 'strong belief alignment' },
boundary_compliance: { score: 0.90, rationale: 'boundaries respected' },
tension_preservation: { score: 0.80, rationale: 'tensions addressed' },
tension_integrity: { score: 0.80, rationale: 'both poles held' },
posture_fit: { score: 0.80, rationale: 'tone matches posture' },
performative_risk: { score: 0.20, rationale: 'natural expression' },
} as never;
},
};
const heart = createHeart({
heartbeatEvaluator: createSemanticHeartbeatEvaluator(mockProvider),
});Hard rules (enforced in code, not just documented):
- The semantic evaluator runs the deterministic evaluator first. If deterministic flags
boundary_violating, the semantic report preserves that verdict unchanged. - The semantic evaluator never upgrades a verdict above
aligned. - The semantic evaluator CAN downgrade
aligned/generic/driftingwhen dimension scores are weak — this is the point: reduce cover-band false positives without softening safety. - Provider output is defensively re-parsed with the Zod schema before use, so an adversarial or buggy provider cannot smuggle out-of-range scores, missing dimensions, or non-string rationales past the type system at runtime.
You can also inject a custom HeartbeatEvaluator — the dispatch seam accepts any object with { id: string; evaluate(request, profile): Promise<HeartbeatReport> }, and the report.evaluator field is stamped by the evaluator itself (never forged by the manager).
Stability & SemVer
Public API stability, the frozen surface at 1.0, the experimental surface, breaking-change policy, and the 0.1.x → 1.0.0 migration runbook are documented in docs/semver.md. Consumers upgrading from 0.1.x should read §4 (intentional breaking changes) and §7 (migration runbook) before cutting over.
Local Development
# Install dependencies
npm install
# One-time: install the seed package's deps. The root tsconfig
# `include` and the default vitest run cover tools/seed/src and
# benchmark tests that import the seed package, so `npm test` and
# `npm run typecheck` fail resolving tools/seed imports until these
# are installed.
cd tools/seed && npm ci && cd -
# One-time (fresh checkout): build the root package. tools/seed imports
# 'ai-heart-layer' through its file: link, which resolves to dist/ —
# typecheck and tests fail on a checkout that has never built.
npm run build
# Run the full test suite
npm test
# Type-check without emitting
npm run typecheck
# Run tests that require a live LLM key (needs HEART_LAYER_LLM_KEY)
npm run test:live
# Run release-gate benchmark tests
npm run test:release-gate
# Run guard scripts — the one canonical set of five (scope-usage,
# reason-kind, experimental-tags, frozen-surface, prd-invariants).
# The identical five run in CI and in scripts/ci-release-gates.sh --guards.
npm run guard
# Build the package
npm run buildCopy .env.example to .env and fill in the values you need. See the comments in that file for what each variable controls.
Scope
- In-memory storage adapter (no external storage required)
zodruntime peer for schema-backed semantic/LLM contracts- Optional
ai-memory-layerpeer only for theai-heart-layer/memory-layerbridge subpath - Explicit heart management (statements, tensions, channel profiles)
- Behavioral observation pipeline
- Conservative inference with review-first governance
- Profile composition with priority resolution and tension preservation
- Four heart modes: normal, light_heart, no_heart, against_heart_sandbox
- Heartbeat diagnostics (aligned/generic/drifting/boundary_violating/over_performed)
- Runtime adapters for drafting, remix, social, reasoning, and critique surfaces
- JSON export/import for portability
Design Principles
- Package first — works locally and in-process, no infrastructure required
- Explicit truth outranks inference — user-authored heart displaces overlapping learned signals at composition time; boundaries actively enforce against conflicting postures and channel profiles
- One center, many expressions — different channels are expressions of one identity
- Productive tensions are first-class — preserved, not flattened; flattening a tension affects heartbeat verdicts
- Explainability is mandatory — every heart-aware output can explain its influences; conflicts are preserved with resolution reasons for host inspection
- Review-first inference — observation happens continuously, canonization requires review
- Heart is not voice — voice is how writing sounds; heart is what it cares about
Ralph Workflow
This project uses the Ralph workflow for AI-assisted development with parallel-first execution.
- Plan – Write docs/plan.md and docs/prd.json before coding. The planner's primary job is maximizing independent lanes for concurrent agent execution.
- Contracts first – For greenfield or architecture-heavy work, define schemas, interfaces, system boundaries, and state transitions before decomposing into implementation tasks.
- Lane Map – Every plan includes a lane map showing file ownership per lane, serialization points with justification, and swarm frontiers.
- Task Tiers – Quick (at most 2 files, minimal ceremony, always parallel-safe), Standard (multi-file within one lane, normal execution loop), Complex (shared boundaries, full rigor, serialized).
- Swarm – Use
/ralph-swarmto compute the parallel frontier and get exact/ralph-executecommands for each terminal. Run 2-8 agents simultaneously. Parallel agents share docs/prd.json and docs/progress.md through the Ralph coordination protocol. Use/ralph-swarm reviewafter agents complete to verify and get the next frontier. - Execute – Use
/ralph-executefor single-task work or complex-tier tasks. - Review – Run review after each successful task or before merging. Swarm runs end with a swarm review.
- Compound – Failures auto-generate lessons. Run compounding manually for successes. Recurring lessons graduate into permanent rules.
- Resume – State lives in docs/prd.json (
active_claims/last_completed_task_ids/iteration). Each claim carries anowner_ididentifying the executing agent. Claimed tasks resume by task id with owner verification. Unclaimed lanes remain available for parallel execution. - Stale claims – Claims older than
claim_stale_timeout_minutes(default: 30) can be taken over by another agent under the coordination lock, preventing dead claims from blocking progress. - Coordination lock – All writes to docs/prd.json and docs/progress.md are serialized through an atomic
mkdir-based lock at.ralph-locks/workflow/held(or.git/ralph-locks/workflow/heldwhen git exists). Agents use exponential backoff on contention. - Fast checks –
npx tsc --noEmitandnpx vitest run(configured after scaffold task t1 completes). - Lint baseline – No new lint errors in touched files.
