SDK
Rune has SDKs for Go and Python. Both build extensions: standalone programs that Rune launches as child processes and talks to over a private, local channel. Through that channel an extension registers commands, reacts to editor and workspace events, drives windows and tabs, reads and writes files, calls language servers and models, and serves persistent UIs.
The Extensions guide covers the runtime model, the
permission system, and the extensions console command. This section covers
authoring: writing an extension with each SDK, iterating on it inside a
workspace, testing it, and packaging it for pkg install.
Pick your SDK
| SDK | Repository | Notes |
|---|---|---|
| Go | rune-go-sdk | Complete API surface, plus a component framework for in-terminal plugins. |
| Python | rune-python-sdk | Complete API surface, plus Rich and Textual adapters. Ships as source, with no build step. |
| Rust | rune-rust-sdk | Coming soon. Async Rust on tokio, with an early-stage port under way. |
Whichever you choose, an extension has the same shape:
- Metadata. Declare the extension's id, version, and the permissions it needs.
- Setup. The SDK performs the handshake and hands your setup function a workspace handle whose typed clients call into Rune. Every call is gated on a permission you declared; an undeclared capability is rejected.
- Return. Wire capabilities, register commands and event handlers, and return. The SDK owns the process lifetime until the workspace closes.
The development loop
You never run your extension directly: Rune launches it and connects to it. Start a work-in-progress extension in a workspace from the console:
extensions start myext /path/to/entrypoint --config '{"key":"value"}'
The entrypoint can be a compiled binary, a .py script, a Go main package
directory containing go.mod and go.sum, or a .rs file inside a Cargo
project. Source and package entrypoints run through the matching language
package's toolchain automatically (see
source and package extensions),
so you can iterate without a build step. The rest of the lifecycle is managed
from the same command:
| Command | What it does |
|---|---|
extensions status | List every workspace extension with status, pid, and uptime. |
extensions info <id> | Detailed state for one extension, including restart counts. |
extensions logs <id> [--tail <N>] | What the extension wrote to stderr, where startup failures and crashes show up. |
extensions restart <id> | Relaunch with the current config, the fastest way to pick up a change. |
extensions stop <id> | Stop it. |
Permissions are enforced at two layers: a call into a capability the
extension never declared is rejected outright, and the first time it uses a
declared capability Rune prompts the user to allow or deny it. If a
capability seems unreachable, check authorizer list for a lingering
deny always decision and clear it with authorizer revoke <permission>.
Sample responses with runectl
runectl wraps the same services the SDKs expose, and most of
its commands accept --format json. Running the equivalent command by hand
shows the exact shape of a response before you write code against it:
runectl storage list --format json
runectl lsp hover MySymbol --format json
Ship it
Extensions are distributed from a public git repository and installed
with pkg install <host>/<owner>/<repo>, for example
pkg install github.com/<owner>/<repo>. Any host Rune can clone over HTTPS
works, including GitHub, GitLab, Bitbucket, and self-hosted servers. Rune
clones the repo, reads a config.yaml at its root that registers the
extension under extensions.<id>, provisions the language toolchain it
requires, and runs your extension from source, so one repository serves
every platform. Each guide ends with the packaging recipe for its language;
see Packages for the
full format and how versions (latest, tags, commits) work.