ghocentric-ghost-engine 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: ghocentric-ghost-engine
3
+ Version: 0.1.1
4
+ Summary: Ghost cognitive engine
5
+ Author: Shane Heckathorn
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+
9
+ # ghocentric-ghost-engine
10
+
11
+ A lightweight internal state reasoning engine (proof-of-architecture).
12
+
13
+ This package contains the core Ghost Engine, designed to experiment with
14
+ stateful reasoning, internal memory, symbolic processing, and emergent behavior.
15
+ It is intentionally minimal and focused on architecture rather than polish.
16
+
17
+ INSTALLATION
18
+
19
+ pip install ghocentric-ghost-engine
20
+
21
+ BASIC USAGE
22
+
23
+ from ghost import engine
24
+
25
+ Note: This is an early-stage engine. APIs may change as the architecture evolves.
26
+
27
+ PROJECT STRUCTURE
28
+
29
+ ghost/ core engine modules
30
+ tests/ internal test cases
31
+ npc_demo.py simple demonstration script
32
+ pyproject.toml build and packaging configuration
33
+
34
+ STATUS
35
+
36
+ This project is currently in v0.1.x and should be considered a
37
+ proof-of-concept. Stability is not yet guaranteed.
38
+
39
+ LICENSE
40
+
41
+ MIT License
@@ -0,0 +1,33 @@
1
+ # ghocentric-ghost-engine
2
+
3
+ A lightweight internal state reasoning engine (proof-of-architecture).
4
+
5
+ This package contains the core Ghost Engine, designed to experiment with
6
+ stateful reasoning, internal memory, symbolic processing, and emergent behavior.
7
+ It is intentionally minimal and focused on architecture rather than polish.
8
+
9
+ INSTALLATION
10
+
11
+ pip install ghocentric-ghost-engine
12
+
13
+ BASIC USAGE
14
+
15
+ from ghost import engine
16
+
17
+ Note: This is an early-stage engine. APIs may change as the architecture evolves.
18
+
19
+ PROJECT STRUCTURE
20
+
21
+ ghost/ core engine modules
22
+ tests/ internal test cases
23
+ npc_demo.py simple demonstration script
24
+ pyproject.toml build and packaging configuration
25
+
26
+ STATUS
27
+
28
+ This project is currently in v0.1.x and should be considered a
29
+ proof-of-concept. Stability is not yet guaranteed.
30
+
31
+ LICENSE
32
+
33
+ MIT License
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: ghocentric-ghost-engine
3
+ Version: 0.1.1
4
+ Summary: Ghost cognitive engine
5
+ Author: Shane Heckathorn
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+
9
+ # ghocentric-ghost-engine
10
+
11
+ A lightweight internal state reasoning engine (proof-of-architecture).
12
+
13
+ This package contains the core Ghost Engine, designed to experiment with
14
+ stateful reasoning, internal memory, symbolic processing, and emergent behavior.
15
+ It is intentionally minimal and focused on architecture rather than polish.
16
+
17
+ INSTALLATION
18
+
19
+ pip install ghocentric-ghost-engine
20
+
21
+ BASIC USAGE
22
+
23
+ from ghost import engine
24
+
25
+ Note: This is an early-stage engine. APIs may change as the architecture evolves.
26
+
27
+ PROJECT STRUCTURE
28
+
29
+ ghost/ core engine modules
30
+ tests/ internal test cases
31
+ npc_demo.py simple demonstration script
32
+ pyproject.toml build and packaging configuration
33
+
34
+ STATUS
35
+
36
+ This project is currently in v0.1.x and should be considered a
37
+ proof-of-concept. Stability is not yet guaranteed.
38
+
39
+ LICENSE
40
+
41
+ MIT License
@@ -0,0 +1,16 @@
1
+ README.md
2
+ pyproject.toml
3
+ ghocentric_ghost_engine.egg-info/PKG-INFO
4
+ ghocentric_ghost_engine.egg-info/SOURCES.txt
5
+ ghocentric_ghost_engine.egg-info/dependency_links.txt
6
+ ghocentric_ghost_engine.egg-info/top_level.txt
7
+ ghost/__init__.py
8
+ ghost/engine.py
9
+ tests/test_environment_isolation.py
10
+ tests/test_explicit_run_control.py
11
+ tests/test_external_input.py
12
+ tests/test_npc_actor_memory.py
13
+ tests/test_npc_emotional_modulation.py
14
+ tests/test_npc_intent_decay.py
15
+ tests/test_npc_intent_processing.py
16
+ tests/test_public_api.py
@@ -0,0 +1,43 @@
1
+ """
2
+ Ghost public API (pip-facing).
3
+ This file defines the ONLY supported entry points.
4
+ """
5
+
6
+ from .engine import GhostEngine
7
+
8
+ _ENGINE = None
9
+
10
+
11
+ def init():
12
+ """Initialize a new Ghost engine."""
13
+ global _ENGINE
14
+ _ENGINE = GhostEngine()
15
+ return _ENGINE
16
+
17
+
18
+ def step(input_data=None):
19
+ """Advance the engine by one cycle."""
20
+ if _ENGINE is None:
21
+ raise RuntimeError("Ghost not initialized. Call ghost.init() first.")
22
+ return _ENGINE.step(input_data)
23
+
24
+
25
+ def state():
26
+ """Return a mutable view of the current state."""
27
+ if _ENGINE is None:
28
+ raise RuntimeError("Ghost not initialized. Call ghost.init() first.")
29
+ return _ENGINE.state()
30
+
31
+
32
+ def snapshot():
33
+ """Return an immutable snapshot of the current state."""
34
+ if _ENGINE is None:
35
+ raise RuntimeError("Ghost not initialized. Call ghost.init() first.")
36
+ return _ENGINE.snapshot()
37
+
38
+
39
+ def reset():
40
+ """Reset the engine."""
41
+ global _ENGINE
42
+ _ENGINE = GhostEngine()
43
+ return _ENGINE
@@ -0,0 +1,77 @@
1
+ class GhostEngine:
2
+ def __init__(self, context: dict | None = None):
3
+ """
4
+ Core Ghost engine.
5
+ Monolithic, self-contained v0.1 implementation.
6
+ """
7
+
8
+ # Initialize context if not provided
9
+ if context is None:
10
+ context = {}
11
+
12
+ self._ctx = context
13
+
14
+ # Required baseline state
15
+ self._ctx.setdefault("cycles", 0)
16
+ self._ctx.setdefault("input", None)
17
+ self._ctx.setdefault("last_step", None)
18
+
19
+ def step(self, input_data=None):
20
+ """
21
+ Advance the Ghost engine by one cycle.
22
+ """
23
+
24
+ ctx = self._ctx
25
+ ctx["cycles"] += 1
26
+
27
+ # Ensure npc bucket exists
28
+ npc = ctx.setdefault("npc", {})
29
+ npc.setdefault("threat_level", 0.0)
30
+ npc.setdefault("last_intent", None)
31
+ npc.setdefault("actors", {})
32
+
33
+ # --- PROCESS INPUT FIRST ---
34
+ received_threat = False
35
+
36
+ if input_data:
37
+ ctx["raw_input"] = input_data
38
+ ctx["input"] = input_data
39
+
40
+ if input_data.get("source") == "npc_engine":
41
+ intent = input_data.get("intent")
42
+ intensity = float(input_data.get("intensity", 0.0))
43
+ actor = input_data.get("actor", "unknown")
44
+
45
+ if intent == "threat":
46
+ received_threat = True
47
+
48
+ # Actor memory
49
+ actor_bucket = npc["actors"].setdefault(
50
+ actor,
51
+ {"threat_count": 0}
52
+ )
53
+ actor_bucket["threat_count"] += 1
54
+
55
+ # Mood modulation
56
+ mood = ctx.get("state", {}).get("mood", 0.5)
57
+ mood_multiplier = 0.5 + mood # 0.5 → 1.5
58
+
59
+ threat_gain = intensity * mood_multiplier
60
+ npc["threat_level"] += threat_gain
61
+ npc["last_intent"] = "threat"
62
+
63
+ # --- DECAY ONLY IF NO NEW THREAT ---
64
+ if not received_threat:
65
+ DECAY_RATE = 0.15
66
+ npc["threat_level"] = max(0.0, npc["threat_level"] - DECAY_RATE)
67
+
68
+ return ctx
69
+
70
+ def state(self):
71
+ """Return the live engine state (mutable)."""
72
+ return self._ctx
73
+
74
+ def snapshot(self):
75
+ """Return an immutable snapshot of engine state."""
76
+ import copy
77
+ return copy.deepcopy(self._ctx)
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ghocentric-ghost-engine"
7
+ version = "0.1.1"
8
+ description = "Ghost cognitive engine"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ authors = [
12
+ { name="Shane Heckathorn" }
13
+ ]
14
+
15
+ dependencies = []
16
+
17
+ [tool.setuptools.packages.find]
18
+ where = ["."]
19
+ include = ["ghost*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ # tests/test_environment_isolation.py
2
+
3
+ import os
4
+ import sys
5
+ import copy
6
+
7
+
8
+ def test_no_environment_side_effects():
9
+ """
10
+ Importing and initializing Ghost must not mutate
11
+ global environment variables or sys.path.
12
+ """
13
+
14
+ env_before = dict(os.environ)
15
+ path_before = list(sys.path)
16
+
17
+ import ghost
18
+
19
+ # Explicit init is allowed, but must be clean
20
+ ghost.init()
21
+
22
+ assert dict(os.environ) == env_before
23
+ assert list(sys.path) == path_before
@@ -0,0 +1,24 @@
1
+ import copy
2
+ import time
3
+
4
+
5
+ def test_no_implicit_execution():
6
+ """
7
+ Ghost must not mutate state unless explicitly stepped.
8
+ """
9
+
10
+ from ghost.engine import GhostEngine
11
+
12
+ engine = GhostEngine()
13
+
14
+ # Capture initial engine state
15
+ initial_state = engine.state()
16
+
17
+ # Wait to catch any background mutation
18
+ time.sleep(0.2)
19
+
20
+ # Capture state again without stepping
21
+ later_state = engine.state()
22
+
23
+ # State must be identical
24
+ assert later_state == initial_state
@@ -0,0 +1,23 @@
1
+ def test_external_input_passthrough():
2
+ """
3
+ External input passed to step() must be recorded in state.
4
+ """
5
+
6
+ from ghost.engine import GhostEngine
7
+
8
+ engine = GhostEngine()
9
+
10
+ event = {
11
+ "source": "npc_engine",
12
+ "intent": "threat",
13
+ "actor": "player",
14
+ "intensity": 0.5,
15
+ }
16
+
17
+ engine.step(event)
18
+ state = engine.state()
19
+
20
+ assert "input" in state
21
+ assert state["input"] is not None
22
+ assert isinstance(state["input"], dict)
23
+ assert state["input"] == event
@@ -0,0 +1,41 @@
1
+ def test_actor_memory_tracks_threat_counts():
2
+ """
3
+ Ghost must track per-actor threat counts independently.
4
+ """
5
+
6
+ from ghost.engine import GhostEngine
7
+
8
+ engine = GhostEngine()
9
+
10
+ engine.step({
11
+ "source": "npc_engine",
12
+ "actor": "player",
13
+ "intent": "threat",
14
+ "intensity": 0.7,
15
+ })
16
+
17
+ engine.step({
18
+ "source": "npc_engine",
19
+ "actor": "player",
20
+ "intent": "threat",
21
+ "intensity": 0.4,
22
+ })
23
+
24
+ engine.step({
25
+ "source": "npc_engine",
26
+ "actor": "guard",
27
+ "intent": "threat",
28
+ "intensity": 0.9,
29
+ })
30
+
31
+ state = engine.state()
32
+
33
+ assert "npc" in state
34
+ assert "actors" in state["npc"]
35
+
36
+ # Per-actor memory exists
37
+ assert "player" in state["npc"]["actors"]
38
+ assert "guard" in state["npc"]["actors"]
39
+
40
+ assert state["npc"]["actors"]["player"]["threat_count"] == 2
41
+ assert state["npc"]["actors"]["guard"]["threat_count"] == 1
@@ -0,0 +1,40 @@
1
+ def test_emotional_modulation_affects_threat_gain():
2
+ """
3
+ Same threat input, different mood → different threat accumulation.
4
+ Higher mood (anxious) should amplify threat gain.
5
+ """
6
+
7
+ from ghost.engine import GhostEngine
8
+
9
+ # ---- Calm mood engine ----
10
+ calm_engine = GhostEngine()
11
+
12
+ # Inject calm mood into engine state
13
+ calm_state = calm_engine.state()
14
+ calm_state.setdefault("state", {})
15
+ calm_state["state"]["mood"] = 0.1 # calm / low arousal
16
+
17
+ calm_engine.step({
18
+ "source": "npc_engine",
19
+ "intent": "threat",
20
+ "intensity": 1.0,
21
+ })
22
+
23
+ calm_threat = calm_engine.state()["npc"]["threat_level"]
24
+
25
+ # ---- Anxious mood engine ----
26
+ anxious_engine = GhostEngine()
27
+
28
+ anxious_state = anxious_engine.state()
29
+ anxious_state.setdefault("state", {})
30
+ anxious_state["state"]["mood"] = 0.9 # anxious / high arousal
31
+
32
+ anxious_engine.step({
33
+ "source": "npc_engine",
34
+ "intent": "threat",
35
+ "intensity": 1.0,
36
+ })
37
+
38
+ anxious_threat = anxious_engine.state()["npc"]["threat_level"]
39
+
40
+ assert anxious_threat > calm_threat
@@ -0,0 +1,36 @@
1
+ def test_threat_decays_without_new_input():
2
+ """
3
+ Threat level should decay over time if no new threat input is received.
4
+ """
5
+
6
+ from ghost.engine import GhostEngine
7
+
8
+ engine = GhostEngine()
9
+
10
+ # --- Spike threat ---
11
+ engine.step({
12
+ "source": "npc_engine",
13
+ "intent": "threat",
14
+ "intensity": 1.0,
15
+ })
16
+
17
+ s1 = engine.state()
18
+ threat_after_spike = s1["npc"]["threat_level"]
19
+
20
+ # --- Advance cycles with no input (decay only) ---
21
+ engine.step()
22
+ engine.step()
23
+ engine.step()
24
+
25
+ s2 = engine.state()
26
+ threat_after_decay = s2["npc"]["threat_level"]
27
+
28
+ # --- Contracts ---
29
+ assert "npc" in s1
30
+ assert "npc" in s2
31
+
32
+ assert "threat_level" in s1["npc"]
33
+ assert "threat_level" in s2["npc"]
34
+
35
+ # Core invariant: decay must reduce threat without new input
36
+ assert threat_after_decay < threat_after_spike
@@ -0,0 +1,21 @@
1
+ def test_npc_intent_is_classified():
2
+ """
3
+ NPC intent input should be classified and reflected in engine state.
4
+ """
5
+
6
+ from ghost.engine import GhostEngine
7
+
8
+ engine = GhostEngine()
9
+
10
+ engine.step({
11
+ "source": "npc_engine",
12
+ "intent": "threat",
13
+ "intensity": 0.8
14
+ })
15
+
16
+ state = engine.state()
17
+
18
+ # --- Contracts ---
19
+ assert "npc" in state
20
+ assert state["npc"]["last_intent"] == "threat"
21
+ assert state["npc"]["threat_level"] > 0
@@ -0,0 +1,28 @@
1
+ def test_public_api_surface():
2
+ """
3
+ Ghost exposes a stable, minimal public API.
4
+ This is the pip-facing contract.
5
+ """
6
+
7
+ import ghost
8
+
9
+ assert hasattr(ghost, "init")
10
+ assert hasattr(ghost, "step")
11
+ assert hasattr(ghost, "reset")
12
+ assert hasattr(ghost, "state")
13
+ assert hasattr(ghost, "snapshot")
14
+
15
+
16
+ def test_public_api_behavior():
17
+ """
18
+ Public API functions must work end-to-end without importing internals.
19
+ """
20
+
21
+ import ghost
22
+
23
+ ghost.init()
24
+ ghost.step()
25
+ state = ghost.state()
26
+
27
+ assert isinstance(state, dict)
28
+ assert "cycles" in state