// developer entry point
Build a Module or Provider
Start with an ordinary module. Add provider, Mesh, credential-delivery, or listening-post hooks only when the capability owns that behavior. This page maps each integration shape to the implemented daemon and SDK surfaces.
Choose the narrowest contract
| What the capability owns | Implement now | Do not add |
|---|---|---|
| A survey, exploit, or tool invocation against one target | The base Python HovelModule, Go Module, or Rust Module lifecycle |
Mesh or credential hooks merely because the tool uses a network, TLS, or target login |
| Planner-visible capability steps | Python step.* overrides or Go StepProvider |
A Rust step provider: Rust does not dispatch step.* today |
| Payload discovery, generation, reconnect, cleanup, and chunking | Go PayloadProvider; any language may still return installed-payload descriptors from normal execution |
A Python or Rust payload-provider RPC implementation: those SDKs do not dispatch that provider surface today |
| Provider-owned nodes, routes, beacons, tasks, streams, or listening posts | mesh.describe plus only the optional Mesh operations actually supported |
No-op topology, task, listener, or stream methods added only to mimic a full provider |
| Consumption or transformation of Hovel-managed workspace PKI material | credential.describe plus only the advertised runtime, files, encoding, or stamping hook |
A credential descriptor on an ordinary module that never receives assignment-bound material |
| An existing TCP or UDP client reused through a provider route | A daemon OpenMeshBridge call and the language SDK's authenticated bridge dial helper |
Mesh-provider hooks in the consumer merely to understand provider topology |
- base module
- one required extension
- daemon discovery and validation
- package and contract tests
The complete lifecycle, packaging format, test loop, and safety contract are in Module Development. The method-level message shapes are in the module wire protocol.
Credentials: ordinary input versus workspace PKI
Hovel uses the word credential for two different domains. A target
account created or observed during an assessment is chain evidence represented
by CredentialCapability. Workspace PKI is daemon-owned encrypted
custody for certificate generations, keys, trust, revocation, assignments, and
short-lived provider delivery. Never copy one model into the other. See
target credential evidence,
workspace PKI custody,
and TLS and Workspace PKI.
| Need | Current path | Implementation status |
|---|---|---|
| A module authenticates to a target with explicit operator or chain input | Declare normal requirements or consume chain capabilities in the operation's own contract | No workspace-PKI provider hook is required |
| A Mesh listener, task, stream, or bridge needs an active PKI assignment | Advertise strict slots and runtime; the daemon resolves selectors and delivers material before the Mesh method in the same provider process |
Implemented through the privileged daemon API for direct certificate DER, public-key SPKI, and private-key PKCS #8 projections |
| A provider consumes invocation-scoped protected files | Advertise files and implement credential.files |
The typed domain, SDK dispatch, validation, and bookkeeping exist; the current external Mesh selector does not initiate file delivery |
| A provider performs a bounded native encoding or stamps an artifact/deployment | Advertise a matching encoding schema or stamping capability and implement credential.encode or credential.stamp |
The contracts and provider dispatch exist; the daemon OpenAPI currently exposes list/inspect bookkeeping, not a production initiation method |
An ordinary non-Mesh execute call needs automatic workspace-PKI injection |
No general delivery path is wired to base module execution | Future integration point; do not document or depend on implicit injection |
A provider advertises only slots and modes it really consumes. In Go, implement
CredentialDescriber and only the small execution interfaces needed.
In Python and Rust, override only the corresponding methods; unsupported defaults
fail explicitly. If the same descriptor appears in both
credential.describe and MeshDescriptor.credentialDelivery,
Hovel requires their canonical digests to match. Start with the
Credential Provider Development
guide, then use the daemon API chapter
for the currently callable control-plane surface.
Consume a Mesh bridge as local TCP or UDP
Use a bridge when a working client already speaks to a host and port and the
Mesh provider can preserve TCP byte-stream or UDP datagram semantics. The control
plane chooses the provider, route or node, destination, and provider-defined
remote protocol. The separate localNetwork field selects
the daemon's tcp or udp loopback adapter. The consumer
does not need provider topology types.
Use RunMeshTask instead when the provider owns a native survey,
command, upload-and-execute, or loader operation. Use OpenMeshStream
and session APIs for provider-defined flows that should not become a local socket.
ICMP, raw IP, GRE, and custom protocols have no raw local adapter today. A
provider may still expose one of those remote protocols through a local TCP
byte stream or UDP datagram association when its stream contract defines that
mapping.
POST /hovel.daemon.v1.DaemonService/OpenMeshBridge
Content-Type: application/json
{
"moduleId": "lab-relay-mesh@v0.1.0",
"localNetwork": "tcp",
"request": {
"runId": "run-lab-1",
"nodeId": "relay-west",
"destinationHost": "192.0.2.25",
"destinationPort": 443,
"protocol": "tcp"
}
}
{
"operationId": "mesh-op-43",
"sessionId": "run-lab-1-session-1",
"localHost": "127.0.0.1",
"localPort": 43117,
"localNetwork": "tcp",
"localAddress": "127.0.0.1:43117",
"capability": "uL8wGvVukVynTng2uR6U4oqxm8v0cMxfR7VaJkW_1eM"
}
Use Go's
NewMeshBridgeEndpoint and DialMeshBridge,
Python's
MeshBridgeEndpoint and connect_mesh_bridge, or
Rust's
MeshBridgeEndpoint and TCP/UDP connect helpers. Open one bridge
per independent TCP connection or UDP peer association and close it through
CloseMeshBridge when the consumer is finished.
Separate a listening post from the provider adapter
A Mesh listener is the provider-reported listening post or rendezvous resource.
The module process handling mesh.listener.start is an adapter call:
Hovel shuts it down after the response. Therefore a provider-managed listener
that must survive the call needs durable provider-owned runtime state outside
that short-lived adapter process.
| Concern | Owner | Rule |
|---|---|---|
| Provider control adapter | Module process | Validates and forwards list/start/stop calls; it is not automatically a long-lived listener host |
| Listening-post data plane | Provider-owned embedded deployment, separate service, or external manager | Must preserve callbacks and state for the advertised lifecycle |
| Lifecycle identity | Caller and provider | Start and stop are idempotent for the stable caller-selected listenerId; daemon-wide identity is module ID plus listener ID |
| Configuration and credentials | Provider operation input | Write-only: never echo them in listener read models, logs, errors, or daemon operation records |
Choose deployment: separate when the listening post needs an
independent process, host, update cadence, failure boundary, or scale profile.
Choose management: external when Hovel should report but not control
its lifecycle. An embedded listener may share a durable provider
deployment, but it still cannot depend on one start-RPC subprocess remaining alive.
A routed stream is different: Hovel keeps the provider process while its returned
session is active. See Developing Mesh Providers.
Language starting points
| Language | Base module | Provider and bridge entry points | Current boundary |
|---|---|---|---|
| Python | HovelModule, run, serve |
Override supported Mesh/credential hooks; connect_mesh_bridge; API reference |
Supports step.*; no payload-provider RPC dispatch |
| Go | Module, Run, Serve |
Small optional Mesh/credential interfaces; DialMeshBridge; API reference |
Most complete provider surface, including steps and payload providers |
| Rust | Module, run, serve |
Override supported trait methods; TCP/UDP bridge helpers; API reference | Mesh and credential dispatch are implemented; no step.* or payload-provider RPC dispatch |
Completion checklist
- The module starts with valid, stable metadata and explicit chain/target requirements.
handshake,schema, and every advertised describe method are deterministic, offline, and side-effect free.- Stdout contains only framed module RPC; progress uses structured SDK logging.
- Only implemented provider methods are advertised, and unsupported optional methods fail explicitly.
- Workspace-PKI slots constrain purpose, consumer, profile, projection, form, size, and private-material policy; secret bytes, paths, capabilities, and references never enter logs or durable results.
- Mesh bridge consumers use the authenticated SDK helper and preserve TCP stream or UDP datagram semantics.
- Long-lived listening posts survive individual adapter calls; stable listener IDs make start/stop retries converge.
- Outputs, findings, artifacts, sessions, capabilities, and installed-payload descriptors use their intended ownership boundaries.
- Dangerous behavior is tagged and remains behind Hovel's persisted-plan, confirmation, and
--allow-dangeroussafeguards. - Direct logic tests and framed-RPC contract tests cover success, malformed input, unsupported hooks, failures, cleanup, and secret non-disclosure.
- The package manifest selects a real launcher, and
hovel module checkvalidates discovery without executing the module. - In-repository work finishes through the strongest available Task-backed slice check.