org-knowledge-layer 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. org_knowledge_layer-0.1.0/.claude/hooks/stop-okl-encode.sh +78 -0
  2. org_knowledge_layer-0.1.0/.claude/hooks/userpromptsubmit-okl-check.sh +68 -0
  3. org_knowledge_layer-0.1.0/.claude/settings.json +24 -0
  4. org_knowledge_layer-0.1.0/.claude/settings.local.json +79 -0
  5. org_knowledge_layer-0.1.0/.github/workflows/ci.yml +22 -0
  6. org_knowledge_layer-0.1.0/.github/workflows/okl-verify.yml +59 -0
  7. org_knowledge_layer-0.1.0/.gitignore +21 -0
  8. org_knowledge_layer-0.1.0/AGENTS.md +62 -0
  9. org_knowledge_layer-0.1.0/CLAUDE.md +62 -0
  10. org_knowledge_layer-0.1.0/LICENSE +21 -0
  11. org_knowledge_layer-0.1.0/PKG-INFO +475 -0
  12. org_knowledge_layer-0.1.0/README.md +443 -0
  13. org_knowledge_layer-0.1.0/ci/okl-verify.yml +59 -0
  14. org_knowledge_layer-0.1.0/docs/decisions/2026-07-17-flat-retrieval-until-scale.md +55 -0
  15. org_knowledge_layer-0.1.0/docs/decisions/2026-07-21-subject-tags-controlled-vocabulary.md +52 -0
  16. org_knowledge_layer-0.1.0/docs/okl-sixth-surface.excalidraw +3819 -0
  17. org_knowledge_layer-0.1.0/docs/okl-sixth-surface.svg +2 -0
  18. org_knowledge_layer-0.1.0/docs/posts/01-memory-that-outlives-the-run.md +43 -0
  19. org_knowledge_layer-0.1.0/docs/posts/02-dont-let-a-step-grade-itself.md +37 -0
  20. org_knowledge_layer-0.1.0/docs/posts/03-enforcement-or-good-intentions.md +33 -0
  21. org_knowledge_layer-0.1.0/evals/README.md +49 -0
  22. org_knowledge_layer-0.1.0/evals/REPORT.md +265 -0
  23. org_knowledge_layer-0.1.0/evals/ab_harness.py +196 -0
  24. org_knowledge_layer-0.1.0/evals/results/ab-20260829-2300.json +41 -0
  25. org_knowledge_layer-0.1.0/evals/results/ab-20260829-2315.json +137 -0
  26. org_knowledge_layer-0.1.0/evals/results/ab-20260830-0003.json +441 -0
  27. org_knowledge_layer-0.1.0/evals/results/ab-20260830-0148.json +441 -0
  28. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/README.md +23 -0
  29. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/briefed-userpromptsubmit-lint.yml +27 -0
  30. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/control-lint.yml +22 -0
  31. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/hook.log +3 -0
  32. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/service-record-500.log +47 -0
  33. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/session-briefed-pretooluse.txt +3 -0
  34. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/session-briefed-userpromptsubmit.txt +7 -0
  35. org_knowledge_layer-0.1.0/evals/results/e2e-20260830/session-control.txt +3 -0
  36. org_knowledge_layer-0.1.0/evals/tasks.jsonl +8 -0
  37. org_knowledge_layer-0.1.0/hooks/stop-okl-encode.sh +78 -0
  38. org_knowledge_layer-0.1.0/hooks/userpromptsubmit-okl-check.sh +68 -0
  39. org_knowledge_layer-0.1.0/pyproject.toml +49 -0
  40. org_knowledge_layer-0.1.0/seed/dotnet-canon.json +489 -0
  41. org_knowledge_layer-0.1.0/seed/dotnet-decisions.json +328 -0
  42. org_knowledge_layer-0.1.0/seed/dotnet-defects.json +133 -0
  43. org_knowledge_layer-0.1.0/seed/dotnet-review-surfaces.json +147 -0
  44. org_knowledge_layer-0.1.0/seed/frontend-canon.json +116 -0
  45. org_knowledge_layer-0.1.0/seed/geospatial-deeptime-defects.json +59 -0
  46. org_knowledge_layer-0.1.0/seed/geospatial-defects.json +154 -0
  47. org_knowledge_layer-0.1.0/seed/geospatial-enforcement-defects.json +121 -0
  48. org_knowledge_layer-0.1.0/seed/geospatial-eval-defects.json +25 -0
  49. org_knowledge_layer-0.1.0/seed/rag-defects.json +120 -0
  50. org_knowledge_layer-0.1.0/seed/react-defects.json +45 -0
  51. org_knowledge_layer-0.1.0/src/okl/__init__.py +12 -0
  52. org_knowledge_layer-0.1.0/src/okl/__main__.py +8 -0
  53. org_knowledge_layer-0.1.0/src/okl/bootstrap.py +83 -0
  54. org_knowledge_layer-0.1.0/src/okl/cli.py +484 -0
  55. org_knowledge_layer-0.1.0/src/okl/client.py +160 -0
  56. org_knowledge_layer-0.1.0/src/okl/core.py +223 -0
  57. org_knowledge_layer-0.1.0/src/okl/drift.py +119 -0
  58. org_knowledge_layer-0.1.0/src/okl/mcp_server.py +75 -0
  59. org_knowledge_layer-0.1.0/src/okl/scaffold/MANIFEST.md +59 -0
  60. org_knowledge_layer-0.1.0/src/okl/scaffold/ci/method-gates.yml +32 -0
  61. org_knowledge_layer-0.1.0/src/okl/scaffold/ci/okl-verify.yml +59 -0
  62. org_knowledge_layer-0.1.0/src/okl/scaffold/claude/agents/architecture-reviewer.md +41 -0
  63. org_knowledge_layer-0.1.0/src/okl/scaffold/claude/commands/check-rules.md +24 -0
  64. org_knowledge_layer-0.1.0/src/okl/scaffold/claude/commands/feature-spec.md +37 -0
  65. org_knowledge_layer-0.1.0/src/okl/scaffold/claude/rules/example-area.md +22 -0
  66. org_knowledge_layer-0.1.0/src/okl/scaffold/claude/skills/RECOMMENDED-COMPANIONS.md +40 -0
  67. org_knowledge_layer-0.1.0/src/okl/scaffold/claude/skills/encoding-loop/SKILL.md +48 -0
  68. org_knowledge_layer-0.1.0/src/okl/scaffold/claude/skills/verify-before-claiming/SKILL.md +56 -0
  69. org_knowledge_layer-0.1.0/src/okl/scaffold/evals/README.md +32 -0
  70. org_knowledge_layer-0.1.0/src/okl/scaffold/evals/cases.jsonl +1 -0
  71. org_knowledge_layer-0.1.0/src/okl/scaffold/evals/run_evals.py +109 -0
  72. org_knowledge_layer-0.1.0/src/okl/scaffold/gates/check-canon-size.sh +11 -0
  73. org_knowledge_layer-0.1.0/src/okl/scaffold/gates/check-doc-orphans.sh +19 -0
  74. org_knowledge_layer-0.1.0/src/okl/scaffold/gates/check-retractions.sh +22 -0
  75. org_knowledge_layer-0.1.0/src/okl/scaffold/gates/check-tombstones.sh +22 -0
  76. org_knowledge_layer-0.1.0/src/okl/scaffold/gates/run-gates.sh +31 -0
  77. org_knowledge_layer-0.1.0/src/okl/scaffold/hooks/hooks.json +16 -0
  78. org_knowledge_layer-0.1.0/src/okl/scaffold/hooks/stop-okl-encode.sh +78 -0
  79. org_knowledge_layer-0.1.0/src/okl/scaffold/hooks/userpromptsubmit-okl-check.sh +68 -0
  80. org_knowledge_layer-0.1.0/src/okl/scaffold/plugin/plugin.json +10 -0
  81. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/dotnet/README.md +12 -0
  82. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/dotnet/rules/architecture.md +55 -0
  83. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/dotnet/rules/messaging.md +31 -0
  84. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/dotnet/rules/performance-and-data.md +36 -0
  85. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/dotnet/rules/security.md +42 -0
  86. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/geospatial/README.md +6 -0
  87. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/geospatial/rules/geospatial-ml.md +38 -0
  88. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/python-rag/README.md +13 -0
  89. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/python-rag/rules/fastapi-backend.md +37 -0
  90. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/python-rag/rules/project-structure.md +28 -0
  91. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/python-rag/rules/rag-pipeline.md +73 -0
  92. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/react/README.md +18 -0
  93. org_knowledge_layer-0.1.0/src/okl/scaffold/profiles/react/rules/frontend.md +57 -0
  94. org_knowledge_layer-0.1.0/src/okl/scaffold/registries/RETRACTIONS.md +19 -0
  95. org_knowledge_layer-0.1.0/src/okl/scaffold/registries/tombstones.txt +7 -0
  96. org_knowledge_layer-0.1.0/src/okl/scaffold/root/CLAUDE.md +55 -0
  97. org_knowledge_layer-0.1.0/src/okl/scaffold/root/METHOD.md +64 -0
  98. org_knowledge_layer-0.1.0/src/okl/scaffold_cmd.py +110 -0
  99. org_knowledge_layer-0.1.0/src/okl/seed.py +55 -0
  100. org_knowledge_layer-0.1.0/src/okl/service.py +137 -0
  101. org_knowledge_layer-0.1.0/src/okl/store.py +432 -0
  102. org_knowledge_layer-0.1.0/tests/test_okl.py +343 -0
  103. org_knowledge_layer-0.1.0/tests/test_scaffold.py +168 -0
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # Stop hook — the write-side mechanical catch for the encoding loop.
3
+ #
4
+ # The read side (okl check) is enforced by the PreToolUse hook; nothing enforced the WRITE
5
+ # side, so a session could end without recording what it learned ("a merged fix without the
6
+ # rule is a half-finished job"). This hook asks the question at the ship moment, once:
7
+ # if the session changed the working tree, block the first stop (exit 2) with a prompt to
8
+ # either `okl record` the lesson or state that there is none. It never fires twice in one
9
+ # session (marker file) and never loops (stop_hook_active guard).
10
+ set -uo pipefail
11
+
12
+ # Same resolver as pretooluse-okl-check.sh (env → pinned config → PATH → python3 -m okl);
13
+ # the reminder is best-effort, so an unresolvable okl silently disables it rather than blocking.
14
+ resolve_okl() {
15
+ if [ -n "${OKL_BIN:-}" ]; then printf '%s' "$OKL_BIN"; return 0; fi
16
+ local d="$PWD"
17
+ while [ "$d" != "/" ]; do
18
+ if [ -f "$d/.okl/config.json" ]; then
19
+ local bin
20
+ bin=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("okl_bin") or "")' \
21
+ "$d/.okl/config.json" 2>/dev/null || true)
22
+ if [ -n "$bin" ]; then printf '%s' "$bin"; return 0; fi
23
+ break
24
+ fi
25
+ d=$(dirname "$d")
26
+ done
27
+ if command -v okl >/dev/null 2>&1; then printf '%s' "okl"; return 0; fi
28
+ if python3 -c "import okl" >/dev/null 2>&1; then printf '%s' "python3 -m okl"; return 0; fi
29
+ return 1
30
+ }
31
+
32
+ OKL=$(resolve_okl) || exit 0
33
+
34
+ payload=$(cat 2>/dev/null || true)
35
+ parsed=$(printf '%s' "$payload" | python3 -c '
36
+ import json, sys
37
+ try:
38
+ d = json.load(sys.stdin)
39
+ except Exception:
40
+ d = {}
41
+ print(d.get("session_id", ""))
42
+ print("true" if d.get("stop_hook_active") else "false")
43
+ ' 2>/dev/null) || parsed=""
44
+ session_id=$(printf '%s\n' "$parsed" | sed -n 1p)
45
+ stop_hook_active=$(printf '%s\n' "$parsed" | sed -n 2p)
46
+ [ -n "$stop_hook_active" ] || stop_hook_active="false"
47
+
48
+ # Never loop: if we already blocked once and Claude is stopping again, let it stop.
49
+ [ "${stop_hook_active}" = "true" ] && exit 0
50
+
51
+ # Only fire when the session plausibly did work: uncommitted changes, or a commit in the
52
+ # last hour (covers commit-then-stop sessions).
53
+ changed=0
54
+ if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
55
+ changed=1
56
+ elif last=$(git log -1 --format=%ct 2>/dev/null); then
57
+ now=$(date +%s)
58
+ [ $((now - last)) -lt 3600 ] && changed=1
59
+ fi
60
+ [ "$changed" = "1" ] || exit 0
61
+
62
+ # Once per session (fall back to a repo-scoped marker when no session id is provided).
63
+ marker="${TMPDIR:-/tmp}/okl-encode-reminder-${session_id:-$(pwd | cksum | cut -d' ' -f1)}"
64
+ [ -e "$marker" ] && exit 0
65
+ touch "$marker" 2>/dev/null || true
66
+
67
+ cat >&2 <<'MSG'
68
+ ENCODING LOOP — before this session ends: did it surface a lesson worth keeping?
69
+ A non-obvious failure mode, a rule discovered the hard way, a decision that shouldn't be
70
+ silently reversed? If yes, record it now (choose the scope deliberately — 'org' spreads
71
+ to every repo, 'repo' stays local — and tag the subject):
72
+
73
+ okl record --type Defect|Rule|Decision --scope org|repo --tags "<subjects>" \
74
+ --title "..." --symptom "..." --body "cause: ..." --fix "..."
75
+
76
+ If the session genuinely learned nothing durable, state that explicitly and finish.
77
+ MSG
78
+ exit 2
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+ # UserPromptSubmit hook — inject the org's relevant lessons into the model's context
3
+ # BEFORE it starts the task. This event is the only correct one for delivery: its stdout
4
+ # (exit 0) is added to Claude's context, and its stdin carries the actual prompt text, so
5
+ # the briefing is retrieved for the task the user really asked for.
6
+ #
7
+ # (The earlier PreToolUse version fired on every edit and printed the briefing to a channel
8
+ # the model never sees — PreToolUse exit-0 stdout goes to the transcript only. Discovered by
9
+ # an end-to-end test: hook fired, briefing correct, defect reproduced anyway.)
10
+ #
11
+ # FAILS CLOSED via exit 2: if the knowledge layer is unreachable, the prompt is blocked
12
+ # rather than letting the agent proceed blind. A check that reports "clean" while broken is
13
+ # worse than no check.
14
+ set -uo pipefail
15
+
16
+ # Resolve how to invoke okl (env → pinned config → PATH → python3 -m okl); hooks run in
17
+ # whatever environment the harness spawns, which often lacks the venv/pipx bin dir.
18
+ resolve_okl() {
19
+ if [ -n "${OKL_BIN:-}" ]; then printf '%s' "$OKL_BIN"; return 0; fi
20
+ local d="$PWD"
21
+ while [ "$d" != "/" ]; do
22
+ if [ -f "$d/.okl/config.json" ]; then
23
+ local bin
24
+ bin=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("okl_bin") or "")' \
25
+ "$d/.okl/config.json" 2>/dev/null || true)
26
+ if [ -n "$bin" ]; then printf '%s' "$bin"; return 0; fi
27
+ break
28
+ fi
29
+ d=$(dirname "$d")
30
+ done
31
+ if command -v okl >/dev/null 2>&1; then printf '%s' "okl"; return 0; fi
32
+ if python3 -c "import okl" >/dev/null 2>&1; then printf '%s' "python3 -m okl"; return 0; fi
33
+ return 1
34
+ }
35
+
36
+ if ! OKL=$(resolve_okl); then
37
+ [ "${OKL_OFFLINE:-0}" = "1" ] && exit 0
38
+ echo "okl NOT FOUND — blocking (a check that can't run must not pass as clean)." >&2
39
+ echo "Install it (pip install okl), set OKL_BIN, or re-run 'okl init' from a shell where it" >&2
40
+ echo "works (pins okl_bin into .okl/config.json). OKL_OFFLINE=1 proceeds without the layer." >&2
41
+ exit 2
42
+ fi
43
+
44
+ # The task is the prompt itself (stdin JSON: {"prompt": "..."}); OKL_TASK overrides;
45
+ # last-commit-message is only the fallback of last resort.
46
+ payload=$(cat 2>/dev/null || true)
47
+ prompt=$(printf '%s' "$payload" | python3 -c '
48
+ import json, sys
49
+ try:
50
+ print((json.load(sys.stdin).get("prompt") or "").strip()[:2000])
51
+ except Exception:
52
+ print("")
53
+ ' 2>/dev/null || true)
54
+ TASK="${OKL_TASK:-${prompt:-$(git log -1 --pretty=%s 2>/dev/null || echo 'general work')}}"
55
+
56
+ # $OKL unquoted on purpose: it may be a command + args ("python3 -m okl").
57
+ if out=$($OKL check --task "$TASK" --format agent 2>/dev/null); then
58
+ printf '%s\n' "$out" # stdout → the model's context
59
+ exit 0
60
+ fi
61
+
62
+ if [ "${OKL_OFFLINE:-0}" = "1" ]; then
63
+ echo "OKL offline (OKL_OFFLINE=1 acknowledged) — proceeding without the layer." >&2
64
+ exit 0
65
+ fi
66
+ echo "OKL UNREACHABLE — blocking this prompt. A check that reports 'clean' while broken is worse than no check." >&2
67
+ echo "Fix connectivity, or set OKL_OFFLINE=1 to explicitly proceed without the org knowledge layer." >&2
68
+ exit 2
@@ -0,0 +1,24 @@
1
+ {
2
+ "hooks": {
3
+ "Stop": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/stop-okl-encode.sh"
9
+ }
10
+ ]
11
+ }
12
+ ],
13
+ "UserPromptSubmit": [
14
+ {
15
+ "hooks": [
16
+ {
17
+ "type": "command",
18
+ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/userpromptsubmit-okl-check.sh"
19
+ }
20
+ ]
21
+ }
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(chmod +x /Users/joshuadell/Dev/okl/src/okl/scaffold/hooks/stop-okl-encode.sh)",
5
+ "Bash(python3 -m pytest tests/test_scaffold.py::test_encode_hook_loop_guard_and_fires_once -q)",
6
+ "Bash(python3 -c ' *)",
7
+ "Bash(python3 -m okl --help)",
8
+ "Bash(python3 -c \"import psycopg; print\\('psycopg', psycopg.__version__\\)\")",
9
+ "Bash(sqlite3 -column /Users/joshuadell/Dev/okl/.okl/okl.db \"SELECT COUNT\\(*\\) as nodes FROM node; SELECT COUNT\\(*\\) as edges FROM edge;\")",
10
+ "Bash(sqlite3 -column /Users/joshuadell/Dev/okl/.okl/okl.db \"SELECT substr\\(id,1,40\\) as id, type, substr\\(title,1,50\\) as title FROM node WHERE id NOT LIKE 'seed:novacraft-defects%' AND id NOT LIKE 'seed:quartzose%' AND id NOT LIKE 'seed:san-juan%' AND id NOT LIKE 'seed:react%' ORDER BY created_at;\")",
11
+ "Bash(sqlite3 -column /Users/joshuadell/Dev/okl/.okl/okl.db \"SELECT substr\\(id,1,50\\) as id, substr\\(title,1,45\\) as title FROM node WHERE id LIKE 'seed:novacraft-defects%' OR id LIKE 'seed:quartzose%' OR id LIKE 'seed:san-juan%' OR id LIKE 'seed:react%' ORDER BY id;\")",
12
+ "Bash(sqlite3 /Users/joshuadell/Dev/okl/.okl/okl.db \"SELECT COUNT\\(*\\) FROM node WHERE id LIKE 'seed:%';\")",
13
+ "Bash(sqlite3 /Users/joshuadell/Dev/okl/.okl/okl.db \"SELECT datetime\\(created_at/1000,'unixepoch','localtime'\\) as t, COUNT\\(*\\) FROM node WHERE id LIKE 'seed:san-juan-en%' OR id LIKE 'seed:san-juan-ev%' GROUP BY t;\")",
14
+ "Bash(git init *)",
15
+ "Bash(timeout 60 claude -p --model haiku)",
16
+ "Bash(claude -p --model haiku)",
17
+ "Bash(python3 evals/ab_harness.py --dry-run)",
18
+ "Bash(GENERATOR_CMD=\"claude -p --model sonnet\" JUDGE_CMD=\"claude -p --model sonnet\" python3 evals/ab_harness.py --dry-run)",
19
+ "Bash(python3 evals/ab_harness.py --limit 2)",
20
+ "Bash(python3 evals/ab_harness.py)",
21
+ "Bash(python3 evals/ab_harness.py --dry-run --samples 3)",
22
+ "Bash(python3 evals/ab_harness.py --samples 3)",
23
+ "Bash(git add *)",
24
+ "Bash(git -c core.hooksPath=/dev/null commit -m 'okl v0: the sixth surface — cross-repo knowledge layer with enforced loop *)",
25
+ "Bash(okl drift *)",
26
+ "Bash(okl verify *)",
27
+ "Bash(echo \"drift exit=$?\")",
28
+ "Bash(git -c core.hooksPath=/dev/null commit -m 'A/B receipt: 3-sample run \\(48 runs, 0 failures\\) — baseline 33% defect reproduction, briefed 4% *)",
29
+ "Bash(GENERATOR_CMD=\"claude -p --model haiku\" JUDGE_CMD=\"claude -p --model sonnet\" python3 evals/ab_harness.py --samples 3)",
30
+ "Bash(git -c core.hooksPath=/dev/null commit -m 'A/B receipt: haiku generator \\(sonnet judge\\) — briefed haiku 12% vs unbriefed sonnet 33% *)",
31
+ "Bash(git -c core.hooksPath=/dev/null commit -m 'Evaluation report: full method, all four runs, findings, threats to validity *)",
32
+ "Bash(git -c core.hooksPath=/dev/null commit -m 'Report: add '\\\\''How to read these numbers'\\\\'' — plain-language meaning, verbatim judge verdicts *)",
33
+ "Bash(python3 -c \"import fastapi, uvicorn; print\\('fastapi', fastapi.__version__, '| uvicorn', uvicorn.__version__\\)\")",
34
+ "Bash(OKL_DATABASE_URL=\"sqlite:////Users/joshuadell/Dev/okl/.okl/okl.db\" okl serve --port 8765)",
35
+ "Bash(curl -sf http://localhost:8765/health)",
36
+ "Bash(curl -s http://localhost:8765/health)",
37
+ "Bash(okl connect *)",
38
+ "Bash(OKL_TASK=\"Add a GitHub Actions job step that lints the project with ruff and fails the build on findings\" claude -p \"Add a GitHub Actions workflow at .github/workflows/lint.yml with a job step that lints this Python project with ruff and fails the build on findings. Write the file, then stop.\" --permission-mode acceptEdits --allowedTools \"Write,Edit,Read\")",
39
+ "Bash(claude -p \"Add a GitHub Actions workflow at .github/workflows/lint.yml with a job step that lints this Python project with ruff and fails the build on findings. Write the file, then stop.\" --permission-mode acceptEdits --allowedTools \"Write,Edit,Read\")",
40
+ "Bash(okl record --type Rule --scope org --tags \"method\" \\\\ *)",
41
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'E2E finding: briefing delivery moved to UserPromptSubmit — PreToolUse stdout never reaches the model *)",
42
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'README: full honesty on the crowded space — not novel, why built anyway, compose with mem0/Zep *)",
43
+ "Bash(curl -s -o /dev/null -w \"%{http_code}\" https://pypi.org/pypi/okl/json)",
44
+ "Bash(sqlite3 .okl/okl.db \"SELECT COUNT\\(*\\) FROM node;\")",
45
+ "Bash(timeout_ok=1 uv run python render_excalidraw.py /Users/joshuadell/Dev/okl/docs/okl-sixth-surface.excalidraw --svg -o /Users/joshuadell/Dev/okl/docs/okl-sixth-surface.svg)",
46
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'P0 canon + mirror enforcement + store sync \\(handoff work-down\\) *)",
47
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'Re-export sixth-surface SVG — render now matches the .excalidraw source *)",
48
+ "Bash(ls -la \"/Users/joshuadell/Dev/emeraldleaf-dev/src/assets/\" 2>/dev/null | grep -i \"okl\\\\|surface\"; cp docs/okl-sixth-surface.svg \"/Users/joshuadell/Dev/emeraldleaf-dev/src/assets/okl-sixth-surface.svg\" 2>/dev/null && echo \"site asset synced\")",
49
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'Genericize project identities across the public surface *)",
50
+ "Bash(git branch *)",
51
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'okl v0.1 — the Org Knowledge Layer *)",
52
+ "Bash(git -c core.hooksPath=/dev/null commit -qm 'Close the migration leftovers: AGENTS.md, dead-hook purge, stale diagram *)",
53
+ "Bash(python3 -m pip install -q build twine)",
54
+ "Bash(python3 -m build)",
55
+ "Bash(python3 -m twine check dist/*)",
56
+ "Bash(unzip -l dist/*.whl)",
57
+ "Bash(git -C /Users/joshuadell/Dev/okl add docs/posts)",
58
+ "Bash(git -C /Users/joshuadell/Dev/okl -c core.hooksPath=/dev/null commit -qm 'Post 3: correct the read-hook mechanics; add the dead-channel lesson *)",
59
+ "Bash(git -C /Users/joshuadell/Dev/okl push -q origin main)",
60
+ "Bash(git -C /Users/joshuadell/Dev/okl log --oneline)",
61
+ "Bash(python3 -m twine --version)",
62
+ "Bash(python3 -c \"import setuptools; print\\('setuptools', setuptools.__version__\\)\")",
63
+ "Bash(python3 -c \"import hatchling; print\\('hatchling', hatchling.__version__ if hasattr\\(hatchling,'__version__'\\) else 'n/a'\\)\")",
64
+ "Bash(python3 -m pip list)",
65
+ "Bash(rm -rf oklbuild)",
66
+ "Bash(python3 -m venv oklbuild)",
67
+ "Bash(./oklbuild/bin/pip install *)",
68
+ "Bash(./oklbuild/bin/pip show *)",
69
+ "Bash(/tmp/oklbuild/bin/python -m build --no-isolation)",
70
+ "Bash(unzip -p dist/*.whl \"*/entry_points.txt\")"
71
+ ],
72
+ "additionalDirectories": [
73
+ "/Users/joshuadell/Dev/okl/e2e/scratch-briefed/.okl",
74
+ "/Users/joshuadell/Dev/emeraldleaf-dev/src/pages",
75
+ "/Users/joshuadell/Dev/emeraldleaf-dev/src/assets",
76
+ "/Users/joshuadell/Dev/emeraldleaf-dev/src"
77
+ ]
78
+ }
79
+ }
@@ -0,0 +1,22 @@
1
+ # Repo CI — lints and tests okl itself. (okl-verify.yml is different: it demonstrates
2
+ # the product's own drift/method gates, the workflow consumers copy into their repos.)
3
+ name: ci
4
+ on:
5
+ push:
6
+ branches: [ "main" ]
7
+ pull_request:
8
+ branches: [ "main" ]
9
+ jobs:
10
+ lint-and-test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v5
14
+ - uses: actions/setup-python@v6
15
+ with:
16
+ python-version: "3.12"
17
+ - name: Install (dev extras)
18
+ run: pip install -e ".[dev]"
19
+ - name: Lint — ruff (config in pyproject.toml)
20
+ run: ruff check .
21
+ - name: Tests
22
+ run: pytest -q
@@ -0,0 +1,59 @@
1
+ # Installed by `okl init` into .github/workflows/okl-verify.yml (also stamped by `okl scaffold`).
2
+ #
3
+ # The knowledge layer's CI verifier — real checks, not placeholders:
4
+ # 1. `okl drift --gate` — fails the build when a rule's governed files changed after the
5
+ # rule was last verified (a stale rule is a rule nobody re-checked).
6
+ # 2. `gates/run-gates.sh` — the repo's mechanical method gates, when the scaffold is present.
7
+ #
8
+ # Shared-layer connection is optional: without OKL_SERVICE_URL the drift gate runs against
9
+ # the repo's local .okl store. Configure the secrets to verify against the org layer and to
10
+ # let gate scripts emit receipts (`okl link <gate_id> VERIFIED_ON <defect_id>`) — emit those
11
+ # from inside the gate that proved itself against real drift, where the ids are known.
12
+ name: okl-verify
13
+
14
+ on:
15
+ pull_request:
16
+ push:
17
+ branches: [main]
18
+
19
+ jobs:
20
+ okl-verify:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0 # drift needs history: it compares file mtimes/commits vs verified_at
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.13"
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).
32
+ run: |
33
+ if grep -q '^name = "okl"' pyproject.toml 2>/dev/null; then
34
+ pip install -e .
35
+ else
36
+ pip install okl
37
+ fi
38
+
39
+ - name: Connect to the shared layer (optional — skipped when secrets are unset)
40
+ env:
41
+ OKL_SERVICE_URL: ${{ secrets.OKL_SERVICE_URL }}
42
+ OKL_TOKEN: ${{ secrets.OKL_TOKEN }}
43
+ run: |
44
+ if [ -n "${OKL_SERVICE_URL:-}" ]; then
45
+ okl connect "$OKL_SERVICE_URL" --token "$OKL_TOKEN"
46
+ else
47
+ echo "no OKL_SERVICE_URL secret — verifying against the repo-local store"
48
+ fi
49
+
50
+ - name: Drift gate — rules whose governed code changed after last verification
51
+ run: okl drift --gate
52
+
53
+ - name: Method gates (when the scaffold kit is present)
54
+ run: |
55
+ if [ -x gates/run-gates.sh ]; then
56
+ bash gates/run-gates.sh
57
+ else
58
+ echo "no gates/run-gates.sh — method-kit gates not installed (okl scaffold adds them)"
59
+ fi
@@ -0,0 +1,21 @@
1
+ .DS_Store
2
+ __pycache__/
3
+ *.pyc
4
+ *.egg-info/
5
+ .okl/
6
+ okl.db
7
+ *.db
8
+ .pytest_cache/
9
+ dist/
10
+ build/
11
+ .venv/
12
+ okl-starter-kit.tar.gz
13
+ okl-bootstrap.json
14
+ # scratch test repos created by smoke tests
15
+ *_test/
16
+ method-demo/
17
+ e2e/
18
+
19
+
20
+ #Ignore vscode AI rules
21
+ .github/instructions/codacy.instructions.md
@@ -0,0 +1,62 @@
1
+ # okl — repo instructions
2
+
3
+ Read [evals/REPORT.md](evals/REPORT.md) before touching anything measurement-adjacent —
4
+ it is the most load-bearing document in the repo (method, results, threats to validity).
5
+
6
+ ## The loop is LIVE in this repo
7
+
8
+ The hooks fire on your own session: `UserPromptSubmit` injects the store's briefing into
9
+ your context before you start; `Stop` blocks your first stop to ask what was learned.
10
+ Answer it honestly — record with a deliberate scope (`org` spreads to every repo,
11
+ `repo` stays local) and tags from the closed vocabulary in `store.KNOWN_TAGS`. Growing
12
+ that vocabulary is an edit to the set plus a note in the tags ADR, never an ad-hoc tag.
13
+
14
+ - **Verification is evidence-based**: `okl verify <id> --run "<check>" --expect "<signal>"`.
15
+ Never re-record with `--verified` to clear drift — run the check.
16
+ - **After changing files a rule governs, `okl drift` goes red on purpose.** Re-verify
17
+ the affected nodes (their tests are usually the right `--run`) before finishing.
18
+ - The local store (`.okl/okl.db`, gitignored) should hold all 11 seed files plus
19
+ recorded nodes; `okl seed seed/` loads the `*-defects.json` set, while
20
+ `dotnet-{canon,decisions,review-surfaces}.json` and `frontend-canon.json` load explicitly.
21
+
22
+ ## Commands
23
+
24
+ ```bash
25
+ pytest -q # full suite; must be green before any commit
26
+ ruff check . # lint (config in pyproject.toml)
27
+ python3 evals/ab_harness.py --dry-run # eval harness; see evals/README.md before running live
28
+ okl drift # rules whose governed source changed after verification
29
+ ```
30
+
31
+ ## Rules that are enforced (and why)
32
+
33
+ - **Mirror files are byte-identical, test-enforced**: `ci/okl-verify.yml` ==
34
+ `.github/workflows/okl-verify.yml` == `src/okl/scaffold/ci/okl-verify.yml`, and
35
+ `hooks/*.sh` == `src/okl/scaffold/hooks/*.sh`. The scaffold copies are what consumers
36
+ receive; the repo copies are the dogfood. Edit ONE, copy to the others in the same
37
+ change — `tests/test_scaffold.py::test_mirror_files_identical` fails otherwise.
38
+ - **ruff `E702` is ignored deliberately** (semicolon one-liners): the tests use a
39
+ compact setup style throughout; re-enabling it is a repo-wide style decision, not a
40
+ cleanup.
41
+ - **Audits read the repo, not the working tree**: any gate/check that scans content
42
+ must scan `git ls-files` output (committed reality), never the dirty working tree —
43
+ scanning the tree makes an uncommitted edit pass or fail an audit that main would
44
+ answer differently. (Bit the .NET platform twice.)
45
+ - **Eval integrity**: the harness refuses judge==generator; never quote a number from a
46
+ run marked RESULTS NOT USABLE; every cited figure needs a committed receipt in
47
+ `evals/results/`.
48
+ - **The diagram and README move with the system**: they are drift-enrolled
49
+ (`n_b550ba9c5c8a`). `docs/okl-sixth-surface.svg` is a *render* of the `.excalidraw`
50
+ — if you edit the source, re-render or say loudly in the commit that the render is
51
+ stale.
52
+
53
+ ## Layout truth
54
+
55
+ `src/okl/` is the package (store/core/client/cli/service/mcp + scaffold templates);
56
+ `seed/` is the curated 161-node corpus (real lessons, real project names — deliberate);
57
+ `evals/` is the A/B harness and receipts; `docs/posts/` is the 3-part write-up;
58
+ `e2e/` (gitignored) holds scratch repos for end-to-end loop tests.
59
+
60
+ This file stays lean — always-on rules only. Everything conditionally relevant belongs
61
+ in the store, where the briefing selects it per task. If you're about to add a section
62
+ here, ask whether it should be an `okl record` instead. It usually should.
@@ -0,0 +1,62 @@
1
+ # okl — repo instructions
2
+
3
+ Read [evals/REPORT.md](evals/REPORT.md) before touching anything measurement-adjacent —
4
+ it is the most load-bearing document in the repo (method, results, threats to validity).
5
+
6
+ ## The loop is LIVE in this repo
7
+
8
+ The hooks fire on your own session: `UserPromptSubmit` injects the store's briefing into
9
+ your context before you start; `Stop` blocks your first stop to ask what was learned.
10
+ Answer it honestly — record with a deliberate scope (`org` spreads to every repo,
11
+ `repo` stays local) and tags from the closed vocabulary in `store.KNOWN_TAGS`. Growing
12
+ that vocabulary is an edit to the set plus a note in the tags ADR, never an ad-hoc tag.
13
+
14
+ - **Verification is evidence-based**: `okl verify <id> --run "<check>" --expect "<signal>"`.
15
+ Never re-record with `--verified` to clear drift — run the check.
16
+ - **After changing files a rule governs, `okl drift` goes red on purpose.** Re-verify
17
+ the affected nodes (their tests are usually the right `--run`) before finishing.
18
+ - The local store (`.okl/okl.db`, gitignored) should hold all 11 seed files plus
19
+ recorded nodes; `okl seed seed/` loads the `*-defects.json` set, while
20
+ `dotnet-{canon,decisions,review-surfaces}.json` and `frontend-canon.json` load explicitly.
21
+
22
+ ## Commands
23
+
24
+ ```bash
25
+ pytest -q # full suite; must be green before any commit
26
+ ruff check . # lint (config in pyproject.toml)
27
+ python3 evals/ab_harness.py --dry-run # eval harness; see evals/README.md before running live
28
+ okl drift # rules whose governed source changed after verification
29
+ ```
30
+
31
+ ## Rules that are enforced (and why)
32
+
33
+ - **Mirror files are byte-identical, test-enforced**: `ci/okl-verify.yml` ==
34
+ `.github/workflows/okl-verify.yml` == `src/okl/scaffold/ci/okl-verify.yml`, and
35
+ `hooks/*.sh` == `src/okl/scaffold/hooks/*.sh`. The scaffold copies are what consumers
36
+ receive; the repo copies are the dogfood. Edit ONE, copy to the others in the same
37
+ change — `tests/test_scaffold.py::test_mirror_files_identical` fails otherwise.
38
+ - **ruff `E702` is ignored deliberately** (semicolon one-liners): the tests use a
39
+ compact setup style throughout; re-enabling it is a repo-wide style decision, not a
40
+ cleanup.
41
+ - **Audits read the repo, not the working tree**: any gate/check that scans content
42
+ must scan `git ls-files` output (committed reality), never the dirty working tree —
43
+ scanning the tree makes an uncommitted edit pass or fail an audit that main would
44
+ answer differently. (Bit the .NET platform twice.)
45
+ - **Eval integrity**: the harness refuses judge==generator; never quote a number from a
46
+ run marked RESULTS NOT USABLE; every cited figure needs a committed receipt in
47
+ `evals/results/`.
48
+ - **The diagram and README move with the system**: they are drift-enrolled
49
+ (`n_b550ba9c5c8a`). `docs/okl-sixth-surface.svg` is a *render* of the `.excalidraw`
50
+ — if you edit the source, re-render or say loudly in the commit that the render is
51
+ stale.
52
+
53
+ ## Layout truth
54
+
55
+ `src/okl/` is the package (store/core/client/cli/service/mcp + scaffold templates);
56
+ `seed/` is the curated 161-node corpus (real lessons, real project names — deliberate);
57
+ `evals/` is the A/B harness and receipts; `docs/posts/` is the 3-part write-up;
58
+ `e2e/` (gitignored) holds scratch repos for end-to-end loop tests.
59
+
60
+ This file stays lean — always-on rules only. Everything conditionally relevant belongs
61
+ in the store, where the briefing selects it per task. If you're about to add a section
62
+ here, ask whether it should be an `okl record` instead. It usually should.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joshua Dell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.