kcoral 0.1.1__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 (169) hide show
  1. kcoral-0.1.1/.claude/skills/kcoral-client/SKILL.md +271 -0
  2. kcoral-0.1.1/.coderabbit.yaml +119 -0
  3. kcoral-0.1.1/.github/workflows/build_wheels.yml +98 -0
  4. kcoral-0.1.1/.github/workflows/docs.yml +54 -0
  5. kcoral-0.1.1/.github/workflows/publish_pypi.yml +37 -0
  6. kcoral-0.1.1/.gitignore +28 -0
  7. kcoral-0.1.1/.pre-commit-config.yaml +39 -0
  8. kcoral-0.1.1/Cargo.lock +2328 -0
  9. kcoral-0.1.1/Cargo.toml +3 -0
  10. kcoral-0.1.1/MANIFEST.in +4 -0
  11. kcoral-0.1.1/PKG-INFO +148 -0
  12. kcoral-0.1.1/README.md +127 -0
  13. kcoral-0.1.1/docker/Dockerfile.cu132.dev +39 -0
  14. kcoral-0.1.1/docker/Dockerfile.cu132.dev.dockerignore +17 -0
  15. kcoral-0.1.1/docker/compose.yaml +28 -0
  16. kcoral-0.1.1/docs/_static/brand/kcoral-icon.png +0 -0
  17. kcoral-0.1.1/docs/_static/brand/kcoral-logo-dark.png +0 -0
  18. kcoral-0.1.1/docs/_static/brand/kcoral-logo-light.png +0 -0
  19. kcoral-0.1.1/docs/_static/custom.css +74 -0
  20. kcoral-0.1.1/docs/_static/router-architecture.png +0 -0
  21. kcoral-0.1.1/docs/_templates/components/view-this-page.html +25 -0
  22. kcoral-0.1.1/docs/_templates/sidebar/version-switcher.html +14 -0
  23. kcoral-0.1.1/docs/client-guide/builtin-cli-tools.md +534 -0
  24. kcoral-0.1.1/docs/client-guide/protocol.md +683 -0
  25. kcoral-0.1.1/docs/client-guide/remote-functions.md +63 -0
  26. kcoral-0.1.1/docs/client-guide/writing-a-program.md +347 -0
  27. kcoral-0.1.1/docs/conf.py +78 -0
  28. kcoral-0.1.1/docs/getting-started/installation.md +125 -0
  29. kcoral-0.1.1/docs/getting-started/quickstart.md +91 -0
  30. kcoral-0.1.1/docs/index.md +73 -0
  31. kcoral-0.1.1/docs/python-api/index.rst +116 -0
  32. kcoral-0.1.1/docs/requirements.in +4 -0
  33. kcoral-0.1.1/docs/requirements.txt +81 -0
  34. kcoral-0.1.1/docs/server-guide/launch-the-server.md +310 -0
  35. kcoral-0.1.1/docs/server-guide/logging.md +110 -0
  36. kcoral-0.1.1/docs/server-guide/router.md +186 -0
  37. kcoral-0.1.1/docs/tutorials/agent-integration.md +91 -0
  38. kcoral-0.1.1/docs/tutorials/benchmark-kernel.md +243 -0
  39. kcoral-0.1.1/docs/tutorials/remote-compilation.md +223 -0
  40. kcoral-0.1.1/examples/basics/first_program.py +38 -0
  41. kcoral-0.1.1/examples/basics/remote_function.py +31 -0
  42. kcoral-0.1.1/examples/benchmark_kernel/benchmark_kernel.py +84 -0
  43. kcoral-0.1.1/examples/cpu_compile/cpu_compile_gpu_execute.py +169 -0
  44. kcoral-0.1.1/examples/cpu_compile/library_upload.py +135 -0
  45. kcoral-0.1.1/examples/multi_gpu/multiprocess.py +125 -0
  46. kcoral-0.1.1/examples/multi_gpu/single_process.py +95 -0
  47. kcoral-0.1.1/examples/thor/.gitignore +3 -0
  48. kcoral-0.1.1/examples/thor/PROMPT.md +241 -0
  49. kcoral-0.1.1/examples/thor/README.md +202 -0
  50. kcoral-0.1.1/examples/thor/bench.py +724 -0
  51. kcoral-0.1.1/examples/thor/definition.json +27 -0
  52. kcoral-0.1.1/examples/thor/initial_kernel.py +68 -0
  53. kcoral-0.1.1/examples/thor/launch_server.sh +106 -0
  54. kcoral-0.1.1/examples/thor/workload.jsonl +4 -0
  55. kcoral-0.1.1/pyproject.toml +75 -0
  56. kcoral-0.1.1/python/kcoral/__init__.py +50 -0
  57. kcoral-0.1.1/python/kcoral/__main__.py +35 -0
  58. kcoral-0.1.1/python/kcoral/artifacts.py +339 -0
  59. kcoral-0.1.1/python/kcoral/builtins.py +324 -0
  60. kcoral-0.1.1/python/kcoral/client/__init__.py +16 -0
  61. kcoral-0.1.1/python/kcoral/client/functions.py +245 -0
  62. kcoral-0.1.1/python/kcoral/client/http.py +278 -0
  63. kcoral-0.1.1/python/kcoral/client/program.py +415 -0
  64. kcoral-0.1.1/python/kcoral/client/result.py +402 -0
  65. kcoral-0.1.1/python/kcoral/config.py +58 -0
  66. kcoral-0.1.1/python/kcoral/errors.py +73 -0
  67. kcoral-0.1.1/python/kcoral/protocol.py +601 -0
  68. kcoral-0.1.1/python/kcoral/runtime/__init__.py +1 -0
  69. kcoral-0.1.1/python/kcoral/runtime/engine.py +565 -0
  70. kcoral-0.1.1/python/kcoral/runtime/gpu.py +463 -0
  71. kcoral-0.1.1/python/kcoral/runtime/lease.py +282 -0
  72. kcoral-0.1.1/python/kcoral/runtime/pool.py +501 -0
  73. kcoral-0.1.1/python/kcoral/runtime/python.py +233 -0
  74. kcoral-0.1.1/python/kcoral/runtime/worker.py +902 -0
  75. kcoral-0.1.1/python/kcoral/schemas.py +119 -0
  76. kcoral-0.1.1/python/kcoral/server/__init__.py +1 -0
  77. kcoral-0.1.1/python/kcoral/server/_generated/__init__.py +1 -0
  78. kcoral-0.1.1/python/kcoral/server/_generated/kcoral_gateway_pb2.py +64 -0
  79. kcoral-0.1.1/python/kcoral/server/_generated/kcoral_gateway_pb2_grpc.py +145 -0
  80. kcoral-0.1.1/python/kcoral/server/app.py +668 -0
  81. kcoral-0.1.1/python/kcoral/server/cache.py +282 -0
  82. kcoral-0.1.1/python/kcoral/server/cli.py +350 -0
  83. kcoral-0.1.1/python/kcoral/server/events.py +161 -0
  84. kcoral-0.1.1/python/kcoral/server/tunnel.py +374 -0
  85. kcoral-0.1.1/python/kcoral/support/__init__.py +1 -0
  86. kcoral-0.1.1/python/kcoral/support/cuda.py +127 -0
  87. kcoral-0.1.1/python/kcoral/support/platform.py +181 -0
  88. kcoral-0.1.1/python/kcoral/support/sandbox.py +412 -0
  89. kcoral-0.1.1/python/kcoral/tools/__init__.py +10 -0
  90. kcoral-0.1.1/python/kcoral/tools/cli.py +301 -0
  91. kcoral-0.1.1/python/kcoral/tools/compute_sanitizer.py +17 -0
  92. kcoral-0.1.1/python/kcoral/tools/ncu.py +42 -0
  93. kcoral-0.1.1/python/kcoral/tools/python.py +48 -0
  94. kcoral-0.1.1/python/kcoral/tools/run_iket.py +32 -0
  95. kcoral-0.1.1/python/kcoral/tools/runner.py +90 -0
  96. kcoral-0.1.1/python/kcoral/tools/shell.py +17 -0
  97. kcoral-0.1.1/python/kcoral.egg-info/PKG-INFO +148 -0
  98. kcoral-0.1.1/python/kcoral.egg-info/SOURCES.txt +168 -0
  99. kcoral-0.1.1/python/kcoral.egg-info/dependency_links.txt +1 -0
  100. kcoral-0.1.1/python/kcoral.egg-info/entry_points.txt +2 -0
  101. kcoral-0.1.1/python/kcoral.egg-info/requires.txt +15 -0
  102. kcoral-0.1.1/python/kcoral.egg-info/scm_file_list.json +164 -0
  103. kcoral-0.1.1/python/kcoral.egg-info/scm_version.json +8 -0
  104. kcoral-0.1.1/python/kcoral.egg-info/top_level.txt +1 -0
  105. kcoral-0.1.1/rust/kcoral/Cargo.toml +47 -0
  106. kcoral-0.1.1/rust/kcoral/README.md +126 -0
  107. kcoral-0.1.1/rust/kcoral/build.rs +11 -0
  108. kcoral-0.1.1/rust/kcoral/proto/kcoral_gateway.proto +87 -0
  109. kcoral-0.1.1/rust/kcoral/src/bin/node.rs +196 -0
  110. kcoral-0.1.1/rust/kcoral/src/bin/router.rs +71 -0
  111. kcoral-0.1.1/rust/kcoral/src/headers.rs +68 -0
  112. kcoral-0.1.1/rust/kcoral/src/lib.rs +67 -0
  113. kcoral-0.1.1/rust/kcoral/src/process.rs +180 -0
  114. kcoral-0.1.1/rust/kcoral/src/router/gateway.rs +176 -0
  115. kcoral-0.1.1/rust/kcoral/src/router/http.rs +482 -0
  116. kcoral-0.1.1/rust/kcoral/src/router/mod.rs +17 -0
  117. kcoral-0.1.1/rust/kcoral/src/router/pool.rs +1047 -0
  118. kcoral-0.1.1/rust/kcoral/src/router/slot.rs +135 -0
  119. kcoral-0.1.1/rust/kcoral/src/supervisor.rs +592 -0
  120. kcoral-0.1.1/rust/kcoral/tests/network.rs +694 -0
  121. kcoral-0.1.1/scripts/build_docs.py +125 -0
  122. kcoral-0.1.1/scripts/generate_gateway.py +54 -0
  123. kcoral-0.1.1/setup.cfg +4 -0
  124. kcoral-0.1.1/setup.py +40 -0
  125. kcoral-0.1.1/tests/support/README.md +14 -0
  126. kcoral-0.1.1/tests/support/__init__.py +1 -0
  127. kcoral-0.1.1/tests/support/_common.py +20 -0
  128. kcoral-0.1.1/tests/support/core.py +50 -0
  129. kcoral-0.1.1/tests/support/cuda.py +202 -0
  130. kcoral-0.1.1/tests/support/cutedsl.py +54 -0
  131. kcoral-0.1.1/tests/support/fake.py +42 -0
  132. kcoral-0.1.1/tests/support/programs.py +73 -0
  133. kcoral-0.1.1/tests/support/runtime.py +150 -0
  134. kcoral-0.1.1/tests/support/triton.py +55 -0
  135. kcoral-0.1.1/tests/test_builtins.py +15 -0
  136. kcoral-0.1.1/tests/test_cache.py +180 -0
  137. kcoral-0.1.1/tests/test_cli.py +197 -0
  138. kcoral-0.1.1/tests/test_client.py +914 -0
  139. kcoral-0.1.1/tests/test_cpu_runtime.py +56 -0
  140. kcoral-0.1.1/tests/test_cuda_error_api.py +25 -0
  141. kcoral-0.1.1/tests/test_engine.py +600 -0
  142. kcoral-0.1.1/tests/test_events.py +439 -0
  143. kcoral-0.1.1/tests/test_file_return.py +237 -0
  144. kcoral-0.1.1/tests/test_folder.py +132 -0
  145. kcoral-0.1.1/tests/test_functions.py +121 -0
  146. kcoral-0.1.1/tests/test_gateway.py +563 -0
  147. kcoral-0.1.1/tests/test_gpu_cleanup.py +88 -0
  148. kcoral-0.1.1/tests/test_gpu_jobs.py +634 -0
  149. kcoral-0.1.1/tests/test_gpu_runtime.py +1248 -0
  150. kcoral-0.1.1/tests/test_keys.py +21 -0
  151. kcoral-0.1.1/tests/test_lease.py +169 -0
  152. kcoral-0.1.1/tests/test_multi_gpu_jobs.py +67 -0
  153. kcoral-0.1.1/tests/test_multipart.py +53 -0
  154. kcoral-0.1.1/tests/test_node_processes.py +143 -0
  155. kcoral-0.1.1/tests/test_packaging.py +81 -0
  156. kcoral-0.1.1/tests/test_pool.py +755 -0
  157. kcoral-0.1.1/tests/test_process_state.py +96 -0
  158. kcoral-0.1.1/tests/test_sandbox.py +964 -0
  159. kcoral-0.1.1/tests/test_schemas.py +474 -0
  160. kcoral-0.1.1/tests/test_server_e2e.py +1289 -0
  161. kcoral-0.1.1/tests/test_service_cli.py +518 -0
  162. kcoral-0.1.1/tests/test_shutdown.py +229 -0
  163. kcoral-0.1.1/tests/test_tool_cli.py +255 -0
  164. kcoral-0.1.1/tests/test_tunnel.py +405 -0
  165. kcoral-0.1.1/uv.lock +1926 -0
  166. kcoral-0.1.1/website/README.md +36 -0
  167. kcoral-0.1.1/website/assets/site.css +261 -0
  168. kcoral-0.1.1/website/assets/site.js +15 -0
  169. kcoral-0.1.1/website/index.html +203 -0
@@ -0,0 +1,271 @@
1
+ ---
2
+ name: kcoral-client
3
+ description: >-
4
+ Write client code for KCoral's POST /execute instruction
5
+ protocol. Use when writing, reviewing, or debugging programs that upload
6
+ kernels (TIRx, CUDA C, CuTeDSL, Triton), create tensors, compile, check
7
+ correctness, or benchmark on a remote GPU server, or when using the
8
+ kcoral Client and Program API.
9
+ ---
10
+
11
+ # KCoral client
12
+
13
+ Facts needed to write a protocol-conformant client. `docs/client-guide/protocol.md` is the
14
+ authoritative field-level specification; where this page and that file
15
+ disagree, that file wins.
16
+
17
+ ## Model
18
+
19
+ - The client endpoints are `POST /execute` and `GET /health`.
20
+ - A request body is a **program**: an ordered list of instructions executed
21
+ top to bottom on a GPU or CPU worker.
22
+ - There is no session state. Handles (`id`s) live for one request; a second
23
+ `execute` shares nothing with the first, so every program uploads everything
24
+ it needs.
25
+ - `run` computes a value but does not send it back. The response carries only
26
+ what `return` selects.
27
+ - A reference has the exact form `{"$ref": "<id>"}` and must point to an
28
+ earlier instruction.
29
+ - The `GET /health` response includes the GPU `target` (e.g. `{"arch": "sm_100a"}`),
30
+ installed `versions`, and `load`: `request_capacity` (occupied + free capacity),
31
+ `requests_in_progress` (assigned requests), and `requests_waiting`
32
+ (requests awaiting assignment).
33
+
34
+ ## Python client
35
+
36
+ For simple tasks, use `@client.function(timeout=30)` and call `.remote()` for the
37
+ decoded value, or `.execute()` for the full `ProgramResult`. Define the function
38
+ in a file, import dependencies inside it, and pass inputs explicitly. Configure
39
+ the server on `Client` and keep it open for remote calls. See
40
+ [Remote functions](../../../docs/client-guide/remote-functions.md)
41
+ for supported inputs and execution boundaries.
42
+
43
+ Upload a harness, select its entry point, run it and return what you want to inspect:
44
+
45
+ ```python
46
+ from kcoral import Client, Program
47
+
48
+ program = Program()
49
+ module = program.upload(kind="module", source="""
50
+ import torch
51
+
52
+ def main(n):
53
+ x = torch.arange(n, dtype=torch.float32, device="cuda")
54
+ y = x + 1
55
+ torch.testing.assert_close(y, x + 1)
56
+ return {"ok": True, "output": y}
57
+ """)
58
+ main = program.get_function(module=module, name="main")
59
+ report = program.run(fn=main, args=[256])
60
+ program.return_(key="report", value=report)
61
+ with Client("http://127.0.0.1:8000") as client:
62
+ result = client.execute(program, timeout_seconds=120)
63
+ print(result.results)
64
+ ```
65
+
66
+ Uploaded Python can perform tasks such as compilation, tensor allocation,
67
+ validation, measurement, or invoking scripts and CLI tools. `run.fn` references
68
+ an earlier callable; a callable returned by a `run` can be used by a later call.
69
+
70
+ API surface:
71
+
72
+ ```python
73
+ Program.upload(kind="module", source=...) -> Register
74
+ Program.upload(kind="tensor", value=..., dtype=None, shape=None) -> Register
75
+ Program.upload(kind="bytes", value=...) -> Register
76
+ Program.upload(kind="library", value=...) -> Register
77
+ Program.upload_file(blob=..., path=...) -> Register
78
+ Program.upload_folder(folder, *, path=...) -> None
79
+ Program.get_function(module=..., name=..., cpu_only=False) -> Register
80
+ Program.run(fn=..., args=[]) -> Register
81
+ Program.return_(key=..., value=...) -> None
82
+ Program.return_file(key=..., path=...) -> None # str or Register resolving to str
83
+ Program.return_folder(key=..., path=...) -> None # str or Register resolving to str
84
+
85
+ Client(base_url, *, headers=None, connect_timeout_seconds=10)
86
+ Client.execute(program, *, timeout_seconds=None, output_limit_bytes=None, gpu_count=None) -> ProgramResult
87
+ Client.health() -> dict
88
+ Client.target() -> dict # e.g. {"arch": "sm_100a"}
89
+ Client.close() -> None
90
+ ```
91
+
92
+ `Program` automatically generates an ID for each value-producing instruction.
93
+ Use the optional `id` field to customize it.
94
+
95
+ The client derives `blob`, `dtype`, and `shape` from a tensor `value`. It sends
96
+ no blob parts at first, retries a `CACHE_MISS` with the missing parts, and falls
97
+ back to resending every local blob if the cache changes between the two
98
+ requests. Returned tensors decode to CPU `numpy.ndarray` (`bfloat16` and
99
+ `float8_*` via `ml_dtypes`).
100
+
101
+ `upload_folder` snapshots a local directory into ordinary file upload
102
+ instructions; retries send the same instructions with different blob parts.
103
+ It includes hidden files, rejects links, special files and repeated directories,
104
+ and omits empty directories and original permissions/timestamps. A failed call
105
+ leaves the program unchanged. Caching is automatic and best-effort.
106
+
107
+ `return_file` and `return_folder` capture workspace-relative paths at that
108
+ instruction; `path` may be an earlier register containing a path string.
109
+ Use `result[key].save(destination)` to save locally. File results also provide
110
+ `read_bytes()`; folder results provide `files` and `directories`. Folders include
111
+ hidden files and empty directories. Missing paths, symlinks, and special files
112
+ fail collection. Earlier returns survive later ordinary instruction failures.
113
+ Saves require an existing parent; file replacement needs `overwrite=True`, and
114
+ folder destinations must be new. Transfers are buffered and subject to server
115
+ limits. See [client usage](../../../docs/client-guide/writing-a-program.md#return-files-and-folders).
116
+
117
+ ## Instructions
118
+
119
+ ### `upload`
120
+
121
+ Each field is required for the listed kinds:
122
+
123
+ | Field | Kinds | Notes |
124
+ |---|---|---|
125
+ | `id` | all | Unique handle name |
126
+ | `kind` | all | `"module"`, `"tensor"`, `"bytes"`, `"file"`, or `"library"` |
127
+ | `source` | module | Python source executed to define a module |
128
+ | `blob` | tensor, bytes, file, library | SHA-256 of the raw bytes |
129
+ | `path` | file | Relative path in the request working directory |
130
+ | `dtype` | tensor | Tensor data type |
131
+ | `shape` | tensor | Tensor shape |
132
+
133
+ A module upload binds its full source namespace. Use `get_function` to select a
134
+ named Python object. Uploaded Python is ordinary code
135
+ executed on the worker (torch included), so a plain function works as a
136
+ reference baseline.
137
+
138
+ A `bytes` upload binds the blob's bytes unchanged. They stay in CPU memory and
139
+ can be passed to uploaded Python code, which suits files and other binary
140
+ formats the server should parse.
141
+
142
+ A `library` upload is a prebuilt TVM FFI shared library loaded with
143
+ `tvm_ffi.load_module`; use `get_function` to bind one of its exported functions.
144
+
145
+ A `file` upload binds its normalized relative path as a string. Use
146
+ `upload_file(blob=..., path=...)` in the Python client, where `blob` is bytes-like;
147
+ the wire field holds its SHA-256. The server copies it into the request's private
148
+ working directory with mode `0600` and removes that directory after execution.
149
+ Its content can remain in the disk cache across requests and server restarts.
150
+
151
+ ### `get_function`
152
+
153
+ Select an object from an uploaded module with `get_function(module=..., name=...)`.
154
+ The returned `Register` stores its instruction ID and can be passed as `fn` to `run`.
155
+
156
+ `get_function(..., cpu_only=True)` declares that later calls to this function
157
+ use no GPU. Before its `run`, a GPU worker synchronizes and releases the lease.
158
+ A detected CUDA call fails with `gpu_access`. This is a best-effort check.
159
+ The flag applies to the selected function's calls; the Python module upload
160
+ executes top-level code under the GPU lease.
161
+
162
+ ### `run`
163
+
164
+ `{"op": "run", "id": ..., "fn": {"$ref": "function_id"}, "args": [...]}`
165
+ calls an earlier callable. In Python, pass the `Register` returned by
166
+ `get_function` (or a `run` that returned a callable); the client encodes its ID
167
+ as `{"$ref": "function_id"}`. Top-level argument references resolve to values;
168
+ other JSON values pass as literals.
169
+
170
+ ### `return`
171
+
172
+ `{"op": "return", "key": ..., "value": {"$ref": id}}` — selects a handle for
173
+ the response `results` object. A `return` that already ran keeps its entry
174
+ even if a later instruction fails, so returning early checkpoints partial
175
+ work.
176
+
177
+ ## Multi-GPU programs
178
+
179
+ Use `Client.execute(program, gpu_count=N)` for 1–8 GPUs on one direct server.
180
+ Upload definitions and files, select an entry point with `get_function`, then
181
+ execute with `run`. Single- and multi-GPU workers share instruction-level leasing:
182
+ `cpu_only` synchronizes and releases the entire set, and later GPU instructions
183
+ reacquire the same devices. The script owns communication and must join GPU
184
+ subprocesses before returning. Spawn workers need an importable `.py` file.
185
+ Do not mark a GPU launcher CPU-only. See the [two single-file examples](../../../docs/client-guide/writing-a-program.md#run-a-multi-gpu-program)
186
+ and [execution protocol](../../../docs/client-guide/protocol.md#multi-gpu-execution).
187
+
188
+ ## Compilation and measurement helpers
189
+
190
+ For convenience, uploaded Python can import `compile_tirx` and `benchmark` from
191
+ `kcoral.builtins`. You can also use your own compilation and measurement harness.
192
+ See the [API reference](../../../docs/python-api/index.rst#gpu-utilities)
193
+ for signatures and options, and the
194
+ [compilation tutorial](../../../docs/tutorials/benchmark-kernel.md#choose-where-to-compile)
195
+ for GPU-server, CPU-server and local compilation examples.
196
+
197
+ ## Tensors
198
+
199
+ Two ways to provide tensors are to upload Python that initializes them remotely,
200
+ or to upload local tensors with `kind="tensor"`.
201
+
202
+ - `kind="tensor"` accepts a NumPy array, a torch tensor, any DLPack object,
203
+ or raw bytes with `dtype` and `shape`.
204
+ - Accepted dtypes: `bool`, `uint8`, `int8`, `int16`, `int32`, `int64`,
205
+ `float16`, `float32`, `float64`, `bfloat16`, `float8_e4m3fn`,
206
+ `float8_e5m2`.
207
+ - To hand a returned `bfloat16` array to torch:
208
+ `torch.from_numpy(value.view(np.uint8)).view(torch.bfloat16)`.
209
+
210
+ ## Correctness and timing
211
+
212
+ Your uploaded code can configure, for example, tolerances, assertions, profiler
213
+ invocation, warmup, and measurement methodology. Return reports and relevant
214
+ artifacts explicitly. Synchronize and wait for GPU subprocesses before
215
+ returning or releasing a lease.
216
+
217
+ ## Request timing
218
+
219
+ The execution response contains top-level `queue_ms`, `elapsed_ms`,
220
+ `lease_wait_ms`, and `lease_held_ms` fields. The Python client exposes them as
221
+ attributes of the `ProgramResult` returned by `Client.execute`, for example
222
+ `result.lease_held_ms`.
223
+
224
+ `queue_ms` measures the wait for a worker. `elapsed_ms` starts once a worker is
225
+ assigned and includes waiting for the GPU lease (`lease_wait_ms`), holding it
226
+ (`lease_held_ms`), and other worker work. Holding the lease reserves the GPU;
227
+ it does not imply continuous GPU activity. Kernel latency is measured separately
228
+ by `benchmark` or your own measurement code.
229
+
230
+ ## Outcomes
231
+
232
+ - `options`: `timeout_seconds` (server defaults: 300, maximum 900),
233
+ `output_limit_bytes` (default 1 MiB per stream). Values above a maximum are
234
+ clamped. `stdout`/`stderr` come back with the response.
235
+ - `COMPLETED` — every instruction ran; `results` holds the returned values.
236
+ - `FAILED` — one instruction failed and the rest were skipped; returns that
237
+ already ran stay in `results`. `error` carries `kind` (`parse`, `compile`,
238
+ `runtime`, `gpu_access`, `correctness`, `serialization`, `unavailable`,
239
+ `engine`), `message`, `instruction_index`, `instruction_id`, `traceback`.
240
+ - `CACHE_MISS` — blobs missing; the Python client retries with the missing
241
+ blobs, then with all local blobs if that retry misses again.
242
+ - Exceptions: `KCoralError` (carries `status_code` and `kind`; 503
243
+ means no worker free, 504 means `timeout_seconds` hit), `TransportError`
244
+ (no HTTP response could be obtained; execution may have occurred),
245
+ `ProtocolError` (malformed response or failed cache recovery).
246
+
247
+ ## Non-Python clients
248
+
249
+ The wire format is `multipart/form-data` with a `program` part
250
+ (`application/json`) plus one `blob:<sha256>` part
251
+ (`application/octet-stream`) per tensor, bytes, file, or library blob, where
252
+ `<sha256>` is the lowercase hex SHA-256 of the part bytes. Blobs are cached by
253
+ hash: on `status: CACHE_MISS`, resend the program with the parts listed in
254
+ `missing_blobs`, and resend every blob if that retry misses again. Responses
255
+ containing tensors or bytes are multipart with a `result` JSON part and
256
+ `return:<index>` binary parts. The typed value encoding, blob-cache rules, and
257
+ full error table are in `docs/client-guide/protocol.md`.
258
+
259
+ ## References
260
+
261
+ - `docs/client-guide/protocol.md` — field-level wire specification: request envelope,
262
+ value encoding, library upload build routes (TVM FFI, TIRx
263
+ `export_library`, CuTeDSL `--enable-tvm-ffi`) and their link flags, full
264
+ HTTP error table.
265
+ - `docs/client-guide/writing-a-program.md` — narrative guide: server-side compile vs prebuilt
266
+ library trade-offs, measurement guidance.
267
+ - `examples/basics/first_program.py` — runnable: upload a function and tensor, then
268
+ execute and return the result.
269
+ - `examples/benchmark_kernel/benchmark_kernel.py` — CPU-only TIRx compilation and GPU measurement on one server.
270
+ - `examples/cpu_compile/library_upload.py` — client build and library upload.
271
+ - `examples/cpu_compile/cpu_compile_gpu_execute.py` — CPU build and GPU execution.
@@ -0,0 +1,119 @@
1
+ # yaml-language-server: $schema=https://www.coderabbit.ai/integrations/schema.v2.json
2
+ language: en-US
3
+ early_access: false
4
+ inheritance: false
5
+ tone_instructions: >-
6
+ Be concise and specific. Prioritize actionable correctness, security, concurrency,
7
+ and performance regressions. Explain the failing scenario; avoid speculative
8
+ findings, style-only feedback, and duplicating Ruff or formatting checks.
9
+
10
+ reviews:
11
+ profile: chill
12
+ request_changes_workflow: false
13
+ allow_author_approval: false
14
+ high_level_summary: false
15
+ review_status: true
16
+ collapse_walkthrough: true
17
+ sequence_diagrams: false
18
+ poem: false
19
+ in_progress_fortune: false
20
+ suggested_labels: false
21
+ auto_apply_labels: false
22
+ suggested_reviewers: false
23
+ auto_assign_reviewers: false
24
+ fail_commit_status: false
25
+ auto_review:
26
+ enabled: true
27
+ auto_incremental_review: true
28
+ # Bound review noise and usage on frequently updated PRs. Resume on demand.
29
+ auto_pause_after_reviewed_commits: 5
30
+ drafts: false
31
+ # The default branch (main) is always included; no additional target branches.
32
+ base_branches: []
33
+ ignore_title_keywords:
34
+ - "[skip ai review]"
35
+ path_filters:
36
+ - "!Cargo.lock"
37
+ - "!uv.lock"
38
+ - "!python/kcoral/server/_generated/**"
39
+ - "!docs/_static/brand/**"
40
+ path_instructions:
41
+ - path: "**/*"
42
+ instructions: >-
43
+ KCoral executes client-supplied programs on trusted, isolated networks.
44
+ Intentional remote execution is part of the API, not by itself a new
45
+ vulnerability. Review changes for regressions against the documented
46
+ trust model, isolation, resource bounds, cleanup, and protocol contracts.
47
+ Report concrete failures introduced by the diff and cite affected code.
48
+ - path: "python/kcoral/runtime/**"
49
+ instructions: >-
50
+ Check GPU lease ownership, single- and multi-GPU scheduling, CPU-only
51
+ transitions, cancellation, timeouts, worker death, and descendant cleanup.
52
+ Check that failure paths release capacity and cannot leave a GPU leased
53
+ forever. Compilation may initialize CUDA; do not assume it is CPU-only.
54
+ - path: "python/kcoral/server/**"
55
+ instructions: >-
56
+ Check bounded request and response handling, multipart validation,
57
+ content hashes, cache pinning and eviction, filesystem races, backpressure,
58
+ cancellation, and tunnel reconnection. Keep blocking work off the event
59
+ loop and preserve the protocol in docs/client-guide/protocol.md.
60
+ - path: "python/kcoral/support/**"
61
+ instructions: >-
62
+ Check sandbox mounts, path and symlink handling, spawn failures, temporary
63
+ directory cleanup, and process lifetime. Preserve documented behavior when
64
+ bubblewrap is unavailable and avoid broadening access to host resources.
65
+ - path: "python/kcoral/client/**"
66
+ instructions: >-
67
+ Check HTTP protocol compatibility, cache-miss retry semantics, response
68
+ validation, and resource closure. Never replay a possibly executed program
69
+ automatically after an ambiguous transport failure.
70
+ - path: "rust/kcoral/**"
71
+ instructions: >-
72
+ Check node and slot identity, admission and capacity accounting, bounded
73
+ streaming, cancellation safety, shutdown, supervisor child cleanup, and
74
+ the unknown-outcome boundary after request bytes reach an execution slot.
75
+ Keep the protobuf contract compatible with the Python tunnel and review
76
+ changes to the source .proto instead of generated bindings.
77
+ - path: "tests/**"
78
+ instructions: >-
79
+ Prefer deterministic tests for observable failures, especially resource
80
+ release and protocol compatibility. Distinguish CPU process/protocol
81
+ coverage from real GPU lease and CUDA behavior; simulated workers do not
82
+ prove GPU correctness. Avoid timing-based assertions when synchronization
83
+ can express the requirement.
84
+ - path: ".github/workflows/**"
85
+ instructions: >-
86
+ Check token permissions, fork PR trust boundaries, secret exposure, and
87
+ release/deployment conditions. Do not run untrusted PR code with privileged
88
+ credentials. Preserve existing build, docs, and publishing behavior.
89
+ finishing_touches:
90
+ docstrings:
91
+ enabled: false
92
+ unit_tests:
93
+ enabled: false
94
+ simplify:
95
+ enabled: false
96
+ autofix:
97
+ enabled: false
98
+ fix_ci:
99
+ enabled: false
100
+ resolve_merge_conflict:
101
+ enabled: false
102
+
103
+ chat:
104
+ auto_reply: false
105
+ # External contributors still receive automatic reviews.
106
+ allow_non_org_members: false
107
+
108
+ knowledge_base:
109
+ opt_out: true
110
+ web_search:
111
+ enabled: false
112
+ automatic_linking_mode: disabled
113
+ linked_repositories: []
114
+
115
+ issue_enrichment:
116
+ auto_enrich:
117
+ enabled: false
118
+ planning:
119
+ enabled: false
@@ -0,0 +1,98 @@
1
+ name: Build wheels
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+ tags: ['v[0-9]*']
8
+ workflow_call:
9
+ inputs:
10
+ ref:
11
+ description: 'Optional tag, branch, or SHA; defaults to the caller ref'
12
+ type: string
13
+ required: false
14
+ workflow_dispatch:
15
+ inputs:
16
+ ref:
17
+ description: 'Optional tag, branch, or SHA; defaults to the selected workflow ref'
18
+ type: string
19
+ required: false
20
+
21
+ permissions:
22
+ contents: read
23
+
24
+ jobs:
25
+ build-linux:
26
+ name: Linux ${{ matrix.arch }}
27
+ runs-on: ${{ matrix.os }}
28
+ timeout-minutes: 40
29
+ strategy:
30
+ fail-fast: false
31
+ matrix:
32
+ include:
33
+ - {os: ubuntu-24.04, arch: x86_64}
34
+ - {os: ubuntu-24.04-arm, arch: aarch64}
35
+ steps:
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
+ with:
38
+ ref: ${{ inputs.ref || github.ref }}
39
+ fetch-depth: 0
40
+ persist-credentials: false
41
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
42
+ with:
43
+ python-version: '3.12'
44
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
45
+ - name: Build and smoke-test manylinux wheels
46
+ uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0
47
+ env:
48
+ # The wheel has no Python ABI dependency; build once per architecture.
49
+ CIBW_BUILD: cp310-manylinux_${{ matrix.arch }}
50
+ CIBW_ARCHS_LINUX: ${{ matrix.arch }}
51
+ CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
52
+ CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
53
+ CIBW_BEFORE_ALL_LINUX: >-
54
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/rustup-init.sh &&
55
+ sh /tmp/rustup-init.sh -y --profile minimal --default-toolchain 1.87.0
56
+ CIBW_ENVIRONMENT_LINUX: 'PATH="$HOME/.cargo/bin:$PATH" KCORAL_BUILD_RUST=1'
57
+ CIBW_TEST_COMMAND: kcoral router --help && kcoral-node --help
58
+ with:
59
+ output-dir: wheelhouse
60
+ - name: Check wheel metadata
61
+ run: uv tool run twine check --strict wheelhouse/*.whl
62
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
63
+ with:
64
+ name: kcoral-dist-linux-${{ matrix.arch }}
65
+ path: wheelhouse/*.whl
66
+ if-no-files-found: error
67
+
68
+ build-pure:
69
+ name: Pure wheel and sdist
70
+ runs-on: ubuntu-24.04
71
+ timeout-minutes: 15
72
+ steps:
73
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
74
+ with:
75
+ ref: ${{ inputs.ref || github.ref }}
76
+ fetch-depth: 0
77
+ persist-credentials: false
78
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
79
+ with:
80
+ python-version: '3.12'
81
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
82
+ - name: Build the sdist and a wheel without the Rust programs
83
+ env:
84
+ KCORAL_BUILD_RUST: '0'
85
+ run: uv build --out-dir dist
86
+ - name: Check the wheel is pure
87
+ run: |
88
+ wheel=$(ls dist/*-py3-none-any.whl)
89
+ if unzip -l "$wheel" | grep -E 'kcoral-(router|node)$'; then exit 1; fi
90
+ - name: Check metadata
91
+ run: uv tool run twine check --strict dist/*.whl dist/*.tar.gz
92
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
93
+ with:
94
+ name: kcoral-dist-pure
95
+ path: |
96
+ dist/*.whl
97
+ dist/*.tar.gz
98
+ if-no-files-found: error
@@ -0,0 +1,54 @@
1
+ name: Documentation
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+ tags: ['v[0-9]*']
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: write
12
+ pages: write
13
+
14
+ concurrency:
15
+ group: documentation-${{ github.event_name == 'pull_request' && github.ref || 'publish' }}
16
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
17
+
18
+ env:
19
+ PUBLISH: ${{ github.repository == 'mlc-ai/kcoral' && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) }}
20
+
21
+ jobs:
22
+ build:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
+ with:
27
+ # A new release rebuilds latest from main as well as every release tag.
28
+ ref: ${{ startsWith(github.ref, 'refs/tags/') && 'main' || github.ref }}
29
+ fetch-depth: 0
30
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
31
+ with:
32
+ python-version: '3.12'
33
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
34
+ with:
35
+ enable-cache: true
36
+ cache-dependency-glob: |
37
+ docs/requirements.txt
38
+ pyproject.toml
39
+ - name: Build the documentation website
40
+ run: python scripts/build_docs.py ${{ github.event_name == 'pull_request' && '--latest-only' || '' }}
41
+ - name: Publish to gh-pages
42
+ if: env.PUBLISH == 'true'
43
+ uses: peaceiris/actions-gh-pages@329bcc8f12caed2cefe5a5b80781499a6f3b361b # v4
44
+ with:
45
+ github_token: ${{ secrets.GITHUB_TOKEN }}
46
+ publish_dir: _site
47
+ publish_branch: gh-pages
48
+ cname: kcoral.mlc.ai
49
+ - name: Request GitHub Pages build
50
+ if: env.PUBLISH == 'true'
51
+ env:
52
+ GH_TOKEN: ${{ github.token }}
53
+ # GITHUB_TOKEN pushes do not automatically trigger a Pages build.
54
+ run: gh api --method POST "repos/$GITHUB_REPOSITORY/pages/builds"
@@ -0,0 +1,37 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: pypi-${{ github.event.release.tag_name }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ build:
16
+ uses: ./.github/workflows/build_wheels.yml
17
+ with:
18
+ ref: refs/tags/${{ github.event.release.tag_name }}
19
+
20
+ publish:
21
+ needs: build
22
+ runs-on: ubuntu-latest
23
+ environment:
24
+ name: pypi
25
+ url: https://pypi.org/p/kcoral
26
+ steps:
27
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
28
+ with:
29
+ pattern: kcoral-dist-*
30
+ merge-multiple: true
31
+ path: dist
32
+ - name: Publish to PyPI
33
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
34
+ with:
35
+ password: ${{ secrets.PYPI_API_TOKEN }}
36
+ attestations: false
37
+ verbose: false
@@ -0,0 +1,28 @@
1
+ # OS
2
+ .DS_Store
3
+ Thumbs.db
4
+
5
+ # Editors
6
+ .idea/
7
+ .vscode/
8
+ *.swp
9
+ *.swo
10
+
11
+ # Python
12
+ __pycache__/
13
+ *.py[cod]
14
+ *.egg-info/
15
+ venv/
16
+
17
+ # Build artifacts
18
+ build/
19
+ dist/
20
+ docs/_build/
21
+ _site/
22
+ .docs-venv/
23
+ target/
24
+
25
+ # Misc
26
+ *.log
27
+ tmp/
28
+ **/logs
@@ -0,0 +1,39 @@
1
+ # Formatting and hygiene checks.
2
+ #
3
+ # Run on the whole repo:
4
+ #
5
+ # uvx pre-commit run --all-files
6
+ #
7
+ # Or install as a git hook so it runs on every commit:
8
+ #
9
+ # uvx pre-commit install
10
+ #
11
+ # Update pinned hook versions with:
12
+ #
13
+ # uvx pre-commit autoupdate
14
+
15
+ repos:
16
+ # Standard hygiene hooks
17
+ - repo: https://github.com/pre-commit/pre-commit-hooks
18
+ rev: v6.0.0
19
+ hooks:
20
+ - id: check-added-large-files
21
+ # Preserve the original high-resolution icon.
22
+ exclude: ^docs/_static/brand/kcoral-icon\.png$
23
+ - id: check-case-conflict
24
+ - id: check-merge-conflict
25
+ - id: check-symlinks
26
+ - id: check-yaml
27
+ - id: check-toml
28
+ - id: end-of-file-fixer
29
+ - id: mixed-line-ending
30
+ - id: trailing-whitespace
31
+
32
+ # Python lint + format; configured in pyproject.toml [tool.ruff].
33
+ # ruff-check with the "I" rules also handles import sorting (isort).
34
+ - repo: https://github.com/astral-sh/ruff-pre-commit
35
+ rev: v0.15.22
36
+ hooks:
37
+ - id: ruff-check
38
+ args: [--fix]
39
+ - id: ruff-format