Your first managed child
Start with a read-only echo operation. A managed child is an isolated process: the host supplies its startup context, authenticates it, checks health, and dispatches negotiated calls. Your code implements the operation.
This guide targets SDK 0.4.0. Publication is pending; there is no public installation command yet. Use an approved SDK wheel supplied through the developer distribution channel. Do not substitute the private owner package for the authoring SDK.
1. Define the descriptor
from skulk_capability_sdk.contracts import Descriptor
TEXT_SCHEMA = {
"type": "object",
"properties": {"text": {"type": "string", "maxLength": 1024}},
"required": ["text"],
"additionalProperties": False,
}
ECHO = Descriptor(
id="echo", version="1.0.0", title="Echo",
description="Return up to 1024 characters of input text unchanged.",
io_mode="unary",
input_schema=TEXT_SCHEMA,
output_schema=TEXT_SCHEMA,
)
print(ECHO.qualified_id)
print(ECHO.revision)
Declare this descriptor in the installation's manifest. The host's exact manifest digest, executable digest, protocol and Skulk™ version constraint must agree with the installed runtime. See contracts and startup and packaging.
2. Read the inherited startup record
Your executable accepts the host's --config-fd argument and calls storage.read_startup with that descriptor number. The bounded startup record provides socket, token, identities, manifest, bounds and configuration. It is not a file supplied by a caller.
from skulk_capability_sdk.storage import read_startup
startup = read_startup(config_fd)
config_fd comes from your command-line argument parser. Never log the startup record, token, credential paths or credential values. Refuse invalid startup instead of trying arbitrary sockets or discovering another executable on PATH.
3. Authenticate and answer the control channel
Connect with asyncio.open_unix_connection(startup.socket). Send a Hello whose protocol matches startup.manifest.protocol and whose identity fields come from the startup record:
| Hello field | Value |
|---|---|
host_id | startup.host_id |
transport_node_id | startup.transport_id |
capability_node_id | startup.node_id |
bundle_id, bundle_version | The startup manifest's bundle identity |
token | startup.token |
manifest_sha256 | manifest_digest(startup.manifest) |
Use read_message and write_message for the primary channel. Answer a Health challenge with the same nonce and your actual readiness. Invoke starts one unary operation; reply with one correlated Result containing either a payload or a typed error. Shutdown ends the loop and cleans up owned resources.
4. Keep the operation independently testable
def echo(payload: dict[str, object]) -> dict[str, object]:
"""Return schema-valid input unchanged without external effects."""
text = payload.get("text")
if not isinstance(text, str) or len(text) > 1024:
raise ValueError("Expected text of at most 1024 characters")
return {"text": text}
assert echo({"text": "Hello from the fabric."}) == {
"text": "Hello from the fabric."
}
The host performs schema validation, but provider validation still protects your own direct test and internal call paths. Translate a known invalid input into invalid_payload; do not disguise an unexpected bug as an input failure.
5. Add streaming when needed
Protocol 4 sends StreamInvoke on the control channel. Own a separate task running streams.execute_stream(startup, message, handler), continue answering health, and cancel/await that task on shutdown or control-channel loss. Use the managed streaming guide for a bidirectional handler and exact terminal/cleanup rules.
Complete example
The managed echo example puts startup, authentication, health, invocation and shutdown together in one child entrypoint.
6. Qualify before distribution
Test wrong startup identity and digest, invalid input/output, deadlines, overload, cancellation, lost connections and restart. Then qualify a real signed installation with the compatible host and Skulk™ reader. A direct function test does not establish package or Fabric readiness.
For a complete runnable public extension package available today, use the in-process echo tutorial. Managed packaging tooling and SDK distribution complete a separate delivery gate.