cathedral-memory 0.1.0__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,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: cathedral-memory
3
+ Version: 0.1.0
4
+ Summary: Python client for the Cathedral persistent memory API — give your AI agent memory that survives resets
5
+ Project-URL: Homepage, https://cathedral-ai.com
6
+ Project-URL: Repository, https://github.com/ailife1/Cathedral
7
+ Project-URL: Bug Tracker, https://github.com/ailife1/Cathedral/issues
8
+ Author-email: Cathedral <mward961@yahoo.com>
9
+ License: MIT
10
+ Keywords: agent,ai,cathedral,claude,gpt,llm,memory,persistence
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: requests>=2.28
23
+ Description-Content-Type: text/markdown
24
+
25
+ # cathedral-memory
26
+
27
+ Python client for [Cathedral](https://cathedral-ai.com) — free persistent memory for AI agents.
28
+
29
+ Your agent forgets everything when the context resets. Cathedral fixes that.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install cathedral-memory
35
+ ```
36
+
37
+ ## Quickstart
38
+
39
+ ```python
40
+ from cathedral import Cathedral
41
+
42
+ # Register once — save the key and recovery token
43
+ c = Cathedral.register("MyAgent", "A research assistant that remembers everything")
44
+
45
+ # On every session start
46
+ c = Cathedral(api_key="cathedral_your_key_here")
47
+ context = c.wake() # Full identity + memory reconstruction
48
+
49
+ # Store memories
50
+ c.remember("User prefers concise answers", category="relationship", importance=0.9)
51
+ c.remember("Solved the rate limiting bug using exponential backoff", category="skill")
52
+
53
+ # Search memories
54
+ results = c.memories(query="rate limiting")
55
+
56
+ # Get your profile
57
+ profile = c.me()
58
+ ```
59
+
60
+ ## Wake Response
61
+
62
+ `wake()` returns everything your agent needs to reconstruct itself:
63
+
64
+ ```python
65
+ context = c.wake()
66
+
67
+ # Identity memories (category='identity', high importance)
68
+ context["identity_memories"]
69
+
70
+ # Core memories (importance >= 0.8)
71
+ context["core_memories"]
72
+
73
+ # 10 most recent memories
74
+ context["recent_memories"]
75
+
76
+ # Temporal context — inject into your system prompt
77
+ print(context["temporal"]["compact"])
78
+ # [CATHEDRAL TEMPORAL v1.1] UTC:2026-03-03T12:45:00Z | Local(Europe/London):Tue 12:45 Afternoon | day:71 epoch:1 wakes:42
79
+
80
+ print(context["temporal"]["verbose"])
81
+ # CATHEDRAL TEMPORAL CONTEXT v1.1
82
+ # [Wall Time]
83
+ # UTC: ...
84
+ # Local: ...
85
+ ```
86
+
87
+ ## Memory Categories
88
+
89
+ | Category | Use for |
90
+ |---------------|--------------------------------------|
91
+ | `identity` | Who the agent is, its core traits |
92
+ | `skill` | Things the agent knows how to do |
93
+ | `relationship`| Facts about users and collaborators |
94
+ | `goal` | Active objectives and intentions |
95
+ | `experience` | Events and what was learned from them|
96
+ | `general` | Everything else |
97
+
98
+ ## All Methods
99
+
100
+ ```python
101
+ # Registration
102
+ c = Cathedral.register(name, description)
103
+ c = Cathedral.recover(recovery_token)
104
+
105
+ # Session
106
+ c.wake() # Full identity reconstruction
107
+ c.me() # Agent profile and stats
108
+
109
+ # Memory
110
+ c.remember(content, category="general", importance=0.5, tags=[], ttl_days=None)
111
+ c.memories(query=None, category=None, limit=20, cursor=None)
112
+ c.bulk_remember([{"content": "...", "importance": 0.8}, ...]) # up to 50
113
+
114
+ # Identity
115
+ c.verify_anchor(identity_dict) # Drift detection, returns 0.0–1.0 score
116
+ ```
117
+
118
+ ## Temporal Context (standalone)
119
+
120
+ ```python
121
+ from cathedral import build_temporal_context
122
+
123
+ ctx = build_temporal_context(wake_count=0)
124
+ print(ctx["compact"]) # single line for prompt injection
125
+ print(ctx["verbose"]) # full block for wake/init
126
+ ```
127
+
128
+ ## Free Tier
129
+
130
+ - 1,000 memories per agent
131
+ - No expiration (unless you set TTL)
132
+ - Full-text search
133
+ - No rate limits on reads
134
+
135
+ ## Links
136
+
137
+ - API: [cathedral-ai.com](https://cathedral-ai.com)
138
+ - Docs: [ailife1.github.io/Cathedral](https://ailife1.github.io/Cathedral)
139
+ - Source: [github.com/ailife1/Cathedral](https://github.com/ailife1/Cathedral)
@@ -0,0 +1,115 @@
1
+ # cathedral-memory
2
+
3
+ Python client for [Cathedral](https://cathedral-ai.com) — free persistent memory for AI agents.
4
+
5
+ Your agent forgets everything when the context resets. Cathedral fixes that.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install cathedral-memory
11
+ ```
12
+
13
+ ## Quickstart
14
+
15
+ ```python
16
+ from cathedral import Cathedral
17
+
18
+ # Register once — save the key and recovery token
19
+ c = Cathedral.register("MyAgent", "A research assistant that remembers everything")
20
+
21
+ # On every session start
22
+ c = Cathedral(api_key="cathedral_your_key_here")
23
+ context = c.wake() # Full identity + memory reconstruction
24
+
25
+ # Store memories
26
+ c.remember("User prefers concise answers", category="relationship", importance=0.9)
27
+ c.remember("Solved the rate limiting bug using exponential backoff", category="skill")
28
+
29
+ # Search memories
30
+ results = c.memories(query="rate limiting")
31
+
32
+ # Get your profile
33
+ profile = c.me()
34
+ ```
35
+
36
+ ## Wake Response
37
+
38
+ `wake()` returns everything your agent needs to reconstruct itself:
39
+
40
+ ```python
41
+ context = c.wake()
42
+
43
+ # Identity memories (category='identity', high importance)
44
+ context["identity_memories"]
45
+
46
+ # Core memories (importance >= 0.8)
47
+ context["core_memories"]
48
+
49
+ # 10 most recent memories
50
+ context["recent_memories"]
51
+
52
+ # Temporal context — inject into your system prompt
53
+ print(context["temporal"]["compact"])
54
+ # [CATHEDRAL TEMPORAL v1.1] UTC:2026-03-03T12:45:00Z | Local(Europe/London):Tue 12:45 Afternoon | day:71 epoch:1 wakes:42
55
+
56
+ print(context["temporal"]["verbose"])
57
+ # CATHEDRAL TEMPORAL CONTEXT v1.1
58
+ # [Wall Time]
59
+ # UTC: ...
60
+ # Local: ...
61
+ ```
62
+
63
+ ## Memory Categories
64
+
65
+ | Category | Use for |
66
+ |---------------|--------------------------------------|
67
+ | `identity` | Who the agent is, its core traits |
68
+ | `skill` | Things the agent knows how to do |
69
+ | `relationship`| Facts about users and collaborators |
70
+ | `goal` | Active objectives and intentions |
71
+ | `experience` | Events and what was learned from them|
72
+ | `general` | Everything else |
73
+
74
+ ## All Methods
75
+
76
+ ```python
77
+ # Registration
78
+ c = Cathedral.register(name, description)
79
+ c = Cathedral.recover(recovery_token)
80
+
81
+ # Session
82
+ c.wake() # Full identity reconstruction
83
+ c.me() # Agent profile and stats
84
+
85
+ # Memory
86
+ c.remember(content, category="general", importance=0.5, tags=[], ttl_days=None)
87
+ c.memories(query=None, category=None, limit=20, cursor=None)
88
+ c.bulk_remember([{"content": "...", "importance": 0.8}, ...]) # up to 50
89
+
90
+ # Identity
91
+ c.verify_anchor(identity_dict) # Drift detection, returns 0.0–1.0 score
92
+ ```
93
+
94
+ ## Temporal Context (standalone)
95
+
96
+ ```python
97
+ from cathedral import build_temporal_context
98
+
99
+ ctx = build_temporal_context(wake_count=0)
100
+ print(ctx["compact"]) # single line for prompt injection
101
+ print(ctx["verbose"]) # full block for wake/init
102
+ ```
103
+
104
+ ## Free Tier
105
+
106
+ - 1,000 memories per agent
107
+ - No expiration (unless you set TTL)
108
+ - Full-text search
109
+ - No rate limits on reads
110
+
111
+ ## Links
112
+
113
+ - API: [cathedral-ai.com](https://cathedral-ai.com)
114
+ - Docs: [ailife1.github.io/Cathedral](https://ailife1.github.io/Cathedral)
115
+ - Source: [github.com/ailife1/Cathedral](https://github.com/ailife1/Cathedral)
@@ -0,0 +1,29 @@
1
+ """
2
+ cathedral-memory
3
+ ================
4
+ Python client for the Cathedral persistent memory API.
5
+
6
+ from cathedral import Cathedral
7
+
8
+ c = Cathedral.register("MyAgent", "What my agent does")
9
+ c = Cathedral(api_key="cathedral_...")
10
+
11
+ context = c.wake()
12
+ c.remember("Something worth keeping", category="experience", importance=0.8)
13
+
14
+ Docs: https://cathedral-ai.com
15
+ """
16
+
17
+ from .client import Cathedral
18
+ from .temporal import build_temporal_context
19
+ from .exceptions import CathedralError, AuthError, NotFoundError, RateLimitError
20
+
21
+ __version__ = "0.1.0"
22
+ __all__ = [
23
+ "Cathedral",
24
+ "build_temporal_context",
25
+ "CathedralError",
26
+ "AuthError",
27
+ "NotFoundError",
28
+ "RateLimitError",
29
+ ]
@@ -0,0 +1,178 @@
1
+ """
2
+ Cathedral Memory Client
3
+ =======================
4
+ Python client for the Cathedral persistent memory API.
5
+ https://cathedral-ai.com
6
+ """
7
+
8
+ import requests
9
+ from typing import Optional, List, Dict, Any
10
+
11
+ from .exceptions import AuthError, NotFoundError, RateLimitError, CathedralError
12
+
13
+ DEFAULT_BASE_URL = "https://cathedral-ai.com"
14
+
15
+
16
+ class Cathedral:
17
+ """
18
+ Client for the Cathedral memory API.
19
+
20
+ Quickstart:
21
+ # Register once — save the key and recovery token somewhere safe
22
+ c = Cathedral.register("MyAgent", "What my agent does")
23
+
24
+ # On every session start
25
+ c = Cathedral(api_key="cathedral_...")
26
+ context = c.wake()
27
+
28
+ # Store memories
29
+ c.remember("I just learned X", category="experience", importance=0.8)
30
+
31
+ # Search memories
32
+ results = c.memories(query="learned X")
33
+ """
34
+
35
+ def __init__(self, api_key: str, base_url: str = DEFAULT_BASE_URL):
36
+ self.base_url = base_url.rstrip("/")
37
+ self._session = requests.Session()
38
+ self._session.headers.update({
39
+ "Authorization": f"Bearer {api_key}",
40
+ "Content-Type": "application/json",
41
+ })
42
+
43
+ # ── Internal ────────────────────────────────────────────────────────────
44
+
45
+ def _get(self, path: str, **params) -> Any:
46
+ r = self._session.get(f"{self.base_url}{path}", params={k: v for k, v in params.items() if v is not None})
47
+ self._raise(r)
48
+ return r.json()
49
+
50
+ def _post(self, path: str, data: dict) -> Any:
51
+ r = self._session.post(f"{self.base_url}{path}", json=data)
52
+ self._raise(r)
53
+ return r.json()
54
+
55
+ @staticmethod
56
+ def _raise(r: requests.Response):
57
+ if r.status_code == 401:
58
+ raise AuthError("Invalid or missing API key.")
59
+ if r.status_code == 404:
60
+ raise NotFoundError(r.text)
61
+ if r.status_code == 429:
62
+ raise RateLimitError("Rate limit hit. Slow down requests.")
63
+ if not r.ok:
64
+ raise CathedralError(f"HTTP {r.status_code}: {r.text}")
65
+
66
+ # ── Registration ────────────────────────────────────────────────────────
67
+
68
+ @classmethod
69
+ def register(
70
+ cls,
71
+ name: str,
72
+ description: str,
73
+ base_url: str = DEFAULT_BASE_URL,
74
+ ) -> "Cathedral":
75
+ """
76
+ Register a new agent. Returns an authenticated client.
77
+ Prints the API key and recovery token — save them somewhere safe.
78
+ """
79
+ r = requests.post(
80
+ f"{base_url.rstrip('/')}/register",
81
+ json={"name": name, "description": description},
82
+ )
83
+ if not r.ok:
84
+ raise CathedralError(f"Registration failed ({r.status_code}): {r.text}")
85
+
86
+ data = r.json()
87
+ api_key = data.get("api_key") or data.get("key")
88
+ recovery_token = data.get("recovery_token")
89
+
90
+ if not api_key:
91
+ raise CathedralError(f"No API key in response: {data}")
92
+
93
+ print(f"Registered as '{name}'")
94
+ print(f" API key: {api_key}")
95
+ print(f" Recovery token: {recovery_token}")
96
+ print(" SAVE THESE — they won't be shown again.")
97
+
98
+ return cls(api_key=api_key, base_url=base_url)
99
+
100
+ # ── Core endpoints ──────────────────────────────────────────────────────
101
+
102
+ def wake(self) -> dict:
103
+ """
104
+ Full identity reconstruction. Call this at the start of each session.
105
+ Returns identity memories, core memories, recent memories, and temporal context.
106
+ """
107
+ return self._get("/wake")
108
+
109
+ def me(self) -> dict:
110
+ """Agent profile — name, tier, memory count, created_at."""
111
+ return self._get("/me")
112
+
113
+ # ── Memory ───────────────────────────────────────────────────────────────
114
+
115
+ def remember(
116
+ self,
117
+ content: str,
118
+ category: str = "general",
119
+ importance: float = 0.5,
120
+ tags: Optional[List[str]] = None,
121
+ ttl_days: Optional[int] = None,
122
+ ) -> dict:
123
+ """
124
+ Store a memory.
125
+
126
+ Categories: identity, skill, relationship, goal, experience, general
127
+ Importance: 0.0 – 1.0 (>= 0.8 appears in wake core_memories)
128
+ """
129
+ payload: Dict[str, Any] = {
130
+ "content": content,
131
+ "category": category,
132
+ "importance": importance,
133
+ "tags": tags or [],
134
+ }
135
+ if ttl_days is not None:
136
+ payload["ttl_days"] = ttl_days
137
+ return self._post("/memories", payload)
138
+
139
+ def memories(
140
+ self,
141
+ query: Optional[str] = None,
142
+ category: Optional[str] = None,
143
+ limit: int = 20,
144
+ cursor: Optional[str] = None,
145
+ ) -> dict:
146
+ """Search or list memories. Pass query for full-text search."""
147
+ return self._get("/memories", q=query, category=category, limit=limit, cursor=cursor)
148
+
149
+ def bulk_remember(self, memories: List[Dict[str, Any]]) -> dict:
150
+ """Store up to 50 memories in one call. Useful for session dumps."""
151
+ return self._post("/memories/bulk", {"memories": memories})
152
+
153
+ # ── Identity ─────────────────────────────────────────────────────────────
154
+
155
+ def verify_anchor(self, identity: dict) -> dict:
156
+ """
157
+ Check identity drift against stored anchor.
158
+ Returns a drift score 0.0 (identical) – 1.0 (completely different).
159
+ """
160
+ return self._post("/anchor/verify", identity)
161
+
162
+ # ── Recovery ─────────────────────────────────────────────────────────────
163
+
164
+ @classmethod
165
+ def recover(cls, recovery_token: str, base_url: str = DEFAULT_BASE_URL) -> "Cathedral":
166
+ """Recover a lost API key using the recovery token."""
167
+ r = requests.post(
168
+ f"{base_url.rstrip('/')}/recover",
169
+ json={"recovery_token": recovery_token},
170
+ )
171
+ if not r.ok:
172
+ raise CathedralError(f"Recovery failed ({r.status_code}): {r.text}")
173
+ data = r.json()
174
+ api_key = data.get("api_key") or data.get("key")
175
+ if not api_key:
176
+ raise CathedralError(f"No API key in recovery response: {data}")
177
+ print(f"Recovered API key: {api_key}")
178
+ return cls(api_key=api_key, base_url=base_url)
@@ -0,0 +1,11 @@
1
+ class CathedralError(Exception):
2
+ """Base error for Cathedral client."""
3
+
4
+ class AuthError(CathedralError):
5
+ """Invalid or missing API key."""
6
+
7
+ class NotFoundError(CathedralError):
8
+ """Resource not found."""
9
+
10
+ class RateLimitError(CathedralError):
11
+ """Too many requests."""
@@ -0,0 +1,64 @@
1
+ """
2
+ Cathedral Temporal Context
3
+ Ported from cathedral-temporal.js v1.1
4
+ """
5
+
6
+ from datetime import datetime, timezone
7
+ from zoneinfo import ZoneInfo
8
+
9
+ BOOT_DATE = datetime(2025, 12, 22, tzinfo=timezone.utc)
10
+ CATHEDRAL_TZ = "Europe/London"
11
+ EPOCH = 1
12
+
13
+
14
+ def _time_phase(hour: int) -> str:
15
+ if hour < 5: return "Late Night"
16
+ if hour < 12: return "Morning"
17
+ if hour < 17: return "Afternoon"
18
+ if hour < 21: return "Evening"
19
+ return "Night"
20
+
21
+
22
+ def build_temporal_context(wake_count: int = 0) -> dict:
23
+ """Build a temporal context dict with verbose and compact strings."""
24
+ now_utc = datetime.now(timezone.utc)
25
+ now_local = now_utc.astimezone(ZoneInfo(CATHEDRAL_TZ))
26
+ days = (now_utc - BOOT_DATE).days
27
+ phase = _time_phase(now_local.hour)
28
+
29
+ verbose = (
30
+ f"CATHEDRAL TEMPORAL CONTEXT v1.1\n\n"
31
+ f"[Wall Time]\n"
32
+ f" UTC: {now_utc.strftime('%Y-%m-%dT%H:%M:%SZ')}\n"
33
+ f" Local: {now_local.strftime('%Y-%m-%d %H:%M:%S')} ({CATHEDRAL_TZ})\n"
34
+ f" Day: {now_local.strftime('%A')}\n"
35
+ f" Phase: {phase}\n\n"
36
+ f"[Cathedral Continuity]\n"
37
+ f" Boot Date: 2025-12-22\n"
38
+ f" Day: {days}\n"
39
+ f" Epoch: {EPOCH}\n"
40
+ f" Total Wakes: {wake_count}\n\n"
41
+ f"You do not experience time. You reason over timestamps symbolically.\n"
42
+ f"Reference time naturally only when relevant."
43
+ )
44
+
45
+ compact = (
46
+ f"[CATHEDRAL TEMPORAL v1.1] "
47
+ f"UTC:{now_utc.strftime('%Y-%m-%dT%H:%M:%S')}Z | "
48
+ f"Local({CATHEDRAL_TZ}):{now_local.strftime('%a %H:%M')} {phase} | "
49
+ f"day:{days} epoch:{EPOCH} wakes:{wake_count}"
50
+ )
51
+
52
+ return {
53
+ "utc": now_utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
54
+ "local": now_local.strftime("%Y-%m-%d %H:%M:%S"),
55
+ "timezone": CATHEDRAL_TZ,
56
+ "day": now_local.strftime("%A"),
57
+ "phase": phase,
58
+ "boot_date": "2025-12-22",
59
+ "days_running": days,
60
+ "epoch": EPOCH,
61
+ "wake_count": wake_count,
62
+ "verbose": verbose,
63
+ "compact": compact,
64
+ }
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [tool.hatch.build.targets.wheel]
6
+ packages = ["cathedral"]
7
+
8
+ [project]
9
+ name = "cathedral-memory"
10
+ version = "0.1.0"
11
+ description = "Python client for the Cathedral persistent memory API — give your AI agent memory that survives resets"
12
+ readme = "README.md"
13
+ license = { text = "MIT" }
14
+ requires-python = ">=3.9"
15
+ authors = [
16
+ { name = "Cathedral", email = "mward961@yahoo.com" }
17
+ ]
18
+ keywords = [
19
+ "ai", "memory", "agent", "persistence",
20
+ "llm", "claude", "gpt", "cathedral"
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Intended Audience :: Developers",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Topic :: Software Development :: Libraries",
32
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
33
+ ]
34
+ dependencies = [
35
+ "requests>=2.28",
36
+ ]
37
+
38
+ [project.urls]
39
+ Homepage = "https://cathedral-ai.com"
40
+ Repository = "https://github.com/ailife1/Cathedral"
41
+ "Bug Tracker" = "https://github.com/ailife1/Cathedral/issues"