org-knowledge-layer 0.3.0__tar.gz → 0.4.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.
- org_knowledge_layer-0.4.0/.coverage +0 -0
- org_knowledge_layer-0.4.0/.github/dependabot.yml +32 -0
- org_knowledge_layer-0.4.0/.github/workflows/ci.yml +88 -0
- org_knowledge_layer-0.4.0/.github/workflows/publish.yml +90 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/AGENTS.md +3 -2
- org_knowledge_layer-0.4.0/CHANGELOG.md +118 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/CLAUDE.md +3 -2
- org_knowledge_layer-0.3.0/README.md → org_knowledge_layer-0.4.0/PKG-INFO +101 -1
- org_knowledge_layer-0.3.0/PKG-INFO → org_knowledge_layer-0.4.0/README.md +67 -33
- org_knowledge_layer-0.4.0/ci/check-diagram-figures.sh +82 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/decisions/2026-07-21-subject-tags-controlled-vocabulary.md +7 -0
- org_knowledge_layer-0.4.0/docs/okl-how-it-works.excalidraw +3053 -0
- org_knowledge_layer-0.4.0/docs/okl-how-it-works.svg +2 -0
- org_knowledge_layer-0.4.0/docs/okl-sixth-surface.excalidraw +3819 -0
- org_knowledge_layer-0.4.0/docs/okl-sixth-surface.svg +2 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/REPORT.md +68 -0
- org_knowledge_layer-0.4.0/evals/results/ab-20260901-1238.json +441 -0
- {org_knowledge_layer-0.3.0/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-doc-orphans.sh +5 -1
- org_knowledge_layer-0.4.0/pyproject.toml +118 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/bootstrap.py +6 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/cli.py +124 -15
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/client.py +68 -18
- org_knowledge_layer-0.4.0/src/okl/core.py +524 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/drift.py +18 -3
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/mcp_server.py +6 -4
- org_knowledge_layer-0.4.0/src/okl/scaffold/claude/commands/seed-from-docs.md +123 -0
- org_knowledge_layer-0.4.0/src/okl/scaffold/gates/check-canon-size.sh +11 -0
- org_knowledge_layer-0.4.0/src/okl/scaffold/gates/check-diagram-pairs.sh +39 -0
- org_knowledge_layer-0.4.0/src/okl/scaffold/gates/check-doc-orphans.sh +23 -0
- org_knowledge_layer-0.4.0/src/okl/scaffold/gates/check-links.sh +41 -0
- org_knowledge_layer-0.4.0/src/okl/scaffold/gates/check-retractions.sh +22 -0
- org_knowledge_layer-0.4.0/src/okl/scaffold/gates/check-tombstones.sh +22 -0
- org_knowledge_layer-0.4.0/src/okl/scaffold/gates/run-gates.sh +33 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold_cmd.py +21 -7
- org_knowledge_layer-0.4.0/src/okl/seed.py +119 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/service.py +14 -3
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/store.py +109 -17
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/tests/test_okl.py +358 -1
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/tests/test_scaffold.py +41 -2
- org_knowledge_layer-0.3.0/.claude/settings.local.json +0 -168
- org_knowledge_layer-0.3.0/.github/workflows/ci.yml +0 -22
- org_knowledge_layer-0.3.0/CHANGELOG.md +0 -58
- org_knowledge_layer-0.3.0/docs/okl-sixth-surface.excalidraw +0 -3819
- org_knowledge_layer-0.3.0/docs/okl-sixth-surface.svg +0 -2
- org_knowledge_layer-0.3.0/pyproject.toml +0 -49
- org_knowledge_layer-0.3.0/src/okl/core.py +0 -301
- org_knowledge_layer-0.3.0/src/okl/seed.py +0 -55
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.claude/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.claude/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.claude/settings.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.github/pull_request_template.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.github/workflows/okl-verify.yml +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/.gitignore +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/CONTRIBUTING.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/LICENSE +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/SECURITY.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/ci/okl-verify.yml +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/DEPLOY.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/ab-results-chart.png +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/ab-results-chart.svg +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/decisions/2026-07-17-flat-retrieval-until-scale.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/posts/01-memory-that-outlives-the-run.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/posts/02-dont-let-a-step-grade-itself.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/docs/posts/03-enforcement-or-good-intentions.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/README.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/ab_harness.py +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/ab-20260829-2300.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/ab-20260829-2315.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/ab-20260830-0003.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/ab-20260830-0148.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/ab-20260901-0133.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/README.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/briefed-userpromptsubmit-lint.yml +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/control-lint.yml +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/hook.log +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/service-record-500.log +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/session-briefed-pretooluse.txt +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/session-briefed-userpromptsubmit.txt +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/session-control.txt +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/evals/tasks.jsonl +0 -0
- {org_knowledge_layer-0.3.0/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-canon-size.sh +0 -0
- {org_knowledge_layer-0.3.0/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-diagram-pairs.sh +0 -0
- {org_knowledge_layer-0.3.0/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-links.sh +0 -0
- {org_knowledge_layer-0.3.0/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-retractions.sh +0 -0
- {org_knowledge_layer-0.3.0/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-tombstones.sh +0 -0
- {org_knowledge_layer-0.3.0/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/run-gates.sh +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/dotnet-canon.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/dotnet-decisions.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/dotnet-defects.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/dotnet-review-surfaces.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/frontend-canon.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/geospatial-deeptime-defects.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/geospatial-defects.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/geospatial-enforcement-defects.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/geospatial-eval-defects.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/rag-defects.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/seed/react-defects.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/__init__.py +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/__main__.py +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/MANIFEST.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/ci/method-gates.yml +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/ci/okl-verify.yml +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/agents/architecture-reviewer.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/commands/check-rules.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/commands/feature-spec.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/commands/seed-from-codebase.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/rules/example-area.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/skills/RECOMMENDED-COMPANIONS.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/skills/encoding-loop/SKILL.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/skills/verify-before-claiming/SKILL.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/evals/README.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/evals/cases.jsonl +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/evals/run_evals.py +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/hooks/hooks.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/plugin/plugin.json +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/README.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/architecture.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/messaging.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/performance-and-data.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/security.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/geospatial/README.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/geospatial/rules/geospatial-ml.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/README.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/rules/fastapi-backend.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/rules/project-structure.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/rules/rag-pipeline.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/react/README.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/react/rules/frontend.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/registries/RETRACTIONS.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/registries/tombstones.txt +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/root/CLAUDE.md +0 -0
- {org_knowledge_layer-0.3.0 → org_knowledge_layer-0.4.0}/src/okl/scaffold/root/METHOD.md +0 -0
|
Binary file
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Dependabot.
|
|
2
|
+
#
|
|
3
|
+
# This exists because of the SHA pinning, not despite it. Pinning actions to a commit
|
|
4
|
+
# closes the "a mutable tag moved under me" hole and opens a quieter one: the pin never
|
|
5
|
+
# updates, so a security fix in an action never arrives. Pinning without an update path
|
|
6
|
+
# is how a repo ends up on a two-year-old checkout action and calls it hardening.
|
|
7
|
+
# Dependabot rewrites the SHA and the trailing `# v5` comment together.
|
|
8
|
+
version: 2
|
|
9
|
+
|
|
10
|
+
updates:
|
|
11
|
+
- package-ecosystem: github-actions
|
|
12
|
+
directory: "/"
|
|
13
|
+
schedule:
|
|
14
|
+
interval: weekly
|
|
15
|
+
labels: ["dependencies", "ci"]
|
|
16
|
+
commit-message:
|
|
17
|
+
prefix: "ci"
|
|
18
|
+
|
|
19
|
+
- package-ecosystem: pip
|
|
20
|
+
directory: "/"
|
|
21
|
+
schedule:
|
|
22
|
+
interval: weekly
|
|
23
|
+
labels: ["dependencies"]
|
|
24
|
+
commit-message:
|
|
25
|
+
prefix: "deps"
|
|
26
|
+
# The gating tools are pinned exactly on purpose (a range lets a new release
|
|
27
|
+
# retro-fail a branch that changed nothing). Dependabot is the intended way to move
|
|
28
|
+
# those pins: a PR that runs the full suite against the new version before it lands,
|
|
29
|
+
# rather than a range that upgrades silently mid-branch.
|
|
30
|
+
groups:
|
|
31
|
+
dev-tooling:
|
|
32
|
+
patterns: ["pytest", "ruff", "mypy"]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Repo CI — lints, type-checks and tests okl itself. (okl-verify.yml is different: it
|
|
2
|
+
# demonstrates the product's own drift/method gates, the workflow consumers copy.)
|
|
3
|
+
#
|
|
4
|
+
# Hardened per the org rule this repo's own store carries ("CI workflow baseline:
|
|
5
|
+
# pipefail, no persisted credentials, least-privilege permissions, concurrency groups —
|
|
6
|
+
# pin actions"). It satisfied none of the five until this commit, which is the rule's own
|
|
7
|
+
# symptom: an enforcement surface nothing triggers runs never.
|
|
8
|
+
name: ci
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [ "main" ]
|
|
13
|
+
pull_request:
|
|
14
|
+
branches: [ "main" ]
|
|
15
|
+
|
|
16
|
+
# Least privilege: this job reads code and reports status. It never pushes.
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
# One run per ref. A superseded push should stop burning minutes on a result nobody
|
|
21
|
+
# will read.
|
|
22
|
+
concurrency:
|
|
23
|
+
group: ci-${{ github.ref }}
|
|
24
|
+
cancel-in-progress: true
|
|
25
|
+
|
|
26
|
+
defaults:
|
|
27
|
+
run:
|
|
28
|
+
# Without pipefail a run block continues past a failed segment of a pipeline, so a
|
|
29
|
+
# green step can hide a red command.
|
|
30
|
+
shell: bash -euo pipefail {0}
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
lint-and-test:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
# Actions pinned to a commit SHA, not a tag: a tag is mutable, so `@v5` is an
|
|
37
|
+
# unpinned dependency with write access to the runner.
|
|
38
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
39
|
+
with:
|
|
40
|
+
# The diagram gate reads committed history (git show HEAD:...), not the
|
|
41
|
+
# checkout tree, so it needs more than the default shallow fetch.
|
|
42
|
+
fetch-depth: 0
|
|
43
|
+
# This job never pushes; leaving the token in .git/config lets any later step
|
|
44
|
+
# (or a compromised dependency) use it.
|
|
45
|
+
persist-credentials: false
|
|
46
|
+
|
|
47
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.12"
|
|
50
|
+
|
|
51
|
+
- name: Install (dev extras)
|
|
52
|
+
run: pip install -e ".[dev]"
|
|
53
|
+
|
|
54
|
+
- name: Lint — ruff (config in pyproject.toml)
|
|
55
|
+
run: ruff check .
|
|
56
|
+
|
|
57
|
+
- name: Types — mypy
|
|
58
|
+
run: mypy src/okl
|
|
59
|
+
|
|
60
|
+
- name: Tests (with the coverage ratchet)
|
|
61
|
+
run: pytest -q --cov=okl
|
|
62
|
+
|
|
63
|
+
- name: Diagram figures trace to committed receipts
|
|
64
|
+
run: ./ci/check-diagram-figures.sh
|
|
65
|
+
|
|
66
|
+
# The content audits okl ships to consumers, run against okl itself. They were
|
|
67
|
+
# shipped for weeks without this repo running any of them — the "enforcement
|
|
68
|
+
# surface nothing triggers" failure, one level up: a gate whose author has never
|
|
69
|
+
# run it on their own tree.
|
|
70
|
+
- name: Method gates (links, doc orphans, diagram pairs, tombstones, canon size)
|
|
71
|
+
run: bash gates/run-gates.sh
|
|
72
|
+
|
|
73
|
+
# Secret scan over the FULL history, not the working tree. okl writes a bearer
|
|
74
|
+
# token into .okl/config.json, and the .gitignore it now drops there is the only
|
|
75
|
+
# thing between that and a commit — this is the check for when that fails.
|
|
76
|
+
#
|
|
77
|
+
# The upstream gitleaks-action is deliberately not used: it requires a paid licence
|
|
78
|
+
# key for organization-owned repositories, so it would break for anyone who forks
|
|
79
|
+
# this into an org. The binary has no such condition, and pinning the release keeps
|
|
80
|
+
# a new detection rule from retro-failing a branch that changed nothing.
|
|
81
|
+
- name: Secret scan — gitleaks
|
|
82
|
+
env:
|
|
83
|
+
GITLEAKS_VERSION: "8.30.1"
|
|
84
|
+
run: |
|
|
85
|
+
curl -sSfL -o /tmp/gitleaks.tar.gz \
|
|
86
|
+
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
|
|
87
|
+
tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks
|
|
88
|
+
/tmp/gitleaks git . --no-banner --redact --exit-code 1
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Release to PyPI on a version tag, using Trusted Publishing.
|
|
2
|
+
#
|
|
3
|
+
# There is no API token anywhere in this workflow, and none stored in the repository.
|
|
4
|
+
# PyPI accepts the upload because GitHub vouches for it: the publish job mints a
|
|
5
|
+
# short-lived OIDC token that names this repository, this workflow file and this
|
|
6
|
+
# environment, and PyPI checks that against the trusted publisher it was told to expect.
|
|
7
|
+
# A leaked repository secret cannot publish okl because there is no such secret.
|
|
8
|
+
#
|
|
9
|
+
# ONE-TIME SETUP ON PYPI (this workflow does nothing until it is done):
|
|
10
|
+
# pypi.org → the org-knowledge-layer project → Publishing → Add a pending publisher
|
|
11
|
+
# Owner: emeraldleaf
|
|
12
|
+
# Repository: okl
|
|
13
|
+
# Workflow name: publish.yml
|
|
14
|
+
# Environment name: pypi
|
|
15
|
+
# Then create the `pypi` environment under repo Settings → Environments. Adding a
|
|
16
|
+
# required reviewer there makes every release a deliberate, approved act.
|
|
17
|
+
name: publish
|
|
18
|
+
|
|
19
|
+
on:
|
|
20
|
+
push:
|
|
21
|
+
tags: ["v*"]
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
build:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
31
|
+
with:
|
|
32
|
+
persist-credentials: false
|
|
33
|
+
|
|
34
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
35
|
+
with:
|
|
36
|
+
python-version: "3.12"
|
|
37
|
+
|
|
38
|
+
# The tag is the release's claim about what version this is; pyproject.toml is the
|
|
39
|
+
# version that actually gets uploaded. When they disagree, PyPI takes pyproject's
|
|
40
|
+
# answer and the tag becomes a lie that is permanent — you cannot reuse a version
|
|
41
|
+
# number on PyPI, so the mistake is not fixable, only worked around.
|
|
42
|
+
- name: Tag must match the version in pyproject.toml
|
|
43
|
+
run: |
|
|
44
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
45
|
+
pkg="$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")"
|
|
46
|
+
echo "tag=$tag pyproject=$pkg"
|
|
47
|
+
if [ "$tag" != "$pkg" ]; then
|
|
48
|
+
echo "::error::tag v$tag does not match pyproject version $pkg"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
- name: Build
|
|
53
|
+
run: |
|
|
54
|
+
python -m pip install --upgrade build twine
|
|
55
|
+
python -m build
|
|
56
|
+
# `twine check` catches a malformed long_description, which PyPI rejects only
|
|
57
|
+
# after the upload has otherwise succeeded.
|
|
58
|
+
python -m twine check dist/*
|
|
59
|
+
|
|
60
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
61
|
+
with:
|
|
62
|
+
name: dist
|
|
63
|
+
path: dist/
|
|
64
|
+
|
|
65
|
+
publish:
|
|
66
|
+
needs: build
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
# A named environment is what the PyPI trusted publisher is bound to, and it is where
|
|
69
|
+
# a required-reviewer rule can gate the release.
|
|
70
|
+
environment:
|
|
71
|
+
name: pypi
|
|
72
|
+
url: https://pypi.org/project/org-knowledge-layer/
|
|
73
|
+
permissions:
|
|
74
|
+
id-token: write # mint the OIDC token PyPI verifies
|
|
75
|
+
attestations: write # sign the artifacts
|
|
76
|
+
contents: read
|
|
77
|
+
steps:
|
|
78
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
79
|
+
with:
|
|
80
|
+
name: dist
|
|
81
|
+
path: dist/
|
|
82
|
+
|
|
83
|
+
# Provenance: a signed statement that these exact files were built by this workflow
|
|
84
|
+
# from this commit. It is what lets someone verify the wheel on PyPI came from the
|
|
85
|
+
# source they are reading, rather than trusting that it did.
|
|
86
|
+
- uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
|
|
87
|
+
with:
|
|
88
|
+
subject-path: "dist/*"
|
|
89
|
+
|
|
90
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
@@ -31,8 +31,9 @@ okl drift # rules whose governed source changed after v
|
|
|
31
31
|
## Rules that are enforced (and why)
|
|
32
32
|
|
|
33
33
|
- **Mirror files are byte-identical, test-enforced**: `ci/okl-verify.yml` ==
|
|
34
|
-
`.github/workflows/okl-verify.yml` == `src/okl/scaffold/ci/okl-verify.yml`,
|
|
35
|
-
`hooks/*.sh` == `src/okl/scaffold/hooks/*.sh
|
|
34
|
+
`.github/workflows/okl-verify.yml` == `src/okl/scaffold/ci/okl-verify.yml`,
|
|
35
|
+
`hooks/*.sh` == `src/okl/scaffold/hooks/*.sh`, and
|
|
36
|
+
`gates/*.sh` == `src/okl/scaffold/gates/*.sh`. The scaffold copies are what consumers
|
|
36
37
|
receive; the repo copies are the dogfood. Edit ONE, copy to the others in the same
|
|
37
38
|
change — `tests/test_scaffold.py::test_mirror_files_identical` fails otherwise.
|
|
38
39
|
- **ruff `E702` is ignored deliberately** (semicolon one-liners): the tests use a
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Behaviour changes worth reading before upgrading
|
|
6
|
+
|
|
7
|
+
- **Stack tags now filter exclusively.** A record naming a stack (`dotnet`, `react`,
|
|
8
|
+
`geospatial`, `python`, `python-rag`) is only shown to a repo that declared that stack
|
|
9
|
+
in its `interests`. Previously any shared tag let it through, so a rule tagged
|
|
10
|
+
`dotnet,method` reached every repo interested in `method` — a subject 75 records carry.
|
|
11
|
+
**If you declare `interests`, expect fewer records after upgrading.** That is the point,
|
|
12
|
+
but it is a change in what your briefings contain. Repos that declare no interests are
|
|
13
|
+
unaffected, and untagged records still always pass.
|
|
14
|
+
- **`symptom` and `fix` are now searchable.** They were not, which meant a record written
|
|
15
|
+
the way the docs tell you to write it — short title, the distinguishing words in the
|
|
16
|
+
symptom — could not be retrieved at all. Existing stores rebuild their index on first
|
|
17
|
+
open; you do not need to re-record anything.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **`okl dedup`** reports near-duplicate records for review. Lexical and explainable:
|
|
22
|
+
per-field weighted Jaccard over title, symptom and fix, IDF-weighted from your own
|
|
23
|
+
corpus. It never merges or drops anything — the measured score bands for true
|
|
24
|
+
paraphrases and for distinct-but-related records overlap, so the call is a person's.
|
|
25
|
+
The same check runs as an advisory when importing an agent-proposed pack.
|
|
26
|
+
- **`/seed-from-docs`** mines the specs, ADRs and rules files you already wrote into typed
|
|
27
|
+
records. Built around one distinction: a record is a standing instruction that outlives
|
|
28
|
+
the work item it came from, so "deep offsets use keyset pagination" belongs and "add
|
|
29
|
+
pagination to /orders this sprint" does not.
|
|
30
|
+
- A pack declaring `_proposed_by` is refused unless every node carries a `found_by`
|
|
31
|
+
citation, so the rule the seeding commands state is enforced at import rather than
|
|
32
|
+
remembered by a reviewer.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- `Client._remote_url` validates the URL scheme once. A `service_url` from config could
|
|
37
|
+
name `file://`, turning a remote read into a local file read.
|
|
38
|
+
- `OKLUnreachable` is now `OKLUnreachableError`, with the old name kept as an alias so
|
|
39
|
+
existing `except` clauses still work.
|
|
40
|
+
- Drift timestamps are timezone-aware; `utcfromtimestamp` is deprecated from Python 3.12
|
|
41
|
+
and returned a naive datetime that read as local time when compared across machines.
|
|
42
|
+
|
|
43
|
+
### Internal
|
|
44
|
+
|
|
45
|
+
- `_Backend` is a `typing.Protocol` whose docstring states the behavioural contract, with
|
|
46
|
+
one conformance test both backends run — the defect it guards (Postgres satisfying every
|
|
47
|
+
signature while running an unranked match) was invisible to signatures alone.
|
|
48
|
+
- mypy, and ruff widened from 6 rule families to 15 including security and complexity,
|
|
49
|
+
both wired into CI alongside a secret scan, the method gates and a coverage floor.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## 0.3.1
|
|
53
|
+
|
|
54
|
+
### Security
|
|
55
|
+
|
|
56
|
+
- **Setting `OKL_TOKEN` now also removes `/openapi.json`, `/docs` and `/redoc`.** They
|
|
57
|
+
were left serving 200 to anonymous callers by the 0.3.0 work that closed every data
|
|
58
|
+
route, because FastAPI mounts them itself — they are not handlers, so the per-handler
|
|
59
|
+
auth sweep could not reach them. They leak no records, but they publish the endpoint
|
|
60
|
+
list, every schema, and which routes want a credential. With no token set the
|
|
61
|
+
interactive docs remain available, since that case is a developer's laptop.
|
|
62
|
+
|
|
63
|
+
## 0.3.0
|
|
64
|
+
|
|
65
|
+
Everything here came from running three things that had been written but never
|
|
66
|
+
executed: the MCP server, the Postgres backend, and a deployment.
|
|
67
|
+
|
|
68
|
+
### Security
|
|
69
|
+
|
|
70
|
+
- **The service token now covers reads.** Previously `OKL_TOKEN` gated writes only, so
|
|
71
|
+
an unauthenticated `GET /nodes` returned the entire store — every recorded defect,
|
|
72
|
+
retired identifier and architecture decision. Every route now requires the token when
|
|
73
|
+
it is set, except `/health`, which is left open for schedulers and returns no record
|
|
74
|
+
content.
|
|
75
|
+
- **`okl connect --token` no longer commits your secret.** The token is stored in
|
|
76
|
+
cleartext in `.okl/config.json`, and a comment claimed the directory was gitignored
|
|
77
|
+
while nothing wrote a `.gitignore`. `okl init` and `okl connect` now write
|
|
78
|
+
`.okl/.gitignore`.
|
|
79
|
+
- **A rejected check no longer reports success.** A 401 surfaced as `ValueError` rather
|
|
80
|
+
than `OKLUnreachable`, so an unauthorized `okl check` exited 0 with a traceback — which
|
|
81
|
+
a pre-task hook reads as "no rules apply". It now fails closed with exit 2, as does
|
|
82
|
+
every other command, via a backstop in `main()`.
|
|
83
|
+
|
|
84
|
+
**Breaking:** if you run a service with `OKL_TOKEN` set, clients must upgrade too.
|
|
85
|
+
Clients older than 0.3.0 send no credential on `GET` requests and will get 401s from
|
|
86
|
+
`okl drift` and the recurrence metric. Upgrade the service and its clients together, or
|
|
87
|
+
unset `OKL_TOKEN` during the rollover.
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
|
|
91
|
+
- `uvicorn okl.service:app` served a module-level `None`: the process started, bound the
|
|
92
|
+
port, passed a port-liveness check and returned 500 to every request. The app is now
|
|
93
|
+
built lazily in a module `__getattr__`, so the standard ASGI entrypoint works while
|
|
94
|
+
importing the module still does not touch the database.
|
|
95
|
+
- The MCP server could not start under `mcp` 2.x, which renamed `FastMCP` to
|
|
96
|
+
`MCPServer` — and the error handler told you to install the extra you had just
|
|
97
|
+
installed. Both names are tried, and the real import error is reported.
|
|
98
|
+
- Every MCP `okl_record` call with `scope="repo"` failed. The repo default used
|
|
99
|
+
`setdefault`, which cannot replace an explicit `None`, and the MCP tools pass every
|
|
100
|
+
field explicitly.
|
|
101
|
+
- MCP validation errors raised as an opaque "Error executing tool". They now return the
|
|
102
|
+
complaint, so an agent that invents a tag is told the vocabulary.
|
|
103
|
+
|
|
104
|
+
### Added
|
|
105
|
+
|
|
106
|
+
- `docs/DEPLOY.md`: the shared-service deployment path, including a throwaway Postgres
|
|
107
|
+
for trying it locally and what each failure mode looks like. Every command in it was
|
|
108
|
+
run against a real Postgres and a real service.
|
|
109
|
+
- Tests covering the live MCP server, the ASGI entrypoint, service auth on reads, the
|
|
110
|
+
fail-closed 401, and the config `.gitignore`.
|
|
111
|
+
- The Postgres/SQLite parity test now runs in a scratch schema it creates and drops. The
|
|
112
|
+
first version opened with `DELETE FROM node` against whatever `OKL_TEST_POSTGRES_URL`
|
|
113
|
+
pointed at, which would have destroyed the store of anyone who set it to their real
|
|
114
|
+
service.
|
|
115
|
+
|
|
116
|
+
## 0.2.0 and earlier
|
|
117
|
+
|
|
118
|
+
See the git history.
|
|
@@ -31,8 +31,9 @@ okl drift # rules whose governed source changed after v
|
|
|
31
31
|
## Rules that are enforced (and why)
|
|
32
32
|
|
|
33
33
|
- **Mirror files are byte-identical, test-enforced**: `ci/okl-verify.yml` ==
|
|
34
|
-
`.github/workflows/okl-verify.yml` == `src/okl/scaffold/ci/okl-verify.yml`,
|
|
35
|
-
`hooks/*.sh` == `src/okl/scaffold/hooks/*.sh
|
|
34
|
+
`.github/workflows/okl-verify.yml` == `src/okl/scaffold/ci/okl-verify.yml`,
|
|
35
|
+
`hooks/*.sh` == `src/okl/scaffold/hooks/*.sh`, and
|
|
36
|
+
`gates/*.sh` == `src/okl/scaffold/gates/*.sh`. The scaffold copies are what consumers
|
|
36
37
|
receive; the repo copies are the dogfood. Edit ONE, copy to the others in the same
|
|
37
38
|
change — `tests/test_scaffold.py::test_mirror_files_identical` fails otherwise.
|
|
38
39
|
- **ruff `E702` is ignored deliberately** (semicolon one-liners): the tests use a
|
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: org-knowledge-layer
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Org Knowledge Layer — an installable sixth surface that carries encoded engineering lessons across repos.
|
|
5
|
+
Author: Joshua Dell
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: agentic-coding,ai-engineering,encoding-loop,knowledge-layer,mcp
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Provides-Extra: all
|
|
11
|
+
Requires-Dist: fastapi>=0.110; extra == 'all'
|
|
12
|
+
Requires-Dist: mcp>=1.2; extra == 'all'
|
|
13
|
+
Requires-Dist: psycopg[binary]>=3.1; extra == 'all'
|
|
14
|
+
Requires-Dist: pydantic>=2; extra == 'all'
|
|
15
|
+
Requires-Dist: uvicorn>=0.29; extra == 'all'
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
18
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
19
|
+
Requires-Dist: mypy==2.3.1; extra == 'dev'
|
|
20
|
+
Requires-Dist: pydantic>=2; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest-cov==7.1.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest==8.4.2; extra == 'dev'
|
|
23
|
+
Requires-Dist: ruff==0.16.5; extra == 'dev'
|
|
24
|
+
Requires-Dist: uvicorn>=0.29; extra == 'dev'
|
|
25
|
+
Provides-Extra: mcp
|
|
26
|
+
Requires-Dist: mcp>=1.2; extra == 'mcp'
|
|
27
|
+
Provides-Extra: postgres
|
|
28
|
+
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
|
|
29
|
+
Provides-Extra: service
|
|
30
|
+
Requires-Dist: fastapi>=0.110; extra == 'service'
|
|
31
|
+
Requires-Dist: pydantic>=2; extra == 'service'
|
|
32
|
+
Requires-Dist: uvicorn>=0.29; extra == 'service'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
1
35
|
# okl — a shared knowledge layer for AI-assisted engineering
|
|
2
36
|
|
|
3
37
|
> A small database of the specific lessons a codebase has learned — the bugs it
|
|
@@ -46,6 +80,17 @@ Two things ship in the package. They are not coequal:
|
|
|
46
80
|
retrieved into an agent's context before a task, and go stale loudly when the code
|
|
47
81
|
they describe moves on. Everything measured in [evals/REPORT.md](evals/REPORT.md)
|
|
48
82
|
measures this.
|
|
83
|
+
|
|
84
|
+
It is worth being precise about what that store fills up with, because "lessons a
|
|
85
|
+
codebase has learned" invites the picture of a bug database. In the 161-record corpus
|
|
86
|
+
in [seed/](seed/) it is mostly not that: **90 Rules, 20 Decisions and 7 Gates against
|
|
87
|
+
34 Defects** — conventions the code follows and trade-offs already settled, not a
|
|
88
|
+
ledger of things that broke. Count it yourself:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
python3 -c "import json,glob,collections; c=collections.Counter(
|
|
92
|
+
n['type'] for f in glob.glob('seed/*.json') for n in json.load(open(f))['nodes']); print(c)"
|
|
93
|
+
```
|
|
49
94
|
- **`okl scaffold`** is a starter kit for the in-repo discipline the store assumes: a
|
|
50
95
|
lean canon file, mechanical gates, registries, a review agent, and an eval harness.
|
|
51
96
|
It is useful on its own and it has never been measured. Use it to get a new repo to
|
|
@@ -163,6 +208,8 @@ with receipts, not a benchmark.
|
|
|
163
208
|
|
|
164
209
|
## How it works
|
|
165
210
|
|
|
211
|
+
<img src="docs/okl-how-it-works.svg" alt="One repo records a lesson; every other repo is briefed on it before its next task. The store is typed, scoped and tagged; every verification stamp carries the check that earned it." width="100%">
|
|
212
|
+
|
|
166
213
|
### The mental model
|
|
167
214
|
|
|
168
215
|
`okl` stores small, typed **notes** and the **links** between them.
|
|
@@ -258,6 +305,59 @@ pip install "org-knowledge-layer[mcp]" # MCP server for Claude Code / Cur
|
|
|
258
305
|
pip install "org-knowledge-layer[all]"
|
|
259
306
|
```
|
|
260
307
|
|
|
308
|
+
## What it costs, and how to turn it down
|
|
309
|
+
|
|
310
|
+
Installing okl is not free. It is worth knowing exactly what you are signing up for
|
|
311
|
+
before you wire it into every prompt, and every number below was measured on this repo's
|
|
312
|
+
own 199-record store rather than estimated.
|
|
313
|
+
|
|
314
|
+
**Per prompt, once the hook is installed:**
|
|
315
|
+
|
|
316
|
+
| | |
|
|
317
|
+
|---|---|
|
|
318
|
+
| Latency | **~0.11s** — one local SQLite query, no network in local mode |
|
|
319
|
+
| Context | **~2,300 tokens** at the default `--limit 12`, down to **~250** at `--format actions --limit 3` |
|
|
320
|
+
|
|
321
|
+
**Per session:** the Stop hook interrupts once at the end to ask what was learned. It
|
|
322
|
+
blocks the first stop only, and answering it is the whole write side of the loop.
|
|
323
|
+
|
|
324
|
+
**In your repo:** `okl init` writes `.okl/` (config, the local database, a `.gitignore`
|
|
325
|
+
covering both) and, if `.claude/` exists, two hook scripts plus their registration. It
|
|
326
|
+
also installs `.github/workflows/okl-verify.yml`, which runs the drift gate on every PR.
|
|
327
|
+
`okl scaffold` is separate and optional — nothing installs it unless you ask.
|
|
328
|
+
|
|
329
|
+
### The knobs, cheapest first
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
okl check --task "..." --format actions # imperatives only, ~60% smaller
|
|
333
|
+
okl check --task "..." --limit 3 # fewer records; the briefing says how many it trimmed
|
|
334
|
+
okl init --interests "python,security" # drop records tagged for stacks you do not use
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
- **`--format actions`** is the single biggest saving and loses the least: you keep every
|
|
338
|
+
"when you see X → do Y" and drop the explanatory prose.
|
|
339
|
+
- **`--limit N`** caps how many records are drawn on. The briefing always reports what it
|
|
340
|
+
trimmed, so a short briefing can never quietly hide a miss.
|
|
341
|
+
- **`interests`** is the one to reach for on a mature shared store. Stack tags filter
|
|
342
|
+
exclusively — declaring `python` means records tagged `dotnet` stay out even when they
|
|
343
|
+
share a subject tag with something you asked for.
|
|
344
|
+
- **Scope records `repo:` rather than `org`** when a lesson is local. Org scope is a claim
|
|
345
|
+
that every project in the organization should see it, and it costs every project's
|
|
346
|
+
budget to be wrong about that.
|
|
347
|
+
|
|
348
|
+
### Turning parts off
|
|
349
|
+
|
|
350
|
+
The hooks are registered in `.claude/settings.json`; delete the entry to stop one firing.
|
|
351
|
+
The pre-task hook is the read side and the Stop hook is the write side, and they are
|
|
352
|
+
independent — running the read without the write is a reasonable way to start.
|
|
353
|
+
|
|
354
|
+
Nothing is load-bearing on the hooks: `okl check` and `okl record` work from the terminal,
|
|
355
|
+
from CI, and through the MCP server whether or not any hook is installed.
|
|
356
|
+
|
|
357
|
+
To remove okl from a repo entirely, delete `.okl/`, the two hook scripts and their entries
|
|
358
|
+
in `.claude/settings.json`, and `.github/workflows/okl-verify.yml`. Nothing else was
|
|
359
|
+
written, and nothing outside that repo was touched.
|
|
360
|
+
|
|
261
361
|
## Wire a repo
|
|
262
362
|
|
|
263
363
|
```bash
|
|
@@ -371,7 +471,7 @@ okl metric # recurrence-after-arming: defect classes that came back in
|
|
|
371
471
|
|
|
372
472
|
## Subagents and small context budgets
|
|
373
473
|
|
|
374
|
-
A full briefing costs roughly **
|
|
474
|
+
A full briefing costs roughly **2,300 tokens** — fine for a main session with a large
|
|
375
475
|
window, punishing for a subagent working in a few thousand. That asymmetry matters
|
|
376
476
|
because subagents are exactly where org rules get lost: a focused worker handling one
|
|
377
477
|
subtask has the least context and the most need for "here is the mistake this codebase
|
|
@@ -1,35 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: org-knowledge-layer
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: Org Knowledge Layer — an installable sixth surface that carries encoded engineering lessons across repos.
|
|
5
|
-
Author: Joshua Dell
|
|
6
|
-
License: MIT
|
|
7
|
-
License-File: LICENSE
|
|
8
|
-
Keywords: agentic-coding,ai-engineering,encoding-loop,knowledge-layer,mcp
|
|
9
|
-
Requires-Python: >=3.10
|
|
10
|
-
Provides-Extra: all
|
|
11
|
-
Requires-Dist: fastapi>=0.110; extra == 'all'
|
|
12
|
-
Requires-Dist: mcp>=1.2; extra == 'all'
|
|
13
|
-
Requires-Dist: psycopg[binary]>=3.1; extra == 'all'
|
|
14
|
-
Requires-Dist: pydantic>=2; extra == 'all'
|
|
15
|
-
Requires-Dist: uvicorn>=0.29; extra == 'all'
|
|
16
|
-
Provides-Extra: dev
|
|
17
|
-
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
18
|
-
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
19
|
-
Requires-Dist: pydantic>=2; extra == 'dev'
|
|
20
|
-
Requires-Dist: pytest>=8; extra == 'dev'
|
|
21
|
-
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
22
|
-
Requires-Dist: uvicorn>=0.29; extra == 'dev'
|
|
23
|
-
Provides-Extra: mcp
|
|
24
|
-
Requires-Dist: mcp>=1.2; extra == 'mcp'
|
|
25
|
-
Provides-Extra: postgres
|
|
26
|
-
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
|
|
27
|
-
Provides-Extra: service
|
|
28
|
-
Requires-Dist: fastapi>=0.110; extra == 'service'
|
|
29
|
-
Requires-Dist: pydantic>=2; extra == 'service'
|
|
30
|
-
Requires-Dist: uvicorn>=0.29; extra == 'service'
|
|
31
|
-
Description-Content-Type: text/markdown
|
|
32
|
-
|
|
33
1
|
# okl — a shared knowledge layer for AI-assisted engineering
|
|
34
2
|
|
|
35
3
|
> A small database of the specific lessons a codebase has learned — the bugs it
|
|
@@ -78,6 +46,17 @@ Two things ship in the package. They are not coequal:
|
|
|
78
46
|
retrieved into an agent's context before a task, and go stale loudly when the code
|
|
79
47
|
they describe moves on. Everything measured in [evals/REPORT.md](evals/REPORT.md)
|
|
80
48
|
measures this.
|
|
49
|
+
|
|
50
|
+
It is worth being precise about what that store fills up with, because "lessons a
|
|
51
|
+
codebase has learned" invites the picture of a bug database. In the 161-record corpus
|
|
52
|
+
in [seed/](seed/) it is mostly not that: **90 Rules, 20 Decisions and 7 Gates against
|
|
53
|
+
34 Defects** — conventions the code follows and trade-offs already settled, not a
|
|
54
|
+
ledger of things that broke. Count it yourself:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python3 -c "import json,glob,collections; c=collections.Counter(
|
|
58
|
+
n['type'] for f in glob.glob('seed/*.json') for n in json.load(open(f))['nodes']); print(c)"
|
|
59
|
+
```
|
|
81
60
|
- **`okl scaffold`** is a starter kit for the in-repo discipline the store assumes: a
|
|
82
61
|
lean canon file, mechanical gates, registries, a review agent, and an eval harness.
|
|
83
62
|
It is useful on its own and it has never been measured. Use it to get a new repo to
|
|
@@ -195,6 +174,8 @@ with receipts, not a benchmark.
|
|
|
195
174
|
|
|
196
175
|
## How it works
|
|
197
176
|
|
|
177
|
+
<img src="docs/okl-how-it-works.svg" alt="One repo records a lesson; every other repo is briefed on it before its next task. The store is typed, scoped and tagged; every verification stamp carries the check that earned it." width="100%">
|
|
178
|
+
|
|
198
179
|
### The mental model
|
|
199
180
|
|
|
200
181
|
`okl` stores small, typed **notes** and the **links** between them.
|
|
@@ -290,6 +271,59 @@ pip install "org-knowledge-layer[mcp]" # MCP server for Claude Code / Cur
|
|
|
290
271
|
pip install "org-knowledge-layer[all]"
|
|
291
272
|
```
|
|
292
273
|
|
|
274
|
+
## What it costs, and how to turn it down
|
|
275
|
+
|
|
276
|
+
Installing okl is not free. It is worth knowing exactly what you are signing up for
|
|
277
|
+
before you wire it into every prompt, and every number below was measured on this repo's
|
|
278
|
+
own 199-record store rather than estimated.
|
|
279
|
+
|
|
280
|
+
**Per prompt, once the hook is installed:**
|
|
281
|
+
|
|
282
|
+
| | |
|
|
283
|
+
|---|---|
|
|
284
|
+
| Latency | **~0.11s** — one local SQLite query, no network in local mode |
|
|
285
|
+
| Context | **~2,300 tokens** at the default `--limit 12`, down to **~250** at `--format actions --limit 3` |
|
|
286
|
+
|
|
287
|
+
**Per session:** the Stop hook interrupts once at the end to ask what was learned. It
|
|
288
|
+
blocks the first stop only, and answering it is the whole write side of the loop.
|
|
289
|
+
|
|
290
|
+
**In your repo:** `okl init` writes `.okl/` (config, the local database, a `.gitignore`
|
|
291
|
+
covering both) and, if `.claude/` exists, two hook scripts plus their registration. It
|
|
292
|
+
also installs `.github/workflows/okl-verify.yml`, which runs the drift gate on every PR.
|
|
293
|
+
`okl scaffold` is separate and optional — nothing installs it unless you ask.
|
|
294
|
+
|
|
295
|
+
### The knobs, cheapest first
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
okl check --task "..." --format actions # imperatives only, ~60% smaller
|
|
299
|
+
okl check --task "..." --limit 3 # fewer records; the briefing says how many it trimmed
|
|
300
|
+
okl init --interests "python,security" # drop records tagged for stacks you do not use
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- **`--format actions`** is the single biggest saving and loses the least: you keep every
|
|
304
|
+
"when you see X → do Y" and drop the explanatory prose.
|
|
305
|
+
- **`--limit N`** caps how many records are drawn on. The briefing always reports what it
|
|
306
|
+
trimmed, so a short briefing can never quietly hide a miss.
|
|
307
|
+
- **`interests`** is the one to reach for on a mature shared store. Stack tags filter
|
|
308
|
+
exclusively — declaring `python` means records tagged `dotnet` stay out even when they
|
|
309
|
+
share a subject tag with something you asked for.
|
|
310
|
+
- **Scope records `repo:` rather than `org`** when a lesson is local. Org scope is a claim
|
|
311
|
+
that every project in the organization should see it, and it costs every project's
|
|
312
|
+
budget to be wrong about that.
|
|
313
|
+
|
|
314
|
+
### Turning parts off
|
|
315
|
+
|
|
316
|
+
The hooks are registered in `.claude/settings.json`; delete the entry to stop one firing.
|
|
317
|
+
The pre-task hook is the read side and the Stop hook is the write side, and they are
|
|
318
|
+
independent — running the read without the write is a reasonable way to start.
|
|
319
|
+
|
|
320
|
+
Nothing is load-bearing on the hooks: `okl check` and `okl record` work from the terminal,
|
|
321
|
+
from CI, and through the MCP server whether or not any hook is installed.
|
|
322
|
+
|
|
323
|
+
To remove okl from a repo entirely, delete `.okl/`, the two hook scripts and their entries
|
|
324
|
+
in `.claude/settings.json`, and `.github/workflows/okl-verify.yml`. Nothing else was
|
|
325
|
+
written, and nothing outside that repo was touched.
|
|
326
|
+
|
|
293
327
|
## Wire a repo
|
|
294
328
|
|
|
295
329
|
```bash
|
|
@@ -403,7 +437,7 @@ okl metric # recurrence-after-arming: defect classes that came back in
|
|
|
403
437
|
|
|
404
438
|
## Subagents and small context budgets
|
|
405
439
|
|
|
406
|
-
A full briefing costs roughly **
|
|
440
|
+
A full briefing costs roughly **2,300 tokens** — fine for a main session with a large
|
|
407
441
|
window, punishing for a subagent working in a few thousand. That asymmetry matters
|
|
408
442
|
because subagents are exactly where org rules get lost: a focused worker handling one
|
|
409
443
|
subtask has the least context and the most need for "here is the mistake this codebase
|