Engine SDK
SDK Examples
Go (Phase 1)
package main
import "getarcan.dev/sdk"
type Postgres struct{}
func (e *Postgres) Describe() sdk.Descriptor {
return sdk.Descriptor{
Name: "postgres", Version: "0.1.0", DisplayName: "PostgreSQL",
Capabilities: []string{"host:sql", "engine:dynamic_credentials", "engine:root_rotation"},
}
}
func (e *Postgres) Ping(ctx sdk.Context) error {
_, err := ctx.SQL("SELECT 1")
return err
}
func (e *Postgres) CreateCredentials(ctx sdk.Context) (*sdk.Credentials, error) {
user := ctx.GenerateUsername()
pass := ctx.GeneratePassword(24)
ctx.SQLExec(`CREATE ROLE "$1" LOGIN PASSWORD '$2' VALID UNTIL '$3'`, user, pass, ctx.TTL())
ctx.SQLExec(`GRANT $1 TO "$2"`, ctx.Role().Grants, user)
return sdk.NewCredentials(user, pass), nil
}
func (e *Postgres) RevokeCredentials(ctx sdk.Context) error {
ref := ctx.LeaseID()
ctx.SQLExec(`DROP ROLE IF EXISTS "$1"`, sdk.SanitizeID(ref, 32))
return nil
}
func main() { sdk.Serve(&Postgres{}) }
TypeScript (Phase 2)
import { Engine, Context, Credentials } from '@getarcan/sdk';
export default class Postgres extends Engine {
name = 'postgres';
version = '0.1.0';
capabilities = ['host:sql', 'engine:dynamic_credentials'];
async ping(ctx: Context): Promise<void> {
await ctx.sql('SELECT 1');
}
async createCredentials(ctx: Context): Promise<Credentials> {
const user = ctx.generateUsername();
const pass = ctx.generatePassword(24);
await ctx.sqlExec(`CREATE ROLE "${user}" LOGIN PASSWORD '${pass}'`);
await ctx.sqlExec(`GRANT ${ctx.role().grants} TO "${user}"`);
return ctx.credentials(user, pass);
}
}
Python (Phase 3)
from arcan_sdk import Engine, Context, Credentials
class Postgres(Engine):
name = "postgres"
version = "0.1.0"
capabilities = ["host:sql", "engine:dynamic_credentials"]
def ping(self, ctx: Context):
ctx.sql("SELECT 1")
def create_credentials(self, ctx: Context) -> Credentials:
user = ctx.generate_username()
pwd = ctx.generate_password(24)
ctx.sql_exec(f'CREATE ROLE "{user}" LOGIN PASSWORD \'{pwd}\'')
ctx.sql_exec(f'GRANT {ctx.role().grants} TO "{user}"')
return ctx.credentials(user, pwd)
Sandboxed Runtime Phases
| Phase | Runtime | Plugin Format | Who Creates |
|---|---|---|---|
| v0.1 | Core-only -- KV built-in, no plugins | N/A | Just us |
| v0.2 | Go compiled binary (bridge) | Compiled .arcanpkg | Us + early contributors |
| v0.3 | WASM sandbox (wazero) | .wasm in .arcanpkg | Anyone, any language |
Why WASM Is the Target
- Language agnostic -- Go, Rust, TypeScript, Python all compile to WASM
- Sandboxed by design -- WASM modules cannot access network, filesystem, or host memory
- Portable -- one
.wasmbinary runs on every OS/arch, no cross-compilation - No separate process -- runs inside core via wazero (pure Go, zero CGo)
- Host functions -- core exposes exactly the functions the plugin needs, nothing more
The contracts (ArcanContext, package format, descriptor) are stable across all phases. Only the execution mechanism changes. This is why contracts are defined now and the runtime implementation is deferred.
SDK Versioning
sdk_version = 1 (initial release)
Rules:
- Adding new host functions → same SDK version (additive)
- Adding new engine methods → same SDK version (additive)
- Changing host function semantics → bump SDK version
- Removing host functions → bump SDK version
- Core supports SDK versions N and N-1 (one version back)
- Plugin declares sdk_version in descriptor
- Core rejects unsupported versions with clear error