knowop 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 (150) hide show
  1. knowop-0.1.0/.gitignore +140 -0
  2. knowop-0.1.0/.pre-commit-config.yaml +468 -0
  3. knowop-0.1.0/AI_POLICY.md +13 -0
  4. knowop-0.1.0/CHANGELOG.md +26 -0
  5. knowop-0.1.0/CODE_OF_CONDUCT.md +25 -0
  6. knowop-0.1.0/CONTRIBUTING.md +45 -0
  7. knowop-0.1.0/LICENSE +201 -0
  8. knowop-0.1.0/PKG-INFO +153 -0
  9. knowop-0.1.0/README.md +117 -0
  10. knowop-0.1.0/RELEASING.md +80 -0
  11. knowop-0.1.0/SECURITY.md +34 -0
  12. knowop-0.1.0/conftest.py +19 -0
  13. knowop-0.1.0/knowop/__init__.py +1 -0
  14. knowop-0.1.0/knowop/__main__.py +17 -0
  15. knowop-0.1.0/knowop/agent/__init__.py +14 -0
  16. knowop-0.1.0/knowop/agent/__main__.py +19 -0
  17. knowop-0.1.0/knowop/agent/box_hook/__init__.py +4 -0
  18. knowop-0.1.0/knowop/agent/box_hook/__main__.py +21 -0
  19. knowop-0.1.0/knowop/agent/box_hook/entry.py +14 -0
  20. knowop-0.1.0/knowop/agent/box_hook/entry_test.py +27 -0
  21. knowop-0.1.0/knowop/agent/box_hook/hook.py +414 -0
  22. knowop-0.1.0/knowop/agent/box_hook/hook_test.py +535 -0
  23. knowop-0.1.0/knowop/agent/claude_stream.py +756 -0
  24. knowop-0.1.0/knowop/agent/claude_stream_test.py +1573 -0
  25. knowop-0.1.0/knowop/agent/cli.py +184 -0
  26. knowop-0.1.0/knowop/agent/cli_test.py +380 -0
  27. knowop-0.1.0/knowop/agent/codex.py +19 -0
  28. knowop-0.1.0/knowop/agent/codex_app.py +837 -0
  29. knowop-0.1.0/knowop/agent/codex_app_fake.py +91 -0
  30. knowop-0.1.0/knowop/agent/codex_app_fake_test.py +119 -0
  31. knowop-0.1.0/knowop/agent/codex_app_test.py +1488 -0
  32. knowop-0.1.0/knowop/agent/commands.py +194 -0
  33. knowop-0.1.0/knowop/agent/commands_test.py +235 -0
  34. knowop-0.1.0/knowop/agent/custom_types.py +57 -0
  35. knowop-0.1.0/knowop/agent/detach.py +747 -0
  36. knowop-0.1.0/knowop/agent/detach_test.py +1542 -0
  37. knowop-0.1.0/knowop/agent/entrypoint_test.py +84 -0
  38. knowop-0.1.0/knowop/agent/errors.py +39 -0
  39. knowop-0.1.0/knowop/agent/headless.py +708 -0
  40. knowop-0.1.0/knowop/agent/headless_test.py +1074 -0
  41. knowop-0.1.0/knowop/agent/inbound.py +282 -0
  42. knowop-0.1.0/knowop/agent/inbound_test.py +327 -0
  43. knowop-0.1.0/knowop/agent/materialize.py +689 -0
  44. knowop-0.1.0/knowop/agent/materialize_test.py +933 -0
  45. knowop-0.1.0/knowop/agent/placement.py +107 -0
  46. knowop-0.1.0/knowop/agent/placement_test.py +140 -0
  47. knowop-0.1.0/knowop/agent/program.py +12 -0
  48. knowop-0.1.0/knowop/agent/prompt_bridge.py +601 -0
  49. knowop-0.1.0/knowop/agent/prompt_bridge_test.py +997 -0
  50. knowop-0.1.0/knowop/agent/resume.py +347 -0
  51. knowop-0.1.0/knowop/agent/resume_test.py +1145 -0
  52. knowop-0.1.0/knowop/agent/session.py +3851 -0
  53. knowop-0.1.0/knowop/agent/session_capture_test.py +197 -0
  54. knowop-0.1.0/knowop/agent/session_test.py +10204 -0
  55. knowop-0.1.0/knowop/agent/sink.py +1440 -0
  56. knowop-0.1.0/knowop/agent/sink_test.py +2990 -0
  57. knowop-0.1.0/knowop/agent/slash.py +202 -0
  58. knowop-0.1.0/knowop/agent/slash_test.py +150 -0
  59. knowop-0.1.0/knowop/agent/testdata/seams/goalCommand.json +30 -0
  60. knowop-0.1.0/knowop/agent/testdata/seams/trustAnswer.json +10 -0
  61. knowop-0.1.0/knowop/agent/testdata/seams/trustCard.json +36 -0
  62. knowop-0.1.0/knowop/agent/testdata/sessions/claude_main.jsonl +28 -0
  63. knowop-0.1.0/knowop/agent/testdata/sessions/claude_sidechain.jsonl +4 -0
  64. knowop-0.1.0/knowop/agent/testdata/sessions/codex_main.jsonl +16 -0
  65. knowop-0.1.0/knowop/agent/truncate.py +273 -0
  66. knowop-0.1.0/knowop/agent/truncate_test.py +310 -0
  67. knowop-0.1.0/knowop/agent/trust.py +411 -0
  68. knowop-0.1.0/knowop/agent/trust_test.py +575 -0
  69. knowop-0.1.0/knowop/agent/worktree_diff.py +461 -0
  70. knowop-0.1.0/knowop/agent/worktree_diff_cli_test.py +109 -0
  71. knowop-0.1.0/knowop/agent/worktree_diff_test.py +479 -0
  72. knowop-0.1.0/knowop/cli.py +524 -0
  73. knowop-0.1.0/knowop/cli_test.py +1161 -0
  74. knowop-0.1.0/knowop/import_boundary_test.py +108 -0
  75. knowop-0.1.0/knowop/jobs/__init__.py +1 -0
  76. knowop-0.1.0/knowop/jobs/__main__.py +17 -0
  77. knowop-0.1.0/knowop/jobs/cli.py +87 -0
  78. knowop-0.1.0/knowop/jobs/cli_test.py +249 -0
  79. knowop-0.1.0/knowop/jobs/entrypoint_test.py +75 -0
  80. knowop-0.1.0/knowop/jobs/job.py +620 -0
  81. knowop-0.1.0/knowop/jobs/job_fetch.py +246 -0
  82. knowop-0.1.0/knowop/jobs/job_fetch_test.py +472 -0
  83. knowop-0.1.0/knowop/jobs/job_records.py +114 -0
  84. knowop-0.1.0/knowop/jobs/job_records_test.py +312 -0
  85. knowop-0.1.0/knowop/jobs/job_source.py +356 -0
  86. knowop-0.1.0/knowop/jobs/job_source_test.py +716 -0
  87. knowop-0.1.0/knowop/jobs/job_ssh.py +423 -0
  88. knowop-0.1.0/knowop/jobs/job_ssh_test.py +533 -0
  89. knowop-0.1.0/knowop/jobs/job_test.py +1342 -0
  90. knowop-0.1.0/knowop/lib/__init__.py +1 -0
  91. knowop-0.1.0/knowop/lib/testing/__init__.py +15 -0
  92. knowop-0.1.0/knowop/lib/testing/posix.py +162 -0
  93. knowop-0.1.0/knowop/lib/testing/posix_test.py +143 -0
  94. knowop-0.1.0/knowop/lib/testing/resources.py +918 -0
  95. knowop-0.1.0/knowop/lib/testing/resources_test.py +863 -0
  96. knowop-0.1.0/knowop/lib/testing/runner.py +39 -0
  97. knowop-0.1.0/knowop/lib/testing/runner_test.py +39 -0
  98. knowop-0.1.0/knowop/machines.py +364 -0
  99. knowop-0.1.0/knowop/machines_test.py +566 -0
  100. knowop-0.1.0/knowop/shell/__init__.py +1 -0
  101. knowop-0.1.0/knowop/shell/exec_command.py +359 -0
  102. knowop-0.1.0/knowop/shell/exec_command_test.py +181 -0
  103. knowop-0.1.0/knowop/shell/exec_host.py +296 -0
  104. knowop-0.1.0/knowop/shell/exec_host_test.py +871 -0
  105. knowop-0.1.0/knowop/shell/exec_stream.py +101 -0
  106. knowop-0.1.0/knowop/shell/exec_stream_test.py +86 -0
  107. knowop-0.1.0/knowop/shell/machine_host.py +371 -0
  108. knowop-0.1.0/knowop/shell/machine_host_test.py +851 -0
  109. knowop-0.1.0/knowop/shell/serve.py +278 -0
  110. knowop-0.1.0/knowop/shell/serve_test.py +730 -0
  111. knowop-0.1.0/knowop/shell/terminal_direct.py +392 -0
  112. knowop-0.1.0/knowop/shell/terminal_direct_aiortc.py +115 -0
  113. knowop-0.1.0/knowop/shell/terminal_direct_aiortc_test.py +198 -0
  114. knowop-0.1.0/knowop/shell/terminal_direct_test.py +589 -0
  115. knowop-0.1.0/knowop/shell/terminal_host.py +558 -0
  116. knowop-0.1.0/knowop/shell/terminal_host_test.py +1302 -0
  117. knowop-0.1.0/knowop/shell/trax_context.py +35 -0
  118. knowop-0.1.0/knowop/shell/trax_context_test.py +49 -0
  119. knowop-0.1.0/knowop/skills/README.md +12 -0
  120. knowop-0.1.0/knowop/skills/agent/SKILL.md +103 -0
  121. knowop-0.1.0/knowop/skills/jobs/SKILL.md +69 -0
  122. knowop-0.1.0/knowop/skills/shell/SKILL.md +97 -0
  123. knowop-0.1.0/pyproject.toml +722 -0
  124. knowop-0.1.0/tools/__init__.py +1 -0
  125. knowop-0.1.0/tools/gate/__init__.py +1 -0
  126. knowop-0.1.0/tools/gate/__main__.py +17 -0
  127. knowop-0.1.0/tools/gate/fakes.py +155 -0
  128. knowop-0.1.0/tools/gate/fakes_test.py +105 -0
  129. knowop-0.1.0/tools/gate/gate.py +364 -0
  130. knowop-0.1.0/tools/gate/gate_test.py +283 -0
  131. knowop-0.1.0/tools/gate/spool.py +93 -0
  132. knowop-0.1.0/tools/gate/spool_test.py +87 -0
  133. knowop-0.1.0/tools/gate/worker_count.py +304 -0
  134. knowop-0.1.0/tools/gate/worker_count_test.py +384 -0
  135. knowop-0.1.0/tools/testing/__init__.py +1 -0
  136. knowop-0.1.0/tools/testing/__main__.py +17 -0
  137. knowop-0.1.0/tools/testing/coverage_summary.py +85 -0
  138. knowop-0.1.0/tools/testing/coverage_summary_test.py +143 -0
  139. knowop-0.1.0/tools/testing/testing.py +296 -0
  140. knowop-0.1.0/tools/testing/testing_test.py +549 -0
  141. knowop-0.1.0/tools/testing/tiers.py +89 -0
  142. knowop-0.1.0/tools/testing/tiers_test.py +62 -0
  143. knowop-0.1.0/tools/typecheck/__init__.py +1 -0
  144. knowop-0.1.0/tools/typecheck/__main__.py +17 -0
  145. knowop-0.1.0/tools/typecheck/scope.py +61 -0
  146. knowop-0.1.0/tools/typecheck/scope_test.py +71 -0
  147. knowop-0.1.0/tools/typecheck/typecheck.py +179 -0
  148. knowop-0.1.0/tools/typecheck/typecheck_test.py +281 -0
  149. knowop-0.1.0/typings/.gitkeep +0 -0
  150. knowop-0.1.0/uv.lock +1566 -0
@@ -0,0 +1,140 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ # lib/
18
+ # lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ .testmondata
53
+ # Covers the SQLite sidecars testmon leaves behind (-journal, -shm, -wal).
54
+ .testmondata-*
55
+ cover/
56
+
57
+ # Translations
58
+ *.mo
59
+ *.pot
60
+
61
+ # Sphinx documentation
62
+ docs/_build/
63
+
64
+ # PyBuilder
65
+ .pybuilder/
66
+ target/
67
+
68
+ # Jupyter Notebook
69
+ .ipynb_checkpoints
70
+
71
+ # IPython
72
+ profile_default/
73
+ ipython_config.py
74
+
75
+ # pyenv
76
+ .python-version
77
+
78
+ # pipenv
79
+ Pipfile.lock
80
+
81
+ # poetry
82
+ poetry.lock
83
+
84
+ # pdm
85
+ .pdm.toml
86
+ .pdm-python
87
+ .pdm-build/
88
+
89
+ # PEP 582
90
+ __pypackages__/
91
+
92
+ # Celery stuff
93
+ celerybeat-schedule
94
+ celerybeat.pid
95
+
96
+ # SageMath parsed files
97
+ *.sage.py
98
+
99
+ # Environments
100
+ .env
101
+ .venv
102
+ env/
103
+ venv/
104
+ ENV/
105
+ env.bak/
106
+ venv.bak/
107
+
108
+ # Spyder project settings
109
+ .spyderproject.db
110
+ .spyproject
111
+
112
+ # Rope project settings
113
+ .ropeproject
114
+
115
+ # mkdocs documentation
116
+ /site
117
+
118
+ # mypy
119
+ .mypy_cache/
120
+ .dmypy.json
121
+ dmypy.json
122
+
123
+ # Pyre type checker
124
+ .pyre/
125
+
126
+ # pytype static type analyzer
127
+ .pytype/
128
+
129
+ # Cython debug symbols
130
+ cython_debug/
131
+
132
+ # IDE
133
+ .idea/
134
+ .vscode/
135
+ *.swp
136
+ *.swo
137
+
138
+ # OS
139
+ .DS_Store
140
+ Thumbs.db
@@ -0,0 +1,468 @@
1
+ # NEVER EDIT THIS FILE!
2
+
3
+ # Universal Style and Quality Enforcement
4
+ # Pre-commit/pre-push checks _and_ source-of-truth for Github workflows.
5
+ #
6
+ # Usage:
7
+ # The `pre-commit` dependency group supplies every tool the hooks below
8
+ # invoke. Naming it explicitly is belt-and-braces, NOT a requirement: uv
9
+ # defaults `default-groups` to `["dev"]`, and pyproject's `dev` includes
10
+ # `pre-commit`, so a bare `uv run` already resolves the tools (verified on a
11
+ # scratch project). Name it anyway so the command does not depend on that
12
+ # chain staying intact.
13
+ #
14
+ # uv --quiet run --frozen --group pre-commit pre-commit install
15
+ # uv --quiet run --frozen --group pre-commit pre-commit autoupdate
16
+ # uv --quiet run --frozen --group pre-commit pre-commit run --all-files
17
+ #
18
+ # May need: git config --unset-all core.hooksPath
19
+ # if: [ERROR] Cowardly refusing to install hooks with `core.hooksPath` set.
20
+ #
21
+ # Stages. `default_stages: [pre-commit]` below means a bare `run` sees only
22
+ # the pre-commit hooks; the heavy ones (ty-check-global, basedpyright-global,
23
+ # pytest*) declare `stages: [pre-push]` and need it named explicitly:
24
+ #
25
+ # uv --quiet run --frozen --group pre-commit pre-commit run --all-files
26
+ # uv --quiet run --frozen --group pre-commit pre-commit run --all-files --hook-stage pre-push
27
+ # uv --quiet run --frozen --group pre-commit pre-commit run --all-files --hook-stage commit-msg
28
+ #
29
+ # Always pass --files or --all-files. Bare `run` (and the hook `git commit`
30
+ # fires on a dirty tree) STASHES your changes -- a git mutation, and this
31
+ # worktree is shared.
32
+ #
33
+ #
34
+ # NUL-delimited, per AGENTS.md: a path containing a space becomes two
35
+ # arguments under `$(...)` or a bare `xargs`, and a rename record yields the
36
+ # name that no longer exists.
37
+ #
38
+ # # Harvest all changed files from the perspective of CWD.
39
+ # git -C "$(git rev-parse --show-toplevel)" diff -z --name-only --diff-filter=d HEAD \
40
+ # | xargs -0 --no-run-if-empty uv --quiet run --frozen --group pre-commit pre-commit run --files
41
+ #
42
+ # # Run only the files from the CWD.
43
+ # git --no-pager diff -z --name-only --cached --relative \
44
+ # | xargs -0 --no-run-if-empty uv --quiet run --frozen --group pre-commit pre-commit run --files
45
+ #
46
+ # # Run all the files from CWD.
47
+ # uv --quiet run --frozen --group pre-commit pre-commit run --files $(git ls-files .)
48
+ #
49
+ # One hook at a time, by id (`ruff-check`, `ty-check`, `pytest-global`, ...):
50
+ # uv --quiet run --frozen --group pre-commit pre-commit run ruff-check --all-files
51
+ # uv --quiet run --frozen --group pre-commit pre-commit run pytest-global --hook-stage pre-push
52
+ #
53
+ # Force full pytest tiers despite testmon's warm dependency database:
54
+ # PYTEST_FORCE_ALL=1 uv --quiet run --frozen --group pre-commit pre-commit run pytest-global --hook-stage pre-push
55
+ #
56
+ # Individual tests: the pytest hooks take no test selector, so call pytest
57
+ # directly.
58
+ #
59
+ # uv --quiet run --frozen --group pre-commit pytest path/to/thing_test.py
60
+ # uv --quiet run --frozen --group pre-commit pytest path/to/thing_test.py::test_name
61
+ # uv --quiet run --frozen --group pre-commit pytest -k some_substring path/to/
62
+ # uv --quiet run --frozen --group pre-commit pytest -n 5 path/to/
63
+ #
64
+ # Marker tiers mirror the pytest-slow-global / -ci-smoke-global /
65
+ # -integration-global hooks; the
66
+ # default `-m` filter lives in pyproject addopts, so ask for them by name:
67
+ #
68
+ # uv --quiet run --frozen --group pre-commit pytest -m slow path/to/
69
+ #
70
+ # Skipping. SKIP takes hook ids, comma-separated, and reports "Skipped":
71
+ #
72
+ # SKIP=ruff-check uv --quiet run --frozen --group pre-commit pre-commit run --all-files
73
+ # SKIP=pytest-global,pytest-slow-global uv --quiet run --frozen --group pre-commit pre-commit run --hook-stage pre-push --all-files
74
+ #
75
+ # `git commit --no-verify` / `git push --no-verify` bypass every hook. Both
76
+ # are a last resort, not a way past a red gate -- the gates are house rules
77
+ # (see AGENTS.md "Never suppress gates"). Fix the code the hook protects.
78
+ # The legitimate use is an unrelated pre-existing failure blocking an
79
+ # urgent unrelated commit; say so in the commit message when you do it.
80
+ #
81
+ #
82
+ # On Source of Truthness:
83
+ #
84
+ # Preferred location for any tool setting, in order:
85
+ # pyproject.toml > .pre-commit-config.yaml > .github/workflows/ci.yml
86
+ #
87
+ # Put a setting as high in this chain as the tool allows. Only drop to a
88
+ # lower file when the higher one cannot express it (e.g. a CLI-only flag with
89
+ # no config key). pyproject.toml holds tool config; .pre-commit-config.yaml
90
+ # is the sole source for how hooks run (thread/worker counts, heap caps);
91
+ # .github/workflows/ci.yml only invokes the hooks and must not redefine
92
+ # any of these.
93
+ #
94
+ #
95
+ # Design Philosophy;
96
+ #
97
+ # Only fail if there's things which cannot be auto-fixed.
98
+ # Hooks fix files in place; if anything changes, pre-commit reports
99
+ # "files were modified" and the commit is aborted. Run `git add -u`
100
+ # then re-commit -- the second attempt always passes.
101
+ #
102
+ # See also:
103
+ #
104
+ # https://pre-commit.com
105
+ # https://pre-commit.com/hooks.html
106
+ # https://learn.scientific-python.org/development/guides/style/
107
+
108
+ fail_fast: false
109
+ default_stages: [pre-commit]
110
+
111
+ repos:
112
+
113
+ # === Pre-Commit Gates =======================================================
114
+
115
+ - repo: https://github.com/pre-commit/pre-commit-hooks
116
+ rev: v6.0.0
117
+ hooks:
118
+
119
+ - id: end-of-file-fixer
120
+ name: end-of-file-fixer
121
+ stages: [pre-commit]
122
+ exclude: |
123
+ (?x)^(
124
+ (.*/)?third_party/
125
+ )
126
+
127
+ - id: trailing-whitespace
128
+ name: trailing-whitespace
129
+ stages: [pre-commit]
130
+ exclude: |
131
+ (?x)^(
132
+ (.*/)?third_party/
133
+ )
134
+
135
+ - id: check-added-large-files
136
+ name: check-added-large-files
137
+ stages: [pre-commit]
138
+ args: [--maxkb=800, --enforce-all]
139
+ exclude: |
140
+ (?x)^(
141
+ uv\.lock
142
+ |typings/
143
+ |(.*/)?chrome/chrome_(desktop|android)_useragents\.txt
144
+ )
145
+
146
+ - id: check-merge-conflict
147
+ name: check-merge-conflict
148
+ stages: [pre-commit]
149
+ args: [--assume-in-merge]
150
+
151
+ - id: check-yaml
152
+ name: check-yaml
153
+ stages: [pre-commit]
154
+
155
+ - id: check-toml
156
+ name: check-toml
157
+ stages: [pre-commit]
158
+
159
+ # Type-checks `${{ }}` expressions, action inputs, runner labels, and `run:`
160
+ # shell. A workflow expression error fails the job in 0s with no log, so
161
+ # nothing downstream catches it; `check-yaml` only proves the file parses.
162
+ # Self-selects on `^\.github/workflows/`.
163
+ #
164
+ # `actionlint`, not `-docker`/`-system`: only the golang hook provisions
165
+ # itself. `-docker` needs a daemon this host lacks, `-system` a hand-installed
166
+ # binary -- both fail closed on a fresh checkout, which is how the tool went
167
+ # uninstalled while the docs cited it.
168
+ #
169
+ # SC2016 only: the export workflows single-quote
170
+ # `--validation-command 'wheel="$wheel" ...'` deliberately -- those `$` belong
171
+ # to the inner shell, so "expressions don't expand" inverts the intent. Every
172
+ # other shellcheck rule stays live, and shellcheck runs only where installed,
173
+ # so this is stricter on CI than on a dev box.
174
+ - repo: https://github.com/rhysd/actionlint
175
+ rev: v1.7.12
176
+ hooks:
177
+ - id: actionlint
178
+ name: actionlint
179
+ stages: [pre-commit]
180
+ args: [-ignore, "SC2016:"]
181
+
182
+ # Validates uv.lock matches pyproject.toml (no network needed).
183
+ # Run `uv lock` manually when changing dependencies.
184
+ - repo: https://github.com/astral-sh/uv-pre-commit
185
+ rev: 0.12.17
186
+ hooks:
187
+
188
+ - id: uv-lock
189
+ name: uv-lock
190
+ stages: [pre-commit]
191
+ files: ^(pyproject\.toml|uv\.lock)$
192
+
193
+ - repo: local
194
+ hooks:
195
+ # Worker counts. Every heavy hook below sizes its own pool with
196
+ # `gate.workers`, which falls back to
197
+ # `tools.gate.worker_count.default_workers`, whose docstring derives the
198
+ # formula, and runs below interactive priority. Overrides, most specific
199
+ # first: `WORKERS_<HOOK_ID>` (`WORKERS_PYTEST_GLOBAL=1`),
200
+ # then `WORKERS_DEFAULT`. Per hook is what CI needs: the integration tier
201
+ # holds ~1.8 GB of torch/jax per worker and OOM-killed a 2-vCPU runner at
202
+ # two, while a type checker on the same box wants more.
203
+ #
204
+ - id: codespell
205
+ name: codespell
206
+ language: system
207
+ stages: [pre-commit]
208
+ types_or: [python, markdown, jupyter, shell]
209
+ entry: uv --quiet run --frozen --group pre-commit codespell
210
+ args: [-w]
211
+ exclude: |
212
+ (?x)^(
213
+ typings/
214
+ |(.*/)?third_party/
215
+ |docs/symbols\.md
216
+ )
217
+
218
+ - repo: https://github.com/astral-sh/ruff-pre-commit
219
+ rev: v0.16.8
220
+ hooks:
221
+ # Exclusions defined in pyproject.toml.
222
+ #
223
+ # `require_serial: true` on all: ruff is rayon-parallel, so pre-commit's
224
+ # argv partitioning stacks cpu_count saturating processes on top. Cheap
225
+ # here (sub-second tree-wide), same defect `basedpyright` below documents.
226
+ #
227
+ # format -> check --fix -> format, deliberately. COM812 is enabled so
228
+ # that any bracket the formatter wraps gets a trailing comma and is
229
+ # exploded one-element-per-line. The formatter's hug layout has no
230
+ # trailing comma, so COM812 only fires AFTER a format pass; the second
231
+ # format honors the comma it added. The single check->format order
232
+ # upstream documents converges only on the next commit attempt.
233
+ # COM812 is ignored in pyproject.toml (it makes `ruff format` warn) and
234
+ # selected only here: format -> fix (adds trailing comma to compact
235
+ # multi-line args) -> format (explodes them one-per-line). Dropping
236
+ # `--extend-select COM812` silently loses that explosion (ruff#9216).
237
+ - id: ruff-format
238
+ name: ruff-format-pre
239
+ stages: [pre-commit]
240
+ require_serial: true
241
+ types_or: [python, pyi, jupyter]
242
+ - id: ruff-check
243
+ name: ruff-check
244
+ stages: [pre-commit]
245
+ require_serial: true
246
+ types_or: [python, pyi, jupyter]
247
+ args: [--fix, --extend-select, COM812]
248
+ - id: ruff-format
249
+ name: ruff-format
250
+ stages: [pre-commit]
251
+ require_serial: true
252
+ types_or: [python, pyi, jupyter]
253
+
254
+ - repo: local
255
+ hooks:
256
+ # No official ty hook yet (https://github.com/astral-sh/ty/issues/269).
257
+ # The `typecheck` module holds these gates: each runs once over the
258
+ # files its `-spool` twin collected, sizes its own workers, and drops
259
+ # what `[tool.pyrefly] project-excludes` names. `pyrefly-check` checks
260
+ # the files `ty-check` checked, so a graph walk runs once.
261
+ #
262
+ # Each twin's `alias` is its gate's id, so `pre-commit run ty-check`
263
+ # selects both; a gate whose spool was never written fails rather than
264
+ # pass on nothing.
265
+ #
266
+ # `require_serial: true`: the checkers saturate every core alone, and
267
+ # pre-commit would otherwise run cpu_count of them at once.
268
+ - id: ty-check-spool
269
+ name: ty-check-spool
270
+ alias: ty-check
271
+ language: system
272
+ stages: [pre-commit]
273
+ require_serial: true
274
+ types_or: [python, pyi]
275
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool ty-check
276
+ - id: ty-check
277
+ name: ty-check
278
+ language: system
279
+ stages: [pre-commit]
280
+ require_serial: true
281
+ pass_filenames: false
282
+ # See `superseded-at-pre-push` at the head of the Pre-Push Gates section.
283
+ alias: superseded-at-pre-push
284
+ types_or: [python, pyi]
285
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.typecheck ty-check
286
+ # Off: `pyrefly-check` is the checker. Run with `--hook-stage manual`.
287
+ # Named files bypass pyproject's `[tool.basedpyright] exclude`, so the
288
+ # twin's exclude mirrors it.
289
+ - id: basedpyright-spool
290
+ name: basedpyright-spool
291
+ alias: basedpyright
292
+ language: system
293
+ stages: [manual]
294
+ require_serial: true
295
+ types_or: [python, pyi]
296
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool basedpyright
297
+ exclude: |
298
+ (?x)^(
299
+ typings/
300
+ |(.*/)?third_party/
301
+ )
302
+ - id: basedpyright
303
+ name: basedpyright
304
+ language: system
305
+ stages: [manual]
306
+ # Pre-commit discards a PASSING hook's output (see the Pre-Push Gates
307
+ # note on `verbose`); this keeps basedpyright's summary line visible.
308
+ verbose: true
309
+ require_serial: true
310
+ pass_filenames: false
311
+ types_or: [python, pyi]
312
+ entry: >-
313
+ env NODE_OPTIONS=--max-old-space-size=2048
314
+ uv --quiet run --frozen --group pre-commit python -m tools.typecheck
315
+ basedpyright
316
+ # Default type checker; `basedpyright` above runs only under
317
+ # `--hook-stage manual`.
318
+ - id: pyrefly-check-spool
319
+ name: pyrefly-check-spool
320
+ alias: pyrefly-check
321
+ language: system
322
+ stages: [pre-commit]
323
+ require_serial: true
324
+ types_or: [python, pyi]
325
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool pyrefly-check
326
+ - id: pyrefly-check
327
+ name: pyrefly-check
328
+ language: system
329
+ stages: [pre-commit]
330
+ require_serial: true
331
+ pass_filenames: false
332
+ # See `superseded-at-pre-push` at the head of the Pre-Push Gates section.
333
+ alias: superseded-at-pre-push
334
+ types_or: [python, pyi]
335
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.typecheck pyrefly-check
336
+ - repo: local
337
+ hooks:
338
+ # Each heavy hook below is a `-spool` twin, which collects pre-commit's
339
+ # file chunks, then the hook, which runs once over all of them through
340
+ # the `gate` or `testing` module at this machine's worker count.
341
+ #
342
+ # Runs the tests PAIRED with each changed file (`x_test.py`, `test_x.py`,
343
+ # beside it or under `tests/`), then applies `fail_under` to the changed
344
+ # sources alone. ~1s, versus the whole suite at pre-push. Green with no
345
+ # pair found means "untested", acceptable only because pre-push is the
346
+ # gate. Exit 5 (nothing collected) passes: a selection whose every test
347
+ # carries a deselected marker is not a failure.
348
+ #
349
+ #
350
+ # `-n` only from 16 test files (SIDECAR_XDIST_MIN overrides): xdist's ~5s
351
+ # startup lost below that on the 16-thread workstation at 5 workers.
352
+ #
353
+ # files 8 12 16 20 60
354
+ # serial 5.7s 7.6s 6.8s 12.4s 27.8s
355
+ # -n5 8.1s 9.0s 7.5s 8.0s 16.3s
356
+ #
357
+ # Coverage targets are directories, never dotted modules: coverage
358
+ # imports a dotted target's package before collection, and a package
359
+ # importing torch then fails every later torch import.
360
+ - id: pytest-spool
361
+ name: pytest-spool
362
+ # `run pytest` selects this twin too, so its spool exists.
363
+ alias: pytest
364
+ language: system
365
+ stages: [pre-commit]
366
+ require_serial: true
367
+ types: [python]
368
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool pytest
369
+ - id: pytest
370
+ name: pytest
371
+ language: system
372
+ stages: [pre-commit]
373
+ require_serial: true
374
+ pass_filenames: false
375
+ # A passing hook's output is discarded otherwise, which made "did any
376
+ # test run at all?" unanswerable from a green line.
377
+ verbose: true
378
+ # See `superseded-at-pre-push` at the head of the Pre-Push Gates section.
379
+ alias: superseded-at-pre-push
380
+ types: [python]
381
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.testing pytest
382
+ # === Pre-Push Gates =========================================================
383
+ #
384
+ # To enable: uv run pre-commit install --hook-type pre-push
385
+ # To disable: uv run pre-commit uninstall --hook-type pre-push
386
+ #
387
+ # `ty-check`, `pyrefly-check` and `pytest` above each answer a strictly weaker
388
+ # question than a hook here, so all three carry
389
+ # `alias: superseded-at-pre-push` -- a plain `SKIP=` selector letting a lane
390
+ # that runs the pre-push tier drop them in one token, with no hook ids to
391
+ # drift. pre-commit skips every hook sharing an alias.
392
+ #
393
+ # Not cosmetic: the per-file `basedpyright` turned repo-wide when CI's
394
+ # periodic lane ran the commit stage `--all-files` (passing filenames also
395
+ # voids pyproject's excludes), and on a 2-vCPU runner it blew the 30-minute
396
+ # job cap while `basedpyright-global` answered the same question in 12.
397
+ #
398
+ # The pytest tiers are defined in the `testing` module's `tiers.py`: each
399
+ # tier's marker, empty-collection tolerance and capability guard, and the
400
+ # rules for when testmon may select. `verbose: true` because pre-commit prints
401
+ # a PASSING hook's output only under it, and every tier runs for minutes.
402
+
403
+ - repo: local
404
+ hooks:
405
+ - id: ty-check-global
406
+ name: ty-check-global
407
+ language: system
408
+ always_run: true
409
+ pass_filenames: false
410
+ stages: [pre-push]
411
+ entry: uv --quiet run --frozen --group pre-commit ty check
412
+ # Exclusions defined in pyproject.toml.
413
+
414
+ - id: basedpyright-global
415
+ name: basedpyright-global
416
+ language: system
417
+ always_run: true
418
+ pass_filenames: false
419
+ # Off: `pyrefly-check-global` is the checker. Run with `--hook-stage manual`.
420
+ stages: [manual]
421
+ entry: >-
422
+ env NODE_OPTIONS=--max-old-space-size=2048
423
+ uv --quiet run --frozen --group pre-commit python -m tools.gate
424
+ threaded basedpyright-global -- basedpyright --threads={workers}
425
+
426
+ - id: pyrefly-check-global
427
+ name: pyrefly-check-global
428
+ language: system
429
+ always_run: true
430
+ pass_filenames: false
431
+ stages: [pre-push]
432
+ entry: >-
433
+ uv --quiet run --frozen --group pre-commit python -m tools.gate
434
+ threaded pyrefly-check-global -- pyrefly check --threads={workers}
435
+
436
+ - id: pytest-global
437
+ name: pytest-global
438
+ language: system
439
+ always_run: true
440
+ pass_filenames: false
441
+ stages: [pre-push]
442
+ verbose: true
443
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-global
444
+ - id: pytest-slow-global
445
+ name: pytest-slow-global
446
+ language: system
447
+ always_run: true
448
+ pass_filenames: false
449
+ stages: [pre-push]
450
+ verbose: true
451
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-slow-global
452
+ - id: pytest-ci-smoke-global
453
+ name: pytest-ci-smoke-global
454
+ language: system
455
+ always_run: true
456
+ pass_filenames: false
457
+ stages: [pre-push]
458
+ verbose: true
459
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-ci-smoke-global
460
+ - id: pytest-integration-global
461
+ name: pytest-integration-global
462
+ language: system
463
+ always_run: true
464
+ pass_filenames: false
465
+ stages: [pre-push]
466
+ verbose: true
467
+ entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-integration-global
468
+ # NEVER EDIT THIS FILE!
@@ -0,0 +1,13 @@
1
+ We support using AI (i.e., LLMs) as tools for coding. However, you remain responsible for any code you publish and we are responsible for any code we merge and release. We hold a high bar for all contributions to our projects.
2
+
3
+ **AI should not be used to generate comments when communicating with maintainers**. We expect comments on our projects to be written by humans. We may hide any comments that we believe are AI generated.
4
+
5
+ If you are opening an issue, we expect you to describe the problem in your own words.
6
+
7
+ If you are opening a pull request, we expect you to be able to explain the proposed changes in your own words. This includes the pull request body and responses to questions. **Do not copy responses from the AI when replying to questions from maintainers.**
8
+
9
+ Due to the foundational nature of our projects, we require a human in the loop who understands the work produced by AI. **We do not allow autonomous agents to be used for contributing to our projects**. We will close any pull requests that we believe were created autonomously.
10
+
11
+ If you wish to include context from an interaction with AI in your comments, it must be in a quote block (e.g., using `>`) and disclosed as such. It must be accompanied by human commentary explaining the relevance and implications of the context. Do not share long snippets.
12
+
13
+ We understand that AI is useful when communicating as a non-native English speaker. If you are using AI to edit your comments for this purpose, please take the time to ensure it reflects your own voice and ideas. If using AI for translation, we recommend writing in your native language and including the AI translation in a quote block.
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable knowop changes are documented here. This project follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## Unreleased
7
+
8
+ ## 0.1.0
9
+
10
+ ### Added
11
+
12
+ - `knowop login [ORG|URL]`: device login, approved in a browser. No argument
13
+ means `https://alpha.knowop.ai`; `ORG` means `https://ORG.knowop.ai`.
14
+ - `knowop connect [ORG|URL] [--name N] [--no-exec] [--sandbox]`: logs in when
15
+ needed, enrolling and confirming this computer in the same approval, then
16
+ serves its terminal, and the assistant's commands unless `--no-exec`.
17
+ - `knowop status`, `knowop logout`.
18
+ - `knowop run claude|codex`: Claude Code or Codex in this folder, recorded and
19
+ reachable from Chat; `knowop run attach|ls|log|send|stop NAME` reaches a
20
+ detached run, and `knowop run claude|codex resume SESSION` re-enters a stored
21
+ one.
22
+ - `knowop job`: runs a job on a GPU node from this repository, reads its log and
23
+ results, lists and cancels jobs, and keeps the secrets a job may use.
24
+ - `knowop machine`: the machines campaigns may run on.
25
+ - The `direct` extra: the direct terminal link between the browser and this
26
+ computer.
@@ -0,0 +1,25 @@
1
+ # Code of Conduct
2
+
3
+ We want knowop to be a respectful, productive project for contributors and users.
4
+
5
+ This file gives maintainers a public moderation policy before the repository accepts outside issues and pull requests.
6
+
7
+ ## Expected behavior
8
+
9
+ - Be respectful and constructive.
10
+ - Assume good intent.
11
+ - Focus criticism on ideas and code, not people.
12
+ - Help keep discussions clear and actionable.
13
+
14
+ ## Unacceptable behavior
15
+
16
+ - Harassment, threats, or discriminatory language.
17
+ - Personal attacks or sustained disruption.
18
+ - Publishing private information without consent.
19
+
20
+ Disclose security issues privately through the process in `SECURITY.md`, not in
21
+ a public issue.
22
+
23
+ ## Enforcement
24
+
25
+ Project maintainers may moderate discussions, close issues, or restrict participation when necessary to keep the project safe and productive. Report concerns privately to hello@rekursiv.ai.