mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-10-23 02:01:26 +00:00
feat(docs): add initial drafts for SEP v1 manifest schema, example manifests, and protocol documentation
This commit is contained in:
4 files changed
+574
No files matched your search
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"schemaVersion": "1.0.0",
|
||||
"id": "io.meshchatx.extensions.sample-android-tool",
|
||||
"name": "Sample Android Tool Extension",
|
||||
"description": "Reference Android profile manifest draft for SEP v1 planning",
|
||||
"version": "0.1.0",
|
||||
"apiVersion": "1.0.0",
|
||||
"trustLevel": "first_party",
|
||||
"platformProfile": "android",
|
||||
"entrypoint": {
|
||||
"command": "meshchatx-android-extension-runtime",
|
||||
"args": ["sample_android_tool"],
|
||||
"workingDirectory": ".",
|
||||
"environment": {}
|
||||
},
|
||||
"permissions": ["events.subscribe", "messages.read", "notifications.create", "tools.register"],
|
||||
"events": {
|
||||
"subscribe": ["message.received", "peer.online"]
|
||||
},
|
||||
"health": {
|
||||
"startupTimeoutMs": 12000,
|
||||
"heartbeatIntervalMs": 20000,
|
||||
"unhealthyAfterMissedHeartbeats": 2
|
||||
},
|
||||
"limits": {
|
||||
"maxRequestBytes": 32768,
|
||||
"maxRequestsPerSecond": 30,
|
||||
"maxConcurrentRequests": 8
|
||||
},
|
||||
"android": {
|
||||
"runtimeMode": "packaged_module",
|
||||
"allowBackgroundExecution": false,
|
||||
"maxStartupTimeMs": 12000,
|
||||
"maxMemoryMb": 256
|
||||
},
|
||||
"compatibility": {
|
||||
"meshchatx": ">=4.5.0",
|
||||
"platforms": ["android-arm64"]
|
||||
},
|
||||
"signing": {
|
||||
"required": true,
|
||||
"keyId": "meshchatx-release-key",
|
||||
"signature": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"schemaVersion": "1.0.0",
|
||||
"id": "io.meshchatx.extensions.sample-tool",
|
||||
"name": "Sample Tool Extension",
|
||||
"description": "Reference manifest draft for SEP v1 planning",
|
||||
"version": "0.1.0",
|
||||
"apiVersion": "1.0.0",
|
||||
"trustLevel": "trusted_third_party",
|
||||
"platformProfile": "desktop",
|
||||
"entrypoint": {
|
||||
"command": "python3",
|
||||
"args": ["main.py"],
|
||||
"workingDirectory": ".",
|
||||
"environment": {
|
||||
"PYTHONUNBUFFERED": "1"
|
||||
}
|
||||
},
|
||||
"permissions": ["events.subscribe", "messages.read", "messages.send", "notifications.create", "tools.register"],
|
||||
"events": {
|
||||
"subscribe": ["message.received", "message.sent", "peer.online"]
|
||||
},
|
||||
"health": {
|
||||
"startupTimeoutMs": 10000,
|
||||
"heartbeatIntervalMs": 15000,
|
||||
"unhealthyAfterMissedHeartbeats": 3
|
||||
},
|
||||
"limits": {
|
||||
"maxRequestBytes": 65536,
|
||||
"maxRequestsPerSecond": 50,
|
||||
"maxConcurrentRequests": 16
|
||||
},
|
||||
"ui": {
|
||||
"toolPanels": [
|
||||
{
|
||||
"id": "sample-tool-panel",
|
||||
"title": "Sample Tool",
|
||||
"slot": "tools.page.primary"
|
||||
}
|
||||
]
|
||||
},
|
||||
"compatibility": {
|
||||
"meshchatx": ">=4.5.0",
|
||||
"platforms": ["linux-x64", "linux-arm64", "windows-x64"]
|
||||
},
|
||||
"signing": {
|
||||
"required": false,
|
||||
"keyId": "",
|
||||
"signature": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://meshchatx.com/schemas/sep_manifest.schema.json",
|
||||
"title": "MeshChatX Sidecar Extension Protocol Manifest",
|
||||
"description": "Draft schema for SEP v1 extension manifest files.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schemaVersion",
|
||||
"id",
|
||||
"name",
|
||||
"version",
|
||||
"apiVersion",
|
||||
"trustLevel",
|
||||
"entrypoint",
|
||||
"permissions",
|
||||
"health",
|
||||
"limits"
|
||||
],
|
||||
"properties": {
|
||||
"schemaVersion": {
|
||||
"type": "string",
|
||||
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)+$",
|
||||
"minLength": 3,
|
||||
"maxLength": 128
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 80
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"maxLength": 512
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"pattern": "^\\d+\\.\\d+\\.\\d+(?:[-+][A-Za-z0-9._-]+)?$"
|
||||
},
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
||||
},
|
||||
"trustLevel": {
|
||||
"type": "string",
|
||||
"enum": ["first_party", "trusted_third_party", "untrusted_local"]
|
||||
},
|
||||
"platformProfile": {
|
||||
"type": "string",
|
||||
"enum": ["desktop", "android"]
|
||||
},
|
||||
"entrypoint": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["command", "args"],
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 256
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"maxLength": 2048
|
||||
},
|
||||
"maxItems": 64
|
||||
},
|
||||
"workingDirectory": {
|
||||
"type": "string",
|
||||
"maxLength": 512
|
||||
},
|
||||
"environment": {
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z_][A-Z0-9_]*$"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"type": "string",
|
||||
"maxLength": 4096
|
||||
},
|
||||
"maxProperties": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"messages.read",
|
||||
"messages.send",
|
||||
"contacts.read",
|
||||
"events.subscribe",
|
||||
"tools.register",
|
||||
"notifications.create"
|
||||
]
|
||||
},
|
||||
"minItems": 0,
|
||||
"maxItems": 64,
|
||||
"uniqueItems": true
|
||||
},
|
||||
"events": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"subscribe": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+(?:\\.[a-z0-9]+)+$",
|
||||
"maxLength": 128
|
||||
},
|
||||
"maxItems": 256,
|
||||
"uniqueItems": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"health": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["startupTimeoutMs", "heartbeatIntervalMs", "unhealthyAfterMissedHeartbeats"],
|
||||
"properties": {
|
||||
"startupTimeoutMs": {
|
||||
"type": "integer",
|
||||
"minimum": 1000,
|
||||
"maximum": 120000
|
||||
},
|
||||
"heartbeatIntervalMs": {
|
||||
"type": "integer",
|
||||
"minimum": 1000,
|
||||
"maximum": 120000
|
||||
},
|
||||
"unhealthyAfterMissedHeartbeats": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 20
|
||||
}
|
||||
}
|
||||
},
|
||||
"limits": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["maxRequestBytes", "maxRequestsPerSecond", "maxConcurrentRequests"],
|
||||
"properties": {
|
||||
"maxRequestBytes": {
|
||||
"type": "integer",
|
||||
"minimum": 1024,
|
||||
"maximum": 4194304
|
||||
},
|
||||
"maxRequestsPerSecond": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 10000
|
||||
},
|
||||
"maxConcurrentRequests": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 1024
|
||||
}
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"toolPanels": {
|
||||
"type": "array",
|
||||
"maxItems": 32,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "title", "slot"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$",
|
||||
"maxLength": 128
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 80
|
||||
},
|
||||
"slot": {
|
||||
"type": "string",
|
||||
"enum": ["tools.page.primary", "tools.page.secondary", "tools.page.advanced"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"compatibility": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"meshchatx": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 64
|
||||
},
|
||||
"platforms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"linux-x64",
|
||||
"linux-arm64",
|
||||
"windows-x64",
|
||||
"windows-arm64",
|
||||
"macos-x64",
|
||||
"macos-arm64",
|
||||
"android-arm64"
|
||||
]
|
||||
},
|
||||
"uniqueItems": true,
|
||||
"maxItems": 16
|
||||
}
|
||||
}
|
||||
},
|
||||
"android": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["runtimeMode", "allowBackgroundExecution"],
|
||||
"properties": {
|
||||
"runtimeMode": {
|
||||
"type": "string",
|
||||
"enum": ["packaged_module", "approved_runtime"]
|
||||
},
|
||||
"allowBackgroundExecution": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"maxStartupTimeMs": {
|
||||
"type": "integer",
|
||||
"minimum": 1000,
|
||||
"maximum": 120000
|
||||
},
|
||||
"maxMemoryMb": {
|
||||
"type": "integer",
|
||||
"minimum": 16,
|
||||
"maximum": 2048
|
||||
}
|
||||
}
|
||||
},
|
||||
"signing": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["required", "keyId", "signature"],
|
||||
"properties": {
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"keyId": {
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"signature": {
|
||||
"type": "string",
|
||||
"maxLength": 8192
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"platformProfile": {
|
||||
"const": "android"
|
||||
}
|
||||
},
|
||||
"required": ["platformProfile"]
|
||||
},
|
||||
"then": {
|
||||
"required": ["android"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
# Sidecar Extension Protocol Draft (SEP v1)
|
||||
|
||||
This is a draft design for extension support in MeshChatX.
|
||||
|
||||
## Goals
|
||||
|
||||
- Keep extension failures isolated from core messaging runtime.
|
||||
- Provide a stable, versioned API for trusted and power-user automation.
|
||||
- Minimize direct access to Reticulum internals, local DB internals, and process memory.
|
||||
- Support repeatable testing, contract validation, and fuzzing from day one.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- No in-process plugin execution in v1.
|
||||
- No arbitrary UI code execution inside the main frontend runtime in v1.
|
||||
- No remote extension installation pipeline in v1.
|
||||
|
||||
## Runtime Model
|
||||
|
||||
- MeshChatX host discovers extension manifests from a local configured directory.
|
||||
- Each extension is started as a separate local process.
|
||||
- Host and extension communicate over a local JSON-RPC channel.
|
||||
- Host enforces capability checks on every privileged request.
|
||||
- Host applies lifecycle controls: startup timeout, health checks, backoff restart policy, and hard stop.
|
||||
|
||||
## Platform Profiles
|
||||
|
||||
SEP v1 uses a shared manifest with platform-specific runtime profiles.
|
||||
|
||||
### Desktop Profile (Linux, Windows, macOS)
|
||||
|
||||
- Sidecar process execution is allowed via manifest entrypoint.
|
||||
- Local IPC transport defaults to Unix domain socket or localhost loopback transport.
|
||||
- Full `entrypoint` command and args model applies.
|
||||
|
||||
### Android Profile
|
||||
|
||||
- Android support is planned as a constrained profile, not a full desktop-equivalent runtime.
|
||||
- Host may reject arbitrary executable launch and require approved runtimes or packaged modules.
|
||||
- Lifecycle contract must tolerate app pause/resume, background restrictions, and process reclaim.
|
||||
- Extensions should assume tighter CPU/memory quotas and more aggressive timeout enforcement.
|
||||
- Long-running background behavior should be explicit and policy-gated by host configuration.
|
||||
|
||||
## Trust Model
|
||||
|
||||
Three trust levels are defined in the manifest:
|
||||
|
||||
- `first_party`: shipped and maintained with MeshChatX.
|
||||
- `trusted_third_party`: explicitly approved by operator policy.
|
||||
- `untrusted_local`: local experiments with restrictive permissions and stricter limits.
|
||||
|
||||
Even for trusted extensions, API permissions are explicit and least-privilege.
|
||||
|
||||
## API Shape (Draft)
|
||||
|
||||
Host to extension:
|
||||
|
||||
- `sep.initialize`
|
||||
- `sep.event`
|
||||
- `sep.health`
|
||||
- `sep.shutdown`
|
||||
|
||||
Extension to host:
|
||||
|
||||
- `host.get_capabilities`
|
||||
- `host.messages.send`
|
||||
- `host.messages.list`
|
||||
- `host.contacts.list`
|
||||
- `host.ui.register_tool_panel`
|
||||
- `host.notifications.toast`
|
||||
|
||||
All methods are version-gated by protocol version and permission checks.
|
||||
|
||||
## Permission Model
|
||||
|
||||
Permissions are stable string capabilities. Initial candidates:
|
||||
|
||||
- `messages.read`
|
||||
- `messages.send`
|
||||
- `contacts.read`
|
||||
- `events.subscribe`
|
||||
- `tools.register`
|
||||
- `notifications.create`
|
||||
|
||||
Permissions should be audited in logs with extension id, method name, decision, and reason.
|
||||
|
||||
## UI Integration Constraints
|
||||
|
||||
v1 should avoid arbitrary extension-rendered code in core UI.
|
||||
|
||||
Allowed model:
|
||||
|
||||
- Extension registers metadata for approved host-owned UI slots.
|
||||
- MeshChatX renders UI components and invokes extension actions through host API.
|
||||
|
||||
This keeps UX consistent and lowers attack surface.
|
||||
|
||||
## Draft Manifest Contract
|
||||
|
||||
See `docs/sep_manifest.example.json` for an initial manifest layout and `docs/sep_manifest.schema.json` for the draft validation contract.
|
||||
|
||||
Required fields:
|
||||
|
||||
- `id`
|
||||
- `name`
|
||||
- `version`
|
||||
- `apiVersion`
|
||||
- `entrypoint`
|
||||
- `permissions`
|
||||
- `trustLevel`
|
||||
- `health`
|
||||
- `limits`
|
||||
|
||||
Optional platform section:
|
||||
|
||||
- `platformProfile`
|
||||
- `android` (required when `platformProfile` is `android`)
|
||||
|
||||
## Error Handling and Resilience
|
||||
|
||||
- Host returns structured errors with stable codes.
|
||||
- Extension failures do not crash host runtime.
|
||||
- Host tracks crash loops and disables extensions after policy threshold.
|
||||
- Startup and request timeouts are mandatory.
|
||||
|
||||
## Observability
|
||||
|
||||
- Per-extension log stream with bounded retention.
|
||||
- Metrics counters: starts, exits, restarts, failed RPC calls, denied permissions.
|
||||
- Optional debug tracing mode for protocol troubleshooting.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Contract Tests
|
||||
|
||||
- Validate manifest schema acceptance/rejection.
|
||||
- Validate capability enforcement per API method.
|
||||
- Validate version negotiation and downgrade behavior.
|
||||
|
||||
### Integration Tests
|
||||
|
||||
- Start host with a fixture extension process and assert lifecycle transitions.
|
||||
- Verify extension crash does not affect messaging flows.
|
||||
- Verify timeout and restart policies.
|
||||
- For Android profile, simulate pause/resume and process restart during active extension calls.
|
||||
|
||||
### End-to-End Tests
|
||||
|
||||
- Register tool panel metadata and validate host UI representation.
|
||||
- Send and receive sample messages through extension API path.
|
||||
- Validate Android profile fallback behavior when sidecar runtime is unavailable.
|
||||
|
||||
### Regression Tests
|
||||
|
||||
- Freeze behavior for error codes and permission-denied responses.
|
||||
- Snapshot protocol payloads for compatibility checks.
|
||||
|
||||
## Fuzzing Plan
|
||||
|
||||
### Message-Level Fuzzing
|
||||
|
||||
- Fuzz JSON-RPC payload structure, field types, nested depth, and size boundaries.
|
||||
- Fuzz invalid method names, duplicate ids, malformed params, and unknown capability requests.
|
||||
|
||||
### State Transition Fuzzing
|
||||
|
||||
- Randomize lifecycle sequences: initialize, event storm, health checks, shutdown, restart loops.
|
||||
- Inject extension process faults during active calls.
|
||||
|
||||
### Boundary Fuzzing
|
||||
|
||||
- Oversized payloads near configured limits.
|
||||
- High-rate event bursts to verify backpressure controls.
|
||||
- Invalid UTF-8 and control character edge cases in text fields.
|
||||
- Android-profile fuzzing for lifecycle churn: rapid foreground/background transitions and delayed heartbeat acknowledgements.
|
||||
|
||||
Fuzzing should run in CI with deterministic seeds plus rotating random seeds for nightly jobs.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Whether `untrusted_local` should be enabled by default.
|
||||
- Whether extension signatures are mandatory in v1 or policy-configurable.
|
||||
- Whether API tokens are needed for local RPC channel or if socket isolation is sufficient.
|
||||
- Whether Android should permit third-party runtime execution or only first-party packaged extensions in v1.
|
||||
|
||||
## Delivery Approach
|
||||
|
||||
1. Finalize manifest schema and protocol error model.
|
||||
2. Implement host-side schema validator and capability gate only.
|
||||
3. Build one first-party reference extension for test coverage.
|
||||
4. Wire CI contract tests and initial fuzz harness.
|
||||
5. Validate Android profile behavior with restricted lifecycle tests.
|
||||
6. Decide on public SDK timing after operational feedback.
|
||||
Reference in new issue
Block a user