Skip to main content
Your plugin code runs inside an isolated sandbox worker, not in a platform process. It has no route back to internal platform addresses and holds no platform credential. Everything it needs from the platform is handed to it through one object: the RemoteExecutionContext (ctx) passed to every call and poll. File and platform access happen as JSON-RPC callbacks on the worker’s own channel, which the platform services in-process against its database and storage — so no key ever enters the sandbox.
There is no context.models, context.artifacts, or HTTP-to-platform surface inside a plugin. The sandbox surface is exactly what’s on RemoteExecutionContext below: files, integration credentials, plugin config, and the group id.

The execution context

Import it from noxus_sdk.plugins.context. Every node’s call(self, ctx, ...) and every trigger’s poll(self, ctx, state) receives one.

Files — host callbacks, no egress

A File input arrives as a File model; return a File (or list[File]) to emit one. Reading or writing a file’s bytes issues a JSON-RPC callback (host.get_content / host.upload_file) on the worker channel. The platform services these in-process, scoped by the single-use call token to the calling workspace — a plugin cannot read or plant files in another tenant. Use the file helper directly, or the higher-level File helpers that wrap it:
The lower-level helper (ctx.get_file_helper()) exposes get_content(file) and upload_file(file_name=, content=, content_type=, group_id=) if you need them, but File.from_bytes(...) / raw.get_content(ctx) cover the common cases.
noxus plugin serve (local dev) has no host to service file callbacks, so file operations raise there. Nodes that read or write platform files can only be exercised under the platform runtime.

Email

noxus_sdk.email.Email parses a raw email into a typed object with a markdown body and its attachments/inline images persisted as Files.
.to_text() renders the email for LLM/tool input; pass zip_attachments=True to collapse attachments into a single zip.

Integration credentials

Credentials are the one per-workspace part of the plugin model — each workspace connects its own. A node declares which integration types it needs and reads them from the context at run time. See Creating Integrations for the full authoring flow.

Typed errors

Raise IntegrationFailedError or UnexpectedError from noxus_sdk.errors — not a bare Exception — when an upstream API or credential fails; the message reaches the node’s failure UI.
The exception type does not cross the sandbox boundary today — only the message does. Make messages actionable, since that string is all the user sees.

Best Practices

Treat file access as I/O over the callback channel. Return File outputs rather than raw bytes so the platform tracks storage and lineage. Use File.from_bytes for derived content and persist_files_locally only when a library truly needs a filesystem path.
Read credentials from ctx.get_integration_credentials(type) at call time — never cache them across calls, since they are per-workspace and can change. Fail with IntegrationFailedError when a required credential is missing.
Pass only what a node needs. ctx.group_id scopes work to the current workspace; do not attempt to reach other groups — the call token overrides any group_id you pass to a callback anyway.
Degrade for expected external flakiness (return an empty typed result), and reserve raised errors for genuine misconfiguration. A raised exception fails the whole run.

Creating Integrations

Build typed credentials and connect nodes to external systems.