No project description provided
Project description
Basilisk
Write Python canisters for the Internet Computer. Deploy in seconds, connect via SSH/SFTP. Forked from Kybra.
Features
- Write IC canisters in pure Python using
@queryand@updatedecorators - Builds in seconds — pre-compiled CPython 3.13 WASM template, no Rust toolchain needed
- SSH & SFTP access — connect to any deployed canister with standard
sshandsftpclients - Interactive shell (bosh) — Python REPL running inside the canister
- Basilisk OS — task scheduling, code management (Codex), and process execution on-chain
- In-memory filesystem — standard
osandopen()calls, accessible via SFTP - Persistent storage —
StableBTreeMapsurvives canister upgrades - IC system APIs:
ic.caller(),ic.time(),ic.print(),ic.canister_balance(), etc. Principal,Opt,Vec,Record,Varianttype support
Quick Start
Prerequisites
- dfx (IC SDK)
- Python 3.10+
Install
pip install ic-basilisk
Create, deploy, and connect
# 1. Scaffold a new project
basilisk new my_project
cd my_project
# 2. Start the local replica and deploy (builds in ~2 seconds)
dfx start --background
dfx deploy
# 3. Call your canister
dfx canister call my_project greet '("World")'
# ("Hello, World! The counter is at 0.")
# 4. Open an interactive Python shell inside the canister
basilisk shell --canister my_project
# 5. Or connect via SSH and SFTP
basilisk sshd --canister my_project
ssh -p 2222 localhost # Python shell over SSH
sftp -P 2222 localhost # browse the canister filesystem
The generated canister code
from basilisk import query, update, text, nat64, ic
counter = 0
@query
def greet(name: text) -> text:
return f"Hello, {name}! The counter is at {counter}."
@query
def get_counter() -> nat64:
return counter
@update
def increment() -> nat64:
global counter
counter += 1
return counter
@query
def get_time() -> nat64:
return ic.time()
@query
def whoami() -> text:
return str(ic.caller())
SSH & SFTP Access
Every Basilisk canister is accessible over SSH and SFTP. Start the proxy and connect with any standard client.
Start the SSH server
# Local replica
basilisk sshd --canister my_project
# IC mainnet
basilisk sshd --canister my_project --network ic
# Custom port
basilisk sshd --canister my_project --port 3333
Connect via SSH
ssh -p 2222 -o StrictHostKeyChecking=no localhost
This drops you into bosh (Basilisk OS Shell) — a Python REPL running inside the canister:
bosh 🐍 ic> print("Hello from the IC!")
Hello from the IC!
bosh 🐍 ic> import os; os.listdir("/")
['data', 'config.json']
bosh 🐍 ic> 1 + 1
2
Run a single command over SSH:
ssh -p 2222 localhost 'print(ic.time())'
Connect via SFTP
sftp -P 2222 -o StrictHostKeyChecking=no localhost
Browse, upload, and download files on the canister's in-memory filesystem:
sftp> ls /
data config.json
sftp> put local_script.py /scripts/myscript.py
sftp> get /data/results.json ./results.json
sftp> mkdir /logs
Shell commands (bosh)
| Command | Description |
|---|---|
%ls [path] |
List canister filesystem |
%cat <file> |
Show file contents |
%mkdir <path> |
Create directory |
%wget <url> <dest> |
Download URL into canister filesystem |
%run <file> |
Execute a local file on the canister |
%task create/run/list |
Create and manage scheduled tasks |
%db dump/clear/count |
Inspect the canister database |
%info |
Show canister info (principal, cycles, status) |
!<cmd> |
Run a local OS command |
Basilisk OS
Basilisk OS provides operating-system-like services for IC canisters: task management, code storage, scheduled execution, and persistent storage — all running on-chain.
┌─────────────────────────────────────────────┐
│ Basilisk OS │
├──────────────┬──────────────┬───────────────┤
│ Task Manager │ Filesystem │ Database │
│ Task │ POSIX-like │ ic-python-db │
│ TaskStep │ in-memory │ Entity ORM │
│ TaskSchedule│ os / open() │ StableBTree │
│ Codex/Call │ │ │
├──────────────┴──────────────┴───────────────┤
│ Basilisk CDK (Python → WASM) │
├─────────────────────────────────────────────┤
│ Internet Computer (IC) │
└─────────────────────────────────────────────┘
Entities
- Codex — Stores executable Python code on the canister filesystem. Code is read/written transparently via the
codeproperty. - Call — Links a Codex to a TaskStep for execution (sync or async).
- Task — A unit of work with one or more steps.
- TaskStep — A single step in a multi-step task workflow.
- TaskSchedule — Defines when and how often a Task runs (one-shot or recurring).
- TaskExecution — Records the result of each execution attempt.
Task management via bosh
# Create a task with inline code
bosh> %task create my_report --code "print('Generating report...'); result = 42"
# Run it immediately
bosh> %task run 1
# Schedule a recurring task (every 60 seconds)
bosh> %task create heartbeat every 60s --code "print('alive at', ic.time())"
# View task details and list all tasks
bosh> %task info 1
bosh> %task list
Using Basilisk OS entities in canister code
from basilisk.os import Task, TaskStep, Codex, Call, TaskSchedule
@update
def create_pipeline() -> text:
codex = Codex(name="etl_script")
codex.code = "data = [x * 2 for x in range(10)]; print(f'Processed {len(data)} items')"
task = Task(name="ETL Pipeline")
step = TaskStep(task=task)
call = Call(codex=codex, task_step=step)
schedule = TaskSchedule(name="hourly", task=task, repeat_every=3600)
return f"Created task: {task.name}"
Remote Code Execution
Execute Python on a deployed canister without redeploying:
# One-liner
basilisk exec --canister my_project 'print(1 + 1)'
# Run a local script on the canister
basilisk exec --canister my_project -f analysis.py
# Pipe code
echo "import os; print(os.listdir('/'))" | basilisk exec --canister my_project
# Target IC mainnet
basilisk exec --canister my_project --network ic 'print(ic.canister_balance())'
Filesystem
Standard Python os operations and open() work inside the canister. The filesystem is also accessible via SFTP (see above).
import os
@update
def setup() -> text:
os.makedirs("/data/reports", exist_ok=True)
with open("/data/config.json", "w") as f:
f.write('{"version": 1}')
return f"exists={os.path.exists('/data/config.json')}"
@query
def load_config() -> text:
with open("/data/config.json", "r") as f:
return f.read()
Note: The filesystem is in-memory (heap). Data persists across calls but resets on canister upgrade. For persistent storage, use
StableBTreeMap.
StableBTreeMap
Key-value storage that survives canister upgrades using IC stable memory:
from basilisk import query, update, text, Opt, StableBTreeMap
db = StableBTreeMap[str, str](memory_id=0, max_key_size=100, max_value_size=100)
@update
def db_set(key: text, value: text) -> text:
db.insert(key, value)
return f"set {key}={value}"
@query
def db_get(key: text) -> Opt[text]:
return db.get(key)
dfx canister call my_project db_set '("name", "Alice")'
dfx canister call my_project db_get '("name")'
# (opt "Alice")
# Data survives upgrades:
dfx deploy my_project --upgrade-unchanged
dfx canister call my_project db_get '("name")'
# (opt "Alice") ← still there!
Python Backends
Basilisk supports two Python backends:
# CPython 3.13 (default) -- fast template builds
basilisk new my_project
# RustPython -- legacy, full Rust build
basilisk new --backend rustpython my_project
CPython vs RustPython
| CPython 3.13 | RustPython | |
|---|---|---|
| Build time | ~seconds (template) | ~60-120s (Cargo build) |
| Wasm size | ~5.3 MB | ~26 MB |
| Python compatibility | Full (reference implementation) | Partial (~3.10) |
Benchmark Results
Wasm instruction counts measured on a PocketIC replica via GitHub Actions CI. Lower is better — fewer instructions means lower cycle cost on the IC.
| Benchmark | CPython (instructions) | RustPython (instructions) | RustPython / CPython |
|---|---|---|---|
| noop (call overhead) | 15,914 | 88,918 | 5.6x |
| increment (state mutation) | 16,050 | 92,485 | 5.8x |
| fibonacci(25) (iterative) | 37,269 | 294,649 | 7.9x |
| fibonacci_recursive(20) | 29,617,903 | 337,795,318 | 11.4x |
| string_ops (100 concatenations) | 275,375 | 2,135,202 | 7.8x |
| list_ops (500 append + sort) | 602,711 | 5,819,267 | 9.7x |
| dict_ops (500 inserts + lookups) | 3,407,101 | 23,087,720 | 6.8x |
| method_overhead (total prelude) | 11,122 | 42,216 | 3.8x |
CPython is 6–11x faster than RustPython for compute-heavy workloads due to its optimized C interpreter. The gap is largest for recursive function calls (11.4x) and list operations (9.7x). Even the minimum overhead per call is lower: 11K vs 42K instructions.
Full CI logs: CPython run · RustPython run
Run it yourself: trigger the Benchmark workflow from the Actions tab — select
cpython,rustpython, orbothas the backend, andlocaloricas the network.
The benchmark source is in benchmarks/counter/.
CLI Reference
basilisk new [--backend cpython|rustpython] <name> Create a new project
basilisk build Build the canister
basilisk exec [--canister <c>] [--network <n>] <code> Execute code on a deployed canister
basilisk shell [--canister <c>] [--network <n>] Interactive shell (bosh)
basilisk sshd [--canister <c>] [--network <n>] [--port <p>] SSH/SFTP server
basilisk --version Print version
Disclaimer
Basilisk may have unknown security vulnerabilities due to the following:
- Limited or no production deployments on the IC
- No extensive automated property tests
- No independent security reviews/audits
Documentation
For detailed architecture notes, see CPYTHON_MIGRATION_NOTES.md.
Discussion
Feel free to open issues.
License
See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ic_basilisk-0.9.4.tar.gz.
File metadata
- Download URL: ic_basilisk-0.9.4.tar.gz
- Upload date:
- Size: 499.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3de5ccd67b043aabfcbcc69d0392853ce30bd1e73bc35a20393fbbfb97f6a37
|
|
| MD5 |
f0adb33454b9ff7cdd44b16cbff758e1
|
|
| BLAKE2b-256 |
bd3239f4c4e57aadbe59d6df38ce6a5770c47620a3e55a938f3db3cc3944b1a8
|
File details
Details for the file ic_basilisk-0.9.4-py3-none-any.whl.
File metadata
- Download URL: ic_basilisk-0.9.4-py3-none-any.whl
- Upload date:
- Size: 619.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23963f02508afc7df611e5c6b2b4b37bf6478253ad1ea562d05988129a65f9d2
|
|
| MD5 |
597e1595c03be4aeed5baf3e4b05df05
|
|
| BLAKE2b-256 |
3cabe73808c686e38b8230b7dfac0d6dc132edb9cae8809d38bff46d0384d424
|