1.0.0 · five SDKs · execution stable, PTY not yet
Powerful terminal execution, everywhere.
Run operating-system commands, drive interactive processes, and stream their output — with one conceptual API across Python, TypeScript, Dart, Java and Kotlin. All five pass the same conformance corpus.
from kryon import Runtime
runtime = Runtime(encoding="utf-8", timeout=30)
# Run it and tell me what happened.
result = runtime.execute("git", ["status", "--porcelain"])
print(result.stdout, result.exit_code, result.ok)
# Start it and let me talk to it.
with runtime.spawn("pip", ["install", "numpy"]) as proc:
for stream, chunk in proc:
print(chunk.decode(), end="")
What makes it different
Not a better subprocess. One well-specified execution model, implemented
natively in each language, with the terminal layers built on the same foundation
instead of alongside it.
The dangerous thing has a different name
execute() passes arguments as a vector — no shell, ever. Shell
semantics live behind execute_shell(), a separate method name rather
than a shell=True flag, so reaching for it is visible in every diff.
Failing to start is an error. Failing while running is a result.
A missing executable raises — nothing ran. A process that exited 1
returns a result, because grep exits 1 to mean “no match”.
check=True opts into strictness, and every error carries the result it
came from, stderr included.
Limits that actually hold
Timeouts terminate, wait a documented grace period, then kill — including a process
that ignores SIGTERM. Output caps bound memory during the
flood, not after buffering it.
Nothing is left running
Leaving a scope, cancelling an async task, or a timeout firing all terminate the child before control returns. Kryon never hands back the flow of execution with a process still alive.
Streaming with real backpressure
Output arrives as it is produced, through a bounded queue. Stop consuming and Kryon stops reading, so the child blocks instead of your heap growing.
One behaviour, enforced not promised
Every SDK runs the same conformance corpus — one JSON file, never forked per language, where each case records what would break in the real world if it regressed.
Zero dependencies
The Python SDK depends on nothing. Adding a dependency to a package that already runs arbitrary programs is adding supply-chain risk to the worst possible place.
No hidden behaviour
No telemetry, no analytics, no update check, no phoning home, no implicit shell, no global state. Kryon makes no network calls of its own, and has no configuration that could enable any.
Five layers, each useful alone
Most projects in this space fuse two or three of these, and that fusion is what makes
them hard to reuse. Running git status needs no terminal. A web terminal
rendering with an existing component needs a PTY but not an emulator. Turning a
recorded CI log into a rendered screen needs the emulator and nothing else.
Only layer 1 exists today — and it exists in all five languages. Read the architecture or check the status table.
Examples
Every snippet here runs today against the Python SDK.
from kryon import Runtime
runtime = Runtime(encoding="utf-8")
result = runtime.execute("git", ["log", "--oneline", "-5"])
print(result.stdout)
print(result.exit_code, result.ok, result.duration)
# A non-zero exit is information, not an exception.
changed = runtime.execute("git", ["diff", "--quiet"]).exit_code == 1
from kryon import Runtime, Stream
runtime = Runtime()
# Output arrives as it is produced, through a bounded queue.
with runtime.spawn("pip", ["install", "numpy"]) as proc:
for stream, chunk in proc:
where = "err" if stream is Stream.STDERR else "out"
print(f"[{where}] {chunk.decode()}", end="")
result = proc.wait()
# Leaving the block terminates the process. Always.
filename = input("file: ") # "; rm -rf ~"
# Safe. One literal argument. No shell is involved.
runtime.execute("wc", ["-l", filename])
# Command injection — and it is named so that it looks like one.
runtime.execute_shell(f"wc -l {filename}")
# Keep your credentials out of the child process.
runtime.execute(
"./untrusted-build.sh",
clear_env=True,
env={"PATH": "/usr/bin:/bin", "HOME": "/tmp/build"},
)
import asyncio
from kryon.aio import AsyncRuntime
async def main():
runtime = AsyncRuntime(encoding="utf-8")
results = await asyncio.gather(
runtime.execute("git", ["rev-parse", "HEAD"]),
runtime.execute("git", ["status", "--porcelain"]),
)
# Cancelling the task terminates the child before CancelledError propagates.
task = asyncio.create_task(runtime.execute("./forever"))
await asyncio.sleep(1)
task.cancel()
asyncio.run(main())
result = runtime.execute(
"./slow-thing",
timeout=30, # terminate, wait kill_grace, then kill
max_output_bytes=1 << 20, # per stream, enforced during the flood
)
if result.termination.value == "TIMEOUT":
# Output collected before the kill is kept — it is the only
# evidence of what the process was doing.
print(result.stdout)
# These keep YOUR process healthy. They do not contain a hostile one.
Five SDKs, one specification
Honest status. A row says “implemented” only when it is implemented, tested, and passing the shared conformance corpus on Linux, macOS and Windows.
| Language | Package | Registry | Status |
|---|---|---|---|
| Python | kryon |
PyPI | Implemented · published |
| TypeScript / JavaScript | kryon-exec | npm | Implemented · published |
| Dart | kryon | pub.dev | Implemented · published |
| Java | io.github.piyush-mishra-00:kryon | Maven Central | Implemented · published |
| Kotlin | io.github.piyush-mishra-00:kryon-kotlin | Maven Central | Implemented · published |
All five are published at 1.0.0. The Maven Central artifacts are GPG-signed with a key
published to the keyservers, so the download can be verified rather than trusted. On npm
the package is kryon-exec, because the registry
refuses kryon as too similar to cron.
The specification is language-neutral and the corpus is one shared file, so an SDK
cannot quietly disagree: it either passes a case, or skips it with a reason.
How that works.
Security
Kryon executes arbitrary commands. That makes security a feature of the project, not a section of its documentation.
Kryon is not a sandbox
It runs what you tell it to run, with the privileges you already have. Its timeouts and output caps are resource management — they keep your process healthy; they do not contain a hostile one. Isolation is the job of a container, a VM or an unprivileged account.
- Never build an
execute_shellstring from untrusted input. - Never let untrusted input choose the executable.
- Never expose execution to a browser without authentication, authorization, a command allowlist and OS-level isolation — all four.
The only correct shape for a web terminal
Browser rendering only, executes nothing
│ authenticated TLS WebSocket
▼
Your backend authn · authz · allowlist · limits · audit
│
▼
Kryon runtime argument vectors · timeout · output cap
│
▼
Container / VM unprivileged user, destroyed after use
Four layers, and Kryon is only the third. Anything showing the third layer alone is a vulnerability with good typography.
Roadmap
No dates. This is maintained by one person, and a date would be a guess presented as a commitment.
| Phase | What | Status |
|---|---|---|
| 0–2 | Foundation, specification, conformance corpus | Done |
| 1 | Python SDK | Done |
| 3 | TypeScript SDK | Done |
| 4 | Dart SDK | Done |
| 5 | Java SDK | Done |
| 6 | Kotlin SDK | Done |
| 7–8 | Conformance across all five, and 1.0.0 | Done |
| 9 | PTY on POSIX | Next |
| 10 | PTY on Windows (ConPTY) | Planned |
| 11 | Terminal emulator | Planned |
| 12–13 | WebSocket transport and web terminal | Planned |
| 14–15 | SSH adapter, production hardening | Planned |
Full roadmap, including what is deliberately not planned.
Community
Five independent implementations turned the specification from a document into a guarantee — and found three real bugs doing it. What the project needs now is people using it and saying where the model is still wrong.
Discussions
Questions, ideas, “is this a bug?”, and proposals before they become code.
Issues
Bug reports and feature proposals, with templates that ask for what makes them actionable.
Contributing
Setup, branching model, commit conventions, and what gets a pull request declined.
Report a vulnerability
Privately, through GitHub security advisories. Never in a public issue.
Buy me a coffee ☕
Kryon is built by one person and given away under Apache-2.0. Entirely optional, and it changes nothing about the licence or the roadmap.