Skip to content

Game Profile: npc.soul + player.soul graduate into soul_protocol.profiles.game#277

Open
prakashUXtech wants to merge 6 commits into
devfrom
feat/game-profile
Open

Game Profile: npc.soul + player.soul graduate into soul_protocol.profiles.game#277
prakashUXtech wants to merge 6 commits into
devfrom
feat/game-profile

Conversation

@prakashUXtech

Copy link
Copy Markdown
Contributor

Graduates the grudge-kernel experiment into the first Soul Protocol profile. The npc.soul/player.soul runtime moves from examples/ into a proper package, and the Game Profile RFC is written from the working code.

What's in here

  • The experiment itself (4 commits): GrudgeKernel (an NPC that remembers a specific player's wrongs, per-player bonds, grudge levels, and survives a .soul export→awaken), PlayerSoul (portable reputation a never-met NPC reacts to), the pluggable DialogueEngine seam (templated default, LLM optional, claude-cli backend), CostMeter + ReplayCache (deterministic zero-cost replay).
  • Graduation (39bf685): modules move to src/soul_protocol/profiles/game/ via git-mv (history preserved), tests to tests/profiles/game/, examples keep a thin demo shim. Zero modifications to existing core files — the profile claim is empirical.
  • RFC (6c3b1e0): spec/profiles/game.md — profiles-over-core architecture, both roles, normative conventions (grievance/deed tagging, the PUBLIC-visibility rule for reputation memories and the BONDED recall trap it avoids, user_id scoping, round-trip guarantees), graceful degradation, two promote-to-core candidates.

Review notes

  • Base of a 3-PR stack (brain and demo follow). Per house rules: merge this base with --rebase, not squash.
  • The PUBLIC-visibility convention is load-bearing and documented in §Conventions — BONDED memories vanish from recall once bond_strength < 30, which would hide a grudge exactly when it peaks.

Tests

15/15 in tests/profiles/game/ from the new package location; imports verified; full-suite collection healthy (2947 tests, no import errors).

…dge across a .soul reload

A thin, deterministic, zero-LLM layer over one real Soul (examples/npc_soul_grudge/).
A player who wrongs the NPC weakens its per-player bond and plants tagged episodic
grievances; those survive a .soul export -> awaken round-trip, so the NPC still
remembers and reacts with hostility in the next session.

- grudge.py: GrudgeKernel wrapping Soul — record/grievances/grudge_level/react.
  Grievances stored PUBLIC (a weakened bond hides BONDED memories), attributed by
  user_id, tagged via entities + an in-content marker (MemoryEntry has no metadata
  field). Per-player bond via BondRegistry.weaken(user_id=...).
- demo.py: headless walkthrough — Bjorn the butcher goes warm -> hostile, exports,
  awakens fresh, still remembers; a second player stays warm (per-player proof).
- test_grudge_kernel.py: 5 pytest-asyncio tests incl. the export->awaken round-trip.

Imports the real Soul; touches no core files.
…ul grudge kernel

Extract the NPC's spoken line behind a DialogueEngine Protocol so the same
grudge can be voiced by a deterministic template (default, free) or a real LLM,
without touching the bond/grievance/persistence logic. Mirrors Soul Protocol's
own Protocol + fallback + optional real backend pattern.

- dialogue.py: DialogueEngine Protocol; TemplatedDialogueEngine (the original
  branches, verbatim, kept as the default); LLMDialogueEngine(generate) which
  builds a strong in-character prompt from persona + OCEAN + grudge level +
  named grievances + player line and falls back to the template on empty output
  or any error; claude_cli_generate, a no-key backend that shells out to
  `claude -p` (works here, no ANTHROPIC_API_KEY, ~10s/call).
- grudge.py: react() delegates to self._dialogue.speak(...); birth()/awaken()
  accept dialogue_engine. OCEAN is read from soul.dna.personality; persona is
  carried on the kernel (Soul.birth does not retain it). Existing signature
  preserved, so the original tests pass unchanged.
- demo.py: adds a LIVE section replaying the Bjorn->Ragnar arc + reload with
  LLMDialogueEngine(claude_cli_generate), tagging any templated fallback. The
  original deterministic section still runs first.
- tests: add a record-don't-mock spy test that drives the real LLMDialogueEngine
  and asserts the prompt the model would receive carries the grievance content
  and grudge level, plus a fallback test. All deterministic (no live LLM, no
  subprocess, no network). 7 passing.
…NPC reacts to across a .soul reload

Both directions of the relationship ledger: a slight now also records the deed on
the player's own player.soul (PUBLIC = readable reputation). A fresh NPC who has
never met the player reads their player.soul and reacts to their notoriety, and it
survives a player.soul export->awaken. 11 tests green; deterministic + a live path.
…el moves from examples to soul_protocol.profiles.game

The npc_soul_grudge experiment (15/15 tests green) becomes the first
Soul Protocol profile: a package of conventions over the unchanged core.

- git mv grudge.py, player.py, dialogue.py, costmeter.py from
  examples/npc_soul_grudge/ to src/soul_protocol/profiles/game/;
  sibling imports converted to package-relative, behavior unchanged
- soul_protocol.profiles.game exports the public API: GrudgeKernel,
  PlayerSoul, the DialogueEngine seam + engines, CostMeter/ReplayCache/
  PRICING, the grudge-level and notoriety constants, plus Grievance and
  Deed (return types of public accessors)
- git mv test_grudge_kernel.py to tests/profiles/game/; sys.path hack
  removed, imports consolidated from the package, 15/15 still pass
- examples/npc_soul_grudge/ stays as a thin consumer: demo.py imports
  from the package; README points at the package and the upcoming spec
- drop a dead severity local in record_deed (pre-existing F841 surfaced
  by src/ lint coverage; deeds() recomputes severity at recall time)

No core files touched — new files and moves only.
…rotocol profile

Written from the graduated reference runtime at
src/soul_protocol/profiles/game/. Covers the profiles-over-core layering
(L0 core unchanged through L3 products), the two roles (GrudgeKernel /
PlayerSoul), the normative conventions (content-marker + entities
tagging, the PUBLIC-visibility rule and the BONDED recall trap it
avoids, per-player user_id + BondRegistry scoping, bond semantics,
export/awaken round-trip guarantees), graceful degradation for generic
.soul readers, the DialogueEngine seam with cost instrumentation, and
two promote-to-core candidates surfaced by building the profile
(a profiles: field in soul.json; first-class MemoryEntry metadata).
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Security scan: review needed

Potentially dangerous code patterns detected in changed files. A maintainer should verify these are intentional and safe.### src/soul_protocol/profiles/game/dialogue.py

439:    proc = await asyncio.create_subprocess_exec(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant