keep-skill 0.6.0__py3-none-any.whl → 0.8.1__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/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
- Keep - Semantic Memory
2
+ Keep - Reflective Memory
3
3
 
4
- A persistent semantic memory with similarity search, full-text search,
4
+ A persistent reflective memory with similarity search, full-text search,
5
5
  and tag-based retrieval. Remember everything, find by meaning.
6
6
 
7
7
  Quick Start:
@@ -40,7 +40,7 @@ if not os.environ.get("KEEP_VERBOSE"):
40
40
  from .api import Keeper, NOWDOC_ID
41
41
  from .types import Item, filter_non_system_tags, SYSTEM_TAG_PREFIX, INTERNAL_TAGS
42
42
 
43
- __version__ = "0.6.0"
43
+ __version__ = "0.7.0"
44
44
  __all__ = [
45
45
  "Keeper",
46
46
  "Item",
keep/api.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- Core API for associative memory.
2
+ Core API for reflective memory.
3
3
 
4
4
  This is the minimal working implementation focused on:
5
5
  - update(): fetch → embed → summarize → store
@@ -269,7 +269,7 @@ def _text_content_id(content: str) -> str:
269
269
 
270
270
  class Keeper:
271
271
  """
272
- Semantic memory keeper - persistent storage with similarity search.
272
+ Reflective memory keeper - persistent storage with similarity search.
273
273
 
274
274
  Example:
275
275
  kp = Keeper()
@@ -284,7 +284,7 @@ class Keeper:
284
284
  decay_half_life_days: float = 30.0
285
285
  ) -> None:
286
286
  """
287
- Initialize or open an existing associative memory store.
287
+ Initialize or open an existing reflective memory store.
288
288
 
289
289
  Args:
290
290
  store_path: Path to store directory. Uses default if not specified.
@@ -1554,6 +1554,7 @@ class Keeper:
1554
1554
  self,
1555
1555
  limit: int = 10,
1556
1556
  *,
1557
+ since: Optional[str] = None,
1557
1558
  collection: Optional[str] = None,
1558
1559
  ) -> list[Item]:
1559
1560
  """
@@ -1561,16 +1562,24 @@ class Keeper:
1561
1562
 
1562
1563
  Args:
1563
1564
  limit: Maximum number to return (default 10)
1565
+ since: Only include items updated since (ISO duration like P3D, or date)
1564
1566
  collection: Collection to query (uses default if not specified)
1565
1567
 
1566
1568
  Returns:
1567
1569
  List of Items, most recently updated first
1568
1570
  """
1569
1571
  coll = self._resolve_collection(collection)
1570
- records = self._document_store.list_recent(coll, limit)
1571
1572
 
1572
- return [_record_to_item(rec) for rec in records
1573
- ]
1573
+ # Fetch extra when filtering by date
1574
+ fetch_limit = limit * 3 if since is not None else limit
1575
+ records = self._document_store.list_recent(coll, fetch_limit)
1576
+ items = [_record_to_item(rec) for rec in records]
1577
+
1578
+ # Apply date filter if specified
1579
+ if since is not None:
1580
+ items = _filter_by_date(items, since)
1581
+
1582
+ return items[:limit]
1574
1583
 
1575
1584
  def embedding_cache_stats(self) -> dict:
1576
1585
  """
keep/cli.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- CLI interface for associative memory.
2
+ CLI interface for reflective memory.
3
3
 
4
4
  Usage:
5
5
  keepfind "query text"
@@ -47,6 +47,7 @@ def _verbose_callback(value: bool):
47
47
  _json_output = False
48
48
  _ids_output = False
49
49
  _full_output = False
50
+ _store_override: Optional[Path] = None
50
51
 
51
52
 
52
53
  def _json_callback(value: bool):
@@ -76,9 +77,19 @@ def _get_full_output() -> bool:
76
77
  return _full_output
77
78
 
78
79
 
80
+ def _store_callback(value: Optional[Path]):
81
+ global _store_override
82
+ if value is not None:
83
+ _store_override = value
84
+
85
+
86
+ def _get_store_override() -> Optional[Path]:
87
+ return _store_override
88
+
89
+
79
90
  app = typer.Typer(
80
91
  name="keep",
81
- help="Associative memory with semantic search.",
92
+ help="Reflective memory with semantic search.",
82
93
  no_args_is_help=False,
83
94
  invoke_without_command=True,
84
95
  rich_markup_mode=None,
@@ -231,8 +242,15 @@ def main_callback(
231
242
  callback=_full_callback,
232
243
  is_eager=True,
233
244
  )] = False,
245
+ store: Annotated[Optional[Path], typer.Option(
246
+ "--store", "-s",
247
+ envvar="KEEP_STORE_PATH",
248
+ help="Path to the store directory",
249
+ callback=_store_callback,
250
+ is_eager=True,
251
+ )] = None,
234
252
  ):
235
- """Associative memory with semantic search."""
253
+ """Reflective memory with semantic search."""
236
254
  # If no subcommand provided, show the current context (now)
237
255
  if ctx.invoked_subcommand is None:
238
256
  from .api import NOWDOC_ID
@@ -401,9 +419,10 @@ def _format_items(items: list[Item], as_json: bool = False) -> str:
401
419
 
402
420
  def _get_keeper(store: Optional[Path], collection: str) -> Keeper:
403
421
  """Initialize memory, handling errors gracefully."""
404
- # store=None is fine Keeper will use default (git root/.keep)
422
+ # Check global override from --store on main command
423
+ actual_store = store if store is not None else _get_store_override()
405
424
  try:
406
- return Keeper(store, collection=collection)
425
+ return Keeper(actual_store, collection=collection)
407
426
  except Exception as e:
408
427
  typer.echo(f"Error: {e}", err=True)
409
428
  raise typer.Exit(1)
@@ -464,6 +483,7 @@ def find(
464
483
  """
465
484
  Find items using semantic similarity search.
466
485
 
486
+ \b
467
487
  Examples:
468
488
  keep find "authentication" # Search by text
469
489
  keep find --id file:///path/to/doc.md # Find similar to item
@@ -509,71 +529,76 @@ def list_recent(
509
529
  "--limit", "-n",
510
530
  help="Number of items to show"
511
531
  )] = 10,
512
- ):
513
- """
514
- List recent items by update time.
515
-
516
- Default: summary lines. Use --ids for IDs only, --full for YAML.
517
- """
518
- kp = _get_keeper(store, collection)
519
- results = kp.list_recent(limit=limit)
520
- typer.echo(_format_items(results, as_json=_get_json_output()))
521
-
522
-
523
- @app.command()
524
- def tag(
525
- query: Annotated[Optional[str], typer.Argument(
526
- help="Tag key to list values, or key=value to find docs"
532
+ tag: Annotated[Optional[list[str]], typer.Option(
533
+ "--tag", "-t",
534
+ help="Filter by tag (key or key=value, repeatable)"
535
+ )] = None,
536
+ tags: Annotated[Optional[str], typer.Option(
537
+ "--tags", "-T",
538
+ help="List tag keys (--tags=), or values for KEY (--tags=KEY)"
527
539
  )] = None,
528
- list_keys: Annotated[bool, typer.Option(
529
- "--list", "-l",
530
- help="List all distinct tag keys"
531
- )] = False,
532
- store: StoreOption = None,
533
- collection: CollectionOption = "default",
534
- limit: LimitOption = 100,
535
540
  since: SinceOption = None,
536
541
  ):
537
542
  """
538
- List tag values or find items by tag.
543
+ List recent items, filter by tags, or list tag keys/values.
539
544
 
545
+ \b
540
546
  Examples:
541
- keep tag --list # List all tag keys
542
- keep tag project # List values for 'project' tag
543
- keep tag project=myapp # Find docs with project=myapp
547
+ keep list # Recent items
548
+ keep list --tag foo # Items with tag 'foo' (any value)
549
+ keep list --tag foo=bar # Items with tag foo=bar
550
+ keep list --tag foo --tag bar # Items with both tags
551
+ keep list --tags= # List all tag keys
552
+ keep list --tags=foo # List values for tag 'foo'
553
+ keep list --since P3D # Items updated in last 3 days
544
554
  """
545
555
  kp = _get_keeper(store, collection)
546
556
 
547
- # List all keys mode
548
- if list_keys or query is None:
549
- tags = kp.list_tags(None, collection=collection)
550
- if _get_json_output():
551
- typer.echo(json.dumps(tags))
552
- else:
553
- if not tags:
554
- typer.echo("No tags found.")
555
- else:
556
- for t in tags:
557
- typer.echo(t)
558
- return
559
-
560
- # Check if query is key=value or just key
561
- if "=" in query:
562
- # key=value → find documents
563
- key, value = query.split("=", 1)
564
- results = kp.query_tag(key, value, limit=limit, since=since)
565
- typer.echo(_format_items(results, as_json=_get_json_output()))
566
- else:
567
- # key only → list values
568
- values = kp.list_tags(query, collection=collection)
557
+ # --tags mode: list keys or values
558
+ if tags is not None:
559
+ # Empty string means list all keys, otherwise list values for key
560
+ key = tags if tags else None
561
+ values = kp.list_tags(key, collection=collection)
569
562
  if _get_json_output():
570
563
  typer.echo(json.dumps(values))
571
564
  else:
572
565
  if not values:
573
- typer.echo(f"No values for tag '{query}'.")
566
+ if key:
567
+ typer.echo(f"No values for tag '{key}'.")
568
+ else:
569
+ typer.echo("No tags found.")
574
570
  else:
575
571
  for v in values:
576
572
  typer.echo(v)
573
+ return
574
+
575
+ # --tag mode: filter items by tag(s)
576
+ if tag:
577
+ # Parse each tag as key or key=value
578
+ # Multiple tags require all to match (AND)
579
+ results = None
580
+ for t in tag:
581
+ if "=" in t:
582
+ key, value = t.split("=", 1)
583
+ matches = kp.query_tag(key, value, limit=limit, since=since, collection=collection)
584
+ else:
585
+ # Key only - find items with this tag key (any value)
586
+ matches = kp.query_tag(t, limit=limit, since=since, collection=collection)
587
+
588
+ if results is None:
589
+ results = {item.id: item for item in matches}
590
+ else:
591
+ # Intersect with previous results
592
+ match_ids = {item.id for item in matches}
593
+ results = {id: item for id, item in results.items() if id in match_ids}
594
+
595
+ items = list(results.values()) if results else []
596
+ typer.echo(_format_items(items[:limit], as_json=_get_json_output()))
597
+ return
598
+
599
+ # Default: recent items
600
+ results = kp.list_recent(limit=limit, since=since, collection=collection)
601
+ typer.echo(_format_items(results, as_json=_get_json_output()))
577
602
 
578
603
 
579
604
  @app.command("tag-update")
@@ -595,6 +620,7 @@ def tag_update(
595
620
 
596
621
  Does not re-process the document - only updates tags.
597
622
 
623
+ \b
598
624
  Examples:
599
625
  keep tag-update doc:1 --tag project=myapp
600
626
  keep tag-update doc:1 doc:2 --tag status=reviewed
@@ -665,12 +691,14 @@ def update(
665
691
  """
666
692
  Add or update a document in the store.
667
693
 
694
+ \b
668
695
  Three input modes (auto-detected):
669
696
  keep update file:///path # URI mode: has ://
670
697
  keep update "my note" # Text mode: content-addressed ID
671
698
  keep update - # Stdin mode: explicit -
672
699
  echo "pipe" | keep update # Stdin mode: piped input
673
700
 
701
+ \b
674
702
  Text mode uses content-addressed IDs for versioning:
675
703
  keep update "my note" # Creates _text:{hash}
676
704
  keep update "my note" -t done # Same ID, new version (tag change)
@@ -737,6 +765,7 @@ def now(
737
765
  With no arguments, displays the current context.
738
766
  With content, replaces it.
739
767
 
768
+ \b
740
769
  Examples:
741
770
  keep now # Show current context
742
771
  keep now "What's important now" # Update context
@@ -907,6 +936,7 @@ def get(
907
936
 
908
937
  Version identifiers: Append @V{N} to get a specific version.
909
938
 
939
+ \b
910
940
  Examples:
911
941
  keep get doc:1 # Current version with similar items
912
942
  keep get doc:1 -V 1 # Previous version with prev/next nav
keep/config.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- Configuration management for associative memory stores.
2
+ Configuration management for reflective memory stores.
3
3
 
4
4
  The configuration is stored as a TOML file in the store directory.
5
5
  It specifies which providers to use and their parameters.
@@ -145,17 +145,17 @@ Ask about scope before large changes." \
145
145
  **Temporal queries using system tags:**
146
146
  ```bash
147
147
  # Find items updated today
148
- keep tag _updated_date=2026-01-30
148
+ keep list --tag _updated_date=2026-01-30
149
149
 
150
150
  # Find all inline content (from remember)
151
- keep tag _source=inline
151
+ keep list --tag _source=inline
152
152
  ```
153
153
 
154
154
  **Progressive refinement:**
155
155
  ```bash
156
156
  # Start broad, then narrow
157
157
  keep find "authentication"
158
- keep tag module=auth
158
+ keep list --tag module=auth
159
159
  ```
160
160
 
161
161
  ---
@@ -173,7 +173,7 @@ Only then commit to action. Breakdown risk: Promising too early leads to rework.
173
173
  --tag type=conversation_pattern --tag domain=general
174
174
 
175
175
  # Later, retrieve it
176
- keep tag type=conversation_pattern
176
+ keep list --tag type=conversation_pattern
177
177
  ```
178
178
 
179
179
  See [conversations.md](conversations.md) for the full framework.
keep/data/system/now.md CHANGED
@@ -5,8 +5,7 @@ tags:
5
5
  ---
6
6
  # Now
7
7
 
8
- This is top-of-mind right now. Reminders for essential practice.
9
- (Keep this updated as you need)
8
+ Now: reflect on this work using `keep`.
10
9
 
11
10
  **Before acting:**
12
11
  - Where are we in the conversation?
@@ -16,4 +15,4 @@ This is top-of-mind right now. Reminders for essential practice.
16
15
  **After acting:**
17
16
  - What happened? `keep update "what I learned" -t context=learning`
18
17
  - What do I save? `keep update`
19
- - What now? `keep now "Current focus: ..."`
18
+ - What now? `keep now "Current intention: ..."`
@@ -1,5 +1,5 @@
1
1
  """
2
- Provider interfaces for associative memory services.
2
+ Provider interfaces for reflective memory services.
3
3
 
4
4
  Each provider type defines a protocol that concrete implementations must follow.
5
5
  Providers are configured at store initialization and handle the heavy lifting of:
keep/types.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- Data types for associative memory.
2
+ Data types for reflective memory.
3
3
  """
4
4
 
5
5
  from dataclasses import dataclass, field
@@ -27,7 +27,7 @@ def filter_non_system_tags(tags: dict[str, str]) -> dict[str, str]:
27
27
  @dataclass(frozen=True)
28
28
  class Item:
29
29
  """
30
- An item retrieved from the associative memory store.
30
+ An item retrieved from the reflective memory store.
31
31
 
32
32
  This is a read-only snapshot. To modify an item, use api.update()
33
33
  which returns a new Item with updated values.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keep-skill
3
- Version: 0.6.0
4
- Summary: Semantic memory - remember and search documents by meaning
3
+ Version: 0.8.1
4
+ Summary: Reflective 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
7
7
  Author: Hugh Pyle
@@ -51,7 +51,7 @@ Description-Content-Type: text/markdown
51
51
 
52
52
  # keep
53
53
 
54
- **Semantic memory with version history.**
54
+ **Reflective memory with version history.**
55
55
 
56
56
  Index documents and notes. Search by meaning. Track changes over time.
57
57
 
@@ -128,8 +128,8 @@ keep get "ID@V{1}" # Same as -V 1 (version identifier)
128
128
  keep get ID --history # All versions
129
129
 
130
130
  # Tags
131
- keep tag project=myapp # Find by tag
132
- keep tag --list # List all tags
131
+ keep list --tag project=myapp # Find by tag
132
+ keep list --tags= # List all tag keys
133
133
 
134
134
  # Current context
135
135
  keep now # Show what you're working on
@@ -176,35 +176,14 @@ See [docs/QUICKSTART.md](docs/QUICKSTART.md) for configuration and more examples
176
176
  This library was designed as an agent skill — persistent memory that helps agents reflect before acting and learn from experience.
177
177
 
178
178
  **The practice:**
179
- - Pause before acting `keep find` what you already know
180
- - Notice breakdowns — when assumptions surface, index them
181
- - Reflect after `keep update` learnings for future sessions
179
+ - Before acting, use `keep` to reflect on the context.
180
+ - Notice breakdowns — when assumptions surface, index them.
181
+ - After acting, use `keep` to save your context and intentions.
182
182
 
183
183
  See **[SKILL.md](SKILL.md)** for the full practice guide.
184
184
 
185
185
  ---
186
186
 
187
- ## Status
188
-
189
- **Current:** v0.3.0
190
-
191
- **Working:**
192
- - ✅ Semantic search with embeddings
193
- - ✅ Document versioning (all updates retain history)
194
- - ✅ Content-addressed IDs for text (same content = same ID)
195
- - ✅ Tag queries and full-text search
196
- - ✅ Current context tracking (`keep now`)
197
- - ✅ Recency decay (recent items rank higher)
198
- - ✅ Lazy summarization (background processing)
199
- - ✅ Provider abstraction (local or API-based)
200
-
201
- **Planned** (see [later/](later/)):
202
- - ⏳ Private/shared routing
203
- - ⏳ Relationship graphs between items
204
- - ⏳ LLM-based auto-tagging
205
-
206
- ---
207
-
208
187
  ## License
209
188
 
210
189
  MIT
@@ -1,9 +1,9 @@
1
- keep/__init__.py,sha256=lAm_iUUxz76EanZYE5UviCD1p2OSQwUag4Q67EP4oKE,1617
1
+ keep/__init__.py,sha256=yBK7jvbQmx9fRBGanICNgrQdyCQHzt5bNPp098Qvh9E,1621
2
2
  keep/__main__.py,sha256=3Uu70IhIDIjh8OW6jp9jQQ3dF2lKdJWi_3FtRIQMiMY,104
3
- keep/api.py,sha256=Ja_9zKr0bDL2UyBDZ03HrQHYkI9mdOMxuQlstyxJzmo,64477
3
+ keep/api.py,sha256=V_w4ahhgmgk10ehjs5JAvTct8wOvL8xsvW-nko_9Yjw,64858
4
4
  keep/chunking.py,sha256=neAXOLSvVwbUxapbqq7nZrbSNSzMXuhxj-ODoOSodsU,11830
5
- keep/cli.py,sha256=P7oKtv3TFL5BZNEfwh6kAFuqoeeqFxfVYssjdg0RMLc,44761
6
- keep/config.py,sha256=gw_QMY0VkCVF6xi-B9zGvZSza4z2QtiJucqgZJF3Xqg,16227
5
+ keep/cli.py,sha256=SAB4LEZrX08sDVBxYD1s_zo2WXTYJBwhZswlQdjVkQ8,46024
6
+ keep/config.py,sha256=hWjiJDg2u6p8IJpksXe0ngVxQNcKHKRFKUDJQBFlG7I,16226
7
7
  keep/context.py,sha256=CNpjmrv6eW2kV1E0MO6qAQfhYKRlfzAL--6v4Mj1nFY,71
8
8
  keep/document_store.py,sha256=UswqKIGSc5E-r7Tg9k0g5-byYnuar3e9FieQ7WNod9k,29109
9
9
  keep/errors.py,sha256=G9e5FbdfeugyfHOuL_SPZlM5jgWWnwsX4hM7IzanBZc,857
@@ -12,13 +12,13 @@ keep/logging_config.py,sha256=IGwkgIyg-TfYaT4MnoCXfmjeHAe_wsB_XQ1QhVT_ro8,3503
12
12
  keep/paths.py,sha256=Dv7pM6oo2QgjL6sj5wPjhuMOK2wqUkfd4Kz08TwJ1ps,3331
13
13
  keep/pending_summaries.py,sha256=_irGe7P1Lmog2c5cEgx-BElpq4YJW-tEmF5A3IUZQbQ,5727
14
14
  keep/store.py,sha256=SBc2QdTyApdDDVjm2uZQI6tGbV5Hurfetgj7dyTO65o,17881
15
- keep/types.py,sha256=_ytiG1O-9fY39o_TOktzYaFxHZBcIfuYgGI_vKsEx30,2316
15
+ keep/types.py,sha256=irvUJYUHQgQdVqC4_lgrG0FbTN1BdZqFxZr0ubVPSG4,2314
16
16
  keep/data/__init__.py,sha256=C1YARrudHwK2Bmlxkh7dZlIaNJ5m5WrSTglCdG8e3T0,24
17
17
  keep/data/system/__init__.py,sha256=Rp92_sBO3kscuWXJomo0HKeHfU-N4BgBeT3-5El0Mcg,28
18
18
  keep/data/system/conversations.md,sha256=jE53wYSUyu5uPFNtO1Tu6w4f5QxqLei7muxLF_kZE2s,9837
19
- keep/data/system/domains.md,sha256=OCRAGvB0EaphsEammxLmx7L-orw2OHzgF6GwAZ8ztUs,5556
20
- keep/data/system/now.md,sha256=vsPCNy-9k3g5KKIgG0MYL21m8qYV3tI0hMa9co6hffc,442
21
- keep/providers/__init__.py,sha256=GFX_12g9OdjmpFUkTekOQBOWvcRW2Ae6yidfVVW2SiI,1095
19
+ keep/data/system/domains.md,sha256=EHE6zU2-lx7UeLqyOTmoWl1WVlvgRq3_QnFb_EZceEY,5584
20
+ keep/data/system/now.md,sha256=GyQo_LizSIVKbj5q52q4ErV-nxz8rzUOlkILjgNu25s,388
21
+ keep/providers/__init__.py,sha256=6AwJYc6cF1ZT6BcU_6ATyeWk7MHohdVU2-ccqDSvCHU,1094
22
22
  keep/providers/base.py,sha256=7Ug4Kj9fK2Dq4zDcZjn-GKsoZBOAlB9b-FMk969ER-g,14590
23
23
  keep/providers/documents.py,sha256=EXeSy5i3RUL0kciIC6w3ldAEfbTIyC5fgfzC_WAI0iY,8211
24
24
  keep/providers/embedding_cache.py,sha256=gna6PZEJanbn2GUN0vj1b1MC0xVWePM9cot2KgZUdu8,8856
@@ -26,8 +26,8 @@ keep/providers/embeddings.py,sha256=zi8GyitKexdbCJyU1nLrUhGt_zzPn3udYrrPZ5Ak8Wo,
26
26
  keep/providers/llm.py,sha256=BxROKOklKbkGsHcSADPNNgWQExgSN6Bg4KPQIxVuB3U,12441
27
27
  keep/providers/mlx.py,sha256=aNl00r9tGi5tCGj2ArYH7CmDHtL1jLjVzb1rofU1DAo,9050
28
28
  keep/providers/summarization.py,sha256=MlVTcYipaqp2lT-QYnznp0AMuPVG36QfcTQnvY7Gb-Q,3409
29
- keep_skill-0.6.0.dist-info/METADATA,sha256=lTAvkxt0X4pgtkLVfqZMBOdeGKz_tqO6KMm-nM2egjU,6606
30
- keep_skill-0.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
31
- keep_skill-0.6.0.dist-info/entry_points.txt,sha256=W8yiI4kNeW0IC8ji4EHRWrvdhFxzaqTIePUhJAJAMOo,39
32
- keep_skill-0.6.0.dist-info/licenses/LICENSE,sha256=zsm0tpvtyUkevcjn5BIvs9jAho8iwxq3Ax9647AaOSg,1086
33
- keep_skill-0.6.0.dist-info/RECORD,,
29
+ keep_skill-0.8.1.dist-info/METADATA,sha256=ClBi2sP1kofuCjyjM1UsO8Yo_ouw-XxhLPIpMyDcVjE,6042
30
+ keep_skill-0.8.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
31
+ keep_skill-0.8.1.dist-info/entry_points.txt,sha256=W8yiI4kNeW0IC8ji4EHRWrvdhFxzaqTIePUhJAJAMOo,39
32
+ keep_skill-0.8.1.dist-info/licenses/LICENSE,sha256=zsm0tpvtyUkevcjn5BIvs9jAho8iwxq3Ax9647AaOSg,1086
33
+ keep_skill-0.8.1.dist-info/RECORD,,