keep-skill 0.10.0__tar.gz → 0.11.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.
Files changed (35) hide show
  1. {keep_skill-0.10.0 → keep_skill-0.11.0}/PKG-INFO +1 -1
  2. {keep_skill-0.10.0 → keep_skill-0.11.0}/SKILL.md +10 -6
  3. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/__init__.py +1 -1
  4. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/cli.py +166 -16
  5. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/config.py +28 -0
  6. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/data/system/library.md +2 -2
  7. {keep_skill-0.10.0 → keep_skill-0.11.0}/pyproject.toml +1 -1
  8. {keep_skill-0.10.0 → keep_skill-0.11.0}/.gitignore +0 -0
  9. {keep_skill-0.10.0 → keep_skill-0.11.0}/LICENSE +0 -0
  10. {keep_skill-0.10.0 → keep_skill-0.11.0}/README.md +0 -0
  11. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/__main__.py +0 -0
  12. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/api.py +0 -0
  13. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/chunking.py +0 -0
  14. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/context.py +0 -0
  15. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/data/__init__.py +0 -0
  16. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/data/system/__init__.py +0 -0
  17. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/data/system/conversations.md +0 -0
  18. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/data/system/domains.md +0 -0
  19. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/data/system/now.md +0 -0
  20. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/document_store.py +0 -0
  21. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/errors.py +0 -0
  22. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/indexing.py +0 -0
  23. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/logging_config.py +0 -0
  24. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/paths.py +0 -0
  25. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/pending_summaries.py +0 -0
  26. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/__init__.py +0 -0
  27. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/base.py +0 -0
  28. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/documents.py +0 -0
  29. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/embedding_cache.py +0 -0
  30. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/embeddings.py +0 -0
  31. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/llm.py +0 -0
  32. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/mlx.py +0 -0
  33. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/providers/summarization.py +0 -0
  34. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/store.py +0 -0
  35. {keep_skill-0.10.0 → keep_skill-0.11.0}/keep/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keep-skill
3
- Version: 0.10.0
3
+ Version: 0.11.0
4
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
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: keep
3
- version: 0.10.0
3
+ version: 0.11.0
4
4
  description: Reflective Memory
5
5
  homepage: https://github.com/hughpyle/keep
6
6
  runtime: python:3.12-slim
@@ -121,6 +121,8 @@ This cycle — reflect, act, reflect — is how you develop judgment. Install t
121
121
 
122
122
  Memory isn't storage. It's your mirror.
123
123
 
124
+ * When in conversation, use this practice.
125
+ * When writing a plan, make sure this practice is part of the plan.
124
126
 
125
127
  ## Layer 2: First Time Setup
126
128
 
@@ -128,7 +130,9 @@ Memory isn't storage. It's your mirror.
128
130
  keep init
129
131
  ```
130
132
 
131
- Now read the foundational teachings. These are seed wisdom, not test fixtures:
133
+ Now read the foundational teachings. These are seed wisdom, not test fixtures.
134
+
135
+ Note: When you `update` a document or URL, summarization runs in the background. Until complete, the summary shows as a content truncation. Run `keep process-pending` to check progress.
132
136
 
133
137
  **The Language-Action framework** — conversation types, commitment structure, breakdowns:
134
138
  ```bash
@@ -137,8 +141,8 @@ keep get "_system:conversations"
137
141
 
138
142
  **The mirror teaching** (Ambalaṭṭhikā Rāhulovāda Sutta) — actions reflected upon before, during, after. Read the full source:
139
143
  ```bash
140
- keep update "file://$PWD/docs/library/mn61.html" -t type=teaching -t topic=reflection
141
- keep get "file://$PWD/docs/library/mn61.html"
144
+ keep update "file://$(keep config tool)/docs/library/mn61.html" -t type=teaching -t topic=reflection
145
+ keep get "file://$(keep config tool)/docs/library/mn61.html"
142
146
  ```
143
147
 
144
148
  **Domain organization** — tagging strategies, collection structures:
@@ -148,8 +152,8 @@ keep get "_system:domains"
148
152
 
149
153
  **A Zen teaching with commentary** — notice how each commentator re-enacts the pointing from a different angle:
150
154
  ```bash
151
- keep update "file://$PWD/docs/library/true_person_no_rank.md" -t type=teaching -t topic=commentary
152
- keep get "file://$PWD/docs/library/true_person_no_rank.md"
155
+ keep update "file://$(keep config tool)/docs/library/true_person_no_rank.md" -t type=teaching -t topic=commentary
156
+ keep get "file://$(keep config tool)/docs/library/true_person_no_rank.md"
153
157
  ```
154
158
 
155
159
  **Now reflect:** What did you learn? Save your understanding:
@@ -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.10.0"
43
+ __version__ = "0.11.0"
44
44
  __all__ = [
45
45
  "Keeper",
46
46
  "Item",
@@ -25,6 +25,7 @@ VERSION_SUFFIX_PATTERN = re.compile(r'@V\{(\d+)\}$')
25
25
  _URI_SCHEME_PATTERN = re.compile(r'^[a-zA-Z][a-zA-Z0-9+.-]*://')
26
26
 
27
27
  from .api import Keeper, _text_content_id
28
+ from .config import get_tool_directory
28
29
  from .document_store import VersionInfo
29
30
  from .types import Item
30
31
  from .logging_config import configure_quiet_mode, enable_debug_mode
@@ -809,6 +810,7 @@ def now(
809
810
  With no arguments, displays the current intentions.
810
811
  With content, replaces it.
811
812
 
813
+ \b
812
814
  Tags behave differently based on mode:
813
815
  - With content: -t sets tags on the update
814
816
  - Without content: -t filters version history
@@ -1271,12 +1273,146 @@ def init(
1271
1273
 
1272
1274
 
1273
1275
 
1276
+ def _get_config_value(kp: Keeper, path: str):
1277
+ """
1278
+ Get config value by dotted path.
1279
+
1280
+ Special paths (not in TOML):
1281
+ file - config file location
1282
+ tool - package directory (SKILL.md location)
1283
+ store - store path
1284
+ collections - list of collections
1285
+
1286
+ Dotted paths into config:
1287
+ providers - all provider config
1288
+ providers.embedding - embedding provider name
1289
+ providers.summarization - summarization provider name
1290
+ embedding.* - embedding config details
1291
+ summarization.* - summarization config details
1292
+ tags - default tags
1293
+ """
1294
+ cfg = kp._config
1295
+
1296
+ # Special built-in paths (not in TOML)
1297
+ if path == "file":
1298
+ return str(cfg.config_path) if cfg else None
1299
+ if path == "tool":
1300
+ return str(get_tool_directory())
1301
+ if path == "store":
1302
+ return str(kp._store_path)
1303
+ if path == "collections":
1304
+ return kp.list_collections()
1305
+
1306
+ # Provider shortcuts
1307
+ if path == "providers":
1308
+ if cfg:
1309
+ return {
1310
+ "embedding": cfg.embedding.name,
1311
+ "summarization": cfg.summarization.name,
1312
+ "document": cfg.document.name,
1313
+ }
1314
+ return None
1315
+ if path == "providers.embedding":
1316
+ return cfg.embedding.name if cfg else None
1317
+ if path == "providers.summarization":
1318
+ return cfg.summarization.name if cfg else None
1319
+ if path == "providers.document":
1320
+ return cfg.document.name if cfg else None
1321
+
1322
+ # Tags shortcut
1323
+ if path == "tags":
1324
+ return cfg.default_tags if cfg else {}
1325
+
1326
+ # Dotted path into config attributes
1327
+ if not cfg:
1328
+ raise typer.BadParameter(f"No config loaded, cannot access: {path}")
1329
+
1330
+ parts = path.split(".")
1331
+ value = cfg
1332
+ for part in parts:
1333
+ if hasattr(value, part):
1334
+ value = getattr(value, part)
1335
+ elif hasattr(value, "params") and part in value.params:
1336
+ # Provider config params
1337
+ value = value.params[part]
1338
+ elif isinstance(value, dict) and part in value:
1339
+ value = value[part]
1340
+ else:
1341
+ raise typer.BadParameter(f"Unknown config path: {path}")
1342
+
1343
+ # Return name for provider objects
1344
+ if hasattr(value, "name") and hasattr(value, "params"):
1345
+ return value.name
1346
+ return value
1347
+
1348
+
1349
+ # Settings that may not be configured but are available
1350
+ AVAILABLE_SETTINGS = {
1351
+ "tags": {
1352
+ "description": "Default tags applied to all operations",
1353
+ "example": {"project": "myproject", "topic": "mytopic"},
1354
+ },
1355
+ }
1356
+
1357
+
1358
+ def _format_config_with_defaults(kp: Keeper) -> str:
1359
+ """Format config output with commented defaults for unused settings."""
1360
+ cfg = kp._config
1361
+ config_path = cfg.config_path if cfg else None
1362
+ store_path = kp._store_path
1363
+ lines = []
1364
+
1365
+ # Show paths
1366
+ lines.append(f"file: {config_path}")
1367
+ lines.append(f"tool: {get_tool_directory()}")
1368
+ if cfg and cfg.config_dir and cfg.config_dir.resolve() != store_path.resolve():
1369
+ lines.append(f"store: {store_path}")
1370
+ else:
1371
+ lines.append(f"store: {store_path}")
1372
+
1373
+ lines.append(f"collections: {kp.list_collections()}")
1374
+
1375
+ if cfg:
1376
+ lines.append("")
1377
+ lines.append("providers:")
1378
+ lines.append(f" embedding: {cfg.embedding.name}")
1379
+ lines.append(f" summarization: {cfg.summarization.name}")
1380
+ lines.append(f" document: {cfg.document.name}")
1381
+
1382
+ # Show configured tags if any
1383
+ if cfg.default_tags:
1384
+ lines.append("")
1385
+ lines.append("tags:")
1386
+ for key, value in cfg.default_tags.items():
1387
+ lines.append(f" {key}: {value}")
1388
+ else:
1389
+ # Show commented example for tags
1390
+ lines.append("")
1391
+ lines.append("# tags:")
1392
+ lines.append("# project: myproject")
1393
+ lines.append("# topic: mytopic")
1394
+
1395
+ return "\n".join(lines)
1396
+
1397
+
1274
1398
  @app.command()
1275
1399
  def config(
1400
+ path: Annotated[Optional[str], typer.Argument(
1401
+ help="Config path to get (e.g., 'file', 'tool', 'store', 'providers.embedding')"
1402
+ )] = None,
1276
1403
  store: StoreOption = None,
1277
1404
  ):
1278
1405
  """
1279
- Show current configuration and store location.
1406
+ Show configuration. Optionally get a specific value by path.
1407
+
1408
+ \b
1409
+ Examples:
1410
+ keep config # Show all config
1411
+ keep config file # Config file location
1412
+ keep config tool # Package directory (SKILL.md location)
1413
+ keep config store # Store path
1414
+ keep config providers # All provider config
1415
+ keep config providers.embedding # Embedding provider name
1280
1416
  """
1281
1417
  kp = _get_keeper(store, "default")
1282
1418
 
@@ -1284,28 +1420,42 @@ def config(
1284
1420
  config_path = cfg.config_path if cfg else None
1285
1421
  store_path = kp._store_path
1286
1422
 
1423
+ # If a specific path is requested, return just that value
1424
+ if path:
1425
+ try:
1426
+ value = _get_config_value(kp, path)
1427
+ except typer.BadParameter as e:
1428
+ typer.echo(str(e), err=True)
1429
+ raise typer.Exit(1)
1430
+
1431
+ if _get_json_output():
1432
+ typer.echo(json.dumps({path: value}, indent=2))
1433
+ else:
1434
+ # Raw output for shell scripting
1435
+ if isinstance(value, (list, dict)):
1436
+ typer.echo(json.dumps(value))
1437
+ else:
1438
+ typer.echo(value)
1439
+ return
1440
+
1441
+ # Full config output
1287
1442
  if _get_json_output():
1288
1443
  result = {
1444
+ "file": str(config_path) if config_path else None,
1445
+ "tool": str(get_tool_directory()),
1289
1446
  "store": str(store_path),
1290
- "config": str(config_path) if config_path else None,
1291
1447
  "collections": kp.list_collections(),
1448
+ "providers": {
1449
+ "embedding": cfg.embedding.name if cfg else None,
1450
+ "summarization": cfg.summarization.name if cfg else None,
1451
+ "document": cfg.document.name if cfg else None,
1452
+ },
1292
1453
  }
1293
- if cfg:
1294
- result["embedding"] = cfg.embedding.name
1295
- result["summarization"] = cfg.summarization.name
1454
+ if cfg and cfg.default_tags:
1455
+ result["tags"] = cfg.default_tags
1296
1456
  typer.echo(json.dumps(result, indent=2))
1297
1457
  else:
1298
- # Show paths
1299
- typer.echo(f"Config: {config_path}")
1300
- if cfg and cfg.config_dir and cfg.config_dir.resolve() != store_path.resolve():
1301
- typer.echo(f"Store: {store_path}")
1302
-
1303
- typer.echo(f"Collections: {kp.list_collections()}")
1304
-
1305
- if cfg:
1306
- typer.echo(f"\nProviders:")
1307
- typer.echo(f" Embedding: {cfg.embedding.name}")
1308
- typer.echo(f" Summarization: {cfg.summarization.name}")
1458
+ typer.echo(_format_config_with_defaults(kp))
1309
1459
 
1310
1460
 
1311
1461
  @app.command("process-pending")
@@ -5,6 +5,7 @@ The configuration is stored as a TOML file in the store directory.
5
5
  It specifies which providers to use and their parameters.
6
6
  """
7
7
 
8
+ import importlib.resources
8
9
  import os
9
10
  import platform
10
11
  import tomllib
@@ -22,6 +23,33 @@ CONFIG_VERSION = 3 # Bumped for document versioning support
22
23
  SYSTEM_DOCS_VERSION = 3 # Increment when bundled system docs content changes
23
24
 
24
25
 
26
+ def get_tool_directory() -> Path:
27
+ """
28
+ Return directory containing SKILL.md (package root).
29
+
30
+ For installed package: SKILL.md is at the same level as the keep/ package.
31
+ For development: it's at the repository root.
32
+ """
33
+ # Get the keep package location
34
+ keep_pkg = importlib.resources.files("keep")
35
+ pkg_path = Path(str(keep_pkg))
36
+
37
+ # SKILL.md is one level up from the package
38
+ tool_dir = pkg_path.parent
39
+
40
+ # Verify SKILL.md exists there
41
+ if (tool_dir / "SKILL.md").exists():
42
+ return tool_dir
43
+
44
+ # Fallback: check if we're in a development install
45
+ # where SKILL.md might be at repository root
46
+ if pkg_path.name == "keep" and (pkg_path.parent / "SKILL.md").exists():
47
+ return pkg_path.parent
48
+
49
+ # Last resort: return the package parent anyway
50
+ return tool_dir
51
+
52
+
25
53
  @dataclass
26
54
  class ProviderConfig:
27
55
  """Configuration for a single provider."""
@@ -13,8 +13,8 @@ The content, as well as the format, is relevant to the practice of this skill.
13
13
  The library files are located in the `docs/library/` directory of the keep package.
14
14
  To construct URIs for these files:
15
15
 
16
- 1. **In a cloned repo:** Use `file://$PWD/docs/library/{filename}`
17
- 2. **With installed package:** Use Python to find the path:
16
+ 1. **From shell:** Use `file://$(keep config tool)/docs/library/{filename}`
17
+ 2. **In Python:**
18
18
  ```python
19
19
  from importlib.resources import files
20
20
  library_path = files("keep").parent / "docs" / "library"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "keep-skill"
7
- version = "0.10.0"
7
+ version = "0.11.0"
8
8
  description = "Reflective memory - remember and search documents by meaning"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.14"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes