org-knowledge-layer 0.3.1__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.1 → org_knowledge_layer-0.4.0}/AGENTS.md +3 -2
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/CHANGELOG.md +49 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/CLAUDE.md +3 -2
- org_knowledge_layer-0.3.1/README.md → org_knowledge_layer-0.4.0/PKG-INFO +101 -1
- org_knowledge_layer-0.3.1/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.1 → 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.1 → 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.1/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.1 → org_knowledge_layer-0.4.0}/src/okl/bootstrap.py +6 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/cli.py +124 -15
- {org_knowledge_layer-0.3.1 → 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.1 → org_knowledge_layer-0.4.0}/src/okl/drift.py +18 -3
- {org_knowledge_layer-0.3.1 → 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.1 → 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.1 → org_knowledge_layer-0.4.0}/src/okl/service.py +7 -3
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/store.py +109 -17
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/tests/test_okl.py +320 -1
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/tests/test_scaffold.py +41 -2
- org_knowledge_layer-0.3.1/.claude/settings.local.json +0 -183
- org_knowledge_layer-0.3.1/.github/workflows/ci.yml +0 -22
- org_knowledge_layer-0.3.1/docs/okl-sixth-surface.excalidraw +0 -3819
- org_knowledge_layer-0.3.1/docs/okl-sixth-surface.svg +0 -2
- org_knowledge_layer-0.3.1/pyproject.toml +0 -49
- org_knowledge_layer-0.3.1/src/okl/core.py +0 -301
- org_knowledge_layer-0.3.1/src/okl/seed.py +0 -55
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.claude/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.claude/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.claude/settings.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.github/pull_request_template.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.github/workflows/okl-verify.yml +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/.gitignore +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/CONTRIBUTING.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/LICENSE +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/SECURITY.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/ci/okl-verify.yml +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/docs/DEPLOY.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/docs/ab-results-chart.png +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/docs/ab-results-chart.svg +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/docs/decisions/2026-07-17-flat-retrieval-until-scale.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/docs/posts/01-memory-that-outlives-the-run.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/docs/posts/02-dont-let-a-step-grade-itself.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/docs/posts/03-enforcement-or-good-intentions.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/README.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/ab_harness.py +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/ab-20260829-2300.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/ab-20260829-2315.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/ab-20260830-0003.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/ab-20260830-0148.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/ab-20260901-0133.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/README.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/briefed-userpromptsubmit-lint.yml +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/control-lint.yml +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/hook.log +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/service-record-500.log +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/session-briefed-pretooluse.txt +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/session-briefed-userpromptsubmit.txt +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/results/e2e-20260830/session-control.txt +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/evals/tasks.jsonl +0 -0
- {org_knowledge_layer-0.3.1/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-canon-size.sh +0 -0
- {org_knowledge_layer-0.3.1/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-diagram-pairs.sh +0 -0
- {org_knowledge_layer-0.3.1/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-links.sh +0 -0
- {org_knowledge_layer-0.3.1/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-retractions.sh +0 -0
- {org_knowledge_layer-0.3.1/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/check-tombstones.sh +0 -0
- {org_knowledge_layer-0.3.1/src/okl/scaffold → org_knowledge_layer-0.4.0}/gates/run-gates.sh +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/dotnet-canon.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/dotnet-decisions.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/dotnet-defects.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/dotnet-review-surfaces.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/frontend-canon.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/geospatial-deeptime-defects.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/geospatial-defects.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/geospatial-enforcement-defects.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/geospatial-eval-defects.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/rag-defects.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/seed/react-defects.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/__init__.py +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/__main__.py +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/MANIFEST.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/ci/method-gates.yml +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/ci/okl-verify.yml +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/agents/architecture-reviewer.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/commands/check-rules.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/commands/feature-spec.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/commands/seed-from-codebase.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/rules/example-area.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/skills/RECOMMENDED-COMPANIONS.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/skills/encoding-loop/SKILL.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/claude/skills/verify-before-claiming/SKILL.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/evals/README.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/evals/cases.jsonl +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/evals/run_evals.py +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/hooks/hooks.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/plugin/plugin.json +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/README.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/architecture.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/messaging.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/performance-and-data.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/dotnet/rules/security.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/geospatial/README.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/geospatial/rules/geospatial-ml.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/README.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/rules/fastapi-backend.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/rules/project-structure.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/python-rag/rules/rag-pipeline.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/react/README.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/profiles/react/rules/frontend.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/registries/RETRACTIONS.md +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/registries/tombstones.txt +0 -0
- {org_knowledge_layer-0.3.1 → org_knowledge_layer-0.4.0}/src/okl/scaffold/root/CLAUDE.md +0 -0
- {org_knowledge_layer-0.3.1 → 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
|
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
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
|
+
|
|
3
52
|
## 0.3.1
|
|
4
53
|
|
|
5
54
|
### Security
|
|
@@ -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.1
|
|
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
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Every figure a committed diagram publishes must trace to a committed receipt.
|
|
3
|
+
#
|
|
4
|
+
# The sixth-surface diagram rendered "50% → 6%" and "75% → 8%" under a heading reading
|
|
5
|
+
# "MEASURED (held-fixed A/B, blind judge≠generator)" for weeks, in the repo and on a
|
|
6
|
+
# public site. Those are the 2026-07-17 numbers that REPORT.md §7 quarantines as
|
|
7
|
+
# historical: the raw artifacts were never checked in, so they are not reproducible. The
|
|
8
|
+
# site's own prose cited the receipted figures right beside the image, so the page
|
|
9
|
+
# contradicted itself and a reader had no way to tell which was real.
|
|
10
|
+
#
|
|
11
|
+
# It survived because the drift stamp on the diagram record was earned by grepping for a
|
|
12
|
+
# couple of expected strings. "Some expected text is present" is not "no unsupported
|
|
13
|
+
# claim is present" — only the second is worth a verification stamp.
|
|
14
|
+
#
|
|
15
|
+
# Reads the repo, not the working tree, per the audit rule in CLAUDE.md: an uncommitted
|
|
16
|
+
# edit must not be able to pass or fail an audit that main would answer differently.
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
cd "$(git rev-parse --show-toplevel)"
|
|
19
|
+
|
|
20
|
+
# A marker file, because the checks run inside a `while read` subshell and a variable set
|
|
21
|
+
# there cannot reach this scope.
|
|
22
|
+
work=$(mktemp -d)
|
|
23
|
+
trap 'rm -rf "$work"' EXIT
|
|
24
|
+
|
|
25
|
+
# Every diagram under docs/, rather than a hard-coded path: a diagram added later is
|
|
26
|
+
# covered the day it lands, not the day someone remembers to extend this file.
|
|
27
|
+
#
|
|
28
|
+
# `while read` rather than `mapfile`, which is bash 4+. macOS ships bash 3.2, so mapfile
|
|
29
|
+
# would have passed on ubuntu CI and failed for anyone running it locally — the shape of
|
|
30
|
+
# bug this repo already keeps a rule about.
|
|
31
|
+
git ls-files 'docs/*.excalidraw' | while IFS= read -r src; do
|
|
32
|
+
svg="${src%.excalidraw}.svg"
|
|
33
|
+
echo "-- $src"
|
|
34
|
+
|
|
35
|
+
# 1. Every receipt the diagram names is committed. A diagram that shows a percentage
|
|
36
|
+
# while naming no receipt at all is the original failure and fails here too.
|
|
37
|
+
named=$(git show "HEAD:$src" | grep -oE 'ab-[0-9]{8}-[0-9]{4}' | sort -u || true)
|
|
38
|
+
if [ -z "$named" ]; then
|
|
39
|
+
if git show "HEAD:$src" | grep -qE '[0-9]+ ?%'; then
|
|
40
|
+
echo " FAIL: shows a percentage but names no receipt"
|
|
41
|
+
touch "$work/fail"
|
|
42
|
+
else
|
|
43
|
+
echo " ok: publishes no figures"
|
|
44
|
+
fi
|
|
45
|
+
fi
|
|
46
|
+
for r in $named; do
|
|
47
|
+
if git ls-files --error-unmatch "evals/results/$r.json" >/dev/null 2>&1; then
|
|
48
|
+
echo " ok: $r has a committed receipt"
|
|
49
|
+
else
|
|
50
|
+
echo " FAIL: cites $r, which is not committed under evals/results/"
|
|
51
|
+
touch "$work/fail"
|
|
52
|
+
fi
|
|
53
|
+
done
|
|
54
|
+
|
|
55
|
+
# 2. The figures REPORT.md §7 marks as historical must never appear as current claims.
|
|
56
|
+
for q in '50% → 6%' '75% → 8%'; do
|
|
57
|
+
if git show "HEAD:$src" | grep -qF "$q"; then
|
|
58
|
+
echo " FAIL: publishes '$q', quarantined as historical in REPORT.md §7"
|
|
59
|
+
touch "$work/fail"
|
|
60
|
+
fi
|
|
61
|
+
done
|
|
62
|
+
|
|
63
|
+
# 3. The SVG is a render of the source, so it must carry the same receipts. This is
|
|
64
|
+
# what catches an edited .excalidraw whose SVG was never regenerated — the image is
|
|
65
|
+
# what people actually read, and it is the artifact that ships to the site.
|
|
66
|
+
if git ls-files --error-unmatch "$svg" >/dev/null 2>&1; then
|
|
67
|
+
for r in $named; do
|
|
68
|
+
if ! git show "HEAD:$svg" | grep -qF "$r"; then
|
|
69
|
+
echo " FAIL: $svg is missing $r — re-render it from the source"
|
|
70
|
+
touch "$work/fail"
|
|
71
|
+
fi
|
|
72
|
+
done
|
|
73
|
+
else
|
|
74
|
+
echo " FAIL: $svg is not committed; the source has no published render"
|
|
75
|
+
touch "$work/fail"
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
if [ -e "$work/fail" ]; then
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
echo "DIAGRAM_FIGURES_RECEIPTED"
|
|
@@ -50,3 +50,10 @@ seed-file comments ("eval-integrity lessons are org-scoped") and the scaffold's
|
|
|
50
50
|
|
|
51
51
|
- 2026-07-21: `messaging` added to the vocabulary during the .NET platform canon import — the
|
|
52
52
|
broker/queue/event-driven rules fit no existing subject.
|
|
53
|
+
- 2026-09-02: `python` added. A code review of this repo found 190 records of which 75 were
|
|
54
|
+
tagged `dotnet` — CQRS, aggregates, outbox, DI scopes — governing a Python codebase that has
|
|
55
|
+
none of those things, while okl's own conventions had no subject to file under. `python-rag`
|
|
56
|
+
was the nearest existing tag and is wrong: it is a stack tag for one service's retrieval
|
|
57
|
+
pipeline, not a language. The distinction the vocabulary already draws (stacks vs subjects)
|
|
58
|
+
did not have a slot for "the language this is written in", and adding one is cheaper than
|
|
59
|
+
overloading a stack tag whose meaning other repos depend on.
|