[GhostPaw souls: Change your agent's prompt when the evidence agrees.]
@ghostpaw/souls
[npm] [CI] [site] [runtime deps] [MCP Registry] [node] [license]
Agent identity as an essence plus evidence-backed traits, refined only when the evidence agrees.
Prompt evolution engine for cognitive identity. Stores identity as narrative
essence plus evidence-backed traits, with structured level-up,
crystallization-gated refinement, and full rollback. Not a prompt template
library. Not a configuration manager. An evolutionary algorithm for how agents
think.
Release binary with no runtime needed; library and npm usage require Node 24+. Zero runtime dependencies.
MCP server
Every client below starts the same stdio server: ghostpaw-souls mcp.
For npm-based environments, use npx -y @ghostpaw/souls mcp.
Identity and evidence live in ~/.ghostpaw/souls.db unless the GHOSTPAW_SOULS_DB
environment variable (absolute path) or --db <path> says otherwise.
Claude Code
or as a plugin, which also installs the skill:
Codex CLI (~/.souls/config.toml)
Cursor (.cursor/mcp.json), Claude Desktop (claude_desktop_config.json)
or a project .mcp.json:
Claude Desktop users can also install server.mcpb from the
latest GitHub release.
A Dockerfile is included for container hosts:
docker build -t ghostpaw-souls . && docker run -i --rm -v souls:/data ghostpaw-souls.
The server speaks MCP 2026-07-28 (stateless, server/discover) and the
initialize-based revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05.
CLI
Use ghostpaw-souls skill --short for a compact cheat sheet, skill for full
parameter tables, and skill --list to list runnable workflow guides.
Global flags can appear anywhere: --db <path>, --json, --quiet,
--compact, --help/-h, --version/-V/-v, --no-color.
NO_COLOR is accepted; output uses no terminal colors.
Noun-verb commands print the full tool result as JSON with --json or when
stdout is piped. Terminal output shows the summary and payload.
--quiet suppresses stdout. --compact removes JSON indentation.
Use help soul, soul --help or soul create --help for schema-derived help.
Array flags repeat and kebab-case flags map to schema properties. Values are
literal, including a leading @. Only soul create|update --essence reads a
file: @path (relative to the working directory), @- for stdin and @@text
for a literal @text. Help marks it (@file, @- stdin, @@ literal @); an empty or unreadable path
exits 2. -- ends flags. A positional -, or piped stdin
with no arguments, reads a JSON object; explicit flags override its fields.
Database selection uses --db, GHOSTPAW_SOULS_DB, then ~/.ghostpaw/souls.db.
Errors go to stderr. With --json, usage and internal errors also print
{ok:false,error:{code,message}} to stdout. Tool results retain their full
shape. Legacy tools [--json], describe <tool>, call <tool> [JSON|-]
and <tool_name> --parameter value keep their existing exit codes.
completions bash, completions zsh and completions fish print shell scripts.
Search reads behavioral shards. Creating a soul does not add searchable shards;
use shard drop to deposit observations. Core commands work offline.
Agent Skill
SKILL.md (repo root) and skills/souls/SKILL.md follow the
Agent Skills format and ship in the npm package.
Copy skills/souls/ into your agent's skills folder, or print it:
Install
Release binary (default)
Each line downloads the latest release asset, checks it against the release's SHA256SUMS and installs it on the PATH (~/.local/bin on Linux/macOS; the Windows script adds its folder to the user PATH).
These lines never edit ~/.profile or other shell startup files: export PATH applies to the current shell only. To keep it in new shells, use the ~/.profile line below.
linux-x64:
linux-arm64:
darwin-arm64:
darwin-x64:
windows-x64 (PowerShell; persistently adds the install folder to the user PATH):
Pinned to a release:
Also adding ~/.local/bin to ~/.profile (edits ~/.profile once; skipped if it already mentions ~/.local/bin; zsh login shells read ~/.zprofile instead, so use that file name there):
To skip the persistent user PATH edit (the installer prints the folder to add):
Scripts that compare versions should use --version --short or --version --json.
A session with the 0.4.0 linux-x64 binary against a fresh database (output piped through jq to keep it short):
[ghostpaw-souls 0.4.0: version, soul create, two shard drops, refinement add and cite, search, review readiness and soul show with the rendered identity]
The same session as an animated GIF.
Other release installers:
For aqua, define a
github_release package in aqua.yaml:
souls-registry.yaml:
Install scripts verify SHA256SUMS. To verify a downloaded archive's
build attestation:
Set GHOSTPAW_VERIFY=attestation for attestation verification in install.sh.
Binaries are unsigned; macOS binaries carry an ad-hoc signature. For a browser
download on macOS, remove quarantine with
xattr -d com.apple.quarantine /path/to/ghostpaw-souls.
Linux binaries require glibc 2.28+; use npx on Alpine.
See the binary build workflow.
Sizes for 0.4.0 (Node 26.12.1 inside each binary):
The npm package is 930 KB unpacked and needs Node 24+. Every release is
installed and run on ubuntu-24.04, macos-15 and windows-2025 by the
install check.
Release install checks run on ubuntu-24.04, macos-15 and windows-2025.
npx / npm (for npm-based environments)
The npm package requires Node 24+:
Library (for harnesses embedding it in code)
See Quick Start for library usage.
Quick Start
Docs
The live demo runs the library in your browser against an in-memory SQLite database. Each view below opens a different part of it:
What It Does
A soul is one cognitive identity — not a prompt template, not a config
object. How an agent thinks, judges, and approaches problems.
A trait is a cognitive principle with provenance — evidence proving it was
earned, not invented.
A shard is a behavioral observation from any source, attributed to souls.
Shards accumulate silently. When enough evidence converges across independent
channels over time, the soul becomes eligible for refinement.
Level-up consolidates: merge overlapping traits, promote absorbed ones into
the essence, carry forward those still teaching. The identity restructures and
the generation counter increments.
The rendered identity block (essence + active traits) is static between
mutations — no drift, no context accumulation, no re-rendering overhead. It
does not drift because there is nothing to drift.
API Surface
Core Lifecycle
Shards accumulate from any source. Crystallization gates refinement until
evidence converges across 2+ independent channels over 1+ days. Traits mutate
with provenance. Level-up restructures when the identity outgrows its current
form.
The Mentor
The package ships one built-in soul — the Mentor — tuned for guiding the
entire refinement lifecycle:
Ether — Template Discovery
Browse and search a catalog of open-source system prompts, then manifest them
as fully-formed souls:
Sources are fetched lazily with ETag caching. Refresh is atomic — failed
fetches never erase existing data.
LLM Tools
Wire into any agent framework via JSON Schema tool definitions:
Ecosystem
Souls is one of four faculties in the GhostPaw cognitive substrate:
Each faculty owns one slice of state. Each stays lean at the storage layer
with the same architecture: Node 24+, built-in node:sqlite, zero runtime
dependencies.
Souls is unique in the quartet: it is the only faculty whose output becomes
the system prompt. Questlog produces task state. Affinity produces relationship
state. Codex produces belief state. Souls produces the identity block that
shapes how all other state is interpreted.
Together they form a complete cognitive substrate for agents that grow.
Domain Mapping
The engine provides a single abstraction — identity that evolves from
evidence — that maps to any domain where behavior should improve from
observation:
Demo
An interactive local-first demo app with RPG character sheet aesthetics:
License
MIT
Evidence-backed refinement
Shard lists and searches return arrays with a default limit of 100 (maximum
1000). read.listShardsPage and read.searchShardsPage return
{ items, total, hasMore }; use offset to continue. Both accept status:
pending, sealed, faded, or all. Lists default to pending unsealed shards;
searches retain their all-status default. Query and tags combine with AND.
Trait additions and essence edits warn when crystallization is not ready or no
shardIds are supplied. Pass strict: true to require both. A named operator
bypasses this gate and records an operator correction. Existing trait-addition
capacity enforcement is unchanged; reactivation and new level-up checks warn
unless strict is enabled. addTrait, updateSoul, and refineWithEvidence expose optional
warnings: string[] as a non-enumerable property,
so serialization and object spreads keep the record clean. Facade
data also includes these strings while retaining existing warning objects.
The CLI prints each warning as warning: ... on stderr.
write.refineWithEvidence(db, { soulId, action: 'add' | 'revise', traitId?, principle, provenance, shardIds, reason?, strict?, operator?, expectedRevision? })
updates wording, cites evidence, and stamps attunement atomically. Set
expectedRevision to the latest revision ID for the soul (or 0) to detect
conflicts. Read wording history with read.getRevisionHistory(db, { soulId, traitId?, limit? }), or inspect with history: true.
The facade action is refine_with_evidence; CLI usage:
refinement apply infers revise when --trait-id is supplied; otherwise it adds.
Evidence reports render at most five members per cluster and show +N more.
Set maxMembersPerCluster to change the cap, or full: true to retain every
selected member in the structured payload. Alignment uses the maximum
similarity across all cluster members. Staleness uses the latest citation time,
falling back to trait creation. Tension detection has English-only negation
cues; detectTraitTensions(..., { negationWords }) extends them.
read.formatEvidence(db, soulId, { negationWords: ["nicht"] }) extends the
English-only tension cues through the public library facade.
Publishing identities into host prompts
render prints only the identity, or atomically creates/replaces the content between
<!-- souls:begin --> and <!-- souls:end --> with --into. It appends a block when
markers are absent. --marker selects a different marker name. Successful writes
print wrote <file> sha256:<hash> and record file/block hashes in soul_publications.
--expect-hash requires the current full-file SHA-256 (none for a missing file);
a mismatch exits 4 without writing. Omit it for an unconditional replacement.
--budget counts characters across the entire composed output, including surrounding
file text and markers. It removes lowest-ranked traits first, then shortens essence;
very small budgets can empty the identity block. Text outside the markers stays
intact. An impossible budget exits nonzero without writing. Cuts appear as one
trimmed: line on stderr and as {traitIds, essenceChars} in --json output.
diff prints changed lines, exits 0 when identical and 1 when different; --json
returns {same, added, removed, markerFound}. When no block exists for the requested
marker, diff <soul> --against <file|-> compares the whole input, removing one
trailing newline, with the rendered block and reports markerFound: false.
Diff compares the current full identity, so a
budget-trimmed publication can differ.
Soul create/update accept --external-id; bindings are unique when set and appear
in show/list JSON. CLI soul arguments accept numeric IDs, names, or ext:<id>.
report --expect-ids @file reads one external ID per line (@- reads stdin), compares
active bindings, and prints missing: and extra: lines. It exits 0 for a match,
1 otherwise; JSON returns {missing, extra}.
Shard drop accepts --occurred-at <iso>, --idempotency-key <key>, and --ref <text>.
Repeated ingestion keys return the original shard with duplicate: true. Library
and batch inputs accept occurredAt (ISO or epoch milliseconds), idempotencyKey,
and ref. Occurrence time controls crystallization age/spread, falling back to
creation time. The age spread uses occurredAt (falling back to createdAt): two pending
shards from different sources must be at least one day apart, or live shards
(occurrence time not earlier than insertion time) must span a day on their own.
Otherwise readiness reports Age spread must span at least two sources by occurrence time. Legacy numeric CLI and facade occurrence timestamps retain their creation-time
behavior; insertedAt records insertion time separately for backfill checks.
Strict checks default off. Resolve strict in this order: explicit library strict
or CLI --strict/--no-strict, GHOSTPAW_SOULS_STRICT (1/true/yes or
0/false/no), then the database setting. Use config set strict true|false,
config get [key], and config list. Both read commands report effective boolean values and a source of default, db, or env; text output uses strict: false (default). read.getSoulsConfig(db) reads persisted
values; write.setSoulsConfig(db, 'strict', 'true') writes them. The manage tool
provides config_set, config_get, and config_list actions.
Refinement add/revise and soul update accept --operator <name> for a logged
operator correction; strict evidence readiness can be bypassed with a named
operator. Review output includes corrections. review --no-change records a review
and stamps attuned without editing identity; the facade provides
write.reviewNoChange(db, soulId, {reason}) and the review tool accepts noChange.
Show with --history includes revision and review records. Refinement
add/reactivate/apply and level validate/up accept --trait-limit <n>.
CLI batch ingestion accepts shard drop-batch --shards @file and
shard add --batch @file with a JSON array or JSON Lines. @- reads stdin;
@@ escapes a literal leading at-sign. shard add also aliases shard drop.
Set GHOSTPAW_OUTPUT=json for JSON output. Default database opens print
using default db <path> on stderr; suppress with --quiet or
GHOSTPAW_QUIET=1, or select --db / GHOSTPAW_SOULS_DB.