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.
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/settings.local.json +43 -2
- {org_knowledge_layer-0.1.2/src/okl/scaffold/ci → org_knowledge_layer-0.2.0/.github/workflows}/okl-verify.yml +4 -4
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/CONTRIBUTING.md +11 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/PKG-INFO +170 -16
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/README.md +169 -15
- {org_knowledge_layer-0.1.2/.github/workflows → org_knowledge_layer-0.2.0/ci}/okl-verify.yml +4 -4
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/REPORT.md +30 -0
- org_knowledge_layer-0.2.0/evals/results/ab-20260901-0133.json +441 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/pyproject.toml +1 -1
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/cli.py +128 -16
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/client.py +16 -4
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/core.py +83 -5
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/mcp_server.py +15 -7
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0/src/okl/scaffold}/ci/okl-verify.yml +4 -4
- org_knowledge_layer-0.2.0/src/okl/scaffold/claude/commands/seed-from-codebase.md +90 -0
- org_knowledge_layer-0.2.0/src/okl/scaffold/gates/check-diagram-pairs.sh +39 -0
- org_knowledge_layer-0.2.0/src/okl/scaffold/gates/check-links.sh +41 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/run-gates.sh +2 -0
- org_knowledge_layer-0.2.0/tests/test_okl.py +647 -0
- org_knowledge_layer-0.2.0/tests/test_scaffold.py +429 -0
- org_knowledge_layer-0.1.2/tests/test_okl.py +0 -343
- org_knowledge_layer-0.1.2/tests/test_scaffold.py +0 -168
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.claude/settings.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/pull_request_template.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.github/workflows/ci.yml +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/.gitignore +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/AGENTS.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/CLAUDE.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/LICENSE +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/SECURITY.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/ab-results-chart.png +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/ab-results-chart.svg +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/decisions/2026-07-17-flat-retrieval-until-scale.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/decisions/2026-07-21-subject-tags-controlled-vocabulary.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/okl-sixth-surface.excalidraw +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/okl-sixth-surface.svg +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/posts/01-memory-that-outlives-the-run.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/posts/02-dont-let-a-step-grade-itself.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/docs/posts/03-enforcement-or-good-intentions.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/README.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/ab_harness.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260829-2300.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260829-2315.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260830-0003.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/ab-20260830-0148.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/README.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/briefed-userpromptsubmit-lint.yml +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/control-lint.yml +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/hook.log +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/service-record-500.log +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/session-briefed-pretooluse.txt +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/session-briefed-userpromptsubmit.txt +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/results/e2e-20260830/session-control.txt +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/evals/tasks.jsonl +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-canon.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-decisions.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-defects.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/dotnet-review-surfaces.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/frontend-canon.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-deeptime-defects.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-defects.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-enforcement-defects.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/geospatial-eval-defects.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/rag-defects.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/seed/react-defects.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/__init__.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/__main__.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/bootstrap.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/drift.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/MANIFEST.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/ci/method-gates.yml +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/agents/architecture-reviewer.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/commands/check-rules.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/commands/feature-spec.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/rules/example-area.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/skills/RECOMMENDED-COMPANIONS.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/skills/encoding-loop/SKILL.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/claude/skills/verify-before-claiming/SKILL.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/evals/README.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/evals/cases.jsonl +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/evals/run_evals.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-canon-size.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-doc-orphans.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-retractions.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/gates/check-tombstones.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/hooks/hooks.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/hooks/stop-okl-encode.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/hooks/userpromptsubmit-okl-check.sh +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/plugin/plugin.json +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/README.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/architecture.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/messaging.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/performance-and-data.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/dotnet/rules/security.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/geospatial/README.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/geospatial/rules/geospatial-ml.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/README.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/rules/fastapi-backend.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/rules/project-structure.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/python-rag/rules/rag-pipeline.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/react/README.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/profiles/react/rules/frontend.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/registries/RETRACTIONS.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/registries/tombstones.txt +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/root/CLAUDE.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold/root/METHOD.md +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/scaffold_cmd.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/seed.py +0 -0
- {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.2.0}/src/okl/service.py +0 -0
- {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
|
-
#
|
|
31
|
-
#
|
|
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
|
|
33
|
+
if [ -f src/okl/cli.py ]; then
|
|
34
34
|
pip install -e .
|
|
35
35
|
else
|
|
36
|
-
pip install
|
|
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.
|
|
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
|
|
352
|
-
|
|
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
|
|
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
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
|
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
|
|
320
|
-
|
|
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
|
|
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
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
|
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
|
-
#
|
|
31
|
-
#
|
|
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
|
|
33
|
+
if [ -f src/okl/cli.py ]; then
|
|
34
34
|
pip install -e .
|
|
35
35
|
else
|
|
36
|
-
pip install
|
|
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
|