Files
JWeBot/docs/plugin-contract.md
T

154 lines
4.6 KiB
Markdown

# Plugin Contract
Status: authoritative for the `alpha 0.6.x` extension API.
## Scope
JWeBot extensions run for one configured, preselected WeChat group. They do not
discover groups, choose a destination, switch chats, or send messages directly.
The kernel owns:
- OCR event ordering and deduplication;
- the durable ledger and outboxes;
- acknowledgement ordering;
- model and approved network credentials;
- selected-group fingerprint verification;
- the GUI interaction lock and final WeChat delivery.
Extensions return structured intent. The kernel decides whether and when that
intent becomes a user-visible action.
## API Version
The current extension API is:
```text
api_version = "1"
```
An unsupported API version fails manifest validation before extension code is
loaded.
## Event Input
Extensions receive `jwebot_sdk.Event`, a normalized incoming event containing:
- event ID and observation timestamp;
- untrusted display sender label;
- bounded message text;
- confidence values;
- the current group fingerprint;
- mention flag and source metadata.
The group fingerprint is evidence for kernel delivery safety. It is not a group
selector and must not be used to discover or address another chat.
Display labels are conversational context only. They never grant permission.
## Result Output
An extension returns `jwebot_sdk.ExtensionResult`:
```python
ExtensionResult(
reply=ReplyPlan.text("hello"),
facts=(Fact(kind="topic", text="likes servers"),),
metadata={"source": "example"},
)
```
Limits:
- reply text: at most 900 characters;
- facts: at most 12;
- fact text: at most 120 characters;
- metadata: at most 16 short string entries.
`ReplyPlan.no_reply()` explicitly requests no visible response.
The extension cannot select a target group, draft GUI input, or press Send.
## Extension Types
### Command
Registers one or more reviewed slash-command namespaces. It may return one
reply plan and bounded facts.
### Enrichment
Consumes a normalized event off the reply-critical path. It may emit bounded
facts but cannot register commands or send replies by itself.
### Scheduled
Creates a scheduled intent that re-enters the kernel's ordered event path. It
never delivers directly.
Passive automatic reply extensions are not supported in API version 1.
## Manifest
Every extension has `plugin.toml`:
```toml
id = "hello-command"
author = "example"
description = "Return a local greeting"
help = ["/hello [name]"]
version = "1.0.0"
api_version = "1"
entrypoint = "hello_command:plugin"
type = "command"
[capabilities]
commands = ["/hello"]
storage = false
network_profiles = []
```
Unknown manifest keys and unknown capability names are rejected.
`author` is required, bounded, included in release metadata, and reviewed
against the extension's ownership directory.
Command plugins must declare bounded `description` and `help` metadata. The two
fields appear together; help entries begin with `/` and feed the
Kernel-generated `/功能列表`.
## Lifecycle
1. CI validates source, tests, manifest, API version, and capabilities.
2. Review approves the requested command and network namespaces.
3. CI builds an immutable artifact and canonical release record.
4. A reviewed publisher signs that exact release record with OpenSSH `sshsig`.
5. The target verifies the publisher, artifact digest, and API version.
6. The extension host re-verifies installed content and the publisher signature.
7. The extension host starts the approved release under resource limits.
8. The kernel registers approved manifests during startup and rejects conflicts.
9. The kernel freezes the extension catalog before runtime routing begins.
10. The kernel supplies a `SingleGroupContext`.
11. The extension registers only its declared behavior.
12. Invocation returns an `ExtensionResult` before its deadline.
13. The kernel validates and orders any resulting action.
The local Host, signed activation, and rollback contracts are implemented.
Provisioning and production enablement on production host remain separate work.
Static source validation rejects obvious access to processes, sockets, files,
dynamic execution, and Python object-introspection escape hatches. This is a CI
prefilter only. Production activation still requires a separately sandboxed
extension host with OS-enforced limits.
## Non-Negotiable Rules
- No GUI access.
- No direct WeChat send.
- No chat switching or group enumeration.
- No raw OCR frame or screenshot access.
- No direct ledger or SQLite access.
- No environment or secret reads.
- No shell, subprocess, SSH, or Docker access.
- No arbitrary network access.
- No background thread or process ownership.
- All behavior requires deterministic tests.