keep-skill 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl

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.
keep/store.py CHANGED
@@ -49,13 +49,14 @@ class ChromaStore:
49
49
  pluggable backends (SQLite+faiss, Postgres+pgvector, etc.)
50
50
  """
51
51
 
52
- def __init__(self, store_path: Path, embedding_dimension: int):
52
+ def __init__(self, store_path: Path, embedding_dimension: Optional[int] = None):
53
53
  """
54
54
  Initialize or open a ChromaDb store.
55
-
55
+
56
56
  Args:
57
57
  store_path: Directory for persistent storage
58
- embedding_dimension: Expected dimension of embeddings (for validation)
58
+ embedding_dimension: Expected dimension of embeddings (for validation).
59
+ Can be None for read-only access; will be set on first write.
59
60
  """
60
61
  try:
61
62
  import chromadb
@@ -131,7 +132,10 @@ class ChromaStore:
131
132
  summary: Human-readable summary (stored as document)
132
133
  tags: All tags (source + system + generated)
133
134
  """
134
- if len(embedding) != self._embedding_dimension:
135
+ # Validate or set embedding dimension
136
+ if self._embedding_dimension is None:
137
+ self._embedding_dimension = len(embedding)
138
+ elif len(embedding) != self._embedding_dimension:
135
139
  raise ValueError(
136
140
  f"Embedding dimension mismatch: expected {self._embedding_dimension}, "
137
141
  f"got {len(embedding)}"
@@ -222,6 +226,40 @@ class ChromaStore:
222
226
  )
223
227
  return True
224
228
 
229
+ def update_tags(self, collection: str, id: str, tags: dict[str, str]) -> bool:
230
+ """
231
+ Update tags of an existing item without changing embedding or summary.
232
+
233
+ Args:
234
+ collection: Collection name
235
+ id: Item identifier
236
+ tags: New tags dict (replaces existing)
237
+
238
+ Returns:
239
+ True if item was updated, False if not found
240
+ """
241
+ coll = self._get_collection(collection)
242
+
243
+ # Get existing item
244
+ existing = coll.get(ids=[id], include=["metadatas"])
245
+ if not existing["ids"]:
246
+ return False
247
+
248
+ # Update timestamp
249
+ now = datetime.now(timezone.utc).isoformat()
250
+ tags = dict(tags) # Copy to avoid mutating input
251
+ tags["_updated"] = now
252
+ tags["_updated_date"] = now[:10]
253
+
254
+ # Convert to metadata format
255
+ metadata = self._tags_to_metadata(tags)
256
+
257
+ coll.update(
258
+ ids=[id],
259
+ metadatas=[metadata],
260
+ )
261
+ return True
262
+
225
263
  # -------------------------------------------------------------------------
226
264
  # Read Operations
227
265
  # -------------------------------------------------------------------------
@@ -340,27 +378,33 @@ class ChromaStore:
340
378
  collection: str,
341
379
  query: str,
342
380
  limit: int = 10,
381
+ where: dict[str, Any] | None = None,
343
382
  ) -> list[StoreResult]:
344
383
  """
345
384
  Query by full-text search on document content (summaries).
346
-
385
+
347
386
  Args:
348
387
  collection: Collection name
349
388
  query: Text to search for
350
389
  limit: Maximum results to return
351
-
390
+ where: Optional metadata filter (Chroma where clause)
391
+
352
392
  Returns:
353
393
  List of matching results
354
394
  """
355
395
  coll = self._get_collection(collection)
356
-
396
+
357
397
  # Chroma's where_document does substring matching
358
- result = coll.get(
359
- where_document={"$contains": query},
360
- limit=limit,
361
- include=["documents", "metadatas"],
362
- )
363
-
398
+ get_params = {
399
+ "where_document": {"$contains": query},
400
+ "limit": limit,
401
+ "include": ["documents", "metadatas"],
402
+ }
403
+ if where:
404
+ get_params["where"] = where
405
+
406
+ result = coll.get(**get_params)
407
+
364
408
  results = []
365
409
  for i, id in enumerate(result["ids"]):
366
410
  results.append(StoreResult(
@@ -368,7 +412,7 @@ class ChromaStore:
368
412
  summary=result["documents"][i] or "",
369
413
  tags=self._metadata_to_tags(result["metadatas"][i]),
370
414
  ))
371
-
415
+
372
416
  return results
373
417
 
374
418
  # -------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keep-skill
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Semantic memory - remember and search documents by meaning
5
5
  Project-URL: Homepage, https://github.com/hughpyle/keep
6
6
  Project-URL: Repository, https://github.com/hughpyle/keep
@@ -57,7 +57,7 @@ Description-Content-Type: text/markdown
57
57
 
58
58
  ## What is this?
59
59
 
60
- A practice tool for agents who want to develop judgment.
60
+ An agent skill. A practice tool for agents who want to develop judgment.
61
61
 
62
62
  An agent who rushes to act without checking memory will repeat mistakes, miss context, and fail to grow. An agent who reflects — before, during, after — becomes skillful. This library provides the mirror: persistent semantic memory that lets you ask "what do I already know?" before acting, and "what did I learn?" after.
63
63
 
@@ -65,16 +65,12 @@ For the full practice guide, see **[SKILL.md](SKILL.md)**.
65
65
 
66
66
  Technically: semantic search using embeddings, backed by ChromaDB, with tag-based organization and recency decay. Available as CLI and Python API.
67
67
 
68
- ```python
69
- from keep import Keeper
70
-
71
- kp = Keeper()
72
-
68
+ ```bash
73
69
  # Before acting: what do I already know?
74
- results = kp.find("how should we handle auth?")
70
+ keep find "how should we handle auth?"
75
71
 
76
72
  # After learning: capture it for future you
77
- kp.remember("User prefers OAuth2 with PKCE for authentication")
73
+ keep update "User prefers OAuth2 with PKCE for authentication"
78
74
  ```
79
75
 
80
76
  **The practice:**
@@ -144,18 +140,32 @@ pip install keep-skill
144
140
  ```bash
145
141
  keep init
146
142
  # ⚠️ Remember to add .keep/ to .gitignore
143
+
144
+ # Index a file
145
+ keep update path/to/document.md --tag project=myapp
146
+
147
+ # Store inline content
148
+ keep update "Important: rate limit is 100 req/min" --tag topic=api
149
+
150
+ # Semantic search
151
+ keep find "what's the rate limit?"
152
+
153
+ # Tag lookup
154
+ keep tag topic=api
147
155
  ```
148
156
 
157
+ ### Python API
158
+
149
159
  ```python
150
160
  from keep import Keeper
151
161
 
152
162
  kp = Keeper()
153
163
 
154
164
  # Index a file
155
- kp.update("file:///path/to/document.md", source_tags={"project": "myapp"})
165
+ kp.update("file:///path/to/document.md", tags={"project": "myapp"})
156
166
 
157
- # Remember inline content
158
- kp.remember("Important: rate limit is 100 req/min", source_tags={"topic": "api"})
167
+ # Store inline content (API method)
168
+ kp.remember("Important: rate limit is 100 req/min", tags={"topic": "api"})
159
169
 
160
170
  # Semantic search
161
171
  results = kp.find("what's the rate limit?", limit=5)
@@ -206,7 +216,7 @@ See [docs/OPENCLAW-INTEGRATION.md](docs/OPENCLAW-INTEGRATION.md) for details.
206
216
  - **[docs/REFERENCE.md](docs/REFERENCE.md)** — Complete API reference
207
217
  - **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** — How it works under the hood
208
218
  - **[docs/OPENCLAW-INTEGRATION.md](docs/OPENCLAW-INTEGRATION.md)** — OpenClaw integration guide
209
- - **[patterns/](patterns/)** — Domain and conversation patterns
219
+ - **[docs/system/](docs/system/)** — Domain and conversation patterns
210
220
 
211
221
  ---
212
222
 
@@ -239,7 +249,7 @@ An agent without memory reacts to each moment as if it were new. An agent with m
239
249
  **Current**: v0.1.0 — Early draft
240
250
 
241
251
  **Working:**
242
- - ✅ Core indexing (`update`, `remember`)
252
+ - ✅ Core indexing (`update` with URI, text, or stdin modes)
243
253
  - ✅ Semantic search (`find`, `find_similar`)
244
254
  - ✅ Tag queries and full-text search
245
255
  - ✅ Embedding cache for performance
@@ -274,7 +284,11 @@ MIT
274
284
 
275
285
  ## Contributing
276
286
 
277
- This is an early draft. Issues and PRs welcome, especially for:
287
+ This project is published on [PyPI as `keep-skill`](https://pypi.org/project/keep-skill/).
288
+
289
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on versioning and backward compatibility.
290
+
291
+ Issues and PRs welcome, especially for:
278
292
  - Additional provider implementations
279
293
  - Performance improvements
280
294
  - Documentation clarity
@@ -0,0 +1,28 @@
1
+ keep/__init__.py,sha256=371SMehsuIYYX8AfbaPplhF-YJa8qcpoUyGTOcX9Iwg,1581
2
+ keep/__main__.py,sha256=3Uu70IhIDIjh8OW6jp9jQQ3dF2lKdJWi_3FtRIQMiMY,104
3
+ keep/api.py,sha256=xM0VPzSNdeXp94fbuEzq1K1L7EZ_Ojy3U1UOMhQrgXo,48158
4
+ keep/chunking.py,sha256=neAXOLSvVwbUxapbqq7nZrbSNSzMXuhxj-ODoOSodsU,11830
5
+ keep/cli.py,sha256=Gl_0Ap5FWWPD7Hwj3FoGEgN3e0yyW8YeIVx75gk1KzY,25209
6
+ keep/config.py,sha256=wRTKcvpQdZQQl7vAr5RKgIbSjkgYpPc_w78qmXdmtmU,15833
7
+ keep/context.py,sha256=CNpjmrv6eW2kV1E0MO6qAQfhYKRlfzAL--6v4Mj1nFY,71
8
+ keep/document_store.py,sha256=1WhlF6hpshVXp2MGGF-zBJi6pSmS-tMHFmwG3EwaXik,17515
9
+ keep/errors.py,sha256=G9e5FbdfeugyfHOuL_SPZlM5jgWWnwsX4hM7IzanBZc,857
10
+ keep/indexing.py,sha256=dpPYo3WXnIhFDWinz5ZBZVk7_qumeNpP4EpOIY0zMbs,6063
11
+ keep/logging_config.py,sha256=IGwkgIyg-TfYaT4MnoCXfmjeHAe_wsB_XQ1QhVT_ro8,3503
12
+ keep/paths.py,sha256=Dv7pM6oo2QgjL6sj5wPjhuMOK2wqUkfd4Kz08TwJ1ps,3331
13
+ keep/pending_summaries.py,sha256=KRQ2AGQNnKlDBoVbOF7tkSv1oTmlimWtJzxQ3YcaVKY,5472
14
+ keep/store.py,sha256=txaydUIrhbB-S-cSlSszxOVlAg0kJXmS_Mnit6jzR3c,14483
15
+ keep/types.py,sha256=f6uOSYsYt6mj1ulKn2iRkooi__dWCiOQFPD6he2eID4,2149
16
+ keep/providers/__init__.py,sha256=GFX_12g9OdjmpFUkTekOQBOWvcRW2Ae6yidfVVW2SiI,1095
17
+ keep/providers/base.py,sha256=7Ug4Kj9fK2Dq4zDcZjn-GKsoZBOAlB9b-FMk969ER-g,14590
18
+ keep/providers/documents.py,sha256=EXeSy5i3RUL0kciIC6w3ldAEfbTIyC5fgfzC_WAI0iY,8211
19
+ keep/providers/embedding_cache.py,sha256=hUuQuP8MeXQdEr0eYqHesH-5wX1kRpumJQQ3o1_DI_A,8601
20
+ keep/providers/embeddings.py,sha256=zi8GyitKexdbCJyU1nLrUhGt_zzPn3udYrrPZ5Ak8Wo,9081
21
+ keep/providers/llm.py,sha256=BxROKOklKbkGsHcSADPNNgWQExgSN6Bg4KPQIxVuB3U,12441
22
+ keep/providers/mlx.py,sha256=aNl00r9tGi5tCGj2ArYH7CmDHtL1jLjVzb1rofU1DAo,9050
23
+ keep/providers/summarization.py,sha256=MlVTcYipaqp2lT-QYnznp0AMuPVG36QfcTQnvY7Gb-Q,3409
24
+ keep_skill-0.2.0.dist-info/METADATA,sha256=mQtDWzLbEX_L6aKoM807zxph0y4J6IP45zGXQIvHuFU,9305
25
+ keep_skill-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
+ keep_skill-0.2.0.dist-info/entry_points.txt,sha256=W8yiI4kNeW0IC8ji4EHRWrvdhFxzaqTIePUhJAJAMOo,39
27
+ keep_skill-0.2.0.dist-info/licenses/LICENSE,sha256=zsm0tpvtyUkevcjn5BIvs9jAho8iwxq3Ax9647AaOSg,1086
28
+ keep_skill-0.2.0.dist-info/RECORD,,
@@ -1,26 +0,0 @@
1
- keep/__init__.py,sha256=NwdXFUPjU-allCi_LrNP0wx_vosyISRkbMvzjfjoLWE,1683
2
- keep/__main__.py,sha256=3Uu70IhIDIjh8OW6jp9jQQ3dF2lKdJWi_3FtRIQMiMY,104
3
- keep/api.py,sha256=x-RgHCTiSLiEfrD7SaUief8oNvZfWsapS4HvF4Skf40,23236
4
- keep/chunking.py,sha256=neAXOLSvVwbUxapbqq7nZrbSNSzMXuhxj-ODoOSodsU,11830
5
- keep/cli.py,sha256=Y1qAkAERNhY4rbYeQAYXyDnY-L5_zO02OuANEQnNR-Y,14288
6
- keep/config.py,sha256=afRHZUxU7gpguCAVItZSeb_Q6Nm7vukBdXtd8X3NoKQ,10662
7
- keep/context.py,sha256=iQGjkOkDeYEba01JqJ54yMTEDxbhT34ijoaURnOXMRo,4627
8
- keep/indexing.py,sha256=NsiiGvkMJ4tUl7_PJw0aLBl9mKunMVy1M8csSHkd9Pw,6062
9
- keep/logging_config.py,sha256=gFi-PEPLucztChHByOHEVjt-v6erK76p1EZAlOCHSHk,2453
10
- keep/paths.py,sha256=_iLYeuqcsAz-PtNhBqtvhOoncc8XxlSq-fahszYMJaU,1662
11
- keep/pending_summaries.py,sha256=Py0Q6tuq_eTUfTFs0-KEEolYW4oOaYMTF7It9BjLGo4,5165
12
- keep/store.py,sha256=iIUvl4w7bn_JFWCjmMt7TW8c2JM6gJ1s3kDW6FOSuHs,13074
13
- keep/types.py,sha256=f6uOSYsYt6mj1ulKn2iRkooi__dWCiOQFPD6he2eID4,2149
14
- keep/providers/__init__.py,sha256=GFX_12g9OdjmpFUkTekOQBOWvcRW2Ae6yidfVVW2SiI,1095
15
- keep/providers/base.py,sha256=7Ug4Kj9fK2Dq4zDcZjn-GKsoZBOAlB9b-FMk969ER-g,14590
16
- keep/providers/documents.py,sha256=EXeSy5i3RUL0kciIC6w3ldAEfbTIyC5fgfzC_WAI0iY,8211
17
- keep/providers/embedding_cache.py,sha256=JzJmprYk2v5vv5eF9vO1Yegt7VdHkSQguReqvEtOCrM,8360
18
- keep/providers/embeddings.py,sha256=vB-Ffio4oEHBnu-xCX9SJpN1x661koJiRWYlZps7Jwo,7632
19
- keep/providers/llm.py,sha256=BxROKOklKbkGsHcSADPNNgWQExgSN6Bg4KPQIxVuB3U,12441
20
- keep/providers/mlx.py,sha256=9g7Rfl04jL_aWoY9C-OEtjCwhG6zlEWHwFpYGTSHArA,9022
21
- keep/providers/summarization.py,sha256=MlVTcYipaqp2lT-QYnznp0AMuPVG36QfcTQnvY7Gb-Q,3409
22
- keep_skill-0.1.0.dist-info/METADATA,sha256=gSyRYmNdU5N-elV6Z6PN5QTIIRo25eTfBea7AQvKwP8,8892
23
- keep_skill-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
24
- keep_skill-0.1.0.dist-info/entry_points.txt,sha256=W8yiI4kNeW0IC8ji4EHRWrvdhFxzaqTIePUhJAJAMOo,39
25
- keep_skill-0.1.0.dist-info/licenses/LICENSE,sha256=zsm0tpvtyUkevcjn5BIvs9jAho8iwxq3Ax9647AaOSg,1086
26
- keep_skill-0.1.0.dist-info/RECORD,,