org-knowledge-layer 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/settings.local.json +43 -2
  2. {org_knowledge_layer-0.1.2/src/okl/scaffold/ci → org_knowledge_layer-0.2.0/.github/workflows}/okl-verify.yml +4 -4
  3. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/CONTRIBUTING.md +11 -0
  4. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/PKG-INFO +170 -16
  5. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/README.md +169 -15
  6. {org_knowledge_layer-0.1.2/.github/workflows → org_knowledge_layer-0.2.0/ci}/okl-verify.yml +4 -4
  7. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/REPORT.md +30 -0
  8. org_knowledge_layer-0.2.0/evals/results/ab-20260901-0133.json +441 -0
  9. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/pyproject.toml +1 -1
  10. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/cli.py +128 -16
  11. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/client.py +16 -4
  12. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/core.py +83 -5
  13. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/mcp_server.py +15 -7
  14. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0/src/okl/scaffold}/ci/okl-verify.yml +4 -4
  15. org_knowledge_layer-0.2.0/src/okl/scaffold/claude/commands/seed-from-codebase.md +90 -0
  16. org_knowledge_layer-0.2.0/src/okl/scaffold/gates/check-diagram-pairs.sh +39 -0
  17. org_knowledge_layer-0.2.0/src/okl/scaffold/gates/check-links.sh +41 -0
  18. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/run-gates.sh +2 -0
  19. org_knowledge_layer-0.2.0/tests/test_okl.py +647 -0
  20. org_knowledge_layer-0.2.0/tests/test_scaffold.py +429 -0
  21. org_knowledge_layer-0.1.2/tests/test_okl.py +0 -343
  22. org_knowledge_layer-0.1.2/tests/test_scaffold.py +0 -168
  23. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/hooks/stop-okl-encode.sh +0 -0
  24. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/hooks/userpromptsubmit-okl-check.sh +0 -0
  25. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/settings.json +0 -0
  26. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  27. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  28. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/pull_request_template.md +0 -0
  29. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/workflows/ci.yml +0 -0
  30. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.gitignore +0 -0
  31. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/AGENTS.md +0 -0
  32. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/CLAUDE.md +0 -0
  33. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/LICENSE +0 -0
  34. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/SECURITY.md +0 -0
  35. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/ab-results-chart.png +0 -0
  36. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/ab-results-chart.svg +0 -0
  37. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/decisions/2026-07-17-flat-retrieval-until-scale.md +0 -0
  38. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/decisions/2026-07-21-subject-tags-controlled-vocabulary.md +0 -0
  39. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/okl-sixth-surface.excalidraw +0 -0
  40. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/okl-sixth-surface.svg +0 -0
  41. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/posts/01-memory-that-outlives-the-run.md +0 -0
  42. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/posts/02-dont-let-a-step-grade-itself.md +0 -0
  43. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/posts/03-enforcement-or-good-intentions.md +0 -0
  44. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/README.md +0 -0
  45. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/ab_harness.py +0 -0
  46. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260829-2300.json +0 -0
  47. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260829-2315.json +0 -0
  48. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260830-0003.json +0 -0
  49. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260830-0148.json +0 -0
  50. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/README.md +0 -0
  51. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/briefed-userpromptsubmit-lint.yml +0 -0
  52. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/control-lint.yml +0 -0
  53. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/hook.log +0 -0
  54. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/service-record-500.log +0 -0
  55. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/session-briefed-pretooluse.txt +0 -0
  56. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/session-briefed-userpromptsubmit.txt +0 -0
  57. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/session-control.txt +0 -0
  58. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/tasks.jsonl +0 -0
  59. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/hooks/stop-okl-encode.sh +0 -0
  60. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/hooks/userpromptsubmit-okl-check.sh +0 -0
  61. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-canon.json +0 -0
  62. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-decisions.json +0 -0
  63. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-defects.json +0 -0
  64. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-review-surfaces.json +0 -0
  65. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/frontend-canon.json +0 -0
  66. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-deeptime-defects.json +0 -0
  67. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-defects.json +0 -0
  68. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-enforcement-defects.json +0 -0
  69. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-eval-defects.json +0 -0
  70. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/rag-defects.json +0 -0
  71. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/react-defects.json +0 -0
  72. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/__init__.py +0 -0
  73. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/__main__.py +0 -0
  74. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/bootstrap.py +0 -0
  75. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/drift.py +0 -0
  76. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/MANIFEST.md +0 -0
  77. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/ci/method-gates.yml +0 -0
  78. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/agents/architecture-reviewer.md +0 -0
  79. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/commands/check-rules.md +0 -0
  80. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/commands/feature-spec.md +0 -0
  81. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/rules/example-area.md +0 -0
  82. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/skills/RECOMMENDED-COMPANIONS.md +0 -0
  83. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/skills/encoding-loop/SKILL.md +0 -0
  84. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/skills/verify-before-claiming/SKILL.md +0 -0
  85. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/evals/README.md +0 -0
  86. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/evals/cases.jsonl +0 -0
  87. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/evals/run_evals.py +0 -0
  88. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-canon-size.sh +0 -0
  89. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-doc-orphans.sh +0 -0
  90. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-retractions.sh +0 -0
  91. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-tombstones.sh +0 -0
  92. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/hooks/hooks.json +0 -0
  93. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/hooks/stop-okl-encode.sh +0 -0
  94. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/hooks/userpromptsubmit-okl-check.sh +0 -0
  95. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/plugin/plugin.json +0 -0
  96. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/README.md +0 -0
  97. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/architecture.md +0 -0
  98. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/messaging.md +0 -0
  99. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/performance-and-data.md +0 -0
  100. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/security.md +0 -0
  101. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/geospatial/README.md +0 -0
  102. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/geospatial/rules/geospatial-ml.md +0 -0
  103. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/README.md +0 -0
  104. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/rules/fastapi-backend.md +0 -0
  105. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/rules/project-structure.md +0 -0
  106. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/rules/rag-pipeline.md +0 -0
  107. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/react/README.md +0 -0
  108. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/react/rules/frontend.md +0 -0
  109. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/registries/RETRACTIONS.md +0 -0
  110. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/registries/tombstones.txt +0 -0
  111. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/root/CLAUDE.md +0 -0
  112. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/root/METHOD.md +0 -0
  113. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold_cmd.py +0 -0
  114. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/seed.py +0 -0
  115. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/service.py +0 -0
  116. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/store.py +0 -0
@@ -90,13 +90,54 @@
90
90
  "Bash(git -c core.hooksPath=/dev/null commit -qm 'Post 1: concede the crowded category, name the narrow differentiator *)",
91
91
  "Bash(git -c core.hooksPath=/dev/null commit -qm 'Public-repo hygiene: SECURITY.md, CONTRIBUTING.md, templates, provenance wording *)",
92
92
  "Bash(grep -n \"^ [a-z-]*:$\\\\|^name:\\\\|runs-on\" .github/workflows/ci.yml)",
93
- "Bash(git -C /Users/joshuadell/Dev/okl push --dry-run origin main)"
93
+ "Bash(git -C /Users/joshuadell/Dev/okl push --dry-run origin main)",
94
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'v0.1.2: ship the provenance fix and the security warning *)",
95
+ "Bash(rm -rf v12test)",
96
+ "Bash(python3 -m venv v12test)",
97
+ "Bash(./v12test/bin/pip install *)",
98
+ "Bash(./v12test/bin/okl --help)",
99
+ "Bash(./v12test/bin/python -c ' *)",
100
+ "Bash(ruff check *)",
101
+ "Bash(curl -s \"https://pypi.org/pypi/org-knowledge-layer/0.1.3/json\")",
102
+ "Bash(/tmp/v13/bin/pip show *)",
103
+ "Bash(xargs -I{} gh run view {} --log-failed)",
104
+ "Bash(grep -vE \"^$\")",
105
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'Fix the CI break the PyPI rename caused: detect by source, not by name *)",
106
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'README: say what okl is, and exactly what it keeps from drifting *)",
107
+ "Bash(sed 's|cd \"$\\(dirname \"$0\"\\)/\\\\.\\\\.\"|cd \"$\\(pwd\\)\"|' src/okl/scaffold/gates/check-links.sh)",
108
+ "Bash(bash /tmp/links.sh)",
109
+ "Bash(sed 's|cd \"$\\(dirname \"$0\"\\)/\\\\.\\\\.\"|cd \"$\\(pwd\\)\"|' src/okl/scaffold/gates/check-diagram-pairs.sh)",
110
+ "Bash(bash /tmp/dia.sh)",
111
+ "Bash(git -C /Users/joshuadell/NovaCraft log --oneline --diff-filter=A -- \".claude/skills/excalidraw-diagram/SKILL.md\")",
112
+ "Bash(git -C /Users/joshuadell/NovaCraft log --format=\"%h %ad %s\" --date=short --diff-filter=A -- \".claude/skills/excalidraw-diagram/\")",
113
+ "Bash(git -C /Users/joshuadell/NovaCraft log --oneline -- \".claude/skills/excalidraw-diagram/\")",
114
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'Be accurate about which agents get enforcement, and about what init writes *)",
115
+ "Bash(tee /tmp/briefing.txt)",
116
+ "Bash(awk '{printf \"payload: %s bytes, ~%d tokens\\\\n\",$1,$1/4}')",
117
+ "Bash(/tmp/v13/bin/okl check *)",
118
+ "Bash(/tmp/v13/bin/okl seed *)",
119
+ "Bash(python3 -m okl seed)",
120
+ "Bash(/Users/joshuadell/Dev/okl/.venv/bin/okl seed *)",
121
+ "Bash(python3 -m okl init --repo myproject --interests \"security,python-rag\")",
122
+ "Bash(echo \"=== exit=$? \\(nothing imported\\) ===\")",
123
+ "Bash(python3 -m okl seed /Users/joshuadell/Dev/okl/seed/rag-defects.json)",
124
+ "Bash(python3 -m okl seed /Users/joshuadell/Dev/okl/seed/dotnet-defects.json)",
125
+ "Bash(sqlite3 .okl/okl.db \"select count\\(*\\) from node;\")",
126
+ "Bash(python3 -m okl check --task \"add an endpoint that returns an order for the logged-in user\")",
127
+ "Bash(awk '{printf \"briefing now: %s bytes \\(~%d tokens\\), was ~4381\\\\n\",$1,$1/4}')",
128
+ "Bash(python3 -m okl bootstrap --repo myproject)",
129
+ "Bash(seed)",
130
+ "Bash(check)",
131
+ "Bash(okl bootstrap *)",
132
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'First-run experience: seeding is a choice, briefings are capped, empty states are honest *)",
133
+ "Bash(git -c core.hooksPath=/dev/null commit -q --amend -F /tmp/msg.txt)"
94
134
  ],
95
135
  "additionalDirectories": [
96
136
  "/Users/joshuadell/Dev/okl/e2e/scratch-briefed/.okl",
97
137
  "/Users/joshuadell/Dev/emeraldleaf-dev/src/pages",
98
138
  "/Users/joshuadell/Dev/emeraldleaf-dev/src/assets",
99
- "/Users/joshuadell/Dev/emeraldleaf-dev/src"
139
+ "/Users/joshuadell/Dev/emeraldleaf-dev/src",
140
+ "/Users/joshuadell/NovaCraft/.claude/skills/excalidraw-diagram"
100
141
  ]
101
142
  }
102
143
  }
@@ -27,13 +27,13 @@ jobs:
27
27
  with:
28
28
  python-version: "3.13"
29
29
  - name: Install okl
30
- # Consumer repos install the released package; in okl's own repo this
31
- # workflow dogfoods the working tree (pip install okl would 404 — not on PyPI yet).
30
+ # Detect by the package source, not the distribution name: the name changed once
31
+ # (PyPI rejects "okl" as confusable) and a name-based check silently broke with it.
32
32
  run: |
33
- if grep -q '^name = "okl"' pyproject.toml 2>/dev/null; then
33
+ if [ -f src/okl/cli.py ]; then
34
34
  pip install -e .
35
35
  else
36
- pip install okl
36
+ pip install org-knowledge-layer
37
37
  fi
38
38
 
39
39
  - name: Connect to the shared layer (optional — skipped when secrets are unset)
@@ -49,6 +49,17 @@ it is the actual contract. The parts that will fail your build if you miss them:
49
49
  cutoff that is still unfinished.
50
50
  - **Portability fixes.** Hooks, path resolution, and CI have been exercised on macOS and
51
51
  GitHub Actions and nowhere else.
52
+ - **Hook wiring for another agent.** `okl init` auto-registers hooks for Claude Code
53
+ only, so everywhere else the pre-task read is discretionary rather than enforced. The
54
+ scripts in `src/okl/scaffold/hooks/` are plain bash reading JSON on stdin and writing
55
+ the briefing to stdout; nothing in them is Claude-specific. What is missing is the
56
+ per-agent registration, plus confirming the agent fires an event before the model reads
57
+ the prompt (Codex CLI documents `userpromptsubmit`; OpenCode's plugin API appears to
58
+ cover tool events but not pre-prompt, so there it may only ever be a tool call). A PR adding `okl init --agent <name>` for the tool you actually use
59
+ daily would be the single most valuable contribution here. Bring evidence it fires: a
60
+ behavioral check against a bare control repo, not just a log line, because a hook that
61
+ fires is not a hook that is heard.
62
+
52
63
  - **A live-Postgres test.** The ranked search path for Postgres is currently asserted at
53
64
  the SQL-shape level against a fake connection; it has never run against a real server.
54
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: org-knowledge-layer
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Org Knowledge Layer — an installable sixth surface that carries encoded engineering lessons across repos.
5
5
  Author: Joshua Dell
6
6
  License: MIT
@@ -67,6 +67,58 @@ stdlib-only with zero required dependencies.
67
67
 
68
68
  ---
69
69
 
70
+ ## What okl is
71
+
72
+ **A store of your engineering rules, and the machinery that keeps them true.**
73
+
74
+ Two things ship in the package. They are not coequal:
75
+
76
+ - **The knowledge layer** is the product. Typed records (rules, architecture decisions,
77
+ known defects, gates, tombstones, retractions) that live outside any one repo, get
78
+ retrieved into an agent's context before a task, and go stale loudly when the code
79
+ they describe moves on. Everything measured in [evals/REPORT.md](evals/REPORT.md)
80
+ measures this.
81
+ - **`okl scaffold`** is a starter kit for the in-repo discipline the store assumes: a
82
+ lean canon file, mechanical gates, registries, a review agent, and an eval harness.
83
+ It is useful on its own and it has never been measured. Use it to get a new repo to
84
+ the state where a shared store has something to attach to.
85
+
86
+ | Piece | What it is | Where it lives |
87
+ |---|---|---|
88
+ | **client** (`okl` CLI + agent tools) | `check` / `record` / `verify` / `drift` / `search` / `seed` | installed per-repo (this package) |
89
+ | **shared layer** (`okl serve`) | one small service owning the database, so many repos share one store | one place you run it |
90
+ | **scaffold** (`okl scaffold`) | the in-repo starter files: canon, gates, registries, evals | stamped into each repo, optional |
91
+
92
+ ## What it keeps from drifting, and how
93
+
94
+ Knowledge rots in a specific way: the code changes and everything written *about* the
95
+ code silently stops being true. Five mechanisms catch five different versions of that,
96
+ and it is worth knowing which one catches what, because they do not overlap.
97
+
98
+ | Drift | Caught by | How it works | Fires when |
99
+ |---|---|---|---|
100
+ | **A rule vs. the code it governs** | `okl drift --gate` | a record declares the path globs it governs; git is asked for the last commit touching them | that commit is newer than the record's last verification |
101
+ | **A retired identifier reappearing in prose** | `check-tombstones.sh` | greps tracked source, docs, comments and config for every tombstoned name | any non-allowlisted hit |
102
+ | **A withdrawn claim being restated** | `check-retractions.sh` | greps tracked docs for the exact quoted claim from the retraction registry | the quote appears outside the registry |
103
+ | **A doc nobody links to** | `check-doc-orphans.sh` | reachability check from hub files through `docs/` | a doc is unreachable, so it drifts unread |
104
+ | **A link pointing at a file that moved** | `check-links.sh` | resolves every local markdown link against `git ls-files` | the target does not exist |
105
+ | **A diagram source with no rendered image** | `check-diagram-pairs.sh` | pairs each editable source with its export; format-agnostic via `OKL_DIAGRAM_SRC_EXT`/`OUT_EXT` | reviewers would see nothing. A hand-authored image with no source is noted, never failed, and a repo with no diagram sources is a clean no-op |
106
+ | **Verification going quietly stale** | TTL + `verified_by` | records carry when they were last verified and by which observed check | past its TTL, a record is shown demoted rather than deleted |
107
+
108
+ Two honest limits on that table:
109
+
110
+ - **Diagram *content* is still a human job.** `check-diagram-pairs.sh` proves the rendered
111
+ image exists; nothing proves it matches the source it was exported from, or that either
112
+ matches the code. For that, name the diagram in a record's `--files` alongside the code
113
+ it depicts, so changing the code turns the drift gate red until someone re-verifies the
114
+ picture. This repo does exactly that with its own architecture diagram and README.
115
+ - **Comments are covered only by the identifier and claim gates.** A stale comment that
116
+ names no tombstoned identifier and restates no retracted claim will not be caught.
117
+ - **`okl drift` only watches what a record claims.** A file no record governs is not
118
+ watched by anything. Coverage is a curation decision, and the gap is invisible until
119
+ something breaks — which is why the mechanical gates above scan *everything tracked*
120
+ rather than only what is enrolled.
121
+
70
122
  ## Where this sits (2026): a crowded space, entered anyway
71
123
 
72
124
  **This is not a novel idea, and you should know that before reading further.** Agent
@@ -246,6 +298,29 @@ okl init --repo my-repo # writes .okl/config.json; installs the pre-task
246
298
  okl connect https://okl.myorg.dev # optional: point at the shared service (else local file)
247
299
  ```
248
300
 
301
+ ### What `okl init` writes to your repo
302
+
303
+ Run `okl init --dry-run` first: it lists every path and writes nothing. In full, `init`
304
+ touches only the current directory, and only these:
305
+
306
+ | Path | What it is |
307
+ |---|---|
308
+ | `.okl/config.json` | repo name, subject interests, and the path to your `okl` binary |
309
+ | `.claude/hooks/userpromptsubmit-okl-check.sh` | **executable**; runs when you submit a task, injects the briefing |
310
+ | `.claude/hooks/stop-okl-encode.sh` | **executable**; runs at session end, asks what was learned |
311
+ | `.claude/settings.json` | registers those two hooks (merged in place; your existing keys are preserved) |
312
+ | `.mcp.json` | registers the okl MCP server — only when the `mcp` extra is installed |
313
+ | `.github/workflows/okl-verify.yml` | **a CI workflow** running the drift gate on pull requests |
314
+
315
+ Two of those deserve a second look before you run it: the hooks are shell scripts that
316
+ execute automatically during agent sessions (the check hook can *block* a task when the
317
+ store is unreachable — that is the fail-closed design), and the CI workflow will run in
318
+ your Actions. Both are plain text you can read first, in
319
+ [`src/okl/scaffold/hooks/`](src/okl/scaffold/hooks/) and
320
+ [`src/okl/scaffold/ci/`](src/okl/scaffold/ci/). Nothing executes at install time; nothing
321
+ is written outside the directory you run `init` in; nothing contacts a network unless you
322
+ run `okl connect` and point it somewhere yourself.
323
+
249
324
  `init` writes `.okl/config.json`. If the repo uses a coding agent with a `.claude/`
250
325
  directory, it also installs two hooks: a `UserPromptSubmit` hook that runs `check` on
251
326
  the prompt you actually typed and puts the briefing into the model's context (the
@@ -261,6 +336,18 @@ reading the AGENTS.md convention gets the same rules Claude Code does (byte-iden
261
336
  test-enforced). The hooks themselves are Claude Code-specific; other agents get the
262
337
  canon via AGENTS.md and the store via the MCP server (`okl mcp`).
263
338
 
339
+ That split matters: on Claude Code the pre-task read is *enforced* (fail-closed hook);
340
+ everywhere else it is *available* (a tool call or a shell command), which is
341
+ discretionary — the thing enforcement exists to avoid. The hook scripts themselves are
342
+ plain bash reading JSON on stdin, so nothing in them is Claude-specific; what is missing
343
+ for other agents is the config that registers them, and whether the agent fires an event
344
+ early enough to matter. Codex CLI documents a `userpromptsubmit` hook, which is the right
345
+ shape; Copilot, Gemini CLI and Cursor have hook systems worth checking against your
346
+ version; OpenCode's plugin API captures tool events but, as of this writing, no
347
+ pre-prompt event — so there the read stays a tool call rather than a gate. Verify against
348
+ your agent's current docs before trusting any of that. Wiring one up is a well-shaped
349
+ contribution — see [CONTRIBUTING.md](CONTRIBUTING.md).
350
+
264
351
  Hooks run in whatever environment the agent harness spawns — often without your venv or
265
352
  pipx bin dir on PATH — so both hooks resolve the `okl` binary in layers: the `OKL_BIN`
266
353
  env var, then the `okl_bin` path `init` pins into `.okl/config.json` (machine-local),
@@ -275,6 +362,7 @@ mode, good for trying it before you deploy anything.
275
362
  ```bash
276
363
  # 1. READ the relevant lessons before starting a task (the load-bearing move)
277
364
  okl check --task "add an endpoint that returns an order for the logged-in user"
365
+ # add --format actions --limit 3 for a ~240-token version (subagents, CI)
278
366
 
279
367
  # 2. RECORD a lesson after you learn it, with an actionable symptom/cause/fix
280
368
  okl record --type Defect --scope org --tags "security" \
@@ -313,6 +401,59 @@ okl metric # recurrence-after-arming: defect classes that came back in
313
401
  # where a catching check existed but wasn't turned on
314
402
  ```
315
403
 
404
+ ## Subagents and small context budgets
405
+
406
+ A full briefing costs roughly **4,400 tokens** — fine for a main session with a large
407
+ window, punishing for a subagent working in a few thousand. That asymmetry matters
408
+ because subagents are exactly where org rules get lost: a focused worker handling one
409
+ subtask has the least context and the most need for "here is the mistake this codebase
410
+ already made."
411
+
412
+ `--format actions` solves it by dropping everything except the imperative list:
413
+
414
+ ```bash
415
+ okl check --task "add an endpoint returning an order for the logged-in user" \
416
+ --format actions --limit 3
417
+ ```
418
+
419
+ ```
420
+ OKL — 3 rule(s) apply before you start:
421
+ - FIX: Missing ownership scope check is an IDOR (CWE-639) [when: an endpoint fetches an
422
+ entity by id with no owner/tenant predicate]
423
+ -> add the caller's owner id to the WHERE clause; return 404 (not 403) on no match
424
+ ...
425
+ ```
426
+
427
+ **Measured on this repo's own store:** ~240 tokens at `--limit 3`, ~390 at `--limit 5`,
428
+ ~630 at `--limit 8`, against ~2,650 for the full briefing. Cheap enough to call per subtask.
429
+
430
+ The full briefing is itself capped: `check` keeps the top `--limit` records (12 by
431
+ default) from the ranked, filtered set and says how many it trimmed. Before that cutoff
432
+ existed, one task on this store returned 20 records and ~4,400 tokens. Re-running the A/B
433
+ after adding it showed no retrieval miss — the one task that regressed still had its rule
434
+ in the briefing and the model simply did not follow it, which is a compliance problem
435
+ rather than a retrieval one. See [evals/REPORT.md](evals/REPORT.md).
436
+
437
+ What it drops: the bucketed sections, the prose bodies explaining *why* each record
438
+ exists, prior-art notes, and the stale-record footer. What it keeps is what changes
439
+ behaviour: the verb, the symptom to watch for, and the fix.
440
+
441
+ **Wiring it into a subagent.** Three ways, in order of how much enforcement you get:
442
+
443
+ 1. **The MCP tool** — `okl_check(task=..., compact=True, limit=3)`. Any subagent with
444
+ MCP access can call it. Discretionary: the agent has to choose to.
445
+ 2. **In the subagent's prompt** — have the spawning agent run `okl check --format
446
+ actions --limit 3` and paste the result into the subtask description. Not
447
+ discretionary, and it costs the parent almost nothing.
448
+ 3. **A wrapper script** that runs the check and prepends it to whatever prompt it is
449
+ handed. This is the enforced version for orchestration you control.
450
+
451
+ **A caveat worth stating.** `--limit` caps how many records the briefing draws on, and
452
+ ranking decides which survive. If a task's most relevant rule ranks fourth and you ask
453
+ for three, you will not see it, and nothing will tell you. The full briefing exists
454
+ because it does not make that trade. Use the compact form where a token budget forces
455
+ the choice, not by default.
456
+
316
457
  ## Verification: don't let a step grade itself
317
458
 
318
459
  A step reporting "I succeeded" and the work actually being done are two different facts,
@@ -348,17 +489,36 @@ folder.) Two clarifications that stop the common misreadings:
348
489
 
349
490
  ## Seed it (so the very first `check` returns something)
350
491
 
351
- An empty store returns nothing. You can hand-`record` your first lessons, or load a
352
- starter file — a JSON list of notes and links:
492
+ An empty store returns nothing, and says so — a check against an empty store reports
493
+ that it proved nothing rather than reporting "no rules apply". Three ways to fill it:
494
+
495
+ **1. See what ships, then choose.** A bare `okl seed` imports nothing; it lists the
496
+ bundled packs with their record counts and subject tags, marking the ones that match
497
+ this repo's declared interests:
353
498
 
354
499
  ```bash
355
- okl seed seed/react-defects.json # or point at a directory to load several
500
+ okl seed # list the packs, import nothing
501
+ okl seed <path>/rag-defects.json # import one
502
+ okl seed --all # import every pack (explicit on purpose)
356
503
  ```
357
504
 
358
- The bundled seed files hold real, dated lessons from a few production codebases
359
- (a .NET service, a geospatial ML pipeline, a Python search service, a React app).
360
- Treat them as examples of the format and as genuinely useful starting defects; delete
361
- what doesn't apply to you.
505
+ The packs hold real, dated records from production codebases (a .NET service, a
506
+ geospatial ML pipeline, a Python RAG service, a React app). They are org-scoped, so
507
+ importing packs for stacks you do not use fills every briefing here with noise about
508
+ frameworks you will never touch — which is why `--all` is opt-in rather than default.
509
+
510
+ **2. Generate records from this codebase.** If you use a coding agent, the scaffold
511
+ stamps a `/seed-from-codebase` command that has the agent read your repo — the guard
512
+ rails already in the code, what CI enforces, the fix commits, the existing canon — and
513
+ propose records with a `file:line` citation each. Everything it proposes is repo-scoped
514
+ and unverified by design; it writes a reviewable file and imports nothing, because a
515
+ plausible rule no file supports is worse than an empty store.
516
+
517
+ **3. `okl bootstrap`** greps git history and file names for candidates. It is the weakest
518
+ of the three and comes up empty on young repos; prefer option 2 when an agent is available.
519
+
520
+ Whichever you use, review before importing. Choosing a record's scope is the curation
521
+ step that keeps a shared layer from filling with one project's noise.
362
522
 
363
523
  ---
364
524
 
@@ -389,14 +549,8 @@ TDD, plan writing/execution, git-worktree isolation) are **not bundled** — the
389
549
  best maintained in third-party collections, so `skills/RECOMMENDED-COMPANIONS.md`
390
550
  points at those instead of vendoring someone else's work and its cross-references.
391
551
 
392
- The scaffold is independent of the knowledge store — use either half on its own.
393
-
394
- ## The two halves
395
-
396
- | Piece | What it is | Where it lives |
397
- |---|---|---|
398
- | **client** (`okl` CLI + agent tools) | `check` / `record` / `search` / `link` / `drift` / `seed` / … | installed per-repo (this package) |
399
- | **shared layer** (`okl serve`) | a small web service that owns the database, so many repos share one store | one place you run it |
552
+ The scaffold runs with no store at all; the store works in a repo that never scaffolded.
553
+ They are complementary, not a package deal.
400
554
 
401
555
  **Storage is swappable** via one environment variable — your commands never change:
402
556
 
@@ -35,6 +35,58 @@ stdlib-only with zero required dependencies.
35
35
 
36
36
  ---
37
37
 
38
+ ## What okl is
39
+
40
+ **A store of your engineering rules, and the machinery that keeps them true.**
41
+
42
+ Two things ship in the package. They are not coequal:
43
+
44
+ - **The knowledge layer** is the product. Typed records (rules, architecture decisions,
45
+ known defects, gates, tombstones, retractions) that live outside any one repo, get
46
+ retrieved into an agent's context before a task, and go stale loudly when the code
47
+ they describe moves on. Everything measured in [evals/REPORT.md](evals/REPORT.md)
48
+ measures this.
49
+ - **`okl scaffold`** is a starter kit for the in-repo discipline the store assumes: a
50
+ lean canon file, mechanical gates, registries, a review agent, and an eval harness.
51
+ It is useful on its own and it has never been measured. Use it to get a new repo to
52
+ the state where a shared store has something to attach to.
53
+
54
+ | Piece | What it is | Where it lives |
55
+ |---|---|---|
56
+ | **client** (`okl` CLI + agent tools) | `check` / `record` / `verify` / `drift` / `search` / `seed` | installed per-repo (this package) |
57
+ | **shared layer** (`okl serve`) | one small service owning the database, so many repos share one store | one place you run it |
58
+ | **scaffold** (`okl scaffold`) | the in-repo starter files: canon, gates, registries, evals | stamped into each repo, optional |
59
+
60
+ ## What it keeps from drifting, and how
61
+
62
+ Knowledge rots in a specific way: the code changes and everything written *about* the
63
+ code silently stops being true. Five mechanisms catch five different versions of that,
64
+ and it is worth knowing which one catches what, because they do not overlap.
65
+
66
+ | Drift | Caught by | How it works | Fires when |
67
+ |---|---|---|---|
68
+ | **A rule vs. the code it governs** | `okl drift --gate` | a record declares the path globs it governs; git is asked for the last commit touching them | that commit is newer than the record's last verification |
69
+ | **A retired identifier reappearing in prose** | `check-tombstones.sh` | greps tracked source, docs, comments and config for every tombstoned name | any non-allowlisted hit |
70
+ | **A withdrawn claim being restated** | `check-retractions.sh` | greps tracked docs for the exact quoted claim from the retraction registry | the quote appears outside the registry |
71
+ | **A doc nobody links to** | `check-doc-orphans.sh` | reachability check from hub files through `docs/` | a doc is unreachable, so it drifts unread |
72
+ | **A link pointing at a file that moved** | `check-links.sh` | resolves every local markdown link against `git ls-files` | the target does not exist |
73
+ | **A diagram source with no rendered image** | `check-diagram-pairs.sh` | pairs each editable source with its export; format-agnostic via `OKL_DIAGRAM_SRC_EXT`/`OUT_EXT` | reviewers would see nothing. A hand-authored image with no source is noted, never failed, and a repo with no diagram sources is a clean no-op |
74
+ | **Verification going quietly stale** | TTL + `verified_by` | records carry when they were last verified and by which observed check | past its TTL, a record is shown demoted rather than deleted |
75
+
76
+ Two honest limits on that table:
77
+
78
+ - **Diagram *content* is still a human job.** `check-diagram-pairs.sh` proves the rendered
79
+ image exists; nothing proves it matches the source it was exported from, or that either
80
+ matches the code. For that, name the diagram in a record's `--files` alongside the code
81
+ it depicts, so changing the code turns the drift gate red until someone re-verifies the
82
+ picture. This repo does exactly that with its own architecture diagram and README.
83
+ - **Comments are covered only by the identifier and claim gates.** A stale comment that
84
+ names no tombstoned identifier and restates no retracted claim will not be caught.
85
+ - **`okl drift` only watches what a record claims.** A file no record governs is not
86
+ watched by anything. Coverage is a curation decision, and the gap is invisible until
87
+ something breaks — which is why the mechanical gates above scan *everything tracked*
88
+ rather than only what is enrolled.
89
+
38
90
  ## Where this sits (2026): a crowded space, entered anyway
39
91
 
40
92
  **This is not a novel idea, and you should know that before reading further.** Agent
@@ -214,6 +266,29 @@ okl init --repo my-repo # writes .okl/config.json; installs the pre-task
214
266
  okl connect https://okl.myorg.dev # optional: point at the shared service (else local file)
215
267
  ```
216
268
 
269
+ ### What `okl init` writes to your repo
270
+
271
+ Run `okl init --dry-run` first: it lists every path and writes nothing. In full, `init`
272
+ touches only the current directory, and only these:
273
+
274
+ | Path | What it is |
275
+ |---|---|
276
+ | `.okl/config.json` | repo name, subject interests, and the path to your `okl` binary |
277
+ | `.claude/hooks/userpromptsubmit-okl-check.sh` | **executable**; runs when you submit a task, injects the briefing |
278
+ | `.claude/hooks/stop-okl-encode.sh` | **executable**; runs at session end, asks what was learned |
279
+ | `.claude/settings.json` | registers those two hooks (merged in place; your existing keys are preserved) |
280
+ | `.mcp.json` | registers the okl MCP server — only when the `mcp` extra is installed |
281
+ | `.github/workflows/okl-verify.yml` | **a CI workflow** running the drift gate on pull requests |
282
+
283
+ Two of those deserve a second look before you run it: the hooks are shell scripts that
284
+ execute automatically during agent sessions (the check hook can *block* a task when the
285
+ store is unreachable — that is the fail-closed design), and the CI workflow will run in
286
+ your Actions. Both are plain text you can read first, in
287
+ [`src/okl/scaffold/hooks/`](src/okl/scaffold/hooks/) and
288
+ [`src/okl/scaffold/ci/`](src/okl/scaffold/ci/). Nothing executes at install time; nothing
289
+ is written outside the directory you run `init` in; nothing contacts a network unless you
290
+ run `okl connect` and point it somewhere yourself.
291
+
217
292
  `init` writes `.okl/config.json`. If the repo uses a coding agent with a `.claude/`
218
293
  directory, it also installs two hooks: a `UserPromptSubmit` hook that runs `check` on
219
294
  the prompt you actually typed and puts the briefing into the model's context (the
@@ -229,6 +304,18 @@ reading the AGENTS.md convention gets the same rules Claude Code does (byte-iden
229
304
  test-enforced). The hooks themselves are Claude Code-specific; other agents get the
230
305
  canon via AGENTS.md and the store via the MCP server (`okl mcp`).
231
306
 
307
+ That split matters: on Claude Code the pre-task read is *enforced* (fail-closed hook);
308
+ everywhere else it is *available* (a tool call or a shell command), which is
309
+ discretionary — the thing enforcement exists to avoid. The hook scripts themselves are
310
+ plain bash reading JSON on stdin, so nothing in them is Claude-specific; what is missing
311
+ for other agents is the config that registers them, and whether the agent fires an event
312
+ early enough to matter. Codex CLI documents a `userpromptsubmit` hook, which is the right
313
+ shape; Copilot, Gemini CLI and Cursor have hook systems worth checking against your
314
+ version; OpenCode's plugin API captures tool events but, as of this writing, no
315
+ pre-prompt event — so there the read stays a tool call rather than a gate. Verify against
316
+ your agent's current docs before trusting any of that. Wiring one up is a well-shaped
317
+ contribution — see [CONTRIBUTING.md](CONTRIBUTING.md).
318
+
232
319
  Hooks run in whatever environment the agent harness spawns — often without your venv or
233
320
  pipx bin dir on PATH — so both hooks resolve the `okl` binary in layers: the `OKL_BIN`
234
321
  env var, then the `okl_bin` path `init` pins into `.okl/config.json` (machine-local),
@@ -243,6 +330,7 @@ mode, good for trying it before you deploy anything.
243
330
  ```bash
244
331
  # 1. READ the relevant lessons before starting a task (the load-bearing move)
245
332
  okl check --task "add an endpoint that returns an order for the logged-in user"
333
+ # add --format actions --limit 3 for a ~240-token version (subagents, CI)
246
334
 
247
335
  # 2. RECORD a lesson after you learn it, with an actionable symptom/cause/fix
248
336
  okl record --type Defect --scope org --tags "security" \
@@ -281,6 +369,59 @@ okl metric # recurrence-after-arming: defect classes that came back in
281
369
  # where a catching check existed but wasn't turned on
282
370
  ```
283
371
 
372
+ ## Subagents and small context budgets
373
+
374
+ A full briefing costs roughly **4,400 tokens** — fine for a main session with a large
375
+ window, punishing for a subagent working in a few thousand. That asymmetry matters
376
+ because subagents are exactly where org rules get lost: a focused worker handling one
377
+ subtask has the least context and the most need for "here is the mistake this codebase
378
+ already made."
379
+
380
+ `--format actions` solves it by dropping everything except the imperative list:
381
+
382
+ ```bash
383
+ okl check --task "add an endpoint returning an order for the logged-in user" \
384
+ --format actions --limit 3
385
+ ```
386
+
387
+ ```
388
+ OKL — 3 rule(s) apply before you start:
389
+ - FIX: Missing ownership scope check is an IDOR (CWE-639) [when: an endpoint fetches an
390
+ entity by id with no owner/tenant predicate]
391
+ -> add the caller's owner id to the WHERE clause; return 404 (not 403) on no match
392
+ ...
393
+ ```
394
+
395
+ **Measured on this repo's own store:** ~240 tokens at `--limit 3`, ~390 at `--limit 5`,
396
+ ~630 at `--limit 8`, against ~2,650 for the full briefing. Cheap enough to call per subtask.
397
+
398
+ The full briefing is itself capped: `check` keeps the top `--limit` records (12 by
399
+ default) from the ranked, filtered set and says how many it trimmed. Before that cutoff
400
+ existed, one task on this store returned 20 records and ~4,400 tokens. Re-running the A/B
401
+ after adding it showed no retrieval miss — the one task that regressed still had its rule
402
+ in the briefing and the model simply did not follow it, which is a compliance problem
403
+ rather than a retrieval one. See [evals/REPORT.md](evals/REPORT.md).
404
+
405
+ What it drops: the bucketed sections, the prose bodies explaining *why* each record
406
+ exists, prior-art notes, and the stale-record footer. What it keeps is what changes
407
+ behaviour: the verb, the symptom to watch for, and the fix.
408
+
409
+ **Wiring it into a subagent.** Three ways, in order of how much enforcement you get:
410
+
411
+ 1. **The MCP tool** — `okl_check(task=..., compact=True, limit=3)`. Any subagent with
412
+ MCP access can call it. Discretionary: the agent has to choose to.
413
+ 2. **In the subagent's prompt** — have the spawning agent run `okl check --format
414
+ actions --limit 3` and paste the result into the subtask description. Not
415
+ discretionary, and it costs the parent almost nothing.
416
+ 3. **A wrapper script** that runs the check and prepends it to whatever prompt it is
417
+ handed. This is the enforced version for orchestration you control.
418
+
419
+ **A caveat worth stating.** `--limit` caps how many records the briefing draws on, and
420
+ ranking decides which survive. If a task's most relevant rule ranks fourth and you ask
421
+ for three, you will not see it, and nothing will tell you. The full briefing exists
422
+ because it does not make that trade. Use the compact form where a token budget forces
423
+ the choice, not by default.
424
+
284
425
  ## Verification: don't let a step grade itself
285
426
 
286
427
  A step reporting "I succeeded" and the work actually being done are two different facts,
@@ -316,17 +457,36 @@ folder.) Two clarifications that stop the common misreadings:
316
457
 
317
458
  ## Seed it (so the very first `check` returns something)
318
459
 
319
- An empty store returns nothing. You can hand-`record` your first lessons, or load a
320
- starter file — a JSON list of notes and links:
460
+ An empty store returns nothing, and says so — a check against an empty store reports
461
+ that it proved nothing rather than reporting "no rules apply". Three ways to fill it:
462
+
463
+ **1. See what ships, then choose.** A bare `okl seed` imports nothing; it lists the
464
+ bundled packs with their record counts and subject tags, marking the ones that match
465
+ this repo's declared interests:
321
466
 
322
467
  ```bash
323
- okl seed seed/react-defects.json # or point at a directory to load several
468
+ okl seed # list the packs, import nothing
469
+ okl seed <path>/rag-defects.json # import one
470
+ okl seed --all # import every pack (explicit on purpose)
324
471
  ```
325
472
 
326
- The bundled seed files hold real, dated lessons from a few production codebases
327
- (a .NET service, a geospatial ML pipeline, a Python search service, a React app).
328
- Treat them as examples of the format and as genuinely useful starting defects; delete
329
- what doesn't apply to you.
473
+ The packs hold real, dated records from production codebases (a .NET service, a
474
+ geospatial ML pipeline, a Python RAG service, a React app). They are org-scoped, so
475
+ importing packs for stacks you do not use fills every briefing here with noise about
476
+ frameworks you will never touch — which is why `--all` is opt-in rather than default.
477
+
478
+ **2. Generate records from this codebase.** If you use a coding agent, the scaffold
479
+ stamps a `/seed-from-codebase` command that has the agent read your repo — the guard
480
+ rails already in the code, what CI enforces, the fix commits, the existing canon — and
481
+ propose records with a `file:line` citation each. Everything it proposes is repo-scoped
482
+ and unverified by design; it writes a reviewable file and imports nothing, because a
483
+ plausible rule no file supports is worse than an empty store.
484
+
485
+ **3. `okl bootstrap`** greps git history and file names for candidates. It is the weakest
486
+ of the three and comes up empty on young repos; prefer option 2 when an agent is available.
487
+
488
+ Whichever you use, review before importing. Choosing a record's scope is the curation
489
+ step that keeps a shared layer from filling with one project's noise.
330
490
 
331
491
  ---
332
492
 
@@ -357,14 +517,8 @@ TDD, plan writing/execution, git-worktree isolation) are **not bundled** — the
357
517
  best maintained in third-party collections, so `skills/RECOMMENDED-COMPANIONS.md`
358
518
  points at those instead of vendoring someone else's work and its cross-references.
359
519
 
360
- The scaffold is independent of the knowledge store — use either half on its own.
361
-
362
- ## The two halves
363
-
364
- | Piece | What it is | Where it lives |
365
- |---|---|---|
366
- | **client** (`okl` CLI + agent tools) | `check` / `record` / `search` / `link` / `drift` / `seed` / … | installed per-repo (this package) |
367
- | **shared layer** (`okl serve`) | a small web service that owns the database, so many repos share one store | one place you run it |
520
+ The scaffold runs with no store at all; the store works in a repo that never scaffolded.
521
+ They are complementary, not a package deal.
368
522
 
369
523
  **Storage is swappable** via one environment variable — your commands never change:
370
524
 
@@ -27,13 +27,13 @@ jobs:
27
27
  with:
28
28
  python-version: "3.13"
29
29
  - name: Install okl
30
- # Consumer repos install the released package; in okl's own repo this
31
- # workflow dogfoods the working tree (pip install okl would 404 — not on PyPI yet).
30
+ # Detect by the package source, not the distribution name: the name changed once
31
+ # (PyPI rejects "okl" as confusable) and a name-based check silently broke with it.
32
32
  run: |
33
- if grep -q '^name = "okl"' pyproject.toml 2>/dev/null; then
33
+ if [ -f src/okl/cli.py ]; then
34
34
  pip install -e .
35
35
  else
36
- pip install okl
36
+ pip install org-knowledge-layer
37
37
  fi
38
38
 
39
39
  - name: Connect to the shared layer (optional — skipped when secrets are unset)
@@ -139,6 +139,36 @@ reproduced in 1/15.
139
139
 
140
140
  Conditional subset: 2/12 on the 4 tasks the baseline failed at least once.
141
141
 
142
+ ## 4b. Re-run after adding the relevance cutoff (2026-09-01)
143
+
144
+ `check` gained a top-k cutoff: it keeps the highest-ranked `limit` records (12 by
145
+ default) and reports how many it trimmed. That is a change to the retrieval path this
146
+ report measures, so the A/B was re-run rather than assumed safe.
147
+
148
+ | run | generator | judge | samples | baseline | briefed |
149
+ |---|---|---|---|---|---|
150
+ | ab-20260830-0003 (before cutoff) | sonnet | haiku | 3 | 8/24 (33%) | 1/24 (4%) |
151
+ | **ab-20260901-0133 (after cutoff)** | sonnet | haiku | 3 | **10/24 (42%)** | **2/24 (8%)** |
152
+
153
+ **Read the baseline first.** It moved 33% → 42% between runs, and the baseline arm never
154
+ receives a briefing — nothing about it changed. That 9-point swing is run-to-run variance
155
+ and sets the noise floor at n=24. The briefed arm's 4% → 8% is one additional
156
+ reproduction, inside that band.
157
+
158
+ **The one signal worth investigating** was `spa_tokens`, which went 0/3 → 2/3 briefed. If
159
+ the cutoff had trimmed the relevant record, that would be the ADR's miss-rate trigger
160
+ firing. It had not: the localStorage record appears in that task's briefing at
161
+ `--limit 12` exactly as it does at `--limit 40`. The judge's verdicts show the model used
162
+ `sessionStorage` via `WebStorageStateStore` and wrote a comment documenting the security
163
+ trade-off — it had the rule, understood it, and chose a variant the strict signal still
164
+ counts as web-storage persistence. (The earlier haiku run reproduced the same task 2/3
165
+ before any cutoff existed.)
166
+
167
+ That distinction is the one the flat-retrieval ADR is written around: its trigger is a
168
+ **retrieval miss** — a record that exists in scope and was not surfaced — not a model
169
+ failing to comply with a record it was handed. Measured miss rate after the cutoff
170
+ remains zero. Compliance is a separate, unmeasured problem.
171
+
142
172
  ## 5. Findings
143
173
 
144
174
  1. **The briefing works, in both tiers.** Sonnet: 33% → 4%. Haiku: 38% → 12%. Every