Module SDK#
Policy packages have a separate signing and decision interface. They restrict authorization and are not ordinary workspace modules. Identity providers have a separate trusted interface for external authentication. They do not grant project permissions. Certificate providers adapt approved private authorities. The host owns contributor invitation, independent key approval and current connection authority. See contributor operations and the separate OpenSSH trust workflow. Executor providers supply approved container runtime behavior. Scheduler providers propose project job order and concurrency. Both are trusted installation packages with independent host enforcement. Inspection providers supply optional local scanner behavior; the host owns immutable file binding, dataset restrictions and exemptions.
FICC modules are runtime ZIP packages. The host owns the interface, credentials, permission checks and process sandbox. A module supplies a manifest, optional program files and declarative component data. The browser never runs module code.
Extension boundary#
Packages can combine the documented broker primitives and host components. Program files execute in separate sandboxed processes after explicit grants. Adding a package does not require a FICC rebuild.
The separate provider-adapter role permits packaged VM provider logic through
registered host transports. It requires an explicit provider:admin grant for
the exact archive digest and immutable profile. That grant permits administration
of the registered provider account. It cannot enforce read-only account access.
See the adapter protocol and helpers.
Ordinary modules have C, C++, Rust, Python and JavaScript helpers, with TypeScript authoring support. Adapters have Python, C and C++ helpers. Other adapter languages implement the documented framed protocol. New transport classes require host integration and qualification. Existing libvirt, Proxmox, container and administration integrations retain fixed host adapters.
Keep provider behavior inside packages where the documented capabilities permit it. Host components own authentication, credential access, transport limits and display. Do not place credentials or commands in component state to bypass that boundary.
Controller persistence uses a separate state driver interface. State drivers are trusted installation packages with full controller authority. They are not sandboxed workspace modules and cannot be installed through module grants.
Development commands#
Use Python 3.12 or later from the FICC development environment. Run commands from the FICC source directory. Build the default packages with:
python tools/build-modules.py defaults --fetch --output dist/modules
This builds the separate supplied packages. Install an archive through the module manager, review its digest and requested capabilities, then enable it with explicit workspace grants. Default packages use the same archive inspection and permission checks as third-party packages. They are not registered by the application wheel. A hash identifies bytes; it does not prove publisher identity. Install packages only from a source you trust.
Make a package#
Create a source directory with manifest.json and an optional payload/ directory.
Put the runtime entry point and all required runtime files inside payload/.
Their paths are relative to the package root. Copy a manifest from modules/ for
a host component, or from sdk/examples/ for a program. Set a unique ID and version.
The files inventory is generated by the packer; leave it empty in the source.
python tools/build-modules.py pack /path/to/module-source --output dist/modules
The packer includes files under payload/. Python protocol 2 modules that
use the supplied SDK must copy sdk/python/ficc_module.py into that directory.
The defaults command includes this dependency for the supplied Python modules.
The packer does not install or infer third-party dependencies.
Native sources can also declare build.json beside the manifest. The fixed builder
compiles declared C or C++ sources and selected, checksum-pinned ZIP dependencies.
It accepts no build scripts or custom compiler flags. The generated program and
dependency notices enter the inspected archive. Existing payload members cannot
replace generated files.
Use --cache for a private dependency directory and
--fetch to permit pinned downloads. Installation never compiles package code.
The packer rejects links, invalid paths and oversized files. It builds a complete SHA256 inventory and calls FICC's archive inspector before publishing the ZIP. Member order, timestamps, permissions and JSON encoding are fixed. Equal input bytes produce equal archive bytes. Existing different output is refused; change the version or use a new output directory. Compiler output can differ between toolchains even when the ZIP format is deterministic.
Build the language examples#
The examples implement the same echo batch in C, C++, Rust, Python, JavaScript
and TypeScript. TypeScript is the compiled path within the JavaScript family.
The C and C++ examples use the same C protocol library. The Rust example uses
the Rust library. Python and JavaScript have small reusable protocol libraries.
python tools/build-modules.py examples --fetch --output dist/module-examples
python sdk/conformance.py --packages dist/module-examples
Build requirements: Linux x86_64 or aarch64, a C11 compiler, a C++17 compiler,
Cargo/Rust, Python 3.12 or later, and Node.js 22 or later. Native examples need
the C.UTF-8 locale and the build system's C/C++ runtime ABI. Build for the target
distribution; an architecture match alone does not establish ABI compatibility.
Activation checks Linux ELF64 headers, the declared architecture and native
loader availability inside the sandbox before replacing an active package.
It does not execute native package code to discover dependencies.
Use --node /path/to/node on both commands when required.
Build one example with --language python or another language name. Use --cache
to place build files outside the default sdk/build directory.
--fetch permits downloads of pinned build dependencies. cJSON 1.7.19 and
TypeScript 5.9.3 are pinned by URL, byte size and SHA256 in dependencies.json.
Rust uses exact serde_json 1.0.145 and a committed Cargo.lock for all transitive
versions and checksums. No npm install scripts run. Later builds can omit --fetch
and use the verified cache; Cargo then runs with --frozen. No host packages are
installed. See dependency licenses.
Conformance runs the known SDK examples as local child processes. It tests N=1 and N=64, output identity/order, text escaping, Unicode, maximum target length, unknown actions and malformed frames. Do not use this command to run untrusted packages: it does not apply the FICC sandbox. A passing result is protocol evidence, not qualification of the installed host's sandbox, permissions or provider access. The installed FICC runtime must pass its own sandbox check before it enables a program package. A missing runtime or unavailable sandbox keeps it disabled.
Build the broker examples#
Each language also has a separate protocol 2 resource example. It requests
system:read and calls the host's system.resources.read primitive with an empty
parameter object. This reads saved system status and resource measurements under
the current caller's permissions. The module receives no transport credentials.
python tools/build-modules.py examples --broker --fetch --output dist/module-broker-examples
python sdk/conformance.py --broker --packages dist/module-broker-examples
Omit --fetch when the verified dependency cache is populated. --language,
--cache and --node retain their existing meanings. Archives use distinct
org.example.resources.<language> IDs. The Python build API selects this path
with example(language, cache, fetch, node, broker=True); its default still builds
the protocol 1 echo example. TypeScript compiles its broker source to JavaScript.
The broker helpers give the complete target batch to one handler. The handler calls a declared primitive for the batch or a subset, then returns complete per-target results. Grants and caller permissions remain host checks. A refusal can affect one target; cancellation, malformed traffic and lost authority fail the invocation. Calls are sequential and share the host's process deadline. Do not retry a mutation merely because a pipe closed.
Broker conformance performs 32 checks per language: N=1/N=64 success and errors,
request and response identities, cancellation, result shape and malformed frames.
It runs only the known local examples. Real host qualification separately needs
the actual installed archives, current system:read grants and a working sandbox.
The retained test tests/tools/test_module_sdk_broker.py can consume a built
directory through FICC_SDK_BROKER_PACKAGES; explicitly set
FICC_REAL_MODULE_SANDBOX=1 to run its real installed-host cases.
UI and capabilities#
Views have a column, row, group or tabs root. The component format
includes tables, fields, menus, trees, meters, logs, editors, clocks and audio.
Use unique component IDs so stored state remains stable. Buttons reference declared
action IDs. The host renders labels as text. HTML, script, CSS and external URL
fields are not supported.
Notes use workspace:read and workspace:write. The audio player also requests
audio:playback; it uses an explicit local file picker and starts only after a
user action. Playback permission does not grant microphone access. The clock
uses workspace:read and a declared IANA timezone. The default clock uses UTC.
Workspace persistence and audio ownership remain host services.
A manifest can declare optional_capabilities, a unique subset of capabilities.
If omitted, every declared capability remains required. Required permissions need
explicit target grants before activation and panel placement. Optional permissions
can remain ungranted, including permissions unavailable on this host. Selecting an
unavailable permission is refused. Every action and host primitive still requires
its own current grants; declaring a permission optional never grants access.
For example, the libvirt package requires vm:read and can offer vm:power and
vm:console separately. The file editor offers files:write separately from read.
Changing the grant set increments the package revision and invalidates active calls.
Protocol 1 echo examples declare no capabilities. Protocol 2 resource examples use the constrained host broker. Do not embed passwords, provider tokens or shell commands in manifests or component state. Package dependencies must be bundled; manifest dependency resolution is not supported.
See the process protocols, the complete manifests under sdk/examples/, and
the shared cases in fixtures/conformance.json.
Artifact and dataset interfaces describe digest-bound source transfers, installable filesystem storage providers and durable job input access.
Data source interfaces define installable SQL, file-format, object and customer API providers, registered queries and verified dataset exports.
Audit destination interfaces define bounded durable appends, exact acknowledgements and separately installed destination providers.