knott 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.
- knott-0.1.0/.gitignore +8 -0
- knott-0.1.0/LICENSE +21 -0
- knott-0.1.0/PKG-INFO +146 -0
- knott-0.1.0/README.md +120 -0
- knott-0.1.0/RELEASING.md +28 -0
- knott-0.1.0/SPEC.md +740 -0
- knott-0.1.0/docs/.knott/config.yaml +1 -0
- knott-0.1.0/docs/.knott/schemas/command.yaml +18 -0
- knott-0.1.0/docs/.knott/schemas/concept.yaml +19 -0
- knott-0.1.0/docs/.knott/schemas/decision.yaml +22 -0
- knott-0.1.0/docs/.knott/schemas/guide.yaml +17 -0
- knott-0.1.0/docs/.knott/schemas/issue_code.yaml +17 -0
- knott-0.1.0/docs/README.md +51 -0
- knott-0.1.0/docs/commands/init.md +12 -0
- knott-0.1.0/docs/commands/types.md +18 -0
- knott-0.1.0/docs/commands/validate.md +43 -0
- knott-0.1.0/docs/commands/version.md +9 -0
- knott-0.1.0/docs/concepts/attribute.md +27 -0
- knott-0.1.0/docs/concepts/entity.md +45 -0
- knott-0.1.0/docs/concepts/frontmatter.md +32 -0
- knott-0.1.0/docs/concepts/issue.md +31 -0
- knott-0.1.0/docs/concepts/ontology.md +44 -0
- knott-0.1.0/docs/concepts/reference-resolution.md +35 -0
- knott-0.1.0/docs/concepts/relation.md +37 -0
- knott-0.1.0/docs/concepts/schema.md +53 -0
- knott-0.1.0/docs/concepts/vault.md +37 -0
- knott-0.1.0/docs/decisions/0001-markdown-is-source-of-truth.md +16 -0
- knott-0.1.0/docs/decisions/0002-relative-paths-not-ids.md +16 -0
- knott-0.1.0/docs/decisions/0003-source-side-relations.md +14 -0
- knott-0.1.0/docs/decisions/0004-strict-typing.md +18 -0
- knott-0.1.0/docs/decisions/0005-empty-values.md +24 -0
- knott-0.1.0/docs/decisions/0006-symlinks-and-containment.md +18 -0
- knott-0.1.0/docs/decisions/0007-parser-robustness.md +27 -0
- knott-0.1.0/docs/guides/agent-workflow.md +46 -0
- knott-0.1.0/docs/guides/getting-started.md +72 -0
- knott-0.1.0/docs/guides/obsidian.md +39 -0
- knott-0.1.0/docs/guides/python-api.md +47 -0
- knott-0.1.0/docs/guides/writing-schemas.md +60 -0
- knott-0.1.0/docs/issues/attribute-missing.md +24 -0
- knott-0.1.0/docs/issues/attribute-type-mismatch.md +22 -0
- knott-0.1.0/docs/issues/entity-invalid-frontmatter.md +23 -0
- knott-0.1.0/docs/issues/entity-unknown-type.md +23 -0
- knott-0.1.0/docs/issues/not-an-entity.md +19 -0
- knott-0.1.0/docs/issues/relation-invalid-value.md +21 -0
- knott-0.1.0/docs/issues/relation-missing.md +19 -0
- knott-0.1.0/docs/issues/relation-target-not-entity.md +19 -0
- knott-0.1.0/docs/issues/relation-target-not-found.md +23 -0
- knott-0.1.0/docs/issues/relation-target-outside-vault.md +19 -0
- knott-0.1.0/docs/issues/relation-target-type-mismatch.md +20 -0
- knott-0.1.0/docs/issues/schema-duplicate-type.md +24 -0
- knott-0.1.0/docs/issues/schema-field-conflict.md +24 -0
- knott-0.1.0/docs/issues/schema-invalid-field.md +25 -0
- knott-0.1.0/docs/issues/schema-invalid-yaml.md +23 -0
- knott-0.1.0/docs/issues/schema-unknown-target.md +25 -0
- knott-0.1.0/pyproject.toml +67 -0
- knott-0.1.0/skills/knott/SKILL.md +86 -0
- knott-0.1.0/src/knott/__init__.py +26 -0
- knott-0.1.0/src/knott/_values.py +50 -0
- knott-0.1.0/src/knott/_yaml.py +151 -0
- knott-0.1.0/src/knott/api.py +197 -0
- knott-0.1.0/src/knott/cli.py +140 -0
- knott-0.1.0/src/knott/errors.py +26 -0
- knott-0.1.0/src/knott/models.py +50 -0
- knott-0.1.0/src/knott/py.typed +0 -0
- knott-0.1.0/src/knott/schema/__init__.py +0 -0
- knott-0.1.0/src/knott/schema/loader.py +282 -0
- knott-0.1.0/src/knott/schema/models.py +42 -0
- knott-0.1.0/src/knott/schema/validator.py +263 -0
- knott-0.1.0/src/knott/vault/__init__.py +0 -0
- knott-0.1.0/src/knott/vault/discovery.py +37 -0
- knott-0.1.0/src/knott/vault/entity.py +106 -0
- knott-0.1.0/src/knott/vault/links.py +122 -0
- knott-0.1.0/tests/__init__.py +0 -0
- knott-0.1.0/tests/conftest.py +35 -0
- knott-0.1.0/tests/fixtures/duplicate-schema-type/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/duplicate-schema-type/.knott/schemas/legacy/script.yaml +4 -0
- knott-0.1.0/tests/fixtures/duplicate-schema-type/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/duplicate-schema-type/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/duplicate-schema-type/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/bom-crlf-ok.md +5 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/broken-yaml.md +4 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/not-a-mapping.md +4 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/unclosed.md +3 -0
- knott-0.1.0/tests/fixtures/invalid-frontmatter/unquoted-link.md +5 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/notes/plain.md +1 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/transcripts/episode-42.md +5 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/transcripts/plain-note-target.md +5 -0
- knott-0.1.0/tests/fixtures/missing-relation-target/transcripts/wrong-case.md +5 -0
- knott-0.1.0/tests/fixtures/missing-required-field/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/missing-required-field/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/missing-required-field/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/missing-required-field/scripts/blank-title.md +4 -0
- knott-0.1.0/tests/fixtures/missing-required-field/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/missing-required-field/scripts/untitled.md +4 -0
- knott-0.1.0/tests/fixtures/relation-list/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/relation-list/.knott/schemas/compilation.yaml +8 -0
- knott-0.1.0/tests/fixtures/relation-list/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/relation-list/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/relation-list/compilations/best-of.md +8 -0
- knott-0.1.0/tests/fixtures/relation-list/compilations/empty.md +5 -0
- knott-0.1.0/tests/fixtures/relation-list/compilations/partly-broken.md +7 -0
- knott-0.1.0/tests/fixtures/relation-list/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/relation-list/scripts/episode-43.md +4 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/scripts/episode 43.md +4 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/transcripts/angle.md +5 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/transcripts/link.md +5 -0
- knott-0.1.0/tests/fixtures/relation-markdown-link/transcripts/percent.md +5 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/transcripts/escape.md +5 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/transcripts/invalid-forms.md +10 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/transcripts/not-a-string.md +5 -0
- knott-0.1.0/tests/fixtures/relation-outside-vault/transcripts/unquoted-wikilink.md +5 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/.knott/schemas/Bad_Name.yaml +1 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/.knott/schemas/bad-fields.yaml +15 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/.knott/schemas/broken.yaml +1 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/.knott/schemas/note.yaml +4 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/schema-unknown-key/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/unknown-relation-target-type/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/unknown-relation-target-type/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/unknown-relation-target-type/.knott/schemas/review.yaml +4 -0
- knott-0.1.0/tests/fixtures/unknown-relation-target-type/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/unknown-relation-target-type/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/unknown-type/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/unknown-type/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/unknown-type/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/unknown-type/notes/mystery.md +4 -0
- knott-0.1.0/tests/fixtures/unknown-type/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/valid-vault/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/valid-vault/.knott/schemas/feedback.yaml +17 -0
- knott-0.1.0/tests/fixtures/valid-vault/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/valid-vault/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/valid-vault/.obsidian/ignored.md +4 -0
- knott-0.1.0/tests/fixtures/valid-vault/feedback/episode-42-review.md +11 -0
- knott-0.1.0/tests/fixtures/valid-vault/notes/plain-note.md +3 -0
- knott-0.1.0/tests/fixtures/valid-vault/notes/readme.txt +1 -0
- knott-0.1.0/tests/fixtures/valid-vault/notes/untyped-note.md +4 -0
- knott-0.1.0/tests/fixtures/valid-vault/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/valid-vault/transcripts/episode-42.md +11 -0
- knott-0.1.0/tests/fixtures/wrong-attribute-type/.knott/schemas/record.yaml +14 -0
- knott-0.1.0/tests/fixtures/wrong-attribute-type/bool-as-int.md +4 -0
- knott-0.1.0/tests/fixtures/wrong-attribute-type/datetime-as-date.md +4 -0
- knott-0.1.0/tests/fixtures/wrong-attribute-type/good.md +9 -0
- knott-0.1.0/tests/fixtures/wrong-attribute-type/misc.md +9 -0
- knott-0.1.0/tests/fixtures/wrong-attribute-type/unquoted-no.md +4 -0
- knott-0.1.0/tests/fixtures/wrong-attribute-type/yaml11.md +5 -0
- knott-0.1.0/tests/fixtures/wrong-relation-target-type/.knott/config.yaml +1 -0
- knott-0.1.0/tests/fixtures/wrong-relation-target-type/.knott/schemas/feedback.yaml +1 -0
- knott-0.1.0/tests/fixtures/wrong-relation-target-type/.knott/schemas/podcast/transcript.yaml +17 -0
- knott-0.1.0/tests/fixtures/wrong-relation-target-type/.knott/schemas/script.yaml +9 -0
- knott-0.1.0/tests/fixtures/wrong-relation-target-type/scripts/episode-42.md +8 -0
- knott-0.1.0/tests/fixtures/wrong-relation-target-type/scripts/foo.md +4 -0
- knott-0.1.0/tests/fixtures/wrong-relation-target-type/transcripts/foo.md +5 -0
- knott-0.1.0/tests/test_api.py +55 -0
- knott-0.1.0/tests/test_attributes.py +102 -0
- knott-0.1.0/tests/test_cli.py +249 -0
- knott-0.1.0/tests/test_entities.py +159 -0
- knott-0.1.0/tests/test_relations.py +132 -0
- knott-0.1.0/tests/test_schemas.py +92 -0
- knott-0.1.0/uv.lock +605 -0
knott-0.1.0/.gitignore
ADDED
knott-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ihar Nestsiarenia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
knott-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: knott
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A local, file-first knowledge layer for AI agents: typed Markdown entities, schemas, and semantic relations.
|
|
5
|
+
Project-URL: Homepage, https://github.com/nesterione/knott
|
|
6
|
+
Project-URL: Repository, https://github.com/nesterione/knott
|
|
7
|
+
Project-URL: Issues, https://github.com/nesterione/knott/issues
|
|
8
|
+
Author: Ihar Nestsiarenia
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-agents,frontmatter,knowledge-base,markdown,obsidian,schema
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Requires-Dist: pydantic>=2
|
|
23
|
+
Requires-Dist: pyyaml>=6
|
|
24
|
+
Requires-Dist: typer>=0.12
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# knott
|
|
28
|
+
|
|
29
|
+
A local, file-first knowledge layer for AI agents.
|
|
30
|
+
|
|
31
|
+
Markdown files are the source of truth. Knott adds structure (typed entities), semantics (relations between them), and validation, without turning your notes into an opaque database. A Knott vault stays useful without Knott: browse it in a file manager, read it in any editor, open it in Obsidian, diff it in Git.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
uvx knott --help # run without installing
|
|
37
|
+
uv add knott # or add it to a project
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Requires Python 3.12+.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
mkdir my-vault && knott init my-vault
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Define a type in `my-vault/.knott/schemas/script.yaml`:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
type: script
|
|
52
|
+
description: A script for a recorded episode.
|
|
53
|
+
attributes:
|
|
54
|
+
title:
|
|
55
|
+
type: string
|
|
56
|
+
required: true
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
and one that relates to it, `.knott/schemas/transcript.yaml`:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
type: transcript
|
|
63
|
+
relations:
|
|
64
|
+
derived_from:
|
|
65
|
+
target: script
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Write entities as ordinary Markdown with frontmatter, anywhere in the vault:
|
|
69
|
+
|
|
70
|
+
```markdown
|
|
71
|
+
---
|
|
72
|
+
type: transcript
|
|
73
|
+
title: Episode 42 transcript
|
|
74
|
+
derived_from: "[Episode 42](../scripts/foo.md)"
|
|
75
|
+
---
|
|
76
|
+
# Transcript
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then validate:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
$ knott validate
|
|
83
|
+
✓ 2 schemas
|
|
84
|
+
✓ 2 entities
|
|
85
|
+
✓ 1 relation
|
|
86
|
+
✓ vault is valid
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Commands
|
|
90
|
+
|
|
91
|
+
| Command | Purpose |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `knott init [PATH]` | Create `.knott/schemas/` and `.knott/config.yaml` |
|
|
94
|
+
| `knott validate [PATH...]` | Check all schemas, plus all entities or those under `PATH` (`--format json` for agents) |
|
|
95
|
+
| `knott types [--verbose]` | List discovered types |
|
|
96
|
+
| `knott version` | Print the installed version |
|
|
97
|
+
|
|
98
|
+
Exit codes: `0` valid, `1` validation issues, `2` usage or configuration error.
|
|
99
|
+
|
|
100
|
+
## Schemas
|
|
101
|
+
|
|
102
|
+
Schemas live in `.knott/schemas/**/*.yaml`, one type per file. Attribute types: `string`, `integer`, `number`, `boolean`, `date`, `datetime`. Typing is strict: an unquoted `no` is a boolean, not a string. Relations name a `target` type and are stored only on the source entity.
|
|
103
|
+
|
|
104
|
+
## Relations
|
|
105
|
+
|
|
106
|
+
A relation value is a relative path or a quoted Markdown link, or a list of them, resolved relative to the containing file:
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
derived_from: ../scripts/episode-42.md
|
|
110
|
+
derived_from: "[Episode 42 script](../scripts/episode-42.md)"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Wikilinks, URLs, `#fragments`, and absolute paths are rejected. Matching is case-sensitive on every OS.
|
|
114
|
+
|
|
115
|
+
### Obsidian
|
|
116
|
+
|
|
117
|
+
Markdown links in properties are clickable in Obsidian 1.11+ and are updated on rename. Use these settings:
|
|
118
|
+
|
|
119
|
+
- Files & links → *New link format*: **Relative path to file**
|
|
120
|
+
- *Use [[Wikilinks]]*: **off**
|
|
121
|
+
|
|
122
|
+
## Python API
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from knott import Knott
|
|
126
|
+
|
|
127
|
+
vault = Knott.open(".") # walks up to the vault root
|
|
128
|
+
result = vault.validate() # or vault.validate(["transcripts/foo.md"])
|
|
129
|
+
result.ok, result.issues, result.stats
|
|
130
|
+
vault.types() # ["script", "transcript"]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Validation problems come back as data; only usage errors raise (`KnottError` subclasses).
|
|
134
|
+
|
|
135
|
+
## For agents
|
|
136
|
+
|
|
137
|
+
See [`skills/knott/SKILL.md`](skills/knott/SKILL.md), an Agent Skill describing how to read schemas, write entities and relations, and validate.
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
uv sync
|
|
143
|
+
uv run pytest
|
|
144
|
+
uv run ruff check src tests
|
|
145
|
+
uv run mypy
|
|
146
|
+
```
|
knott-0.1.0/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# knott
|
|
2
|
+
|
|
3
|
+
A local, file-first knowledge layer for AI agents.
|
|
4
|
+
|
|
5
|
+
Markdown files are the source of truth. Knott adds structure (typed entities), semantics (relations between them), and validation, without turning your notes into an opaque database. A Knott vault stays useful without Knott: browse it in a file manager, read it in any editor, open it in Obsidian, diff it in Git.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
uvx knott --help # run without installing
|
|
11
|
+
uv add knott # or add it to a project
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Requires Python 3.12+.
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
mkdir my-vault && knott init my-vault
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Define a type in `my-vault/.knott/schemas/script.yaml`:
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
type: script
|
|
26
|
+
description: A script for a recorded episode.
|
|
27
|
+
attributes:
|
|
28
|
+
title:
|
|
29
|
+
type: string
|
|
30
|
+
required: true
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
and one that relates to it, `.knott/schemas/transcript.yaml`:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
type: transcript
|
|
37
|
+
relations:
|
|
38
|
+
derived_from:
|
|
39
|
+
target: script
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Write entities as ordinary Markdown with frontmatter, anywhere in the vault:
|
|
43
|
+
|
|
44
|
+
```markdown
|
|
45
|
+
---
|
|
46
|
+
type: transcript
|
|
47
|
+
title: Episode 42 transcript
|
|
48
|
+
derived_from: "[Episode 42](../scripts/foo.md)"
|
|
49
|
+
---
|
|
50
|
+
# Transcript
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Then validate:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
$ knott validate
|
|
57
|
+
✓ 2 schemas
|
|
58
|
+
✓ 2 entities
|
|
59
|
+
✓ 1 relation
|
|
60
|
+
✓ vault is valid
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Commands
|
|
64
|
+
|
|
65
|
+
| Command | Purpose |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `knott init [PATH]` | Create `.knott/schemas/` and `.knott/config.yaml` |
|
|
68
|
+
| `knott validate [PATH...]` | Check all schemas, plus all entities or those under `PATH` (`--format json` for agents) |
|
|
69
|
+
| `knott types [--verbose]` | List discovered types |
|
|
70
|
+
| `knott version` | Print the installed version |
|
|
71
|
+
|
|
72
|
+
Exit codes: `0` valid, `1` validation issues, `2` usage or configuration error.
|
|
73
|
+
|
|
74
|
+
## Schemas
|
|
75
|
+
|
|
76
|
+
Schemas live in `.knott/schemas/**/*.yaml`, one type per file. Attribute types: `string`, `integer`, `number`, `boolean`, `date`, `datetime`. Typing is strict: an unquoted `no` is a boolean, not a string. Relations name a `target` type and are stored only on the source entity.
|
|
77
|
+
|
|
78
|
+
## Relations
|
|
79
|
+
|
|
80
|
+
A relation value is a relative path or a quoted Markdown link, or a list of them, resolved relative to the containing file:
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
derived_from: ../scripts/episode-42.md
|
|
84
|
+
derived_from: "[Episode 42 script](../scripts/episode-42.md)"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Wikilinks, URLs, `#fragments`, and absolute paths are rejected. Matching is case-sensitive on every OS.
|
|
88
|
+
|
|
89
|
+
### Obsidian
|
|
90
|
+
|
|
91
|
+
Markdown links in properties are clickable in Obsidian 1.11+ and are updated on rename. Use these settings:
|
|
92
|
+
|
|
93
|
+
- Files & links → *New link format*: **Relative path to file**
|
|
94
|
+
- *Use [[Wikilinks]]*: **off**
|
|
95
|
+
|
|
96
|
+
## Python API
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from knott import Knott
|
|
100
|
+
|
|
101
|
+
vault = Knott.open(".") # walks up to the vault root
|
|
102
|
+
result = vault.validate() # or vault.validate(["transcripts/foo.md"])
|
|
103
|
+
result.ok, result.issues, result.stats
|
|
104
|
+
vault.types() # ["script", "transcript"]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Validation problems come back as data; only usage errors raise (`KnottError` subclasses).
|
|
108
|
+
|
|
109
|
+
## For agents
|
|
110
|
+
|
|
111
|
+
See [`skills/knott/SKILL.md`](skills/knott/SKILL.md), an Agent Skill describing how to read schemas, write entities and relations, and validate.
|
|
112
|
+
|
|
113
|
+
## Development
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
uv sync
|
|
117
|
+
uv run pytest
|
|
118
|
+
uv run ruff check src tests
|
|
119
|
+
uv run mypy
|
|
120
|
+
```
|
knott-0.1.0/RELEASING.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
Releases go to PyPI from GitHub Actions (`.github/workflows/release.yml`) using
|
|
4
|
+
[trusted publishing](https://docs.pypi.org/trusted-publishers/). No API token is stored anywhere.
|
|
5
|
+
|
|
6
|
+
## One-time setup
|
|
7
|
+
|
|
8
|
+
1. Create an account on [pypi.org](https://pypi.org) and enable 2FA.
|
|
9
|
+
2. Add a pending trusted publisher at <https://pypi.org/manage/account/publishing/>:
|
|
10
|
+
- PyPI project name: `knott`
|
|
11
|
+
- Owner: `nesterione`, repository: `knott`
|
|
12
|
+
- Workflow name: `release.yml`
|
|
13
|
+
- Environment name: `pypi`
|
|
14
|
+
3. In the GitHub repo, open Settings → Environments and create an environment named `pypi`.
|
|
15
|
+
Optionally add yourself as a required reviewer so each publish waits for approval.
|
|
16
|
+
|
|
17
|
+
## Each release
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
uv version --bump patch # or minor / major; updates pyproject.toml and uv.lock
|
|
21
|
+
git commit -am "Release v$(uv version --short)"
|
|
22
|
+
git tag "v$(uv version --short)"
|
|
23
|
+
git push origin main --tags
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The workflow runs CI, checks that the tag matches the version in `pyproject.toml`, builds,
|
|
27
|
+
smoke-tests the wheel with `uvx`, and publishes. A new version shows up for `uvx knott`
|
|
28
|
+
within a few minutes. Users with a cached copy can run `uvx knott@latest` to pick it up.
|