org-knowledge-layer 0.1.2__tar.gz → 0.1.3__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 (110) hide show
  1. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.claude/settings.local.json +8 -1
  2. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/PKG-INFO +24 -1
  3. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/README.md +23 -0
  4. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/pyproject.toml +1 -1
  5. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/cli.py +25 -1
  6. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/tests/test_okl.py +22 -0
  7. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.claude/hooks/stop-okl-encode.sh +0 -0
  8. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.claude/hooks/userpromptsubmit-okl-check.sh +0 -0
  9. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.claude/settings.json +0 -0
  10. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  11. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  12. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.github/pull_request_template.md +0 -0
  13. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.github/workflows/ci.yml +0 -0
  14. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.github/workflows/okl-verify.yml +0 -0
  15. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/.gitignore +0 -0
  16. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/AGENTS.md +0 -0
  17. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/CLAUDE.md +0 -0
  18. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/CONTRIBUTING.md +0 -0
  19. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/LICENSE +0 -0
  20. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/SECURITY.md +0 -0
  21. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/ci/okl-verify.yml +0 -0
  22. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/ab-results-chart.png +0 -0
  23. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/ab-results-chart.svg +0 -0
  24. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/decisions/2026-07-17-flat-retrieval-until-scale.md +0 -0
  25. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/decisions/2026-07-21-subject-tags-controlled-vocabulary.md +0 -0
  26. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/okl-sixth-surface.excalidraw +0 -0
  27. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/okl-sixth-surface.svg +0 -0
  28. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/posts/01-memory-that-outlives-the-run.md +0 -0
  29. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/posts/02-dont-let-a-step-grade-itself.md +0 -0
  30. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/docs/posts/03-enforcement-or-good-intentions.md +0 -0
  31. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/README.md +0 -0
  32. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/REPORT.md +0 -0
  33. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/ab_harness.py +0 -0
  34. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/ab-20260829-2300.json +0 -0
  35. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/ab-20260829-2315.json +0 -0
  36. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/ab-20260830-0003.json +0 -0
  37. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/ab-20260830-0148.json +0 -0
  38. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/README.md +0 -0
  39. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/briefed-userpromptsubmit-lint.yml +0 -0
  40. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/control-lint.yml +0 -0
  41. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/hook.log +0 -0
  42. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/service-record-500.log +0 -0
  43. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/session-briefed-pretooluse.txt +0 -0
  44. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/session-briefed-userpromptsubmit.txt +0 -0
  45. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/results/e2e-20260830/session-control.txt +0 -0
  46. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/evals/tasks.jsonl +0 -0
  47. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/hooks/stop-okl-encode.sh +0 -0
  48. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/hooks/userpromptsubmit-okl-check.sh +0 -0
  49. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/dotnet-canon.json +0 -0
  50. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/dotnet-decisions.json +0 -0
  51. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/dotnet-defects.json +0 -0
  52. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/dotnet-review-surfaces.json +0 -0
  53. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/frontend-canon.json +0 -0
  54. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/geospatial-deeptime-defects.json +0 -0
  55. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/geospatial-defects.json +0 -0
  56. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/geospatial-enforcement-defects.json +0 -0
  57. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/geospatial-eval-defects.json +0 -0
  58. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/rag-defects.json +0 -0
  59. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/seed/react-defects.json +0 -0
  60. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/__init__.py +0 -0
  61. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/__main__.py +0 -0
  62. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/bootstrap.py +0 -0
  63. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/client.py +0 -0
  64. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/core.py +0 -0
  65. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/drift.py +0 -0
  66. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/mcp_server.py +0 -0
  67. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/MANIFEST.md +0 -0
  68. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/ci/method-gates.yml +0 -0
  69. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/ci/okl-verify.yml +0 -0
  70. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/claude/agents/architecture-reviewer.md +0 -0
  71. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/claude/commands/check-rules.md +0 -0
  72. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/claude/commands/feature-spec.md +0 -0
  73. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/claude/rules/example-area.md +0 -0
  74. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/claude/skills/RECOMMENDED-COMPANIONS.md +0 -0
  75. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/claude/skills/encoding-loop/SKILL.md +0 -0
  76. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/claude/skills/verify-before-claiming/SKILL.md +0 -0
  77. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/evals/README.md +0 -0
  78. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/evals/cases.jsonl +0 -0
  79. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/evals/run_evals.py +0 -0
  80. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/gates/check-canon-size.sh +0 -0
  81. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/gates/check-doc-orphans.sh +0 -0
  82. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/gates/check-retractions.sh +0 -0
  83. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/gates/check-tombstones.sh +0 -0
  84. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/gates/run-gates.sh +0 -0
  85. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/hooks/hooks.json +0 -0
  86. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/hooks/stop-okl-encode.sh +0 -0
  87. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/hooks/userpromptsubmit-okl-check.sh +0 -0
  88. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/plugin/plugin.json +0 -0
  89. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/dotnet/README.md +0 -0
  90. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/dotnet/rules/architecture.md +0 -0
  91. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/dotnet/rules/messaging.md +0 -0
  92. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/dotnet/rules/performance-and-data.md +0 -0
  93. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/dotnet/rules/security.md +0 -0
  94. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/geospatial/README.md +0 -0
  95. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/geospatial/rules/geospatial-ml.md +0 -0
  96. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/python-rag/README.md +0 -0
  97. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/python-rag/rules/fastapi-backend.md +0 -0
  98. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/python-rag/rules/project-structure.md +0 -0
  99. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/python-rag/rules/rag-pipeline.md +0 -0
  100. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/react/README.md +0 -0
  101. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/profiles/react/rules/frontend.md +0 -0
  102. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/registries/RETRACTIONS.md +0 -0
  103. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/registries/tombstones.txt +0 -0
  104. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/root/CLAUDE.md +0 -0
  105. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold/root/METHOD.md +0 -0
  106. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/scaffold_cmd.py +0 -0
  107. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/seed.py +0 -0
  108. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/service.py +0 -0
  109. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/src/okl/store.py +0 -0
  110. {org_knowledge_layer-0.1.2 → org_knowledge_layer-0.1.3}/tests/test_scaffold.py +0 -0
@@ -90,7 +90,14 @@
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 *)"
94
101
  ],
95
102
  "additionalDirectories": [
96
103
  "/Users/joshuadell/Dev/okl/e2e/scratch-briefed/.okl",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: org-knowledge-layer
3
- Version: 0.1.2
3
+ Version: 0.1.3
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
@@ -246,6 +246,29 @@ okl init --repo my-repo # writes .okl/config.json; installs the pre-task
246
246
  okl connect https://okl.myorg.dev # optional: point at the shared service (else local file)
247
247
  ```
248
248
 
249
+ ### What `okl init` writes to your repo
250
+
251
+ Run `okl init --dry-run` first: it lists every path and writes nothing. In full, `init`
252
+ touches only the current directory, and only these:
253
+
254
+ | Path | What it is |
255
+ |---|---|
256
+ | `.okl/config.json` | repo name, subject interests, and the path to your `okl` binary |
257
+ | `.claude/hooks/userpromptsubmit-okl-check.sh` | **executable**; runs when you submit a task, injects the briefing |
258
+ | `.claude/hooks/stop-okl-encode.sh` | **executable**; runs at session end, asks what was learned |
259
+ | `.claude/settings.json` | registers those two hooks (merged in place; your existing keys are preserved) |
260
+ | `.mcp.json` | registers the okl MCP server — only when the `mcp` extra is installed |
261
+ | `.github/workflows/okl-verify.yml` | **a CI workflow** running the drift gate on pull requests |
262
+
263
+ Two of those deserve a second look before you run it: the hooks are shell scripts that
264
+ execute automatically during agent sessions (the check hook can *block* a task when the
265
+ store is unreachable — that is the fail-closed design), and the CI workflow will run in
266
+ your Actions. Both are plain text you can read first, in
267
+ [`src/okl/scaffold/hooks/`](src/okl/scaffold/hooks/) and
268
+ [`src/okl/scaffold/ci/`](src/okl/scaffold/ci/). Nothing executes at install time; nothing
269
+ is written outside the directory you run `init` in; nothing contacts a network unless you
270
+ run `okl connect` and point it somewhere yourself.
271
+
249
272
  `init` writes `.okl/config.json`. If the repo uses a coding agent with a `.claude/`
250
273
  directory, it also installs two hooks: a `UserPromptSubmit` hook that runs `check` on
251
274
  the prompt you actually typed and puts the briefing into the model's context (the
@@ -214,6 +214,29 @@ okl init --repo my-repo # writes .okl/config.json; installs the pre-task
214
214
  okl connect https://okl.myorg.dev # optional: point at the shared service (else local file)
215
215
  ```
216
216
 
217
+ ### What `okl init` writes to your repo
218
+
219
+ Run `okl init --dry-run` first: it lists every path and writes nothing. In full, `init`
220
+ touches only the current directory, and only these:
221
+
222
+ | Path | What it is |
223
+ |---|---|
224
+ | `.okl/config.json` | repo name, subject interests, and the path to your `okl` binary |
225
+ | `.claude/hooks/userpromptsubmit-okl-check.sh` | **executable**; runs when you submit a task, injects the briefing |
226
+ | `.claude/hooks/stop-okl-encode.sh` | **executable**; runs at session end, asks what was learned |
227
+ | `.claude/settings.json` | registers those two hooks (merged in place; your existing keys are preserved) |
228
+ | `.mcp.json` | registers the okl MCP server — only when the `mcp` extra is installed |
229
+ | `.github/workflows/okl-verify.yml` | **a CI workflow** running the drift gate on pull requests |
230
+
231
+ Two of those deserve a second look before you run it: the hooks are shell scripts that
232
+ execute automatically during agent sessions (the check hook can *block* a task when the
233
+ store is unreachable — that is the fail-closed design), and the CI workflow will run in
234
+ your Actions. Both are plain text you can read first, in
235
+ [`src/okl/scaffold/hooks/`](src/okl/scaffold/hooks/) and
236
+ [`src/okl/scaffold/ci/`](src/okl/scaffold/ci/). Nothing executes at install time; nothing
237
+ is written outside the directory you run `init` in; nothing contacts a network unless you
238
+ run `okl connect` and point it somewhere yourself.
239
+
217
240
  `init` writes `.okl/config.json`. If the repo uses a coding agent with a `.claude/`
218
241
  directory, it also installs two hooks: a `UserPromptSubmit` hook that runs `check` on
219
242
  the prompt you actually typed and puts the briefing into the model's context (the
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  # Distribution name only. The CLI command, the import package, and the repo are all `okl`;
7
7
  # PyPI rejects `okl` as too similar to the existing `oki` (l/i are treated as confusable).
8
8
  name = "org-knowledge-layer"
9
- version = "0.1.2"
9
+ version = "0.1.3"
10
10
  description = "Org Knowledge Layer — an installable sixth surface that carries encoded engineering lessons across repos."
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.10"
@@ -54,8 +54,30 @@ def _merge_hook_settings(claude: Path) -> bool:
54
54
 
55
55
  def cmd_init(args) -> int:
56
56
  """Wire the current repo so the loop runs without manual follow-up steps:
57
- config, hooks (installed AND registered), CI verifier, MCP registration."""
57
+ config, hooks (installed AND registered), CI verifier, MCP registration.
58
+
59
+ `--dry-run` prints every path it would touch and writes nothing. This command
60
+ installs executable hooks and a CI workflow into your repo; you should be able
61
+ to see that list before it happens."""
58
62
  import shutil
63
+ if getattr(args, "dry_run", False):
64
+ repo = args.repo or Path.cwd().name
65
+ print(f"DRY RUN — nothing will be written. `okl init --repo {repo}` would:\n")
66
+ print(" .okl/config.json repo name, interests, and the path to this okl")
67
+ if Path(".claude").exists():
68
+ print(" .claude/hooks/userpromptsubmit-okl-check.sh executable; runs when you submit a task")
69
+ print(" .claude/hooks/stop-okl-encode.sh executable; runs when a session ends")
70
+ print(" .claude/settings.json registers those two hooks (merged, existing keys kept)")
71
+ print(" .mcp.json registers the okl MCP server (only if okl[mcp] is installed)")
72
+ else:
73
+ print(" (no .claude/ directory here, so no hooks would be installed)")
74
+ if Path(".git").exists():
75
+ print(" .github/workflows/okl-verify.yml a CI workflow running the drift gate on PRs")
76
+ else:
77
+ print(" (not a git repository, so no CI workflow and no drift gate)")
78
+ print("\nNothing is written outside this directory. Read the hooks before you register them:")
79
+ print(" https://github.com/emeraldleaf/okl/blob/main/src/okl/scaffold/hooks/")
80
+ return 0
59
81
  repo = args.repo or Path.cwd().name
60
82
  cfg = load_config()
61
83
  cfg["repo"] = repo
@@ -385,6 +407,8 @@ def build_parser() -> argparse.ArgumentParser:
385
407
  pi.add_argument("--repo"); pi.add_argument("--service")
386
408
  pi.add_argument("--interests", help="comma-sep subject tags this repo cares about "
387
409
  "(filters org-scope lessons in `check`; see store.KNOWN_TAGS)")
410
+ pi.add_argument("--dry-run", dest="dry_run", action="store_true",
411
+ help="list every file init would write or modify, and write nothing")
388
412
  pi.set_defaults(func=cmd_init)
389
413
 
390
414
  pc = sub.add_parser("connect", help="point this repo at a shared OKL service URL")
@@ -341,3 +341,25 @@ def test_seed_node_without_repo_stays_unattributed(store, tmp_path, capsys):
341
341
  (n,) = store.all_nodes()
342
342
  assert n.repo is None, "seed node without repo must not inherit the seeding repo"
343
343
  assert "no 'repo'" in capsys.readouterr().err
344
+
345
+ def test_init_dry_run_writes_nothing(tmp_path, monkeypatch, capsys):
346
+ """--dry-run must list what init would touch and leave the filesystem alone.
347
+ Anyone about to let a package install executable hooks and a CI workflow into
348
+ their repo should be able to see the list first."""
349
+ import argparse
350
+
351
+ from okl.cli import cmd_init
352
+ monkeypatch.chdir(tmp_path)
353
+ (tmp_path / ".claude").mkdir()
354
+ (tmp_path / ".git").mkdir()
355
+ before = sorted(p.name for p in tmp_path.iterdir())
356
+ args = argparse.Namespace(repo="demo", service=None, interests=None, dry_run=True)
357
+ assert cmd_init(args) == 0
358
+ out = capsys.readouterr().out
359
+ assert "DRY RUN" in out
360
+ for expected in ("hooks/userpromptsubmit-okl-check.sh", "settings.json",
361
+ ".github/workflows/okl-verify.yml", ".okl/config.json"):
362
+ assert expected in out, f"dry run must disclose {expected}"
363
+ assert sorted(p.name for p in tmp_path.iterdir()) == before, "dry run wrote something"
364
+ assert not (tmp_path / ".okl").exists()
365
+ assert not (tmp_path / ".github").exists()