TNT/docs/MODULE_PROTOCOL.md
m1ngsama 2402c70d6f feat: add module foundation runtime
Add validated input buffering, shared JSON helpers, the tnt.module.v1 protocol helpers, and an opt-in external-process module runtime behind TNT_MODULE_PATHS.

Closes #52
2026-06-04 22:48:21 +08:00

143 lines
4.3 KiB
Markdown

# TNT Module Protocol
This document defines the compatibility contract for external TNT modules.
The first implementation target is external-process modules that exchange
JSON Lines with TNT over stdin/stdout. Keeping modules out of the server
address space makes the community extension surface easier to audit, restart,
rate-limit, and disable.
The protocol is intentionally separate from `messages.log` v1. TNT 1.x keeps
the persisted public history format stable. Module-generated content must
always provide a plain-text fallback that can be stored and rendered by older
or less capable clients.
TNT core should stay conservative: text-first, terminal-compatible, and easy
to deploy over plain SSH. Modules are the extension surface for personalized
workflow features, rich rendering, terminal-specific visuals, and other
experience experiments. Integrating a module with TNT must not make plain
terminal users lose the basic chat path.
## Compatibility
- Protocol version: `tnt.module.v1`
- Transport: UTF-8 JSON Lines
- Framing: one complete JSON object per line
- Direction: TNT sends events to module stdin; modules write responses to
stdout
- Error stream: modules should write diagnostics to stderr
- License: module protocol examples and official community modules should use
the same license as TNT unless a module states stricter terms
Modules are disabled unless `TNT_MODULE_PATHS` is set. The value is a
colon-separated list of module directories, each containing `tnt-module.json`
and the declared executable entrypoint.
TNT may add optional fields to existing messages. Modules must ignore unknown
fields. TNT must ignore unknown response fields unless the response type
explicitly requires them.
## Manifest
Each module directory should include `tnt-module.json`:
```json
{
"protocol": "tnt.module.v1",
"name": "echo",
"version": "0.1.0",
"description": "Echoes public messages for testing",
"entrypoint": "./echo-module.sh",
"permissions": ["message:read", "message:create"],
"events": ["message.created"]
}
```
Required fields:
- `protocol`: protocol compatibility string
- `name`: stable module id, lowercase ASCII, `a-z`, `0-9`, and `-`
- `version`: module version
- `entrypoint`: executable path relative to the manifest directory
- `permissions`: explicit capabilities requested by the module
- `events`: event names the module wants to receive
## Handshake
TNT starts a module process and writes a handshake event:
```json
{"type":"handshake","protocol":"tnt.module.v1","server":{"name":"tnt","version":"1.0.1"}}
```
The module should answer:
```json
{"type":"handshake.ok","protocol":"tnt.module.v1","module":{"name":"echo","version":"0.1.0"}}
```
If the module cannot run, it should answer:
```json
{"type":"error","code":"unsupported_protocol","message":"requires tnt.module.v2"}
```
## Events
Message-created event:
```json
{
"type": "message.created",
"message": {
"id": "local-00000001",
"timestamp": "2026-06-04T12:00:00Z",
"sender": "alice",
"kind": "text",
"plain_text": "hello",
"metadata": {}
}
}
```
The `plain_text` field is mandatory for every user-visible message. Future
rich content, images, and terminal-specific render hints must be represented
as optional metadata or attachment records with a plain-text fallback.
## Responses
Create a public message:
```json
{"type":"message.create","plain_text":"echo: hello"}
```
No-op acknowledgement:
```json
{"type":"event.ok"}
```
Module error:
```json
{"type":"error","code":"bad_request","message":"missing plain_text"}
```
## Security Rules
- Modules are untrusted external processes.
- TNT should enforce per-module permissions before delivering events or
accepting responses.
- TNT should cap stdout line length, startup time, event handling time, and
total queued output.
- TNT should disable a module after repeated invalid JSON, protocol errors, or
timeout failures.
- Modules must never receive private messages unless they request and are
granted an explicit private-message permission.
## Rendering Rules
Every module-created message must be renderable as plain text. Terminal image
protocols such as Kitty graphics or Sixel are optional renderer capabilities,
not message requirements. A module may provide attachment metadata later, but
TNT must be able to fall back to a link, filename, digest, or short label.