---
title: Manifest 参考
description: 理解每个 Lenso Module 公开的可序列化 ModuleManifest 合约。
---

`ModuleManifest` 是 Module 的纯数据合约。它描述 Host 与 Lenso Console 可见的
Business API Route、Runtime Function、Schedule、Event、Lifecycle Work、Console
Surface、依赖与 Capability。

可执行行为不在 Manifest 中。Linked Module 通过 `LinkedBinding` 附加行为；独立
运行的 Service 公开自己的 Provider API，并声明其提供的 Module。纯 Manifest
在两种拓扑中都保持可序列化。

## 最小 Manifest

```rust
use lenso::{
    ConsoleSurface, ConsoleSurfacePresentation, ModuleHttpMethod,
    ModuleHttpRoute, ModuleManifest, ModuleRequirement,
};

pub fn manifest() -> ModuleManifest {
    ModuleManifest::builder("acme/billing")
        .capabilities(vec![
            "billing.invoice.read".to_owned(),
            "billing.invoice.write".to_owned(),
        ])
        .requires(vec![
            ModuleRequirement::new("lenso/auth", "*").expect("valid requirement"),
        ])
        .http_routes(vec![ModuleHttpRoute {
            method: ModuleHttpMethod::Get,
            path: "/v1/billing/invoices".to_owned(),
            capability: Some("billing.invoice.read".to_owned()),
            display_name: Some("List invoices".to_owned()),
            story_title: Some("Billing invoices".to_owned()),
            operation: None,
        }])
        .console(vec![ConsoleSurface {
            name: "billing-invoices".to_owned(),
            label: "Invoices".to_owned(),
            route: "/billing/invoices".to_owned(),
            presentation: ConsoleSurfacePresentation::Esm {
                entry: "invoices".to_owned(),
            },
            icon: Some("receipt".to_owned()),
            required_capabilities: vec!["billing.invoice.read".to_owned()],
            navigation: None,
        }])
        .build()
}
```

## 字段

| 字段 | 用途 |
| --- | --- |
| `module_id` | 规范的完全限定 Module ID，例如 `lenso/auth` 或 `acme/billing`。 |
| `requires` | 必须先安装的完全限定 Module，并显式声明版本要求与可选的所需 Capability。 |
| `capabilities` | Route、Runtime Work 或 Console Page 可引用的点分隔权限名称。 |
| `http_routes` | Module 自有 HTTP Route Metadata。Linked Module 通过 Binding 挂载真实 Axum Route；Service-provided Module 保留相同声明。 |
| `runtime` | Runtime Function 与 Schedule 声明。Handler 位于加载源中，调度仍由 Host 持有。 |
| `events` | Event Handler 声明。Host 通过 Source Binding 注册并调用后备 Handler。 |
| `lifecycle` | Startup Check 与 Activation Job。Host 校验并调度这些条目，不向 Module 提供任意 Startup Callback。 |
| `console` | Declarative 或 ESM Console Surface。可执行 UI 在同一 Module Release 中按摘要绑定，不使用同源 Package Export。 |
| `story_display` | Timeline 与检查 Surface 使用的 Console Story Display Metadata。 |

## Builder 方法

```rust
ModuleManifest::builder("acme/billing")
    .requires(vec![
        ModuleRequirement::new("lenso/auth", "*").expect("valid requirement"),
    ])
    .capabilities(vec!["billing.invoice.read".to_owned()])
    .http_routes(vec![/* ModuleHttpRoute */])
    .runtime(/* RuntimeSurface */)
    .events(/* EventSurface */)
    .lifecycle(/* LifecycleSurface */)
    .console(vec![/* ConsoleSurface */])
    .story_display(vec![/* StoryDisplayDescriptor */])
    .build();
```

## Capability 命名

使用点分隔的小写名称：

```text
<module>.<resource>.<action>
```

推荐示例：

```text
billing.invoice.read
billing.invoice.write
support.tickets.assign
auth.session.revoke
```

避免 `BillingRead`、`billing/read` 或 `read_invoice`。Capability 名称不是点分隔
小写格式，或 Route、Console Permission 引用了 Manifest 未声明的 Capability
时，Manifest Lint 会发出警告。

## Route Metadata

`ModuleHttpRoute` 是 Metadata：

```rust
ModuleHttpRoute {
    method: ModuleHttpMethod::Post,
    path: "/v1/billing/invoices/{invoice_id}/void".to_owned(),
    capability: Some("billing.invoice.write".to_owned()),
    display_name: Some("Void invoice".to_owned()),
    story_title: Some("Invoice voided".to_owned()),
    operation: None,
}
```

保持这些值便于运维人员理解：

- `path` 应是 Host 可见路径；
- `capability` 应匹配 `capabilities` 中的值；
- `display_name` 应足够紧凑，适合 Timeline Node；
- Route 开始一段 Business Story 时，`story_title` 应自然可读。

## Runtime Schedule

`RuntimeSurface.schedules` 声明 Host 何时把 Runtime Function 加入队列：

```rust
ScheduledFunctionDeclaration {
    name: "send-daily-digest".to_owned(),
    function_name: "billing.invoice.send_digest.v1".to_owned(),
    cron: "0 8 * * MON-FRI".to_owned(),
    input: serde_json::json!({ "window": "previous_day" }),
}
```

Schedule 使用 5 字段 UTC Cron。该 Function 也必须存在于
`RuntimeSurface.functions`；Host 会校验关系、持久化 Schedule State，并在到期
时加入正常 `runtime.function_runs` 队列。

## Lint 类别

Host 通过 Module Metadata 公开 `manifest_lints`，Lenso Console 按以下类别分组：

| 类别 | 常见问题 |
| --- | --- |
| `module` | 缺少 Module 名称。 |
| `capability` | 命名错误，或引用了未声明的 Capability。 |
| `routes` | Method/Path 重复、缺少 Display Metadata，或 Remote Route 缺少 Capability。 |
| `runtime` | 缺少 Function 名称、Function 重复、Queue 名称错误或 Retry Policy 无效。 |
| `runtime.schedule` | 缺少 Schedule 名称、Cron 无效，或引用未知 Function。 |
| `events` | 缺少 Event 名称，或 Handler 名称重复。 |
| `lifecycle` | Startup Check 或 Activation Job 引用了未知 Runtime Function。 |
| `console` | Route 重复、Label 缺失、Artifact Shape 无效，或使用保留 Navigation Workspace ID。 |

把 `error` Lint 视为阻断项。除非页面明确说明某个本地实验可接受，否则把
`warning` 视为需要处理的 Operator Experience 问题。

## 何时修改 Manifest

当 Host 或 Console 需要新 Metadata 时修改 Manifest：

- 新的 Public Route 或 Route Capability；
- 新的 Business API Operation 或 Operation Capability；
- 新的 Module-owned Console Page；
- 新的 Runtime Function、Schedule 或 Event Handler；
- Lifecycle Startup Check 或 Activation Job；
- `auth` 等新依赖；
- 将被另一个 Surface 引用的新 Capability。

修改 Manifest Shape 后，运行 Owner-local Check，并打开
[Lenso Console](/docs/zh/runtime-console)检查 Host 可见结果。
